Module 7: Advanced MCP and Tool Integration

1. Introduction: The Problem of Tools at Scale

Overview

Module 6 solved a persistence problem: your agent stopped forgetting everything between sessions. With checkpointing, it picks up interrupted research exactly where it left off. With long-term memory, it remembers user preferences and facts learned over time. With conversation management, it handles long conversation histories without degrading performance. Research Agent v3 has managed short-term memory, durable checkpointing, cross-session long-term memory, and time-travel debugging — it's an agent that plans, reflects, and remembers. But there's a problem that neither intelligence nor memory solves: your agent has exactly the tools you hardcoded into it. Five tools defined with @tool, imported directly in the code, registered by hand in bind_tools. If tomorrow you need the agent to reach Slack, a paper database, or the filesystem — you stop, write the tool, import it, register it, re-deploy, and pray nothing breaks. With 5 tools that works. With 20, it hurts. With 50, it's unsustainable.

This module solves that problem with MCP (Model Context Protocol) — possibly the most differentiating content in the entire guide. MCP is an open standard created by Anthropic and backed by Microsoft, OpenAI and the community that defines how agents discover and use external tools without direct coupling. It's to agents what USB is to peripherals: before USB, every device had its own connector and its own driver. Connecting a printer was a project. After USB, any device connects to any computer with a standard cable — plug and play. MCP does the same for agent tools: MCP servers expose tools through a standard protocol, and MCP clients (your agents) discover and use them dynamically. The agent doesn't need to know in advance which tools exist — it discovers them from the server at runtime. Adding a new tool means deploying an MCP server, without touching a single line of the agent's code.

The transition from M2-M3 to M7 is the natural evolution of tool use in this guide. M2 taught you to build solid tools — Pydantic schemas, error handling, external APIs. M3 taught you patterns to orchestrate them — parallel calls, routing, retry. But both assumed the tools live inside the agent, hardcoded in its code. M7 changes that paradigm: the tools live outside, in independent servers that the agent discovers through a protocol. It's the shift from "importing functions" to "connecting services." The tone of this module is innovative but pragmatic: MCP is new and exciting, but it isn't hype — it's a standard that solves real problems of scalability, maintenance, and decoupling. By the end, you'll know how to implement MCP servers, build MCP clients, integrate dynamic tools into LangGraph agents, and navigate the ecosystem of community servers. You won't just know MCP exists — you'll know how to use it in production.


Where Are We in the Guide?

Context

This guide has 10 modules organized into 3 phases:

Phase 1: Agent Foundations (Modules 1-3)                ✓ COMPLETED
├── Module 01: Anatomy of an AI Agent                   ✓ COMPLETED
├── Module 02: Tool Use Fundamentals                    ✓ COMPLETED
└── Module 03: Function Calling Patterns                ✓ COMPLETED

Phase 2: Agent Architecture (Modules 4-6)               ✓ COMPLETED
├── Module 04: State Machines for Agents                ✓ COMPLETED
├── Module 05: Multi-Step Reasoning and Planning        ✓ COMPLETED
└── Module 06: Memory Systems for Agents                ✓ COMPLETED

Phase 3: Advanced Integration & Production (Modules 7-10) ← YOU ARE HERE
├── Module 07: MCP and Advanced Tool Integration          ← THIS MODULE
├── Module 08: Multi-Agent Orchestration
├── Module 09: Testing and Evaluation of Agents
└── Module 10: Agents in Production and Alternatives

First module of Phase 3 — the bridge between a complete individual agent and a production agent system. Phases 1 and 2 built an agent with all its internal capabilities: tool use (M2-M3), flow control (M4), deliberative intelligence (M5), and persistent memory (M6). Phase 3 takes that agent into the real world: external tools at scale (M7), multi-agent coordination (M8), formal testing (M9), and production deployment (M10).

The progression of Phase 3 is deliberate — each module opens a door the previous one makes possible:

  1. Module 7 — How it connects to the world → MCP servers, clients, dynamic tools, ecosystem ← HERE
  2. Module 8 — How it works in a team → Supervisor, handoffs, subagents, shared state
  3. Module 9 — How you know it works → Golden datasets, trajectory evaluation, regression testing
  4. Module 10 — How you ship it to production → Deployment, observability, costs, alternatives

