← All articles

What is the MCP Protocol?

May 21, 2026 · 16 min read

The Model Context Protocol (MCP) is an open standard for connecting AI assistants to external data and systems. An MCP client (for example Claude Desktop, Cursor, or VS Code) talks to an MCP server over a transport; the server exposes tools, resources, and prompts that the client discovers at runtime and uses during conversations.

MCP client  ←JSON-RPC→  MCP Server  ←APIs→  DB, Jira, files

MCP uses JSON-RPC for messages. The transport only carries bytes—stdio pipes, HTTP POST, or optional SSE streams—not a separate application protocol.

Who created MCP?

Anthropic introduced the Model Context Protocol in November 2024 as an open standard: the specification, SDKs, and reference tooling are open source, and the canonical spec is maintained at modelcontextprotocol.io.

Anthropic was the first major host to ship MCP in Claude Desktop, but the protocol is not Claude-only. Cursor, VS Code, and other clients can connect to the same MCP servers regardless of which model provider powers the assistant. Community and vendor contributions extend the ecosystem—similar to how HTTP outlived any single browser.

What it solves

Chat models cannot reach your databases, ticketing systems, or internal APIs without integrations. Each client used to need custom plugins. MCP standardizes:

  • How capabilities are described and discovered
  • How the model calls tools with typed arguments
  • How context (resources) and workflows (prompts) are supplied
  • How multiple backends can be composed behind one client

Server capabilities: Tools, Resources, and Prompts

An MCP server exposes three capability types. They answer different questions:

Aspect Tools Resources Prompts
Purpose Execute actions Provide context Start structured workflows
Who triggers Model (via client) User or client User (slash command / picker)
Side effects Often yes No (read-only) No (templates only)
Discovery tools/list resources/list prompts/list
Typical example Create ticket, run query API spec, doc, schema Code review, incident runbook

Tools

Tools are functions the model can invoke through the client (tools/call). Each tool has a name, a clear description (the model reads this to decide when to call it), and a JSON Schema for arguments.

Tools may have side effects: creating records, running queries, sending notifications, triggering deployments.

Examples:

  • create_jira_issue(summary, project) — open a ticket
  • run_sql(query) — execute a read-only or guarded query
  • search_customers(email) — look up CRM data

When to use tools

  • The assistant must act on external systems.
  • Operations are discrete, parameterized, and worth auditing individually.
  • You need explicit boundaries (who may call which action).

When not to use tools

  • The user only needs to read a document or file — use a Resource.
  • You want a fixed multi-step experience for humans — consider a Prompt.

Resources

