hands-on labin your browser

Build an MCP Tool Server & Connect a LangChain Agent

Build a Model Context Protocol server that exposes your company's tools and data, then connect a LangChain agent to it and see how MCP decouples tools from agents.

time
40 min
checked steps
6
level
Advanced
setup
None

$29.99a month with Pro

Pro opens all 6 steps of this lab and every other lab. Cancel any time.

no account needed · Pro opens all 6 steps

See Pro plans
Lab cockpit40 min · 6 stepsSession running
5 / 6 steps passingDecision Framework: MCP vs Skills vs @tool · step 6 of 6
hybrid_agent.py▶ Run✓ Check
    print(f"Agent has {len(all_tools)} tools total ({len(mcp_tools)} from MCP + 1 native)")   
TerminalOutput
step 6 of 6, replayed: Decision Framework: MCP vs Skills vs @tool. The code, the output and the check are the lab's own.

The job

Acme SaaS has a platform engineering problem: their AI team keeps reimplementing the same tools in every agent. The support bot has its own check_account, the sales assistant has a different one, and the ops dashboard is yet another rewrite. Every new bot = weeks of tool-wiring work.

Your job: build a Model Context Protocol (MCP) server, one place that exposes Acme's capabilities (account lookup, KB search, ticket creation, customer health metrics), that any LLM agent can plug into. MCP is Anthropic's open protocol for exactly this; Claude Desktop, Claude Code, Cursor, and LangChain agents all speak MCP.

By the end of this lab, you'll have:

What you'll buildPurpose
server_basic.pyMinimal MCP server with 1 tool, runs over stdio
server_full.pyComplete Acme server: 3 tools + 1 resource
client_direct.pyCall MCP tools directly (no LLM), smoke test
agent_with_mcp.pyLangChain agent consuming MCP tools as first-class tools
hybrid_agent.pyMix MCP tools + native @tool tools in one agent
README-decision.mdDecision framework: MCP vs Skills vs native tools

Why this matters for production: MCP turns tool development into a separate concern from agent development. The platform team writes the MCP server once; every agent team plugs into it. Different language? No problem, MCP servers can be written in Python, TypeScript, Rust, anything with a stdio or HTTP binding.

6 steps, each checked when you finish it

A check runs your work at the end of every step. Hints and the full solution are there if you get stuck.

  1. 1

    Why MCP Exists: The N×M Problem

    Every LLM agent needs tools, look up a user, query a database, call an API.

    read this step below ↓

  2. 2

    Build Your First MCP Server

    The official mcp Python SDK is correct but low-level.

  3. 3

    Connect a Client (Direct Call, No Agent)

    An MCP client and server talk JSON-RPC messages over a transport.

  4. 4

    Full Server with Tools + Resources

    A minimal server with one tool is enough to teach the protocol, but production MCP servers typically expose:

  5. 5

    Agent + MCP: End-to-End

    Everything so far has been infrastructure.

  6. 6

    Decision Framework: MCP vs Skills vs @tool

    You now have hands-on experience with MCP.

Step 1 as it appears in the lab

The lab’s own text. The hint and the solution stay inside the lab.

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

PrimitiveWhat it isAnalog in LangChain
ToolsFunctions the LLM can call@tool
ResourcesRead-only data (file-like URIs)RAG document with fixed ID
PromptsReusable prompt templatesChatPromptTemplate

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 MultiServerMCPClient from langchain_mcp_adapters.client to spawn /home/labuser/hello_mcp.py via stdio
  • Calls await client.get_tools() and prints Discovered 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

what you get

  • A hosted environment in your browser
  • A check at the end of every step
  • Hints and the full solution
  • Nothing to install or configure

before you start

  • Completed Lab 1 (ReAct Agent with NIM) or equivalent
  • Comfort with Python decorators and async/await
  • Familiarity with JSON-RPC or stdio-based protocols helps (not required)

Exam domains covered

Agent Architecture and DesignAgent DevelopmentNVIDIA Platform Implementation

Part of the AI agents and MCP track

Lab 13 of 26. Tool loops, ReAct, MCP servers and clients, multi-agent supervisors and agent evaluation.

Questions about this lab

How is MCP different from just exposing tools as a REST API?

A REST API is a bespoke contract; MCP is a standardised envelope. Any MCP client, Claude Desktop, Claude Code, Cursor, LangChain, a random TypeScript app, can connect to any MCP server without per-integration code, because the protocol defines initialize, tools/list, tools/call, resources/list, resources/read, and prompts/list uniformly. You also get typed tool schemas, capability negotiation, and a notification channel built in. Think of it as 'LSP for agent tools': the same reason every editor can use every language's analyser once they all speak the Language Server Protocol.