Where are you coming from?

Module 6 left you with a Research Agent v3 that remembers across sessions:

  • Durable checkpointing: Every node in the graph produces a snapshot. If execution is interrupted, the agent resumes exactly where it stopped — with the same plan, the same partial results, the same reflections
  • Cross-session long-term memory: The agent remembers user preferences ("prefers academic sources"), learned facts ("their company uses FastAPI"), and task history — using InMemoryStore/BaseStore with namespaces
  • Conversation management: Trimming and summarization manage the active history so that long research sessions don't degrade performance or blow up the context window
  • Time-travel debugging: You navigate the agent's full state history, inspect any checkpoint, and replay — debugging the reasoning at the level of "what did the agent know when it made this decision?"

That's a complete agent in terms of internal capabilities. But when you look at its tools, you still see this:

from tools import web_search, calculate, read_file

tools = [web_search, calculate, read_file]
model = ChatOpenAI(model="gpt-4.1").bind_tools(tools)

Three tools. Hardcoded. Imported directly. To add a fourth, you touch the agent's code.

Where are you going?

The transition from M6 to M7 is the jump from "agent with complete internal capabilities" to "agent connected to the outside world at scale." M6 completed the internal architecture: the agent plans, reflects, and remembers. M7 gives it access to an ecosystem of external tools without coupling.

After M7, Module 8 takes the individual agent — now with a state machine, planning, memory, and MCP — and scales it into a team of agents. The transition is: "One agent with unlimited tools via MCP → a team of specialized agents, each with its own set of MCP tools." Without M7, multi-agent would be fragile: each agent would need its tools hardcoded internally, and adding tools to the team would mean modifying every agent one by one.

And beyond that: M9 (Testing) formally evaluates whether the agents work well — including tests for tool discovery and MCP integration. M10 (Production) deploys the MCP servers alongside the agents, with monitoring and auth in a real production setting.


The Problem: Hardcoded Tools Don't Scale

Your agent today

After 6 modules, your Research Agent has a sophisticated graph: intelligent planning, reflection with quality gates, directed re-planning, durable checkpointing, long-term memory. But when you look at how it accesses tools, the code hasn't changed since M2:

@tool
def web_search(query: str) -> str:
    """Search for information on the web."""
    client = TavilyClient()
    results = client.search(query)
    return format_results(results)

@tool
def calculate(expression: str) -> str:
    """Evaluate a math expression."""
    return str(eval(expression))

tools = [web_search, calculate]
model = ChatOpenAI(model="gpt-4.1").bind_tools(tools)
graph = builder.compile(checkpointer=checkpointer)

It works. But now imagine your agent needs to do more:

Scenario: the research agent grows

Your Research Agent v3 is useful, but users want more. The PM shows up with weekly requests: Slack integration for notifications, search over the paper database, reading and writing files, a GitHub connection to create issues, a Notion integration to save reports, translation with DeepL, chart generation...

Eight weeks, eight new tools. Your tools file now has 800 lines. Your bind_tools receives a list of 10 tools. Every deployment requires re-testing everything together. And you're only getting started.

The five problems of the hardcoded approach

1. Direct coupling: Every tool is imported directly into the agent's code. If you change the signature of web_search, you re-deploy the whole agent. With 10 imported tools, a change in any one of them means re-deploying everything.

2. Dependency explosion: Every tool brings its own: slack-sdk, PyGithub, matplotlib, deepl, notion-client... Your requirements.txt grows out of control. A version conflict between PyGithub and slack-sdk blocks the deployment of the entire agent — including the web search that has nothing to do with it.

3. Error surface area: With 10 tools you have 10 independent failure points. Slack's API has different rate limits than GitHub's. An error in notion_save can crash the whole agent if error handling isn't perfect in every tool.

4. The model's tool selection degrades: With 3 tools the model almost always picks right (~95% accuracy). With 10 it starts confusing similar tools (~85%). With 20+ the degradation is significant (~70%). More schemas in every request = more tokens, more cost, more selection errors.

