D2.3 · Domain 2 · Tool Design + Integration · 18% of CCA-F

Model Context Protocol.

8 min read·10 sections·Tier A

MCP is a communication standard that lets Claude access pre-built tools, resources, and prompts from specialized servers without you writing integration code. Connect to a GitHub MCP server instead of writing GitHub API tools yourself. Servers are configured in .mcp.json (project) or ~/.claude.json (user). MCP spec + Claude SDK

Infrastructure standardDomain 23 primitives
Model Context Protocol, hero illustration featuring Loop mascot in a warm gallery scene.
Domain D2Tool Design + Integration · 18%
On this page
01 · Summary

TLDR

MCP is a communication standard that lets Claude access pre-built tools, resources, and prompts from specialized servers without you writing integration code. Connect to a GitHub MCP server instead of writing GitHub API tools yourself. Servers are configured in .mcp.json (project) or ~/.claude.json (user). MCP spec + Claude SDK

3
Primitives
2
Config levels
3
Transports
D2
Exam domain
18+
Pre-built sets
02 · Definition

What it is

Model Context Protocol (MCP) is a standardized interface for connecting Claude to external systems: files, APIs, databases, web services. Think of it as the USB-C of AI integrations. Instead of each application building custom tools, MCP defines a protocol that any tool provider implements once, and any MCP-enabled client uses immediately. A .mcp.json configuration file lists servers; each server exposes tools, resources, and prompts that Claude can invoke.

Two server categories exist: installed (community-maintained or custom, running locally) and cloud-hosted (managed by the vendor, authenticated via env vars). A local server might expose Grep, Read, Bash in the same process as your app. A cloud server (e.g. GitHub MCP) runs on the vendor's infra and authenticates via your token. Both appear in Claude's tool list identically; the distinction is who maintains the code.

The architecture is asymmetric: Claude (the client) sends tool_use blocks; the MCP server receives the request, executes the tool, and returns a result. Claude never talks directly to an external API, the server acts as a proxy. This isolation prevents token leakage (Claude never sees raw credentials), enables caching (server-side response cache), and allows request validation (the server can reject malformed calls before forwarding).

Production failures stem from stale `.mcp.json` configuration, mismatched env vars, vague tool descriptions inherited from old integrations, and forgetting that the server owns error handling. The JSON file is version-controlled; if a teammate updates GitHub's API and doesn't re-run the MCP setup, their tools silently fail. Errors must bubble to Claude as structured data, not be swallowed by the server.

03 · Mechanics

How it works

At startup, your app loads .mcp.json. Each entry specifies a server: installed (local executable) or cloud (managed remote). Installed servers are spawned as child processes; cloud servers are contacted via HTTP with credential headers. Each server is interrogated: "what tools do you expose?" The server responds with names, descriptions, and JSON schemas. All tools merge into a single namespace; Claude sees them as a unified set.

When Claude's loop produces a tool_use block (e.g. {name: "Grep", input: {query: "..."}}), the MCP framework routes the request to the server that owns that tool. The server's code runs: validates input, executes the operation, returns a result. The result is wrapped in a tool_result block and appended to the message list. Claude never knows where the tool ran or what authentication was used.

Each server can expose resources: catalogs of data Claude can query without invoking a tool. A GitHub MCP server might expose a resource listing all open issues; Claude inspects that catalog to decide which tools to call. Resources reduce exploratory tool calls: instead of calling list_issues 20 times, Claude reads the resource once and calls targeted tools. Resources are read-only caches; tools are the write path.

Error handling flows back to Claude via tool_result. If the server hits an API error (timeout, 403, invalid request), it returns a structured message in content: {"error": "github_api_timeout", "hint": "retry after 30s"}. Claude reads the error and adjusts. Silent error suppression (returning empty as success) is the #1 production failure: Claude doesn't know the tool failed and re-requests indefinitely.

Model Context Protocol mechanics, painterly diagram featuring Loop mascot.
04 · In production

Where you'll see it

Team-shared GitHub integration

Project uses GitHub MCP server: PR queries, issue lists, code search, all pre-built. Configure in .mcp.json (committed to repo). Team members run claude mcp sync once. Replaces hand-rolled tool definitions and auth wrappers; tokens come from team env vars.

Custom MCP server for legacy billing

Company has a Unix-only billing API with no SDK. Build a Python MCP server wrapping the API; expose via stdio in .mcp.json. Agent calls standard MCP tools; the server hides the legacy weirdness. New team members inherit the integration automatically.

Resources for upfront schema discovery

Database MCP exposes a resources endpoint listing all tables and columns. Agent reads the resource ONCE at session start instead of calling list_tables / describe_table N times. Cuts exploratory tool calls from 8 → 0 per session.

05 · Implementation

Code examples