When should I pick stdio transport versus HTTP?

Stdio when the server and client are colocated and the trust boundary is 'this process spawned that process', Claude Desktop and Cursor both use stdio by default, and it's what Step 2 and 3 of the lab use. Stdio has no network surface, no TLS config, and trivial auth ('you can launch the binary, you can use it'). Pick HTTP when the server needs to be shared across processes, hosts, or teams, a company-wide MCP server for CRM access, for instance. The protocol is identical in both cases; you just swap the transport binding and add OAuth / bearer auth on the HTTP side.

What's the difference between an MCP Tool and an MCP Resource?

Tools are invocable functions with potential side effects, create_ticket(subject, body), update_record(id, fields). Resources are read-only data surfaces the agent can fetch by URI, a policy document, a product catalogue, a team roster. The distinction matters because clients authorise them differently: Claude Desktop will happily load Resources into context automatically but prompts the user before calling Tools. The lab includes one Resource alongside the three Tools so you see both halves of the protocol and the authorisation consequences.

Do MCP servers have to be written in Python?

No, MCP is a wire protocol, not an SDK. Servers exist in TypeScript (Anthropic's reference), Python (mcp / fastmcp, used here), Rust, Go, C#, Swift, and others. The lab uses FastMCP because its decorator API is the fastest path to a working server and because Python is the default for agent teams, but the exact same client code in Step 3 would talk to a TypeScript server with zero changes. That portability is the whole point, it's why Anthropic pushed a protocol rather than yet another library.

Should I use MCP or LangChain's native @tool decorator?

Use @tool when the tool is tightly coupled to one agent and implemented in the same repo, it's zero-overhead, type-safe, and trivial. Reach for MCP when the tool needs to be shared across multiple agents, especially agents owned by other teams or written in other languages. The hybrid-agent step is deliberate: real production systems use both. Inner-loop tools that only this agent calls stay as @tool; company-wide capabilities (account lookup, KB search, ticketing) become an MCP server everyone plugs into. The final decision framework step formalises the split.

How is MCP different from Anthropic Skills?

Skills are higher-level: a Skill bundles instructions, resources, and often a set of MCP tools into a named capability the agent can load on demand (for example 'financial-report-drafting' skill that activates a specific prompt, a set of reference files, and three related tools). MCP is the tool-and-data transport; Skills sit on top and orchestrate which MCP servers and prompts should be active for a given task. The decision framework in Step 6 walks through the trade: Skills when you want packaged, reusable capabilities; raw MCP when you want maximum flexibility and are wiring the agent yourself.

What you'll build in this MCP tool server lab

Model Context Protocol is the tool-interop standard that Claude Desktop, Claude Code, Cursor, Windsurf, LangChain agents, and OpenAI's Agents SDK all speak, and MCP server skills are becoming a hiring-relevant signal for platform engineers building AI infrastructure in 2026. This lab builds an MCP server from scratch on FastMCP, connects direct and LangChain clients to it, then pits MCP against Anthropic Skills and native @tool in a decision framework you can point at in an architecture review. You finish with a working server, a client that speaks the raw protocol, a LangChain agent consuming MCP tools alongside native ones, and concrete intuition for when each abstraction fits. Everything runs against NVIDIA NIM endpoints we provision.

The substance is tool decoupling. You internalise why MCP flips the N×M problem (M agents re-implementing N tools) into N+M (write each tool once, every client plugs in). You build server_basic.py with a @mcp.tool-decorated check_account(email) served over stdio, then write a direct client that spawns the server as a subprocess, completes the initialize handshake, lists tools via tools/list, and calls tools/call with no LLM in the loop so the protocol is visible. You expand to server_full.py with three tools plus a read-only Resource and an HTTP transport, then wire a LangChain agent via langchain-mcp-adapters. You also internalise Tools versus Resources (Tools are invocable with side effects, Resources are read-only data surfaces authorised differently) and stdio versus HTTP (stdio when colocated, HTTP the moment you share across hosts or teams).

Prerequisites: Python decorators and async/await, the react-agent-nim lab or equivalent LangChain exposure, and a rough sense of JSON-RPC. The hosted environment ships with mcp, fastmcp, langchain-mcp-adapters, and the LangChain NIM integration preinstalled, running against our managed NIM proxy, no keys, no GPU provisioning. About 40 minutes of focused work. You leave with an MCP server, a direct client that round-trips tools/call, an MCP-consuming LangChain agent, a hybrid agent mixing MCP tools with native @tool, and a decision framework (Skills vs MCP vs native tools) you can cite when the next design debate lands.