5. No separation of concerns: Your agent mixes reasoning logic (planning, reflection) with integration logic (Slack OAuth, GitHub pagination, PostgreSQL connection pools). Different teams can't work independently.

The pattern that emerges

Look at those five problems. They all share the same root: the tools are coupled to the agent. Every tool lives inside the agent's process, shares its dependencies, affects its deployment, and adds to its complexity. The solution isn't "write better code" or "organize the files better." The solution is an architectural change: take the tools out of the agent and put them in independent services the agent consumes through a standard protocol.

That's exactly what MCP does.


The USB Analogy

Before and after USB

If you're over 30, you remember the pre-USB era. Every peripheral had its own connector: PS/2 for the keyboard, parallel port for the printer, serial for the modem, SCSI for the scanner, FireWire for the camera. Connecting a new printer was a project: install the driver from the CD, configure the port, reboot, cross your fingers. USB changed the paradigm: one standard connector, one standard protocol. You plug the device in and it works. Plug and play. The operating system discovers the device automatically, loads the right driver, and makes it available. You don't need to know in advance which device the user is going to plug in — the protocol handles discovery.

MCP = USB for agent tools

The hardcoded approach from M2-M3 is the pre-USB era:

Agent → web_search (direct integration with Tavily)
Agent → paper_search (direct integration with PostgreSQL)
Agent → slack_post (direct integration with the Slack API)
Agent → notion_save (direct integration with the Notion API)

Every tool has its own "connector" — its own integration, its own dependencies, its own error handling. Adding a new tool is like plugging in a peripheral in 1995: install, configure, reboot, pray.

MCP is the USB era:

Agent (MCP Client) → Standard protocol → MCP Server: Filesystem
                                       → MCP Server: Web Search
                                       → MCP Server: Slack
                                       → MCP Server: GitHub
                                       → MCP Server: Papers DB
                                       → MCP Server: [any new server]

The agent doesn't know in advance which tools exist. It connects to an MCP server, asks it "what tools do you have?", and receives the list with their schemas. Dynamic discovery. New tools are added by deploying a new server — without touching the agent.

What the analogy teaches

The USB analogy isn't just illustrative — it reveals design principles that MCP implements:

PrincipleUSBMCP
Open standardUSB doesn't belong to Intel — it's a standard any manufacturer adoptsMCP doesn't belong to Anthropic — it's an open protocol any framework adopts
DiscoveryThe OS discovers connected devices automaticallyThe agent discovers the server's tools automatically
DecouplingA USB keyboard works on any computer with a USB portAn MCP server works with any agent that speaks MCP
Hot-plugYou connect a device without rebootingYou add an MCP server without re-deploying the agent
IndependenceThe keyboard maker and the OS maker work independentlyThe server developer and the agent developer work independently

The key point: MCP isn't an Anthropic product — it's a protocol. In the same way USB doesn't belong to Intel even though Intel co-created it. It's an open standard that any framework, model, or service can adopt. That makes it durable: it's worth investing in learning it because it isn't tied to a vendor.


From M2 to M7: The Evolution of Tool Use

The full progression

This guide tells a story of tool use that evolves module by module. M7 doesn't appear out of nowhere — it's the natural destination of a road that started in M2:

M2: BUILD TOOLS
    @tool with Pydantic schemas
    Manual tool execution loop
    Real external APIs
    Robust error handling
    → Result: solid individual tools
    → Limitation: every tool is code inside the agent

        ↓

M3: ORCHESTRATE TOOLS
    Parallel function calling
    Forced tool calls
    Routing between tools
    Retry patterns and circuit breakers
    → Result: professional tool use patterns
    → Limitation: the tools are still hardcoded in the agent

        ↓

M4-M6: EXPAND THE AGENT (without changing tool use)
    M4: State machines and flow control
    M5: Planning and reflection
    M6: Memory and persistence
    → Result: sophisticated agent with simple tools
    → Limitation: 3-5 static tools while the agent grows

        ↓

