MCP Without the SDK

SERIES · 20 NOTES · 2026

The Model Context Protocol, taken apart one JSON message at a time. Every note here writes the work an SDK would do for you: the JSON-RPC 2.0 framing, the initialize handshake and version negotiation, both transports, all three server primitives, the three client primitives, and the plumbing they share. The code is Go. A protocol you have only seen through a wrapper is a protocol you cannot debug.

The series runs in specification order and each note assumes the ones before it. The handshake note takes JSON-RPC for granted, and by the time the security note argues about where the trust boundary sits, it assumes you already know what a tool description is and where it lands in a model’s context. Start at the beginning if any of that is new.

The last note is one server that uses every primitive, runs over both stdio and Streamable HTTP, sits behind OAuth 2.1, is tested end to end, and comes with a single annotated trace through all of it. For the engineering around the protocol rather than the protocol itself, see MCP by Design.

MCP Without the SDK
1

Drive an MCP Server With Four JSON Messages

The Go SDK never prints the protocol. This post does.
MCPGOAIPROTOCOL
2026-05-01
2

MCP Is a Protocol, Not a REST API

The same tool built both ways: what discovery, schemas, and the callback direction actually cost
MCPGOAIPROTOCOL
2026-05-03
3

JSON-RPC 2.0: What Every MCP Message Looks Like

Three message shapes, one error object, and a hundred and fifty lines of Go that every MCP transport is built on
MCPGOPROTOCOLJSON-RPC
2026-05-05
4

The Handshake: initialize, Capabilities, and Version Negotiation

The 2025-11-25 initialize exchange, hand-rolled in Go against a real server. Later revisions dropped it from the protocol core.
MCPGOPROTOCOLJSON-RPC
2026-05-07
5

Transport I, stdio: Two Pipes and a Subprocess

The simplest MCP transport, built by hand on both sides with no SDK, plus the stderr rule that silently breaks servers
MCPGOPROTOCOLSTDIO
2026-05-09
6

Transport II, Streamable HTTP: One Endpoint, Two Directions

A single HTTP path carries the protocol. In 2025-11-25 a session id is optional. In 2026-07-28 it is gone.
MCPGOPROTOCOLHTTP
2026-05-11
7

Tools, Part 1: Discovery and the inputSchema Contract

What the model actually receives when it lists a server's tools, how the schema is built from a Go type, and why a tool's annotations cannot be trusted
MCPGOPROTOCOLTOOLS
2026-05-13
8

Tools, Part 2: Calling, Content Types, and Structured Output

Every shape a tool result can take: the five content types, structured output validated against a schema, and the difference between a failed tool and a failed protocol
MCPGOPROTOCOLTOOLS
2026-05-15
9

Resources: list, read, templates, and subscriptions

The primitive for data the model reads, the counterpart to tools, with URI templates for whole families and live notifications when something changes
MCPGOPROTOCOLRESOURCES
2026-05-17
10

Prompts: Server-Authored Conversation Starters

The third server primitive and the one people misread: templates the user selects, rendered into messages that can embed a server's own resources
MCPGOPROTOCOLPROMPTS
2026-05-19
11

Completion: Argument Autocomplete for Prompts and Resources

One method that suggests values as a user fills in an argument, and the context field that scopes those suggestions to what is already filled
MCPGOPROTOCOLCOMPLETION
2026-05-21
12

Sampling: When the Server Calls Your Model Back

The protocol inverts. A server asks the client to run the host's model, with no API key of its own and a human able to deny every request
MCPGOPROTOCOLSAMPLING
2026-05-23
13

Roots: Telling the Server Where It May Look

The client hands the server a list of directories it is allowed to use, a boundary the server asks for and the client defines and enforces
MCPGOPROTOCOLROOTS
2026-05-25
14

Elicitation: When the Server Needs to Ask the User

The server asks a person for input mid-task, with a flat form for ordinary data and a URL handoff for the secrets a form must never touch
MCPGOPROTOCOLELICITATION
2026-05-27
15

Progress, Cancellation, Ping, Pagination, and _meta

The plumbing every MCP primitive shares: how a long call reports progress, how either side cancels one, how a connection is checked, how a list is paged
MCPGOPROTOCOLAI
2026-05-29
16

Logging and the Notification Family

Structured server logs filtered by severity, and the list_changed notifications that keep a client's view of a server from going stale
MCPGOPROTOCOLLOGGING
2026-05-31
17

Authorization: OAuth 2.1 for HTTP MCP Servers

How a remote server proves who is calling: the discovery chain, resource indicators that bind a token to one server, and the passthrough ban that stops a confused deputy
MCPGOPROTOCOLOAUTH
2026-06-02
18

Security: Tool Poisoning, Prompt Injection, and the Trust Boundary

A server's words flow straight into the model's context. The anatomy of how that becomes an attack, and where the host has to stand to stop it
MCPGOPROTOCOLSECURITY
2026-06-04
19

Tasks: Durable, Async Tool Calls

The experimental 2025-11-25 primitive that turns a request into call-now-fetch-later, hand-rolled on the wire because the SDK has not caught up
MCPGOPROTOCOLTASKS
2026-06-06
20

A Complete MCP Server and Client in Go

One server that uses every primitive, runs over both transports, sits behind auth, and is tested end to end, with one annotated trace through all of it
MCPGOPROTOCOLAI
2026-06-08