.mcp.json, team-shared MCP configuration
{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "command": "uvx",
      "args": ["mcp-server-postgres", "--readonly"],
      "env": {
        "DATABASE_URL": "${DATABASE_URL}"
      }
    },
    "billing-legacy": {
      "command": "python3",
      "args": ["./mcp-servers/billing.py"],
      "env": {
        "BILLING_API_HOST": "${BILLING_API_HOST}",
        "BILLING_API_KEY": "${BILLING_API_KEY}"
      }
    }
  }
}
Env-var expansion (${VAR}) keeps secrets out of the committed file. Team members run claude mcp sync to install all servers consistently.
06 · Distractor patterns

Looks right, isn't

Each row pairs a plausible-looking pattern with the failure it actually creates. These are the shapes exam distractors are built from.

Looks right

MCP and tool-use are competing approaches; pick one.

Actually wrong

MCP is infrastructure (who provides tools); tool-use is the mechanism (Claude calls them). They're complementary, every MCP tool fires through the tool-use protocol.

Looks right

Hardcode API tokens in .mcp.json so the team has a single source of truth.

Actually wrong

.mcp.json is committed to git. Hardcoded secrets leak. Use ${ENV_VAR} expansion; secrets stay in CI/CD or local .env.local files.

Looks right

Expose 30 tools in one MCP server for completeness.

Actually wrong

Same 18-tool degradation applies. Scope MCP servers to focused domains (one per service). Use 'resources' to expose data upfront and avoid forcing N exploratory tool calls.

Looks right

MCP servers run inside Claude's process, so they can read in-memory state from the host app.

Actually wrong

MCP servers run as separate processes (stdio child processes for local servers, remote HTTP for cloud). The protocol is JSON-RPC over a stream; there's no shared memory. Anything the server needs must come through tool inputs or env vars, this isolation is the security boundary, not a bug.

Looks right

An MCP server is a one-time setup, just install it and forget.

Actually wrong

MCP servers have a capability handshake on every client connection: tools, resources, and prompts are re-fetched. If you upgrade the server (new tool added) without restarting clients, those clients never see the new tool. Restart the Claude Code session or run claude mcp sync after server-side changes.

07 · Compare

Side-by-side

AspectMCP serverCustom in-app toolsSDK built-ins
Setup effortLow (config in .mcp.json)Medium (write tool defs in code)Zero (Read/Edit/Bash)
ReusabilityHigh (any Claude client)Per-appBuilt into Claude Code
Best forStandard integrationsBespoke business logicFile ops + shell
AuthEnv-var expansionPer-app configInherits user permissions
Transportstdio (child process) or HTTP/SSE (remote)In-process function callsIn-process; OS-level for Bash
Failure isolationServer crash isolated; client sees tool_errorCrash takes down the whole agentBash failures bubble; Read/Edit are safe
08 · When to use

Decision tree

01

Is this integration with a known service (GitHub, Slack, Postgres, etc.)?

YesSearch for an existing MCP server. Almost always saves work over a custom build.
NoGo to next question.
02

Does the team need to share this integration?

YesPut config in .mcp.json (project root, committed). Use ${ENV_VAR} for secrets.
NoUse ~/.claude.json (personal, not committed).
03

Will the agent need exploratory schema/data lookups?

YesExpose a 'resources' endpoint on your MCP server. Read once, save N exploratory tool calls.
NoTools alone are sufficient.
04

Is the integration internet-facing (third-party API) or internal (intranet/local)?

YesPrefer HTTP/SSE transport with a hosted MCP server, lets ops control rate limits, observability, and rotation.
NoUse stdio transport (local child process). Lower latency and simpler for desktop / dev workflows.
05

Will multiple Claude Code users hit the same backend simultaneously?

YesRun a shared HTTP MCP server behind a load balancer. stdio servers are per-process and won't pool connections, leading to resource exhaustion at scale.
Nostdio is fine; one process per session.
09 · On the exam

Question patterns

Model Context Protocol exam trap, painterly cautionary scene featuring Loop mascot.

36 V2 questions wired to this concept. Tap an answer to check it instantly — you'll see whether it's right and why — then expand the full breakdown for the mental model and all four rationales.

You add a new MCP server to .mcp.json but Claude Code does not see its tools. What did you forget?

Tap your answer to check it.

Two MCP servers expose tools with the same name (e.g. Read). What happens?

Tap your answer to check it.

A cloud MCP server returns {error: "rate_limited"}. Your agent retries 5 times and exhausts budget. Better approach?

Tap your answer to check it.

You hardcoded a GitHub token in .mcp.json. A teammate clones the repo and your token leaks. Fix?

Tap your answer to check it.

An MCP server resource lists 1000 items. Claude calls a tool 1000 times, one per item. What is the architectural fix?

Tap your answer to check it.

Your custom MCP server crashes when Claude calls a tool with malformed JSON. What is the correct error-handling pattern?