M7: MAKE TOOLS DYNAMIC
    MCP servers expose tools as services
    MCP clients discover tools through a protocol
    Dynamic tool loading at runtime
    Ecosystem of community servers
    → Result: agent with unlimited, decoupled tools
    → Next: M8 multi-agent, each agent with its own MCP servers

What fundamentally changes

In M2-M3, the agent has tools:

# M2-M3: The tools are part of the agent
tools = [web_search, calculate, read_file]
model = ChatOpenAI(model="gpt-4.1").bind_tools(tools)

In M7, the agent discovers tools:

# M7: The tools are discovered from external servers
async with MultiServerMCPClient(servers) as mcp_client:
    tools = mcp_client.get_tools()  # Dynamic discovery
    # tools could be 3, could be 30 — the agent didn't know in advance
    model = ChatOpenAI(model="gpt-4.1").bind_tools(tools)

The difference looks subtle in code. Architecturally it's transformational:

AspectM2-M3 (Hardcoded)M7 (MCP)
Adding a toolWrite code, import, re-deploy the agentDeploy an MCP server. The agent doesn't change
DependenciesAll inside the agent's processEach server has its own, isolated
DeploymentAll together — one change in one tool → re-deploy everythingIndependent — each server deploys separately
TeamsEveryone touches the same agent repoIndependent teams maintain independent servers
TestingOne giant test suite covering everythingEach server has its own tests
ScalingScaling the agent scales everything, including tools that don't need itEach server scales independently

The "wow" moment of this module

The moment that defines this module is when your agent discovers tools it didn't know about:

Agent: "Connecting to MCP server 'research-tools'..."
Agent: "Discovered tools: [paper_search, citation_check, 
        abstract_summarize, related_papers]"
Agent: "I discovered 4 tools that didn't exist in my code.
        Using paper_search for the user's query..."

Your agent didn't know abstract_summarize existed 5 seconds ago. It discovered it from the server via MCP, read its schema, and used it correctly. You didn't write a single line of code in the agent to make this work. You deployed an MCP server with those tools, connected the agent to the server, and everything works through a standard protocol.

That's the power of a standard.


Prerequisites

From Module 6 (Memory Systems for Agents)

This module extends the Research Agent v3 from M6. You need these solid:

  • Durable checkpointing: Your agent persists its state with MemorySaver or PostgresSaver. You know how to use thread_id for sessions and resume interrupted executions
  • Cross-session long-term memory: You implemented InMemoryStore/BaseStore for preferences and facts that persist across conversations
  • Conversation management: You manage the active history with trimming and summarization — not just "save everything"
  • Time-travel debugging: You can navigate the state history, inspect checkpoints, and replay

From Module 5 (Multi-Step Reasoning and Planning)

The deliberative intelligence layer is still active:

  • Intelligent planning: The agent breaks tasks into sub-questions with dependencies and re-plans based on gaps
  • Reflection with quality gates: Output evaluation with critique prompts and actionable recommendations
  • Reasoning traces: The thinking process captured as structured data

From Module 4 (State Machines for Agents)

The state machine foundation is fundamental:

  • StateGraph for agents: Functional nodes, explicit edges, controlled cycles
  • Extensible typed state: AgentState with fields that grow module by module without breaking the existing ones
  • Conditional routing: Deterministic decision points based on state
  • Modular subgraphs: Encapsulated capabilities with clear interfaces

From Phase 1 (Modules 1-3)

The agent foundations base is still active — and it's especially relevant here because M7 is the direct evolution of M2-M3:

  • Cognitive architecture (M1): Perceive-reason-act, agent taxonomy
  • Tool use (M2): @tool with Pydantic schemas, tool execution loop, error handling, external APIs — this is the foundation M7 evolves
  • Function calling patterns (M3): Parallel calls, routing, structured extraction, retry — these patterns still apply with MCP tools

Tools for this module

  • Python 3.11+
  • langchain v1.2+ and langchain-openai
  • langgraph v1.0+
  • OpenAI API key (GPT-4.1 or GPT-4.1-mini)
  • tavily-python for web search
  • python-dotenv for environment variables
  • mcp, the official MCP SDK (new in this module)
  • langchain-mcp-adapters for LangGraph-MCP integration (new)
