2026-06-16
I Finally Understood MCP After Ignoring the Tutorials and Opening curl -v
A practical deep dive into the Model Context Protocol (MCP) by reverse engineering a real MCP server with Python, curl, JSON-RPC and Server-Sent Events.
Loading
Fetching scores, snapshots, evidence trails, and company signal drift.
2026-06-16
A practical deep dive into the Model Context Protocol (MCP) by reverse engineering a real MCP server with Python, curl, JSON-RPC and Server-Sent Events.
2026-04-01
SaaSocalypse has raised a $10 million Series A to become the AI-native analytics firm for predicting SaaS collapse, consolidation, and strategic decay.
2026-03-26
Google's March 24, 2026 TurboQuant announcement points to a meaningful compression shift for KV cache memory and vector search, with broader consequences for AI app design.
2026-03-25
Jensen Huang's March 2026 token-spend line captures a real management shift: AI usage is becoming visible, budgetable, and dangerously easy to mistake for productivity.
TL;DR: If you've ever wondered how an AI agent "magically" discovers tools exposed by an MCP server, forget the marketing diagrams for a moment. Grab
curl, inspect the network traffic, and it all starts making sense.
When I first started reading about the Model Context Protocol (MCP), almost every explanation looked something like this:
User
↓
LLM
↓
MCP
↓
Tools
The explanation usually stopped at:
"The LLM discovers tools and calls them."
That wasn't satisfying.
I wanted to know:
So instead of reading more tutorials, I decided to reverse engineer a real MCP server.
I used LangChain's public MCP endpoint:
https://docs.langchain.com/mcp
The first thing I realized is that you don't need an LLM at all.
Using the Python MCP SDK:
tools = await session.list_tools()
The server replied with a list of tools.
This was my first "aha!" moment.
Unlike REST APIs, where developers typically read documentation to learn which endpoints exist, an MCP client simply asks the server:
tools/list
and the server replies with every available tool and its input schema.
Conceptually:
Client
│
│ tools/list
▼
MCP Server
│
▼
Available tools
The MCP server itself becomes the source of truth.
Suppose the server advertises:
search_docs_by_lang_chain(query: string)
I can simply call it.
result = await session.call_tool(
"search_docs_by_lang_chain",
{
"query": "How do I create a LangGraph agent?"
}
)
No LLM.
No reasoning.
No AI.
Just:
Client
│
tools/call
│
▼
MCP Server
│
Runs tool
│
Returns result
This was probably the biggest realization:
MCP is fundamentally a protocol for discovering and invoking tools.
The LLM is just another client.
The obvious next question was:
Is the Python SDK hiding some secret sauce?
Turns out...
Not really.
I replaced it with curl.
First, I listed the available tools.
curl -X POST https://docs.langchain.com/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"tools/list"
}'
The server immediately returned the list of tools.
Then I called one.
{
"jsonrpc":"2.0",
"id":2,
"method":"tools/call",
"params":{
"name":"search_docs_by_lang_chain",
"arguments":{
"query":"How do I create a LangGraph agent?"
}
}
}
It worked.
The SDK wasn't performing magic.
It was simply wrapping the protocol.
curl -v Was More Educational Than the DocsRunning with verbose output:
curl -v ...
revealed far more than I expected.
The first surprise:
Connected to docs.langchain.com
SSL connection using TLSv1.3
HTTP/2
Nothing exotic.
Just HTTPS.
Instead of REST endpoints like:
GET /tools
POST /search
everything goes through a single endpoint:
POST /mcp
The operation is encoded inside the request body.
{
"jsonrpc":"2.0",
"method":"tools/list"
}
or
{
"jsonrpc":"2.0",
"method":"tools/call"
}
This is JSON-RPC.
This confused me initially.
JSON is just structured data.
{
"query":"LangGraph"
}
JSON-RPC is a way of calling remote functions.
{
"jsonrpc":"2.0",
"method":"tools/list",
"params":{}
}
Think of it this way:
JSON
↓
A document
JSON-RPC
↓
A function call encoded as JSON
The response headers included:
content-type: text/event-stream
Instead of returning:
{
"result": ...
}
the server returned:
event: message
data:
{
"result": ...
}
This is Server-Sent Events (SSE).
Most REST APIs work like this:
Request
↓
Response
↓
Connection closes
SSE keeps the connection alive.
Instead of one response, the server can stream many events.
event: message
data: {"progress":10}
event: message
data: {"progress":20}
event: message
data: {"progress":30}
This is why AI APIs often stream tokens, and why MCP uses SSE as its transport.
Even though tools/list only returned a single event, the protocol supports long-running tools that stream progress back to the client.
Suppose the MCP server advertises:
search_docs(query)
fetch_page(url)
list_examples(topic)
A user asks:
"How do I create a LangGraph agent?"
Who decides to call search_docs?
Not the server.
Instead:
tools/call.The MCP server never interprets natural language.
It simply executes requested tools.
Initially I thought of MCP as:
AI magic
After spending an hour with Python, curl and the network inspector, I now think of it as:
HTTPS
+
JSON-RPC
+
Runtime Tool Discovery
+
Tool Invocation
The LLM is not MCP.
The tools are not MCP.
MCP is simply the protocol that allows clients to discover and invoke capabilities exposed by a remote service.
The biggest surprise wasn't that MCP exists.
It was how ordinary it is.
The SDK wasn't doing anything magical.
The protocol wasn't doing anything magical.
Everything ultimately boiled down to a few JSON-RPC messages sent over HTTPS.
Sometimes the fastest way to understand a protocol isn't another tutorial.
It's opening curl -v.
There are still a few things I'd like to explore:
Those will probably become future posts.