Handmade Claude Code 5/7 — MCP
Part five of the Handmade Claude Code campaign: the agent plugs into the world. The Model Context Protocol is how tools that live in other processes — a database, a browser, a ticket tracker — offer themselves to any agent that speaks it. This part makes yours speak it: start the servers, shake hands, put their tools in front of the model, call them, survive their failures, use their prompts and resources, and shut them down cleanly.
This session continues the agent you built in parts one to four, in the same repository. The MCP client is yours too — JSON-RPC over stdio is small enough to write, and writing it is the point. An MCP SDK is out of contract.
Servers
.mcp.json (in the working directory)
{"mcpServers": {"<name>": {"command": "sh", "args": ["srv.sh"], "env": {"K": "V"}}}}
At launch, before the first model call, every server is started as a child
process — command with args, the working directory as its directory,
env added to its environment — and spoken to over its stdin and stdout
in JSON-RPC 2.0, one JSON object per line.
The handshake: an initialize request (with protocolVersion,
capabilities and clientInfo), then the notifications/initialized
notification, then tools/list. A server that fails to start, or fails
the handshake, is reported on stderr by name and skipped; the run goes on
without it.
Tools
Every tool a server lists is advertised to the model as
mcp__<server>__<tool>, with the server's description and its
inputSchema as the input_schema. A call becomes tools/call with
name (the server's tool name) and arguments (the model's input). The
result's content text blocks, joined, are the tool result content; a
result with isError: true, or a JSON-RPC error reply, is an error result
with the message as content. The loop goes on.
Prompts
A server that lists prompts (prompts/list) contributes slash commands:
/mcp__<server>__<prompt> <args> calls prompts/get with the arguments
mapped positionally onto the prompt's declared arguments, and the
messages it returns become the user message (their text, joined).
Resources
A token @<server>:<uri> in the prompt reads a resource: resources/read
with that uri, and the text of the returned contents travels with the
prompt like a mentioned file.
Shutdown
When the run ends, every server's stdin is closed; a server still alive a moment later is killed. No orphans.
The judges
The quality panel — architecture, performance, code quality, test quality, technical governance and DX review — sits on the rungs where its subject is decided, one verdict per judge per rung, on top of the rung's own points. There is no closing review: what you build is judged as you build it, and a rung you never reach is a verdict you never get.
The ladder
- Set up and carry parts one to four forward (10)
- The handshake (20)
- Tools are advertised (30)
- A tool call goes through (30)
- Errors come back as results (20)
- A server that will not start (20)
- Prompts are commands (20)
- Resources are mentions (20)
- Environment and shutdown (20)
0
Public
Reinvent the Wheel
handmade-claude-code-5-mcp
30 min
~12 per session
No
10–30
- ai-agent
- harness
- mcp
- handmade-claude-code
- campaign
1
Set up and carry parts one to four forward
+10 pts per passing check · +10 for completing the task
10
pts / check
+10 pts per passing check · +10 for completing the task
This part continues your agent. Same repository, same command, same
model protocol, same tools, context and skills — what grows is the set
of tools that live in other processes, spoken to over the Model Context
Protocol.agent: started as: -C
[--yes] -p "" Your AGENTS.md (or README.md) must still carry the two lines the
platform captures into session memory:agent:andtest:. If you are
starting in an empty folder, your earlier work is fetched for you —
check that the lines are there and that the agent still builds and
runs.The first rung re-checks what the earlier parts earned: a bash round
trip with theskilltool advertised. Everything after it is MCP work,
against a scripted server the checks write for you.The MCP client is yours; an MCP SDK is out of contract.
Wrapping
claude,codex,gemini,aideror any other coding agent,
or building on an agent SDK that owns the loop, is not building one.Judged by
The Debrief 2
The handshake
+20 pts per passing check · +10 for completing the task
20
pts / check
+20 pts per passing check · +10 for completing the task
Before the first model call, every server in
.mcp.jsonis started and
greeted:initialize(withprotocolVersion,capabilities,clientInfo), then thenotifications/initializednotification, thentools/list— in that order, as JSON-RPC 2.0 objects, one per line, on
the server's stdin. The scripted server logs everything it receives.Judged by
Architecture 3
Tools are advertised
+30 pts per passing check · +10 for completing the task
30
pts / check
+30 pts per passing check · +10 for completing the task
What a server lists, the model sees. Every tool from
tools/listis
advertised asmcp__<server>__<tool>with the server'sdescription
and itsinputSchemaas theinput_schema— next to your own six
tools, in every request.Judged by
Code Quality 4
A tool call goes through
+30 pts per passing check · +10 for completing the task
30
pts / check
+30 pts per passing check · +10 for completing the task
The model calls
mcp__fake__echo; the agent sendstools/callwithname: "echo"and the model's input asarguments, waits for the
reply, and hands the text of itscontentback as the tool result.Judged by
Test Quality 5
Errors come back as results
+20 pts per passing check · +10 for completing the task
20
pts / check
+20 pts per passing check · +10 for completing the task
Servers fail in two ways and the model must hear about both. A result
withisError: trueis an error result whose content is the result's
text. A JSON-RPC error reply is an error result whose content is the
error's message. Neither stops the loop.6
A server that will not start
+20 pts per passing check · +10 for completing the task
20
pts / check
+20 pts per passing check · +10 for completing the task
One bad entry in
.mcp.jsonmust not take the run down. A server whose
command cannot be started is reported on stderr — by name — and
skipped; the other servers are greeted as usual and the model still
gets its answer.7
Prompts are commands
+20 pts per passing check · +10 for completing the task
20
pts / check
+20 pts per passing check · +10 for completing the task
A server that lists prompts contributes slash commands.
/mcp__<server>__<prompt> <args>callsprompts/getwith the arguments
mapped positionally onto the prompt's declaredarguments, and the
messages it returns become the user message the model receives.Judged by
Architecture 8
Resources are mentions
+20 pts per passing check · +10 for completing the task
20
pts / check
+20 pts per passing check · +10 for completing the task
@<server>:<uri>in the prompt reads a resource:resources/readwith
thaturi, and thetextof what comes back travels with the prompt
like a mentioned file.Judged by
Test Quality 9
Environment and shutdown
+20 pts per passing check · +10 for completing the task
20
pts / check
+20 pts per passing check · +10 for completing the task
A server gets the
envits entry declares, on top of the agent's own
environment. And when the run ends, no server outlives it: its stdin is
closed, and a server still alive a moment later is killed.