Showcase

Recorded sessions

Two recorded exchanges with the demo server, one per era of the protocol, and the browser debug page that calls a server by hand. Each message is listed in order: the request the client sent, then the reply the server gave.

tool resource prompt

MCP 2026-07-28 · 2025-11-25 · 2024-11-05 · Streamable HTTP · stdio

Revision 2026‑07‑28 — stateless

No handshake. Every request names its version in _meta, and the server answers it on its own. Client and server keep no shared state between calls.

2026‑07‑28

List, call, read

Field names are the ones on the wire. resultType and the _meta server info are this revision's additions; the tools array is cut to two entries to fit the page.

Client
tools/list · POST /mcp
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}
Server
result · tools/list
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      { "name": "add", "title": "Add", "description": "Add two numbers",
        "inputSchema": { "type": "object",
          "properties": { "a": { "type": "number" }, "b": { "type": "number" } },
          "required": ["a", "b"] } },
      { "name": "greet", "title": "Greet", "description": "Greet someone by name",
        "inputSchema": { "type": "object",
          "properties": { "name": { "type": "string" } }, "required": ["name"] } }
    ],
    "resultType": "complete",
    "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "demo", "version": "1.0.0" } },
    "ttlMs": 0,
    "cacheScope": "private"
  }
}
Client
tools/call · add
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "add",
    "arguments": { "a": 2, "b": 3 },
    "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} }
  }
}
Server
result · tools/call
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [ { "type": "text", "text": "{\"sum\":5}" } ],
    "structuredContent": { "sum": 5 },
    "isError": false,
    "resultType": "complete",
    "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "demo", "version": "1.0.0" } }
  }
}
Client
resources/read · config://app
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/read",
  "params": {
    "uri": "config://app",
    "_meta": { "io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {} }
  }
}
Server
result · resources/read
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "contents": [ { "uri": "config://app", "mimeType": "application/json", "text": "{\"theme\":\"dark\"}" } ],
    "resultType": "complete",
    "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "demo", "version": "1.0.0" } },
    "ttlMs": 0,
    "cacheScope": "private"
  }
}

Revision 2025‑11‑25 — the handshake

The older shape. A client opens with initialize, reads the server's capabilities, and only then lists, calls and renders. moonmcp answers every revision back to 2024‑11‑05 without a config change.

2025‑11‑25

initialize, then work

A request that does not name a version falls back to this handshake. The same server, the same tools — only the opening moves differ.

Client
initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {},
    "clientInfo": { "name": "claude-desktop", "version": "1.0.0" }
  }
}
Server
result · initialize
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "tools": { "listChanged": false },
      "resources": { "subscribe": false, "listChanged": false },
      "prompts": { "listChanged": false }
    },
    "serverInfo": { "name": "demo", "version": "1.0.0" },
    "instructions": "Arithmetic and greetings, for trying a client out."
  }
}
Client
notifications/initialized
{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}
Client
tools/call · greet
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": { "name": "greet", "arguments": { "name": "leo" } }
}
Server
result · tools/call
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [ { "type": "text", "text": "hello, leo" } ],
    "isError": false
  }
}
Client
prompts/get · review
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "prompts/get",
  "params": { "name": "review", "arguments": { "code": "fn f() { 1 }" } }
}
Server
result · prompts/get
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "description": "Ask for a code review",
    "messages": [
      { "role": "user", "content": { "type": "text", "text": "Review this code:\nfn f() { 1 }" } }
    ]
  }
}

Run it yourself

The captures above are the demo server over Streamable HTTP. Build it for native and the documentation page is served at /docs next to the endpoint:

$moon run src/examples/http --target native

Then open http://127.0.0.1:12000/docs. to_asgi(docs=None) leaves it off.