Tap your answer to check it.

30 additional questions for this concept live in the practice pillar. Take a mock exam ↗

10 · FAQ

Frequently asked

What's the difference between MCP `resources` and `tools`?
Resources are read-only data the model browses; tools are actions the model invokes. Resources have URIs (billing://schema); tools have JSON-Schema inputs. Use resources for catalogs/schemas/manifests; use tools for queries and mutations.
Can two MCP servers expose tools with the same name?
Yes, but Claude Code prefixes them: github__create_issue vs gitlab__create_issue if both expose create_issue. Name collisions are namespaced, so there's no hidden override. Verify via claude mcp list to see the resolved tool names.
How does authentication work for cloud MCP servers?
Most use OAuth 2.1 with PKCE or bearer tokens via env vars. The server ingests the token at connection time (e.g., GITHUB_PERSONAL_ACCESS_TOKEN) and uses it for downstream API calls. Claude never sees the token, that's the whole point of the proxy architecture.
Can I run an MCP server in my Convex / Vercel deployment?
Yes for HTTP MCP servers, no for stdio. Convex / Vercel functions are stateless HTTP endpoints, perfect for transport: "http" MCP servers. Stdio assumes a long-lived child process, which serverless platforms don't support.
What happens when an MCP server crashes mid-session?
The MCP framework returns a structured error to Claude (tool_error block) and attempts reconnection on the next tool call. Claude sees the error and can adjust strategy. Without graceful error handling on your side, repeated crashes look like "the tool just stopped working."
How do I scope MCP servers to specific projects?
Place .mcp.json at the project root and Claude Code only loads it for that project. Personal servers go in ~/.claude.json and apply globally. Mixing scopes (project + personal both define github) merges with project taking precedence.
Are MCP tool calls cached by prompt caching?
The tool definitions advertised by the server can be cached as part of the tools array (mark with cache_control). The tool results are not cached, they're dynamic per-call. MCP servers can implement their own response cache, separate from prompt caching.
What's the cost difference between an MCP tool and a custom tool?
Identical from Claude's API billing perspective, both are tool calls. The cost difference is engineering time (MCP saves it via reuse) and hosting cost (HTTP MCP servers add infra). Stdio MCP servers are free to run.
Can MCP servers receive context (e.g., the user's request) for better tool routing?
No, by design. Tools are stateless, the server only sees the input dict for the call it's executing. If you need request-aware behavior, embed the context in the tool input. The model's job is to pass the right context; the server's job is to execute deterministically.
How do I debug 'tool not appearing in the agent's tool list'?
Three checks: (1) claude mcp list shows the server is connected, (2) the server's capability handshake completed (look for tool definitions in the connect log), (3) the .mcp.json is at project root, not buried in a subdirectory. Restart the Claude Code session after .mcp.json edits, the file is read at startup.
11 · Practice with AI

Work this with your AI

Work this concept hands-on with Claude Code, Codex, or claude.ai. Copy a prompt, paste it into your assistant, and practise in tandem. Each one keeps you active (explain it back, get drilled, or build) rather than just reading.

  • Drill it like the exam (scenario MCQs)
    Practice in the exam's scenario-MCQ format with trap awareness.
  • Explain it back (Feynman)
    Build durable, transferable understanding of a concept you can half-state.
  • Test me, adapting the difficulty
    Active recall practice on a concept you think you know.
  • Check my prerequisites first
    Before studying a concept that keeps not sticking.
  • Find the high-leverage 20%
    When a domain feels too big and you are short on time.
Self-check

Test yourself

Three diagnostic questions on this primitive. Reveal each answer when you have a guess. Want a full 60-question mock? Open the mock hub →

Q1You add a new MCP server to `.mcp.json` but Claude Code doesn't see its tools. What did you forget?
Restart the Claude Code session. The framework caches the tool list at startup. Changes to .mcp.json require a restart, or a manual mcp restart command in newer versions.
Q2Two MCP servers expose tools with the same name (`Read`). What happens?
The config is invalid. Tool names must be globally unique across all MCP servers. Prefix tools by server name (GithubRead, FileRead) or disable one of the conflicting servers.
Q3A cloud MCP server returns `{error: "rate_limited"}`. Your agent retries 5 times and exhausts budget. Better approach?
Server should return structured rate-limit info: {error: "rate_limited", retry_after: 30}. Your harness reads this and waits before retrying. Don't hammer; respect the hint.
Last reviewed: 2026-05-04·Refresh cadence: monthly
D2.3 · D2 · Tool Design + Integration

Model Context Protocol, complete.

You've covered the full ten-section breakdown for this primitive, definition, mechanics, code, false positives, comparison, decision tree, exam patterns, and FAQ. One technical primitive down on the path to CCA-F.

More platforms →