Claude Architect Lab
← All domains
Domain 2 · 18% of the exam

Tool Design & MCP Integration

What MCP actually standardizes, how tools differ from resources and prompts, what makes a tool schema good instead of merely functional, and how least-privilege scoping, authentication, and structured error handling combine into a design a reviewer would approve.

What MCP is, architecturally

The Model Context Protocol (MCP) is an open protocol that standardizes how an AI application connects to external tools, data, and systems. Before a shared protocol, every AI application that wanted to reach a given system — a ticketing tool, a database, an internal API — had to write its own bespoke integration for it. Multiply that by every app and every system, and you get an integration built once per pair, rebuilt from scratch each time.

MCP replaces that with one standard interface. A system's capabilities get exposed once, as an MCP server. Any MCP-compatible host application — an IDE, a chat client, a custom agent — can connect to that server through an embedded MCP client and immediately use whatever it exposes, without writing integration code specific to that system. The protocol is the reusable part; the server is where the actual integration work with a given external system lives.

That's the frame for everything else in this domain: MCP isn't a new capability Claude gains, it's a standard way of wiring existing capabilities — tools, data, and prompt templates — into whatever application is using Claude.

Key terms

Key terms for this domain

MCP
An open protocol that standardizes how an AI application connects to external tools, data, and systems, so each integration is built once against the protocol instead of once per application.
MCP host
The AI application itself, such as an IDE, a chat client, or a custom agent, that embeds one or more MCP clients and decides which servers, tools, and resources are available in a given session.
MCP client
The component inside a host that manages a single connection to one MCP server, handling the protocol messages that list and invoke that server's tools, resources, and prompts.
MCP server
A program that exposes a set of tools, resources, or prompts over the protocol, typically wrapping access to one external system such as a database, ticketing system, or file store.
Tool (MCP primitive)
An action the model can choose to invoke during a conversation, with a defined input schema and output shape, used when the task requires the model to decide when and how to act.
Resource (MCP primitive)
A piece of read-only context data, such as a file or a database record, that a client can attach to a conversation for the model to read, distinct from an action the model invokes on its own.
Prompt (MCP primitive)
A reusable, server-defined template for a particular task, exposed so a user or host can select it to start a workflow with the right framing already filled in.
Least privilege
Scoping each tool to only the specific action or data a task genuinely requires, rather than granting broad access that happens to cover it.

MCP client/server architecture

        ┌───────────────────────────┐
        │      Host application       │
        │  (IDE, chat app, agent, ...)  │
        └──────────────┬────────────┘
                        │  embeds
                        ▼
        ┌───────────────────────────┐
        │   MCP client(s)               │
        │   one per connected server     │
        └───────┬───────────┬───────┘
                 │             │
                 ▼             ▼
       ┌──────────────┐ ┌──────────────┐
       │  MCP server A   │ │  MCP server B   │
       │  tools /          │ │  tools /          │
       │  resources /       │ │  resources /       │
       │  prompts            │ │  prompts            │
       └───────┬──────┘ └───────┬──────┘
                ▼                  ▼
       ┌──────────────┐ ┌──────────────┐
       │ External system  │ │ External system  │
       │ e.g. ticketing API│ │ e.g. internal DB    │
       └──────────────┘ └──────────────┘

One MCP server per external system, reusable by any number of hosts. The host never talks to the external system directly — the server owns that connection, including its credentials.

Tools vs. resources vs. prompts

These are the three things an MCP server can expose, and the exam consistently tests whether you can tell them apart — not by what they contain, but by who controls when they're used.

A tool is model-controlled: the model itself decides, mid-conversation, whether to call it and with what input, the same way it decides to call any tool today. A resource is application-controlled: it's read-only context — a file, a database row, a document — that the host or client decides to attach to the conversation, not something the model reaches out and invokes on its own. A prompt is user-controlled: a reusable template the server defines, that a user (or the host, on the user's behalf) explicitly selects to kick off a specific workflow, typically surfaced as something like a menu item or slash command.

The common exam trap is treating all three as interchangeable "things the model can use." A resource sitting in a server's capability list isn't something the model calls the way it calls a tool — it has to actually be attached to the conversation first, by the application, before the model ever sees it. And a prompt template isn't the system prompt; it's a reusable, selectable starting point defined by the server, invoked deliberately by a person, not autonomously by the model.

A well-scoped MCP tool definition

typescript
// A single, narrowly scoped MCP tool — one action, one clear purpose.
const getOrderStatusTool = {
  name: "get_order_status",
  description:
    "Look up the current status of a single customer order by its order ID. " +
    "Returns the order's status, last-updated timestamp, and carrier tracking " +
    "number if shipped. Read-only — does not modify the order.",
  inputSchema: {
    type: "object",
    properties: {
      orderId: {
        type: "string",
        description: "The order ID exactly as shown to the customer, e.g. \"ORD-48213\".",
      },
    },
    required: ["orderId"],
    additionalProperties: false,
  },
};

async function handleGetOrderStatus(input: { orderId: string }) {
  const order = await ordersApi.find(input.orderId);

  if (!order) {
    // A structured, typed error — not a thrown exception — so the model can
    // reason about what happened and decide what to do next (ask the
    // customer to double-check the ID, rather than the whole turn failing
    // with an opaque message).
    return {
      isError: true,
      error: {
        code: "not_found",
        message: `No order found with ID ${input.orderId}.`,
      },
    };
  }

  return {
    isError: false,
    status: order.status,
    lastUpdated: order.lastUpdatedAt,
    trackingNumber: order.trackingNumber ?? null,
  };
}