Resources are addressable, read-only content the client can list and fetch (resources/list, resources/read). Each resource has a URI (for example file:///docs/api.md or jira://PROJECT-123), optional MIME type, and metadata.

Examples:

  • OpenAPI specification, runbook, policy PDF
  • Read-only snapshot of a sprint board
  • Database schema description

When to use resources

  • Ground the model in stable or large context without bloating the system prompt.
  • The user or client explicitly chooses what to attach (resource picker, “@ file” patterns).
  • Data is read on demand and does not require a tool call.

When not to use resources

  • The model must change state — use a Tool.
  • The content is tiny and never changes — it can live in server instructions instead.

Prompts

Prompts are prompt templates with arguments, exposed by the server (prompts/list, prompts/get). The client renders them into a user message—often via slash commands or a command palette.

They encode team workflows: how to run a code review, triage an incident, or format release notes.

Examples:

  • code-review — arguments: repo, pr_number
  • incident-triage — arguments: service, severity
  • summarize-meeting — arguments: transcript_uri (can reference a Resource URI)

When to use prompts

  • Repeatable human-initiated workflows with consistent structure.
  • Discoverability in the UI (“/draft-bug-report”).
  • The server owns the wording and steps, not the host’s generic system prompt.

When not to use prompts

  • The model should decide autonomously whether to act — use Tools.
  • You only need background context — use Resources.

Combining primitives

Real servers usually mix all three:

Support bot

  • Resources: product FAQ, pricing page
  • Tools: lookup_order, create_refund (privileged, audited)
  • Prompts: escalate-to-human with structured fields

Engineering copilot

  • Resources: repo README, architecture doc
  • Tools: run_tests, post_pr_comment
  • Prompts: security-review, changelog-from-commits

Design rule of thumb: start with Resources for context, add Tools only for actions you are willing to audit, add Prompts for workflows your team runs every day.

Lifecycle at runtime

  1. Client connects to the server over a transport.
  2. Client discovers capabilities: tools/list, resources/list, prompts/list.
  3. During a session: the model calls tools; the user or client attaches resources; the user invokes prompts.

Details live in the MCP specification; implementation guides are linked at the end of this article.

Transports

The transport carries JSON-RPC between client and server. Docker is not a transport—it is a way to package and run the same server (stdio or HTTP) in a container.

The protocol defines two standard transports today; an older HTTP+SSE model remains common in existing deployments.

Transport What it is Typical use
stdio Client spawns server as subprocess; messages on stdin / stdout; logs on stderr Local dev, Claude Desktop, Cursor
Streamable HTTP Single MCP HTTP endpoint; client POSTs JSON-RPC; server may reply with JSON or SSE Remote service, multiple clients, production
HTTP + SSE (legacy) Older dual-endpoint design (protocol 2024-11-05) Existing servers; often bridged with mcp-remote

stdio

In stdio transport, the client launches the MCP server as a subprocess. The server reads JSON-RPC from stdin and writes responses to stdout, one message per line. Anything logged by the server should go to stderr so it does not corrupt the protocol stream.

Best for:

  • Local development on your machine
  • Claude Desktop and Cursor when the client manages the process
  • Single-user, single-machine setups

In .NET:

builder.Services
    .AddMcpServer()
    .WithStdioTransport()
    .WithTools<MyTools>();

Streamable HTTP

Streamable HTTP is the current remote transport. The server exposes one HTTP endpoint (for example /mcp). The client sends each JSON-RPC message as an HTTP POST. The server responds with either a single JSON body or an SSE stream when streaming is needed.

Best for:

  • Shared servers behind a load balancer or API gateway
  • Teams that deploy MCP like any other HTTP service
  • Stateless or horizontally scaled backends

Security expectations from the spec: validate the Origin header, bind to localhost in development, and authenticate clients in production. See the transports specification and Build MCP Server with Streamable HTTP for a minimal .NET implementation.

HTTP + SSE (legacy)

Before Streamable HTTP, MCP used a dual-endpoint model: one URL for SSE (server → client) and another for client POSTs. Many tutorials and deployments still use this pattern.

If you maintain such a server, clients often connect through mcp-remote, which bridges HTTP/SSE to stdio for desktop hosts. See Build MCP Server with SSE Transport and Server-Sent Events (SSE) and EventSource for implementation context.

Docker (deployment, not transport)

Docker packages your MCP server binary or container image. The same server can run:

  • stdio inside a container — client runs docker run -i and speaks over the container’s stdin/stdout
  • HTTP inside a container — expose a port, set ASPNETCORE_URLS, put the service behind ingress

See Run MCP Server in Docker for Dockerfile and production notes.

Choosing a transport

  • Local, one user → stdio (with or without Docker).
  • Shared remote service → Streamable HTTP.
  • Legacy SSE deployment → keep HTTP+SSE or plan migration; use mcp-remote for desktop clients.

How to connect

Claude Desktop — stdio

Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "my-server": {
      "command": "dotnet",
      "args": ["run", "--project", "/path/to/MyMcpServer"]
    }
  }
}

Restart Claude Desktop after changes.

Claude Desktop — stdio via Docker

{
  "mcpServers": {
    "my-server": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "my-mcp-server:latest"]
    }
  }
}

The -i flag keeps stdin open so JSON-RPC can flow.

Claude Desktop — Streamable HTTP

Connect directly to a Streamable HTTP endpoint (recommended for new remote servers):

{
  "mcpServers": {
    "remote": {
      "url": "http://localhost:5131/mcp",
      "type": "http"
    }
  }
}

Adjust host, port, and path to match your server (MapMcp("/mcp") or root). See Build MCP Server with Streamable HTTP for the full .NET walkthrough.

Claude Desktop — remote HTTP (legacy SSE)

Use mcp-remote to bridge an HTTP/SSE URL to stdio:

{
  "mcpServers": {
    "remote": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:5071/sse"]
    }
  }
}

Adjust the URL to your server’s SSE endpoint.

Cursor

Project-level .cursor/mcp.json or global ~/.cursor/mcp.json:

{
  "mcpServers": {
    "my-server": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-everything"]
    }
  }
}

Replace command / args with your server executable. For HTTP-based servers, use the URL form supported by your Cursor version and server SDK (Streamable HTTP endpoint or a stdio bridge).

Building your own server

Security

  • Treat every tool as a privileged API: validate inputs, enforce authorization, log invocations.
  • Resources should expose only data the connected user may read.
  • On HTTP transports, validate Origin, use TLS in production, and avoid binding to 0.0.0.0 on developer machines unless intentional.
  • Prefer narrow tool sets per server rather than one “god server” with every integration.

Summary

MCP is a small set of ideas: tools for actions, resources for context, prompts for repeatable workflows—carried over stdio or HTTP (Streamable HTTP for new remote deployments). Pick primitives by intent, pick transport by deployment shape, then wire your host’s config to launch or reach the server.

Next steps

Related articles