AI·Frontier
← Back to Home
AI Tutorials

Build a Custom MCP Server in Python and Wire It to an Agent: 2026 Tutorial

Build a Custom MCP Server in Python and Wire It to an Agent: 2026 Tutorial

Build a Custom MCP Server in Python, Then Wire It to an Agent

The fastest way to understand agent tooling is to build the smallest useful thing: an MCP server that exposes two tools, a client that discovers them, and an agent loop that calls them. You can finish this in an afternoon, and the concepts transfer directly to production work, because almost every agent integration in 2026 is the same protocol wearing different clothes.

We will build a small "notes" server — one tool to search a local notes directory, one to fetch a single note — then test it with the official inspector, wire it into an agent, and finish with the cost and security checks most tutorials skip.

Step 1: Set Up the Project

Use a virtual environment so the SDK cannot collide with anything system-wide.

  • Create the folder and activate a venv: python3 -m venv .venv && source .venv/bin/activate
  • Install the SDK: pip install mcp
  • Create notes/ with a few markdown files, and server.py next to it.

MCP speaks JSON-RPC 2.0. Locally it moves over stdio, which means your process reads requests on stdin and writes responses on stdout — and that has one hard rule you must respect from the first line of code: never print to stdout for logging. Any stray print() corrupts the protocol stream. Log to stderr instead.

Code editor showing a Python project with an MCP server file

Step 2: Define Two Tools

With the modern SDK, a tool is a typed, documented function. The type hints are the schema, and the docstring is what the model reads when deciding whether to call it. That second point is the whole game: a vague docstring produces an agent that calls the wrong tool and then explains itself confidently.

  • Decorate each function with the server's tool decorator.
  • Type every parameter, and return structured data (a dict) rather than a stringified blob.
  • Write docstrings that state the input, the output, and when not to use the tool.
  • Validate and clamp inputs — a path traversal guard on the note filename is one line and non-negotiable.

Two tools is the right scope for a first server, and usually the right scope for a tenth one. Servers with thirty tools are harder for a model to use than five servers with six tools each, because tool selection degrades as the description space grows. Split by domain, not by database table.

Step 3: Test It With the Inspector Before Any Agent Touches It

Run the server under the official inspector in a separate terminal. It launches the server, lists its tools, and lets you call each one with hand-typed arguments and see the raw result. This isolates protocol bugs from prompt bugs, and in practice it is where you discover that your search tool returns 40 KB for a query the model will run every turn.

  • Launch the inspector against your server command.
  • Confirm both tools appear with readable descriptions.
  • Call each with valid input, then with deliberately invalid input — confirm you get a clean error rather than a crash.
  • Check payload sizes. Truncate or paginate anything that can return more than a few kilobytes.

If the Inspector run is clean, most integration failures left are client configuration, not server code.

Step 4: Connect It to a Client

Configuration file showing an MCP server entry with a command and arguments

Desktop and terminal clients discover MCP servers through a small JSON configuration: a name, the command to launch, its arguments, and any environment variables. Two details bite people here. First, use absolute paths — clients do not always inherit your shell's working directory. Second, pass secrets through environment variables rather than baking them into the arguments, because that config file ends up in your dotfiles repo sooner than you expect.

Once connected, the client performs a capability handshake and asks the server what it offers. That negotiation is why MCP spreads well: add a tool to the server and every connected client sees it on the next session, with no client-side redeploy and no prompt rewrite.

Step 5: Write the Agent Loop Around It

Now the part that is actually an agent rather than a chat: a loop that sends the user's goal plus the tool schemas, inspects the model's response for tool calls, executes them, appends the results, and repeats until the model answers without requesting a tool.

  • Cap the loop. A maximum of five to ten iterations prevents runaway spend when a tool keeps returning nothing useful.
  • Return errors as data. An error string the model can read lets it retry intelligently; an exception that kills the process does not.
  • Keep tool output small. Every tool result is context you pay for on every subsequent turn.
  • Put the stable parts first. System instructions and tool schemas at the top, the fresh user turn at the bottom, so the provider's cache can actually fire.

Step 6: The Cost and Security Check

Once it runs, measure before you polish. Log three numbers per run: input tokens, cache-hit tokens, and cost. If your cache-hit rate is near zero, something in your prefix is mutating — a timestamp, a shuffled tool order, or a retrieval result pasted above the instructions. Fixing ordering is usually the single biggest cost win available, and it costs nothing.

On security, treat tool descriptions as untrusted input the moment you install a third-party server. Early-2026 research catalogued dozens of CVEs across MCP servers, clients, and tools, with shell injection making up 43% of them, and risk lists now call out tool poisoning through compromised descriptions, shadow servers running outside governance, and cross-tenant context leaks. Practical rules: run servers you did not write in a sandbox, never interpolate model output into a shell command, and scope filesystem tools to a single directory.

Where to Go Next

From here the natural extensions are a remote transport (streamable HTTP instead of stdio), a memory component that persists across sessions, and publishing the server to a registry so others can install it. Do them in that order, and do them one at a time, with the Inspector in front of each change. The protocol is small; the discipline of testing tools in isolation is what separates an agent that works in a demo from one that works on Monday morning.