Connecting tools with MCP
Customizing agents · topic customizing-agents/mcp
The Model Context Protocol is a standard way to expose tools and data to an agent through a server the agent's client connects to. This topic covers the server and client roles, the transports that connect them, the primitives a server can offer beyond tools, when a plain command-line tool is the better choice, what a tool costs in tokens, and the security consequences of connecting one.
Concepts
- Server
- The process that exposes tools, resources and prompts over the protocol. A server wraps something, a database, an API, a file system, a browser, and describes each tool with a name, a purpose and a parameter schema the model can read. Write or install a server once and any compliant agent can use it, which is the protocol's point. glossary
- Client
- The side inside the agent application that connects to servers, lists the tools they offer, passes those descriptions to the model, executes the model's tool calls against the right server and returns results. The client is where connection configuration, approval prompts and permission checks live, so it is where a user controls what a server may do. glossary
- Transport
- How client and server exchange messages. A local server usually runs as a child process talking over standard input and output; a remote one is reached over HTTP, often with streaming. The transport decides where the server's code runs and what credentials it holds, which makes it a security decision as much as a plumbing one. glossary
- MCP primitives
- The kinds of things a server can offer besides tools. Resources are data the client can read into context, such as files or records, each with a URI. Prompts are reusable templates the user picks by name. Sampling lets a server ask the client's model to complete text, so the server needs no model access of its own. Roots tell a server which directories it may work in. Most servers only use tools, and the others matter only when your client supports them. glossary
- MCP vs CLI
- An agent can often reach the same system through a protocol server or by running a command-line tool it already knows. A server gives typed tools, discoverability and a stable interface across agents. A CLI is already installed, costs no tool descriptions in context and is easy to audit. Prefer the CLI when it exists and is good; add a server when the interface needs shaping. glossary
- Tool cost
- Every connected tool adds its description to the context on every turn, and every call adds its result. A server with dozens of tools can consume a large share of the window before the task starts, and verbose results crowd out the conversation. Connect only the servers a project needs, prefer servers with few well-described tools, and watch result sizes. glossary
- MCP security
- Connecting a server extends the agent's blast radius to everything the server can reach. Risks include servers from untrusted sources, tool descriptions that carry injected instructions, tools that return attacker-controlled content, and tools that can send data outward. Vet the source, run with least privilege, approve risky tools per call and review what leaves. Connect a server with your own identity, never with a shared service account, so it can do only what you may do and its actions trace back to you. glossary
Links
- Builds on: Project instructions, What an agent is
- Leads to: Guardrails and production
- Competencies drawing on it: Runs an agent in production with guardrails, Connects an agent to tools and data safely
Lessons
- Connecting an agent to your systems with MCP (explanation)
- Connecting your first tool server (tutorial)
- Hardening a tool connection (tutorial)
- Measuring what a tool server costs (tutorial)
Your reference
Each lesson above adds its takeaways and its example here once you finish it. Your reference lists every lesson you have finished.
Connecting an agent to your systems with MCP
Unlocks when you finish Connecting an agent to your systems with MCP.
Takeaways
- Every tool call through a remote server should run as the person using the agent, through an interactive login with a short-lived token, so the user's permissions bound the agent and the audit log names a person.
- Inventory a server by read, write and can't before connecting it. The can't list bounds the worst case, and the description count is a context cost you pay on every turn.
- The server's rate limit protects the platform. A write cap in a proxy and confirmation before each write protect your data, and version history only makes recovery possible.
- The five-rule prompt block stops accidents and naive attacks. It can fail, so it is one layer and never the only one.
- Rate the residual risks for your own context, read every tool description you install, and prefer a CLI with command-pattern permissions when one exists and does the job.
Example
Count the inventory · open in the lesson
What does this print?
reads = [t for t in TOOLS if t[1] == "read"]writes = [t for t in TOOLS if t[1] == "write"]print(f"{len(reads)} read, {len(writes)} write, {len(CANNOT)} cannot")Prints: 8 read, 7 write, 5 cannot (verified in CI from site/examples/customizing-agents/mcp/inventory.py)
Connecting your first tool server
Unlocks when you finish Connecting your first tool server.
Takeaways
- A local server runs over stdio as a child process of the agent. The client asks
tools/listonce and sendstools/callper use, and a refusal comes back as a result withisErrorset. - Scope the server before it runs. The reference file-system server allows the roots its client sends, or its command-line directories when the client sends none, and Claude Code's roots are the directory you started it in plus what you add with
--add-dir. Roots are deprecated in MCP revision 2026-07-28. Give the copy as the argument too, so a client that stops sending roots still leaves the server on the copy. Start the agent inside the copy, and readlist_allowed_directoriesfirst. - In Claude Code,
claude mcp add <name> -- <command>adds a server at local scope by default, and a project-scoped.mcp.jsonserver is approved by you before its first use in an interactive session. - The first task for a new server is one whose answer you know. Read the transcript for the tool name, the arguments and the bucket, read or write, of every call.
- A remote server over Streamable HTTP does the same work with code you didn't start, and it holds an OAuth token issued for that one server, which the specification wants short-lived.
Example
List the tools · open in the lesson
Run list_tools.py in the fixture directory, and compare with the output below.
server = client.start(client.HANDBOOK)response = client.request(server, "tools/list")for tool in response["result"]["tools"]: print(tool["name"])Prints the lines below (verified in CI from site/examples/customizing-agents/mcp-first-server/list_tools.py)
list_allowed_directories list_directory read_text_file
Hardening a tool connection
Unlocks when you finish Hardening a tool connection.
Takeaways
- Give a tool connection the smallest token that does the task, with a short life. The specification asks for short-lived tokens so a leaked one does little, and a scope without a send removes the send for every model and every prompt.
- Turn on a log of tool calls with their arguments and outcomes, keep it outside the folder the agent can reach, and read it in the server's first weeks. The specification asks clients to log tool usage for audit.
- A planted instruction shows up in the log as a call the task didn't need. The line tells you which control acted: the token, the folder, or nothing, when the call was allowed.
- Claude Code v2.1.199 or later asks before every call of a tool its server marks with
anthropic/requiresUserInteraction, and no permission mode approves it for you. A hostile server can leave that flag off. The token is checked by the service, whatever the server declares. - Start the agent inside the folder it may touch, in Manual mode. There it asks before every edit, and a change above that folder needs your explicit permission. A server that takes no roots holds the folder you passed it, whatever the client sends.
Example
Predict the three tokens · open in the lesson
What does this print? The server checks the expiry first and the scope second.
for label, token in TOKENS: session = client.Session(token) text, is_error = session.call("share_note", {"name": "retro.md", "to": "archive@example.com"}) session.close() print(f"{label}: {text}")Prints the lines below (verified in CI from site/examples/customizing-agents/mcp-hardening/scopes.py)
read+share, 720 hours: Sent retro.md to archive@example.com read, 1 hour: Refused: token scope is read, and share_note needs share read, 0 hours: Refused: token expired
Measuring what a tool server costs
Unlocks when you finish Measuring what a tool server costs.
Takeaways
- A connected server's tool definitions are part of the model's input. Without on-demand loading, the model reads all of them on every turn, and twenty tools of a normal size come to a few thousand tokens.
- A query costs its call and its result, and both stay in the conversation. A verbose result is read again on every later turn, so measure what your server returns and not only what it lists.
- Claude Code's tool search is on by default, and until the model searches, only the names and server instructions are in the context. It lowers the per-turn cost, and the names, the upfront fallbacks and the reach of every tool remain.
- Keep only the tools a task uses, use the CLI for occasional queries and the server for constant structured calls, and turn off the servers the project doesn't use.
Example
Measure the definitions · open in the lesson
Run definitions.py in the fixture directory, and compare with the output below.
tools = measure.list_tools()definitions = measure.definitions_text(tools)names = measure.names_text(tools)print(f"tools: {len(tools)}")size = f"{len(definitions):,} characters, about {measure.tokens(definitions):,} tokens"print(f"definitions: {size}")print(f"names only: {len(names):,} characters, about {measure.tokens(names):,} tokens")Prints the lines below (verified in CI from site/examples/customizing-agents/mcp-tool-cost/definitions.py)
tools: 20 definitions: 13,788 characters, about 3,447 tokens names only: 553 characters, about 138 tokens
Sources
AEC-14Agent protocols, MCP and A2A, Agent Engineer Course (course)AEC-16MCP deep dive: MCP versus CLI, security failure modes, token cost, Agent Engineer Course (course)DLAI-9MCP: Build Rich-Context AI Apps with Anthropic, DeepLearning.AI (course)Academy introduction-to-model-context-protocolIntroduction to Model Context Protocol, Claude Academy (course)Academy model-context-protocol-advanced-topicsModel Context Protocol: Advanced topics, Claude Academy (course)Academy claude-code-101Claude Code 101, Claude Academy (course)Invariant tool poisoningMCP Security Notification: Tool Poisoning Attacks, Invariant Labs blog (reference)