pip install langchain langchain-openai langgraph tavily-python python-dotenv mcp langchain-mcp-adapters

New dependencies: mcp is the official SDK of the Model Context Protocol — you use it to create servers and clients. langchain-mcp-adapters is the bridge that turns MCP tools into LangChain tools compatible with LangGraph. They're the only two new dependencies compared to M6.


Objectives of Module 7

By the end of this module you'll be able to:

  • Explain what MCP is and its architecture: Host, client, server, transport (stdio, SSE) — not as an abstract concept, but as a system with components you implement. You know why it's an important standard, who backs it, and why it's worth investing in learning it
  • Create MCP servers with the official SDK: Define tools with schemas, expose resources and prompts, configure transports — your server runs and exposes tools that any MCP client can discover and use
  • Build MCP clients that connect to servers: Automatic tool discovery, listing of available tools, calling remote tools — your client connects to a server and uses its tools without knowing in advance which ones they are
  • Integrate MCP as a tool source for LangGraph agents: Dynamic tool loading with langchain-mcp-adapters, runtime tool refresh, tool namespacing to avoid collisions — MCP tools running inside your existing StateGraph
  • Navigate the MCP ecosystem: Community servers (GitHub, Slack, PostgreSQL, filesystem), server registries, and criteria to evaluate third-party servers — you leverage existing work instead of reinventing it
  • Implement MCP in production: Server deployment, authentication, rate limiting, monitoring, error handling, tool versioning — MCP that works not only on your laptop but in a real system
  • Connect the Research Agent to 3 MCP servers: Filesystem (read/write research), web search (replacing the hardcoded tool), and a paper database (custom server) — the Research Agent v4 with dynamic tools

Module Map

#CapsuleWhat you'll learn
02What is MCP?The standard, the architecture (host, client, server, transport), and the why. How MCP solves the tool integration problem at scale. Comparison with alternative approaches (OpenAPI/Swagger, plugins). Why an open standard matters more than a proprietary solution
03MCP Servers: Exposing ToolsCreating MCP servers with the official SDK. Defining tools with schemas, resources with URIs, and prompts as templates. Configuring transports (stdio for development, SSE for production). Your first server running and exposing tools
04MCP Clients: Consuming ToolsBuilding clients that connect to servers. Automatic tool discovery: listing available tools without knowing them in advance. Calling remote tools. Error handling in client-server communication. Multi-server: one client connected to multiple servers at once
05MCP in LangGraph AgentsThe key integration: MCP tools inside your StateGraph. langchain-mcp-adapters as the bridge. Dynamic tool loading: the graph receives tools from the server, not from the code. Runtime refresh: if the server adds tools, the agent detects them. Tool namespacing to avoid collisions between servers
06MCP Ecosystem: External ToolsCommunity servers: GitHub, Slack, PostgreSQL, filesystem, and more. Registries to discover available servers. Evaluating third-party servers: security, maintenance, quality. Using existing servers saves weeks of work
07MCP in ProductionDeploying MCP servers (Docker, cloud). Authentication: who can call the server. Rate limiting: preventing abuse. Monitoring: latency, error, and usage metrics. Versioning: how to update tools without breaking clients. The real challenges of MCP in production
08Project: Agent with MCPResearch Agent v4: replace hardcoded tools with 3 MCP servers — filesystem (read/write research), web search (evolution of the hardcoded Tavily), paper database (custom server). The agent discovers tools dynamically and uses them inside its graph

Learning flow

The module follows a progression of understand the standardbuild the server sidebuild the client sideintegrate into agentsscale with the ecosystemtake it to production.

You start with What is MCP? (capsule 02) because you need the mental model before writing code — the architecture (host, client, server, transport), the vocabulary, and the why. It isn't a theory class: it establishes the base you use throughout the module.

Then MCP Servers (capsule 03) puts you on the provider's side. You create a server that exposes tools with schemas, resources with URIs, and prompts as templates. Hands-on from the first minute — by the end you have a server running with 3 discoverable tools.

Capsule 04 (MCP Clients) puts you on the other side: you build a client that discovers and calls tools from one or several servers. The key moment: you add a tool to the server and the client discovers it automatically without changing its code.

With MCP in LangGraph (capsule 05), the integration that matters arrives: langchain-mcp-adapters turns MCP tools into LangChain tools that your StateGraph uses directly. The agent moves from a hardcoded tools = [web_search] to a dynamic tools = mcp_client.get_tools(). This capsule has the biggest architectural impact.

Capsule 06 (MCP Ecosystem) broadens your horizon: community servers for GitHub, Slack, PostgreSQL, filesystem, and more. You discover, evaluate, and connect existing servers — solving integrations in minutes instead of days.

Capsule 07 (MCP in Production) closes with real deployment: Docker, auth, rate limiting, monitoring, versioning. Security isn't optional when servers expose tools that read files and run queries.

Finally, the project (capsule 08) is the direct evolution of Research Agent v3: the hardcoded tools are replaced with 3 MCP servers. The result is Research Agent v4 with dynamic tools.


Connection with the Evolving Project

Research Agent v3 (M6) → Research Agent v4 (M7)

The Research Agent from M6 has its whole internal architecture solved:

                         ┌─────────────────────────────┐
                         │     CHECKPOINTER            │
                         │  (MemorySaver / PostgreSQL)  │
                         │  Snapshot at every node      │
                         └──────────┬──────────────────┘
                                    │
START → planning_v2 → research → analysis → reflection → [quality ok?]
  │          ▲                                                  │
  │          │                                    ┌─────────────┼──────────┐
  │          │                               "re-plan"     "refine"   "deliver"
  │          │                                    │             │          │
  │          └────────────────────────────────────┘             │          ▼
  │                                                             ▼      synthesis → END
  │                                                      refinement         │
  │                                                             │           │
  │                                                             ▼           │
  │                                                        reflection       │
  │                                                                         │
  └──── LONG-TERM MEMORY STORE ─────────────────────────────────────────────┘

  TOOLS: [web_search, calculate]  ← Hardcoded, imported directly

M7 doesn't change the graph or the memory — it changes where the tools come from:

                         ┌─────────────────────────────┐
                         │     CHECKPOINTER            │
                         │  (MemorySaver / PostgreSQL)  │
                         └──────────┬──────────────────┘
                                    │
START → planning_v2 → research → analysis → reflection → [quality ok?]
  │          ▲                                                  │
  │          │                                    ┌─────────────┼──────────┐
  │          │                               "re-plan"     "refine"   "deliver"
  │          │                                    │             │          │
  │          └────────────────────────────────────┘             │          ▼
  │                                                             ▼      synthesis → END
  │                                                      refinement         │
  │                                                             │           │
  │                                                             ▼           │
  │                                                        reflection       │
  │                                                                         │
  └──── LONG-TERM MEMORY STORE ─────────────────────────────────────────────┘

  TOOLS (via MCP):
  ┌──────────────────────────┐
  │  MCP Server: Filesystem  │ → file_read, file_write, list_directory
  ├──────────────────────────┤
  │  MCP Server: Web Search  │ → web_search, news_search, image_search
  ├──────────────────────────┤
  │  MCP Server: Papers DB   │ → paper_search, citation_check, related_papers
  └──────────────────────────┘
  ↑ Discovered dynamically through the protocol, not imported in code

What changes concretely

1. The tools are discovered from MCP servers

Before (M6):

from tools import web_search, calculate

tools = [web_search, calculate]
model = ChatOpenAI(model="gpt-4.1").bind_tools(tools)
graph = builder.compile(checkpointer=checkpointer, store=store)

After (M7):

from langchain_mcp_adapters.client import MultiServerMCPClient

server_config = {
    "filesystem": {
        "command": "python",
        "args": ["servers/filesystem_server.py"],
        "transport": "stdio",
    },
    "web_search": {
        "command": "python",
        "args": ["servers/web_search_server.py"],
        "transport": "stdio",
    },
    "papers_db": {
        "command": "python",
        "args": ["servers/papers_server.py"],
        "transport": "stdio",
    },
}

async with MultiServerMCPClient(server_config) as mcp_client:
    tools = mcp_client.get_tools()
    # tools = [file_read, file_write, list_directory, web_search,
    #          news_search, paper_search, citation_check, related_papers]
    # → 8 tools discovered dynamically from 3 servers

