Cheat sheets

Model Context Protocol (MCP)

Build, call and serve stateless MCP 2026-07-28 servers over stdio and Streamable HTTP.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

Tasks#

TaskCode
Serve over stdiopython3 main.py
Run the stdio demopython3 main.py --demo
Serve Streamable HTTPpython3 main.py --serve
Probe the HTTP serverpython3 main.py --probe
Discover a servermake_request(1, "server/discover")
List toolsmake_request(2, "tools/list")
Call a toolmake_request(5, "tools/call", {"name": "<tool>", "arguments": <args>})
Add a legacy peerclient.add_server("<name>", <transport>, allow_legacy=True)

From Lesson 13.07, 13.07 code/main.py, 13.08 code/main.py, Lesson 13.09, 13.09 code/main.py

Define and run a tool#

TOOLS = [{
"name": "notes_search",name the model sees
"description": "Search note titles and bodies by keyword.",
"inputSchema": {"type": "object",JSON Schema of arguments
"properties": {"query": {"type": "string"}},
"required": ["query"]},
"annotations": {"readOnlyHint": True},hint only
}]
def handle_tools_call(params):
executor = TOOL_EXECUTORS.get(params.get("name"))
if executor is None:unknown tool
return complete({"content": [...], "isError": True})
content = executor(params.get("arguments", {}))
return complete({"content": content, "isError": False})

From 13.07 code/main.py

One tools/call over HTTP#

POST /mcpone message per POST
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28equals the _meta version
Mcp-Method: tools/callequals the JSON-RPC method
Mcp-Name: notes_searchequals params.name
{"jsonrpc": "2.0", "id": 7, "method": "tools/call",
"params": {"name": "notes_search", "arguments": {"query": "MCP"},
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {}}}}

From Lesson 13.09, Lesson 13.06

Architecture#

routesubprocesstokenPOSTstdin/mcphandlerAgent hostmerges toolcatalogsMultiServerClientone Peer perserverstdioone JSON lineeachMCP serverdispatch,HANDLERSAuthorizationserverissues tokensStreamable HTTPPOST /mcpPrimitivestools, resources,promptsroutesubprocesstokenPOSTstdin/mcphandlerAgent hostmerges tool catalogsMultiServerClientone Peer per serverstdioone JSON line eachMCP serverdispatch, HANDLERSAuthorizationserverissues tokensStreamable HTTPPOST /mcpPrimitivestools, resources,prompts

From Lesson 13.08, 13.08 code/main.py, 13.07 code/main.py, Lesson 13.09, Lesson 13.16

Discover, list, call#

1ClientSends server/discover with version andcapabilities in params._meta.2ServerReturns supportedVersions and capabilities. Nosession starts.3ClientSends tools/list. Gets a sorted list with ttlMsand cacheScope.4ClientSends tools/call with name, arguments and a newid.5Servervalidate_request() checks params._meta. A badversion gives -32022.6Serverdispatch() routes by method tohandle_tools_call().7ServerReturns resultType complete with content andisError.

From Lesson 13.06, 13.07 code/main.py, Lesson 13.07

Tips#

  • Sort list items. Stable order gives stable cache keys and model context.
  • Bind local servers to 127.0.0.1. Origin checks are not authentication.
  • Match origins exactly. Prefix checks accept attacker suffixes.
  • Send the bearer token in Authorization. Never in the URL.
  • Return an explicit state handle. Sticky routing breaks on failover.
  • On a tool name collision, prefix or reject. Never overwrite.

From Lesson 13.06, Lesson 13.08, Lesson 13.09, Lesson 13.16

Methods#

CommandWhat it does
server/discoverVersions, capabilities, instructions, server identity
tools/listLists tools. Cacheable
tools/callRuns one tool. Returns content blocks
resources/listLists URI-addressed data. Cacheable
resources/readReads one resource by URI
prompts/list, prompts/getLists and renders prompt templates
subscriptions/listenLong-lived POST stream for change events
notifications/cancelledCancels a request on stdio. No response

From Lesson 13.06, Lesson 13.09, Lesson 13.29

Key concepts#

Stateless core
Every request carries the metadata to interpret it.
Request metadata
Version and capabilities are required. clientInfo is recommended.
Complete result
Every success has resultType set to complete.
Cacheable result
Lists, reads and discovery carry ttlMs and cacheScope.
Tool annotations
readOnlyHint, destructiveHint are hints. The server enforces.
stdio
Client-launched subprocess. JSON on stdout, logs on stderr.
Streamable HTTP
One /mcp endpoint. Each message is a new POST.
Legacy era
Up to 2025-11-25, initialize then notifications/initialized.

From Lesson 13.06, Lesson 13.07, Lesson 13.09

Defaults#

SettingDefaultNote
PROTOCOL_VERSION2026-07-28Modern revision in the lessons
server/discover ttl3_600_000ms, cacheScope public
tools/list ttl60_000ms, cacheScope public
resources/read ttl5_000ms, cacheScope private
cache_scopeprivatecomplete() default
HTTP port8017--serve binds 127.0.0.1
MAX_REQUEST_BYTES1_048_576HTTP body cap
legacy_probe_timeout_ms1_000Deadline for one initialize probe

From 13.07 code/main.py, 13.08 code/main.py, 13.09 code/main.py

Troubleshooting#

SymptomCauseFix
-32022Version not supportedPick from data.supported. Retry, new id
-32602Missing request metadataStamp _meta on every request
HTTP 400 -32020Header disagrees with bodyMirror version, method and name exactly
HTTP 403 on POSTOrigin not allowedAdd the exact origin to the allowlist
HTTP 405GET or DELETE on /mcpPOST, and subscriptions/listen for events
stdio client fails to parseLogs on stdoutWrite diagnostics to stderr
HTTP 401Invalid, expired or wrong-audience tokenGet a token for this resource
403 insufficient_scopeTool needs more scopeStep up with the challenge scope

From Lesson 13.06, Lesson 13.07, Lesson 13.08, Lesson 13.09, Lesson 13.16

Glossary#

JSON-RPC 2.0
Envelope of every MCP request, response and notification.
SSE
text/event-stream response. Notifications, then the final response.
MRTR
Multi Round-Trip Request. input_required, then a fresh retry.
PKCE
Verifier and S256 challenge. Protects an intercepted code.
CIMD
HTTPS metadata document whose URL is the client id.
DCR
Deprecated dynamic client enrollment for compatibility.
RFC 9728
Protected-resource metadata. Names the authorization servers.

From Lesson 13.06, Lesson 13.09, Lesson 13.12, Lesson 13.16

Questions and answers#

Tool error or protocol error?
isError: true for a valid call that fails. JSON-RPC error for a bad request.
Can a server call the client?
No. It returns input_required. The client retries with a new id.
How do I cancel?
stdio: send notifications/cancelled. HTTP: close the response stream.
Does stdio need OAuth?
No. Authorization applies to HTTP transports.
When do I send initialize?
Only to an allowlisted legacy peer. Never by default.

From Lesson 13.07, Lesson 13.08, Lesson 13.16, Lesson 13.29, Lesson 13.06