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 ticketrun_sql(query)— execute a read-only or guarded querysearch_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_numberincident-triage— arguments:service,severitysummarize-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-humanwith 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
- Client connects to the server over a transport.
- Client discovers capabilities:
tools/list,resources/list,prompts/list. - 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 -iand 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-remotefor 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
- .NET MCP server tutorial —
WithStdioTransport()for local clients - Streamable HTTP guide — recommended remote HTTP in .NET
- SSE transport guide — legacy HTTP+SSE in .NET
- .NET MCP transports — SDK reference
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 to0.0.0.0on 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.