Step 1: Why MCP Exists: The N×M Problem
The integration tax without MCP
Every LLM agent needs tools — look up a user, query a database, call an API. Without a standard, every agent re-implements every tool:
Agent A wants to search the CRM ─▶ Agent A's team writes CRM tool
Agent B wants to search the CRM ─▶ Agent B's team writes CRM tool (differently)
Agent C wants to search the CRM ─▶ Agent C's team writes yet another CRM tool
N agents × M tools = N×M implementations
With 10 agents and 20 tools, that's 200 implementations to maintain, test, and keep in sync. A pricing change ripples through all of them.
What MCP changes
Model Context Protocol (MCP) flips the problem — write each tool once as an MCP server, and any MCP-compatible client can use it:
Agent A ─┐
Agent B ─┼─▶ MCP Server (CRM tools) ──▶ CRM API
Agent C ─┘
N + M (not N×M)
Who speaks MCP
- Claude Desktop / Claude Code — native clients, discover local servers at startup
- Cursor / Windsurf / Zed — IDE clients
- LangChain / LangGraph — via
langchain-mcp-adapters(what we'll use) - OpenAI Agents SDK — MCP support added in late 2025
- Anthropic API — direct MCP server reference
The protocol is transport-agnostic:
- stdio — server runs as a subprocess, client ↔ server over stdin/stdout (simplest, most common for local tools)
- Streamable HTTP — server is a long-running HTTP service; clients connect remotely (shared/remote tools)
- SSE — the older HTTP variant, still widely deployed
What an MCP server exposes
| Primitive | What it is | Analog in LangChain |
|---|---|---|
| Tools | Functions the LLM can call | @tool |
| Resources | Read-only data (file-like URIs) | RAG document with fixed ID |
| Prompts | Reusable prompt templates | ChatPromptTemplate |
Try it before you build it
We ship a tiny prebuilt MCP server at /home/labuser/hello_mcp.py — a one-tool server that greets you. Your first job is to write a 5-line client that spawns this server, discovers its tools, and invokes one. That 5 lines is the whole MCP consumer story in microcosm.
Your task
Write smoke.py — a minimal client that:
- Uses
MultiServerMCPClientfromlangchain_mcp_adapters.clientto spawn/home/labuser/hello_mcp.pyviastdio - Calls
await client.get_tools()and printsDiscovered N tool(s): [names] - Invokes the first tool with
name="MCP"and prints the result
Steps 2–6 are where we build our own MCP server from scratch. This warmup just proves the protocol works end-to-end.
NCP-AAI exam note: The exam tests tool architecture and agent composition. Key concepts: separation of concerns (tool implementation vs agent reasoning), why standardized protocols matter at scale, and the cost model of N×M vs N+M integrations.
hello_mcp.py, the file you edit16 lines
# A tiny prebuilt MCP server you connect to in step 1.
# You don't need to edit this — it's just here so you can see MCP work
# before theorizing about it.
from fastmcp import FastMCP
mcp = FastMCP("hello-server")
@mcp.tool
def greet(name: str) -> str:
"""Greet someone by name."""
return f"Hello {name}, welcome to the Model Context Protocol!"
if __name__ == "__main__":
mcp.run()provided for you:smoke.py