Build & submit taskBetaadvanced

Build a stdio MCP Server From Scratch: JSON-RPC, Two Tools, and a Protocol Oracle

Every Model Context Protocol (MCP) server you have ever configured is a small program speaking JSON-RPC 2.0 over stdin and stdout. In this task you write one yourself in pure standard-library Python: a server named libra exposing two well-designed tools over a 30-book catalog. You handle the full lifecycle (initialize, the initialized notification, tools/list, tools/call), wire the server into your own Claude Code with a project .mcp.json, and use it in a live session. The local self-check is a real MCP client that spawns your server, speaks the protocol to it, verifies your search results against the catalog it loads itself, and catches stray prints that would corrupt the stream.

1.5 hrs

Est. time

3

Outcomes

6

Rubric criteria

65%

Pass score

What you'll learn

Skills you'll have real reps in after shipping this.

An MCP server is a message loop you can write in pure Python: newline-delimited JSON-RPC 2.0 over stdin/stdout, dispatch on method, echo the request id, flush. Every server you configure from now on is this loop wearing different tools.
The lifecycle has exactly three moving parts before tool calls flow: the initialize request/response that negotiates protocolVersion and capabilities, the initialized notification that must go unanswered, and tools/list where your descriptions and schemas teach the model what to call and how.
stdout is the transport. One stray print corrupts the stream, which is why real servers log to stderr, and why tool failures ride inside results as isError true while protocol failures use JSON-RPC error responses.

The scenario

You have wired MCP servers into Claude Code before: a command, some args, approve, and suddenly the session has tools named mcp__something__do_thing. This task removes the mystery by putting you on the other side of the pipe. An MCP server over stdio is a loop you can write in an afternoon: read a line from stdin, parse the JSON-RPC message, dispatch on the method, print one line back, flush. Once you have written that loop, every server you configure afterwards is legible.

The kit is a tiny library catalog called libra: 30 books in data/books.json and a skeleton whose message loop already runs but whose handlers all answer method-not-found. You implement the lifecycle and two tools, and the self-check plays the client role for real: it spawns python3 server.py, initializes, lists your tools, calls them with queries it verifies against the catalog independently, pokes an unknown book id to test your error handling, and fails the run if your server prints anything to stdout that is not a protocol message. When the live exchange passes, the full wire log becomes your machine-generated evidence.

Your role

You are the engineer building your team's first in-house MCP server. Your deliverable is a working stdio server with two well-described tools, proof that it survives a real protocol exchange, a transcript showing your own Claude Code calling it, and notes a teammate could learn the framing rules from, packaged as a single submission.

Start the task to unlock the full brief

You'll get the step-by-step requirements, setup commands, the 6-criterion grading rubric, tips, and the ability to submit your solution for instant AI grading.

Free to start · submit when you're ready

Build a real MCP server from scratch, hands-on

The fastest way to understand the Model Context Protocol (MCP) is to implement it, and this task has you build a working stdio server in pure standard-library Python: newline-delimited JSON-RPC 2.0 over stdin and stdout, the initialize handshake, the initialized notification, and two catalog tools whose descriptions and typed inputSchema are the interface a model actually reasons over. A local oracle plays the client for real: it spawns your server, drives the full lifecycle, verifies your search results against the dataset independently, tests your error handling with an unknown id, and fails the run if a single stray print corrupts the stream. Then you wire the server into your own Claude Code with a project .mcp.json and capture a session where mcp__libra__ tool calls hit code you wrote. You come away able to read any MCP server's wire traffic, design tools a model picks correctly, and debug the framing mistakes that break real integrations.

Frequently asked questions

Do I need an MCP SDK or any pip packages?

No. The whole point is to speak the protocol with nothing but json and sys from the Python standard library, so you see exactly what every SDK does under the hood. The kit's skeleton already runs the message loop; you implement the four handlers, and the self-check needs nothing beyond Python 3 either.

How does the self-check actually test my server?

check.py is a working MCP client. It launches python3 server.py as a subprocess and speaks real JSON-RPC to it: the initialize round-trip, the initialized notification (your server must stay silent), tools/list, and three tools/call rounds whose answers it verifies against data/books.json, which it loads itself. It also captures everything your server writes to stdout and fails the run on any byte that is not a protocol message.

Can I fake the evidence file or hardcode the answers?

The evidence is the full wire log of a live exchange, generated only when every protocol row passes, and the grader cross-checks it against your actual server.py and the bundled catalog: paired request and response ids, search results that match the data, and handlers that really implement what the log shows. A hand-written log, or a server that returns the oracle's three answers as hardcoded literals, reads as fabrication and fails.