Use the official Python MCP SDK to expose two tools over stdio, then wire
them into a real host. By the end you will have called your own tools from
an AI assistant.
What this adds
Lab 03 taught the concept. This is the real thing.
The toy protocol from Lab 03 showed you the shape: discovery, schema,
invocation. Real MCP uses that same shape, but with a standard SDK,
a defined transport (stdio or HTTP), and actual host support.
When this lab works, any MCP-compatible host — Claude Desktop, Cursor,
Copilot CLI, Goose — can discover and call your tool without any
custom integration code.
Run it
cd ai_ecosystem_labs
python3 03b-real-mcp/server.py
Starting here? Quick setup
git clone https://github.com/BanditF/ai_ecosystem_labs
cd ai_ecosystem_labs
python3 -m pip install "mcp[cli]"
python3 03b-real-mcp/server.py
# In a second terminal:
mcp dev 03b-real-mcp/server.py
Requires Python 3.10+, mcp[cli], and one MCP-compatible host installed (see Step 4).
Time guide. Setup: 5–15 min for the SDK and host wiring. Working through it: 20–40 min depending on whether you already use an MCP-compatible host.
Step 1: Install the SDK
pip install mcp
The MCP Python SDK
is the official library from Anthropic. It handles the protocol wire
format, tool registration, and transport — you just define your tools.
Step 2: Define two tools
Create server.py. This server exposes two tools:
count_words and reverse_text. One counts words.
The other reverses a string. That is still small enough to see the whole
shape at once, but it makes the registry feel more real.
FastMCP handles discovery, schema generation, and the
stdio transport. Each @mcp.tool() decorator registers a
callable tool with a name, description (from the docstring), and typed
parameters (from the signature). In this example, the host should see
both count_words and reverse_text.
What to notice
The docstring becomes the tool description a host shows to the model.
That description is how the model decides when to call this tool. Write
it as if you are explaining the tool to someone who has never seen your code.
Step 3: Test it locally
Run the server directly to confirm it starts without errors:
python server.py
It will appear to hang — that is correct. The server is running over
stdio, waiting for a host to connect. Hit Ctrl+C to stop it.
To inspect what the server exposes without a host, use the MCP CLI:
pip install "mcp[cli]"
mcp dev server.py
This opens the MCP Inspector in your browser — a tool that lets you list
tools, call them manually, and see the raw JSON going back and forth.
Step 4: Wire it to a host
Pick one host. Each needs a config entry that tells it where to find
your server.
Reload the window. The tool will be available in Cursor's agent mode.
Step 5: Call it
In Claude Desktop or Cursor, open a chat and ask:
"How many words are in this sentence: The quick brown fox jumps over the lazy dog?"
The model will decide to call count_words, pass the sentence
as text, and return your result. You should see the tool
call appear in the chat — most hosts show a collapsed tool-call badge.
If the tool does not appear
Check the path in the config — it must be absolute.
Confirm python server.py runs without errors.
Restart the host after any config change.
Check the host's MCP logs: Claude Desktop logs to ~/Library/Logs/Claude/.
Try this
Three things to try before moving on.
Call reverse_text with a long phrase.
Try something longer than a one-word test, then compare the result shape to count_words. The operations are different, but the JSON envelope still looks familiar because the protocol layer stays consistent.
Add a third tool to server.py.
For example, create a word_count tool that returns the unique-word count for a string, restart the server, and run tools/list again. You should see it appear automatically from the decorator registration.
Point a different MCP host at the same server.
If you have Claude Desktop, Cursor, Goose, or another MCP-compatible client, connect it to this exact server.py and call the same tools from there. The useful thing to notice is that the server does not care which host is on the other end.
When to use MCP — and when not to
Use MCP when
You want your tool to work across multiple hosts (Cursor, Claude Desktop, Goose, etc.) without custom integration per host
You are building a tool server for a team or product
You want clean separation between the tool and the model host
Skip MCP when
You only need one tool in one app you fully control
Your provider's native function-calling already covers the use case
The host you are targeting has built-in tools that do the job
You want the simplest possible thing first — plain function calling is fine