The agent no longer imports tools — it connects to servers and discovers them. Adding a fourth server means adding an entry to server_config, without touching the rest of the code.

2. Each MCP server is an independent process

Each server runs as a separate process with its own dependencies. A crash in the papers_server doesn't crash the agent. An update to the web_search_server doesn't require re-deploying anything else. Each server has its own lifecycle, its own tests, its own deployment.

3. The research node uses dynamic tools

The graph's research node still exists, but the tools it runs are no longer fixed:

def research(state: AgentState) -> dict:
    subtask = get_next_subtask(state["current_plan"])

    # The available tools come from the MCP client, not from the code
    # If tomorrow the papers_server adds "abstract_summarize",
    # this node can use it without changes
    response = model_with_mcp_tools.invoke([
        SystemMessage(content=f"Research: {subtask['query']}"),
        *state["messages"]
    ])

    return {"tool_results": [*state["tool_results"], response]}

4. MCP fields are added to the state

class AgentState(TypedDict):
    # M4 fields (unmodified)
    messages: Annotated[list[BaseMessage], add_messages]
    current_plan: dict
    iteration_count: int
    tool_results: list[dict]
    quality_score: float
    budget_remaining: float
    metadata: dict
    # M5 fields (unmodified)
    reflection_notes: Optional[dict]
    planning_iterations: int
    completed_subtasks: list[str]
    reasoning_trace: list[dict]
    synthesis_draft: Optional[str]
    # M6 fields (unmodified)
    session_summary: Optional[str]
    resumed_from_checkpoint: bool
    memory_context: Optional[dict]
    # New M7 fields
    available_tools: list[str]
    active_mcp_servers: list[str]
    tool_source: dict  # {tool_name: server_name}

The M4, M5, and M6 fields aren't touched. You only add fields to track which tools are available and which server they come from. The extensible state you designed in M4 keeps paying dividends four modules later.

5. The 3 MCP servers of Research Agent v4

MCP ServerTools it exposesWhat it replaces
Filesystemfile_read, file_write, list_directoryNothing — new capability. The agent can now save research to disk
Web Searchweb_search, news_searchThe hardcoded web_search from M2. Same functionality, different architecture
Papers DBpaper_search, citation_check, related_papersNothing — new capability. Searches an academic paper database

The advantage isn't just having more tools — it's that servers get updated, replaced, or added without modifying the agent. If tomorrow the papers team adds abstract_summarize to their MCP server, the agent discovers it automatically on the next connection.


What This Module Does NOT Cover

  • Tool use fundamentals@tool, Pydantic schemas, and the tool execution loop aren't re-taught. That's M2. Here the tools are built with the MCP SDK, but the schema design principles are still the same
  • Function calling patterns — Parallel calls, routing, and retry aren't re-taught. That's M3. Those patterns still apply with MCP tools — an agent can make parallel calls to tools from different servers
  • State machines or flow control — StateGraph isn't re-taught. That's M4. Here you integrate MCP tools into an existing graph
  • Planning or reflection — Intelligent planning and reflection with quality gates aren't re-taught. That's M5. Here the agent keeps planning and reflecting — but with tools it discovers dynamically
  • Memory or persistence — Checkpointing and long-term memory aren't re-taught. That's M6. Checkpointing and memory keep working exactly the same — only where the tools come from changes
  • Multi-agent with MCP — Multiple agents connected to different MCP servers, with shared tool discovery and coordination. That's M8. Here a single agent connects to multiple servers
  • Creating MCP servers for non-Python frameworks — The MCP SDK exists for TypeScript and other languages. This module uses Python exclusively, consistent with the guide's stack
  • MCP over HTTP in the cloud with advanced auth (OAuth2, mTLS) — Auth principles and a practical example are covered, but enterprise-grade security implementations belong to M10

The boundary is clear: M7 = how the agent connects to external tools through a standard protocol. M2-M3 = how you build and orchestrate individual tools. M6 = how it remembers. M5 = how it thinks.


Evidence of Success