Illustrative lesson content, not a runnable server — no actual mcp/ infrastructure lives in this repo. The shape to notice: a narrow input schema, a description precise enough for the model to use the tool correctly, and a structured error instead of a thrown exception.

Certification Mode

What the exam is actually testing here

The exam won't ask you to define MCP in the abstract. It gives you a scenario — a company's internal system, a proposed tool list, a proposed schema — and tests whether you can:

  • Tell a tool from a resource from a prompt by who controls its invocation, not by what data it happens to carry.
  • Spot an input schema that's too vague or too broad for the model to fill in reliably, versus one that's narrow and well-typed.
  • Recognize least-privilege scoping — several narrow tools beating one tool that "can do anything" — even when the broad option looks simpler to build.
  • Distinguish a structured, recoverable error from an opaque thrown failure, and explain why the difference matters to an agent loop.

The scenario below is built exactly in that shape — work through it before checking the answer.

Scenario: shipment tracking and reroute integration

A logistics company wants Claude, used from both an internal support console and an internal Slack bot, to answer questions using their shipment-tracking system and carrier-rates database, and to submit a shipment reroute request when a delivery is delayed.

Requirements: read shipment status, read carrier rates, and submit a reroute request — all from two separately built internal applications.

Which architecture should you choose?

Permissions and tool boundaries

Least privilege applied to tools means: a tool should be able to do exactly what its task needs, and nothing else. One tool called something like "run_admin_action" that accepts a freeform action string and can create, modify, or delete any record in a system is worse than three separate tools scoped to "look up a customer," "look up recent orders," and "update a shipping address" — even though the broad tool looks simpler to build and more "future-proof."

The reason is blast radius. If the model misfires — misreads an ambiguous instruction, gets manipulated by something like injected text inside a retrieved document — a narrow tool bounds the damage to exactly what that one tool can do. A broad tool bounds the damage to almost anything. This is also why "give the model as many tools as possible" is a misconception rather than a strength: a large, overlapping tool list doesn't just carry more security exposure, it also makes tool selection harder for the model, which shows up as more wrong or ambiguous calls, not more capability.

Tool boundary: one broad tool vs. several narrow ones

  Broad, over-privileged design         Narrow, least-privilege design
  ┌─────────────────────────────┐   ┌────────────────────────────┐
  │  run_admin_action(action: str) │   │  get_customer_by_id(id)      │
  │                                   │   └────────────────────────────┘
  │  → create, modify, or delete       │   ┌────────────────────────────┐
  │     ANY record in ANY system        │   │  get_recent_orders(id)        │
  └─────────────────────────────┘   └────────────────────────────┘
                                        ┌────────────────────────────┐
   one tool call, misused, can            │  update_shipping_address(       │
   touch almost anything                  │    id, newAddress)               │
                                        └────────────────────────────┘

                                     one misused call can only do the
                                     one bounded thing that tool allows

Same underlying capability, two very different blast radii if a call goes wrong.

Error handling: structured, not opaque

A tool that throws a generic, unstructured failure gives the model nothing to act on — it knows that something went wrong, not what, and can't tell an invalid input from a permissions problem from a transient outage. A well-designed tool returns a structured error instead: a typed code (invalid_input, not_found, rate_limited, unavailable) plus a clear message, so the model can reason about the right next step — correct the input and retry, tell the user something specific, wait and retry a transient failure, or escalate.

This is the same principle as a narrow input schema, applied to the output side: predictability. A tool the model can't parse reliably on success is a design flaw; a tool the model can't reason about on failure is the same flaw showing up on the other path through the code.

Exam trap

Exam trap: tools, resources, and prompts blur together

The most common wrong answer in this domain treats "tool," "resource," and "prompt" as roughly the same thing — three names for "content an MCP server can expose." They aren't interchangeable, and the exam tests the distinction directly: a tool is invoked by the model's own decision mid-conversation; a resource is read-only context that the application/client decides to attach; a prompt is a reusable template a user explicitly selects to start a workflow. Mixing these up shows up as answers where "the model calls the resource" or "the tool gets attached to context" — both wrong for the same underlying reason.

A second version of the same trap, specific to tool design: assuming more tools, or a single broader tool, means more capability. A large or poorly scoped tool list tends to produce more wrong tool calls, not fewer, and a single "do anything" tool trades a small implementation convenience for a large increase in what a single mistake can do.

Mini lab

Mini lab: design a tool schema

Using the shipment scenario above, design one of its three tools by hand before moving to Domain 3.

  1. Pick request_reroute and write its full input schema: field names, types, which fields are required, and one sentence per field explaining what the model should put there.
  2. Write the tool's description exactly as the model would see it — precise enough that a model reading only the name, description, and schema could call it correctly without additional examples.
  3. List at least two ways this tool could be scoped too broadly (e.g. accepting any order ID regardless of customer, or allowing an unbounded free-text reason field), and narrow the schema to close each one.
  4. Write the structured error shape this tool should return for two distinct failure cases — an invalid or unknown order ID, and the carrier API being temporarily unavailable — and explain what the model should do differently in each case.
Practice — 20 questions