Lab 02 — Capture and read MCP wire traffic
Lesson 02 · MCP Servers · ~30 min
In Lab 01 you ran a server end-to-end through Claude Desktop and trusted the host to do the right thing. In this lab you sit on the wire between client and server, watch the actual JSON-RPC bytes flow past, identify each lifecycle phase by eye, and hand-craft one request to confirm the server responds exactly the way the spec promises.
Goal: see actual JSON-RPC bytes flowing between client and server; identify each lifecycle phase (Connect / Initialize / Operate / Close); hand-craft one request and observe the server's response.
What you need
- MCP Inspector — invoked via
npx @modelcontextprotocol/inspector. No global install needed;npxdownloads it on demand. - The filesystem server still configured from Lab 01
(
@modelcontextprotocol/server-filesystemvianpx). - The Python venv from Lab 01 — optional for this lab, but keep it handy if you want to wire in your own server later.
- Node.js 18+ on
PATH(verify withnode --version).
Step 1 — Launch the filesystem server under Inspector
Inspector is a tiny proxy: it spawns the MCP server as a subprocess, speaks the protocol on one side, and exposes a browser UI on the other so you can watch every message. Run:
npx @modelcontextprotocol/inspector \
npx -y @modelcontextprotocol/server-filesystem /tmp/mcp-demo
The first invocation will download Inspector if you have never used it. Once it boots it prints a
local URL, typically something like http://127.0.0.1:6274. Open that URL in your
browser. You should see Inspector's split-pane UI with a transcript area, a request composer, and
tabs for tools / resources / prompts.
If the browser tab does not open automatically, copy the URL from the terminal output. If Inspector reports the port is busy, see the troubleshooting box at the bottom of this guide.
Step 2 — Identify the lifecycle phases in the transcript
As soon as Inspector connects to the filesystem server, it runs the standard MCP handshake. Open the transcript pane and read messages top-to-bottom. You should be able to find, in order:
- an outgoing
initializerequest — client tells the server which protocol version it speaks and what client capabilities it supports; - an incoming
initializeresponse — note thecapabilitiesblock: this is the server advertising which feature families it implements (tools, possiblyresources, etc.); - an outgoing
notifications/initialized— fire-and-forget notification from client to server meaning "handshake done, you may start sending events"; - any subsequent tool calls or list queries you trigger from the UI.
The first three messages collectively are the Initialize phase from the theory reading. Everything after them is the Operate phase. The transport itself coming up is Connect; tearing it down is Close.
Step 3 — Hand-craft a tools/list request
Inspector exposes a way to send raw JSON-RPC. Depending on your version it is labelled "Send Raw Request", "Custom Request", or shown as a JSON editor next to the tool list. Locate that pane and paste:
{"jsonrpc":"2.0","id":42,"method":"tools/list","params":{}}
Send it and watch the transcript. You should see your request appear (outgoing), followed by a
response with the same id: 42 and a result.tools array. Each entry has a
name, a human-readable description, and an inputSchema (JSON
Schema). That schema is what a host like Claude Desktop converts into a tool definition for the LLM.
Step 4 — Hand-craft a tools/call request
Now actually call one of the tools the server just advertised. Send:
{"jsonrpc":"2.0","id":43,"method":"tools/call","params":{"name":"list_directory","arguments":{"path":"/tmp/mcp-demo"}}}
The response will have id: 43 and a result.content array. The
content shape is worth memorising — it is typically a list of
{"type": "text", "text": "..."} blocks. MCP intentionally returns content as an array
of typed blocks (text, image, resource reference) rather than a single string, so a server can
return rich, mixed output without inventing its own encoding.
If the path is empty you may get an empty listing or a textual placeholder — that is still a
successful response. An error would arrive as a result with isError: true
(an MCP-level tool error) or as a JSON-RPC error object (a protocol-level error).
Step 5 — Reading a real transcript
Scroll back to the top of the Inspector transcript. Walk the messages in order and, for each one, decide which lifecycle phase it belongs to:
- Connect — transport coming up. Often invisible in the Inspector transcript itself, but you can see it in the terminal as the subprocess being spawned.
- Initialize —
initializerequest,initializeresponse,notifications/initialized. - Operate — every
tools/list,tools/call,resources/list, plus any notifications either side emits mid-session. - Close — what happens when you stop Inspector or the server exits. You will see this when you kill the process at the end of the lab.
Take a screenshot of the transcript with the Initialize phase visible — you'll attach it to your homework write-up.
What you should leave with
By the end of this lab you should be able to answer, in one sentence per phase: "For each lifecycle phase, what JSON-RPC method appears on the wire?" Write that answer down — it is Task 1 of the homework. The point is not to memorise method names; it is to be able to look at any unfamiliar MCP transcript in the future and immediately orient yourself.
Troubleshooting
- Stale node processes hogging Inspector's port. If Inspector refuses to start
because the port is in use, list lingering MCP-related processes with
pgrep -fl modelcontextprotocoland kill the ones you do not need (kill <pid>). On Windows, use Task Manager orGet-Process nodein PowerShell. - JSON typos in raw requests. A missing quote or trailing comma in the
composer will come back as
-32700 Parse error. Paste the request into a JSON validator if the error is not obvious from a glance. - "Method not found" on
prompts/list. This is normal — the filesystem server may not advertise apromptscapability, so the method is legitimately not implemented. Check thecapabilitiesblock of theinitializeresponse to see which feature families are available. - Inspector UI looks different from this guide. Inspector is on a fast release cadence; pane names may shift. The transcript, the tool list, and the raw-request composer are always present — they may just be on different tabs.