By the end of this module, you'll know you succeeded if:

  • ✅ You can create an MCP server that exposes 3+ tools with schemas, running over stdio transport — and verify that a client discovers those tools automatically without knowing in advance which ones they are
  • ✅ You can build an MCP client that connects to multiple servers at once, lists each one's tools, and calls tools from different servers in the same session
  • ✅ Your LangGraph agent receives tools from MCP servers instead of having them hardcoded — and you can add a new tool to the server without changing a line of the agent's code
  • ✅ You can use at least 2 community MCP servers (e.g. GitHub, filesystem) connected to your agent — leveraging existing work instead of reinventing integrations
  • ✅ Your MCP setup has production considerations: you know how to deploy a server with Docker, implement basic auth, and monitor latency and errors
  • ✅ You can explain the difference between MCP and OpenAPI/Swagger as tool integration standards — and argue when MCP adds value vs when it's overkill
  • ✅ Your Research Agent v4 connects to 3 MCP servers (filesystem, web search, papers), discovers the tools dynamically, and uses them inside its planning-research-reflection graph — with no hardcoded tools

Quick self-assessment test

Ask yourself these questions after completing the module:

  1. "If I add a new tool to an MCP server, can my agent use it without me changing its code?" → If yes, your MCP integration is genuinely dynamic
  2. "If an MCP server goes down, does my agent handle the error gracefully or does it crash?" → If it handles the error, your error handling is production-ready
  3. "Can I connect a community server (e.g. the GitHub MCP server) to my agent in under 10 minutes?" → If yes, you understand the ecosystem
  4. "Can I explain to a teammate why MCP is better than simply organizing the tools into Python modules?" → If yes, you understand the why, not just the how

If you answered yes to all four → you're ready for Module 8 (Multi-Agent Orchestration). If you answered no to any → reinforce the corresponding capsule before moving on.


Summary

  • From hardcoded to dynamic: M2-M3 taught you to build and orchestrate tools inside the agent. M7 takes the tools out of the agent and puts them in independent servers the agent discovers through a protocol. It's the shift from "importing functions" to "connecting services"
  • MCP = USB for agents: An open standard protocol that lets any agent use any tool without custom integration. MCP servers expose tools, MCP clients discover them. Adding tools = deploying a server, not modifying the agent
  • The problem is real: 20+ hardcoded tools create coupling, dependency explosion, error surface area, tool selection degradation, and a lack of separation of concerns. MCP solves all five problems at once
  • A standard, not a product: MCP doesn't belong to Anthropic in the same way USB doesn't belong to Intel. It's an open protocol any framework can adopt. That makes it durable — it's worth investing in learning it
  • Hands-on from the start: From capsule 03 you have a server running. From capsule 04, a client connected. From capsule 05, MCP tools inside your LangGraph agent. Practical experience first, theory after
  • The ecosystem saves work: Community servers for GitHub, Slack, PostgreSQL, filesystem, and more. You don't reinvent integrations — you connect existing servers and spend your time on the agent
  • Production, not just demos: Auth, rate limiting, monitoring, versioning, deployment with Docker. MCP in production has real challenges that this module covers
  • The Research Agent evolves again: v1 (M4) had a state machine, v2 (M5) added planning and reflection, v3 (M6) added memory, v4 (M7) replaces hardcoded tools with 3 MCP servers. The extensible state absorbs the new fields without breaking the existing ones

Resources

  1. MCP Specification — The official specification of the Model Context Protocol. Architecture, transports, and full protocol reference
  2. Anthropic: Introducing MCP — Anthropic's original announcement. Context on why they created the standard and what problems it solves
  3. MCP Python SDK — The official Python SDK for creating MCP servers and clients. The main tool of this module
  4. langchain-mcp-adapters — The bridge between MCP and LangChain/LangGraph. Turns MCP tools into LangChain tools for direct integration with agents
  5. MCP Servers Repository — Official collection of community MCP servers. GitHub, Slack, PostgreSQL, filesystem, and more — servers ready to use
  6. Building Effective Agents — Anthropic — Anthropic's perspective on tool integration in agents. Complements the MCP approach with design patterns