Skip to content

Instantly share code, notes, and snippets.

@lalunamel
Created March 27, 2025 13:22
Show Gist options
  • Save lalunamel/21df1908008400d2e9d1d7243f77724a to your computer and use it in GitHub Desktop.
Save lalunamel/21df1908008400d2e9d1d7243f77724a to your computer and use it in GitHub Desktop.
Model Context Protocol - Spec

https://modelcontextprotocol.io/introduction

MCP - A standard protocol (like LSP for IDEs) to connect LLMs with context and tools. Uses JSON-RPC - An RPC standard that uses JSON - pass a method name and some params, get a result back.

Vocab

  • Hosts - LLM applications (i.e. your IDE or Claude Desktop). Takes all the output from the clients and manages it. Acts as the UI.
  • Clients - Connects to one server instance. Does handshaking (capability exchange), manages talking back and forth between host and server.
  • Servers - Implement tools, contexts
  • Resources - Context, data
  • Prompts - Templates for querying an LLM
  • Tools - Functions the LLM can execute
  • Sampling - Server-initiated agentic behaviors and recursive LLM interactions
  • Requests - Messages sent to initiate an operation. Expect a response. Must include ID and method name. (e.g. tool usage)
  • Responses - Messages sent that fulfill a request. Must include same ID as request.
    • Success
    • Error - Includes an error code and message at minimum
  • Notifications - Messages that do not require a response (e.g. status updates)
  • SSE - Server sent events (like websockets, but only push from server to client)

Text(Resources + Prompt) -> LLM -> Text(Output/Tools)

Capabilities

  • Client
    • roots - provide filesystem roots
    • sampling
    • experimental
  • Server
    • prompts - prompt templates
    • resources - readable resources
    • tools - callable tools
    • logging
    • experimental
  • Sub-capabilities
    • list changed - change notifications
    • subscribed - subscribing to individual items' changes

Architecture

There is a host. A host has many clients. Each client has one server connection. Servers are connected to resources.

  • Host
  • Client
  • Server

Principles

  1. Servers are easy to build
  2. Servers are extremely composable
  3. Servers should not be able to read the whole conversation, nor "see into" other servers
  4. Features can be added to servers and clients progressively through negotiation

Message Types

  • Requests - Messages sent to initiate an operation. Expect a response. Must include ID and method name. (e.g. tool usage)
  • Responses - Messages sent that fulfill a request. Must include same ID as request.
  • Notifications - Messages that do not require a response (e.g. status updates)

Capability Negotiation

  • Servers and clients declare capabilities during initial handshaking
  • Additional capabilities can be negotiated through extensions to the protocol

Base Protocol

All nouns are implemented in a typescript schema

Layers

  • Base Protocol - Core JSON-RPC message types
  • Lifecycle Management - Connection initialization, capability negotiation, and session control
  • Server Features - Resources, prompts, and tools exposed by servers
  • Client Features - Sampling and root directory lists provided by clients
  • Utilities - Cross-cutting concerns like logging and argument completion

Message Types

  • Request
    • id
    • method
    • params (hash, nullable)
  • Response (must include either result or error)
    • id
    • result (hash, nullable)
    • error (hash, nullable)
      • code
      • message
      • data (nullable)
  • Notification
    • method
    • params (hash, nullable)

Lifecycle

  1. Initialization - capability negotiation and protocol version agreement
  2. Operation - Normal protocol communication
  3. Shutdown - Graceful termination

Initialization

  1. Client - initialize request
  2. Server - initialize response
  3. Client - initialized notification

Transports

  • stdio
  • HTTP with SSE
    • servers provide
      • SSE endpoint
      • HTTP POST endpoint

Versioning

Versions are specified with a date string e.g. 2024-11-05

Utilities

  • ping - "are you still there?" to the server or client
  • cancellation - "cancel that last" to the server or client (useful for long running operations)
  • progress - "i'm almost done" to server or client (useful for long running operations)

Server Features

  • prompts - canned prompt templates for particular task (think "slash commands" in slack). E.g. your company has a particular workflow for looking up data on the server - you can encapsulate that into a slash command and make it portable to any LLM UI
  • resources - context, input text that can be given to the LLM (e.g. "read")
  • tools - functions the LLM can call to take actions (e.g. "write")

Prompts

  • capabilities
    • listChanged - declares whether or not the server will send a notification when the list of prompts changes
  • messages
    • prompts/list (client to server)
    • prompts/get (client to server)
      • text
      • images
      • embedded resources (i.e. URIs)
    • notifications/prompts/list_changed (server to client)

See message definitions in schema.

List

Request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "prompts/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}

Response

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "prompts": [
      {
        "name": "code_review",
        "description": "Asks the LLM to analyze code quality and suggest improvements",
        "arguments": [
          {
            "name": "code",
            "description": "The code to review",
            "required": true
          }
        ]
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}

Get

Request

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "prompts/get",
  "params": {
    "name": "code_review",
    "arguments": {
      "code": "def hello():\n    print('world')"
    }
  }
}

Response

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "description": "Code review prompt",
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Please review this Python code:\ndef hello():\n    print('world')"
        }
      }
    ]
  }
}

Resources

  • capabilities
    • subscribe - whether the client can subscribe to be notified of changes to individual resources
    • listChanged - whether the server will emit notifications when the list of available resources changes
  • messages
    • resources/list
    • resources/read
    • resources/templates/list
    • notifications/resources/list_changed
    • resources/subscribe

List

Request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "resources/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}

Response

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "resources": [
      {
        "uri": "file:///project/src/main.rs",
        "name": "main.rs",
        "description": "Primary application entry point",
        "mimeType": "text/x-rust"
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}

Read

Request

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "resources/read",
  "params": {
    "uri": "file:///project/src/main.rs"
  }
}

Response

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "contents": [
      {
        "uri": "file:///project/src/main.rs",
        "mimeType": "text/x-rust",
        "text": "fn main() {\n    println!(\"Hello world!\");\n}"
      }
    ]
  }
}

Templates list

Request

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "resources/templates/list"
}

Response

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "resourceTemplates": [
      {
        "uriTemplate": "file:///{path}",
        "name": "Project Files",
        "description": "Access files in the project directory",
        "mimeType": "application/octet-stream"
      }
    ]
  }
}

Tools

  • capabilities
    • listChanged
  • tools/list
  • tools/call
  • notifications/tools/list_changed

List

Request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {
    "cursor": "optional-cursor-value"
  }
}

Response

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "get_weather",
        "description": "Get current weather information for a location",
        "inputSchema": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name or zip code"
            }
          },
          "required": ["location"]
        }
      }
    ],
    "nextCursor": "next-page-cursor"
  }
}

Call

Request

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": {
      "location": "New York"
    }
  }
}

Response

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
      }
    ],
    "isError": false
  }
}

Utilities

Completion

Provide a client autocomplete capabilities. E.g. There's a dog breed MCP with a tool to list dogs that takes an option breed filter. As you are calling the tool and entering a filter, say you start to type "b" - the MCP will return the list of breeds starting with "b" that you can filter on.

Logging

Exposes the ability for a server to send a client log messages.

Pagination

MCP supports pagination using cursors.

Client Features

Roots

Exposes an ability for servers to ask about what files exist and subscribe to changes to those files. e.g. "what's the working directory for this project?"

  • roots/list
  • notifications/roots/list_changed

Sampling

Allows servers to ask clients to use their LLM connection so that the server doesn't need to e.g. have its own API key.

  • capabilities
    • sampling
  • sampling/createMessage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment