laranevans.com
Topics / Context Engineering / Model Context Protocol

The Model Context Protocol (MCP) is an open standard that lets language-model applications connect to external data, tools, and workflows through a uniform interface. Anthropic introduced it in November 2024. Implementations now exist across multiple model providers, IDEs, and command-line agents.

The protocol exists because the alternative scales badly. Without a shared interface, every host application (a chat client, an IDE plugin, a coding agent) needs custom integrations for every data source it wants to read from (Postgres, Google Drive, GitHub, Linear, a private file system). The number of integrations grows as the product of hosts and sources. MCP collapses that to a sum: a host speaks the protocol, and any compliant server is reachable.

The shape of the protocol

MCP runs over JSON-RPC 2.0. A client (inside the host application) opens a session with a server, the server advertises its capabilities, and the two exchange requests and responses through that session for the rest of the conversation.

Transport is decoupled from message format. The reference implementations support two transports out of the box:

  • stdio. The host spawns the server as a subprocess and reads and writes JSON-RPC over stdin and stdout. Used for local servers (a filesystem server reading the user's home directory, a SQLite server reading a local database).
  • HTTP with Server-Sent Events. The host opens an HTTP connection to a remote server, posts requests, and reads responses on a long-lived SSE stream. Used for hosted servers, including official servers run by SaaS vendors.

The server declares which primitives it implements during the initial handshake. The host then knows what it has to work with for the rest of the session.

The four primitives

MCP servers expose capability through four named primitives. Each one has a different purpose, and a server typically implements a subset rather than all four.

Resources

Read-only context the model treats as material to reason over. A file on disk, a row in a database, a snapshot of a Notion page. The server returns the resource's contents (text, JSON, or binary with a MIME type) and the host adds it to the model's context window.

Resources have URIs. The host uses the URI as a stable handle so the user (or the model) refers back to the same resource across turns without re-fetching every time.

Tools

Functions the model invokes through structured tool calls. Each tool definition includes a name, a description, and a JSON Schema for its parameters. When the model decides to use a tool, the host receives the call, the server executes it, and the result flows back through the host into the model's next turn. See Tool Calling for the underlying mechanic.

Tools have side effects. A "send email" tool sends email. A "create issue" tool creates an issue. The protocol carries no rollback semantics, which means tool design has to account for accidental or adversarial invocation.

Prompts

Pre-built prompt templates the server exposes for the user (or the host application) to invoke explicitly. A code-review server might expose a /review-diff prompt that loads the current diff, applies a review template, and submits it. Unlike resources, prompts are user-initiated rather than model-initiated.

Sampling

A reverse channel through which the server requests LLM completions from the host. Useful when a server needs the model's help to produce a result, such as summarizing a long document before returning it as a resource. Sampling lets servers stay model-agnostic: the host owns the model relationship, the server borrows the inference.

Sampling is the least-implemented primitive across the ecosystem. Many servers never need it. Hosts vary in whether they expose it at all.

Server patterns

MCP servers cluster along three structural axes (what the server is responsible for, how it manages state, and how it is deployed) plus a cross-cutting tool-design dimension. The transport question is already covered above. The other axes deserve their own treatment because the choices ripple into security, observability, and what the agent experiences when using the server.

By responsibility

A loose taxonomy of what MCP servers are built for. Reference and community servers across the ecosystem (modelcontextprotocol/servers) cover all of these shapes:

  • Filesystem gateways. Expose a bounded directory tree through tools like read_file, write_file, list_directory. Almost always scoped to one or a few root paths. The official filesystem server is the canonical example.
  • Database adapters. A thin query proxy that isolates the agent from raw credentials. Tools like list_tables, describe_table, execute_query. The official PostgreSQL server fits this pattern.
  • API facades. Wrap a SaaS API (GitHub, Slack, Linear, Sentry, Jira) behind a small set of intent-shaped tools. The server hides keys, pagination, rate limits, and OAuth from the model.
  • Retrieval connectors. Expose a search index, vector store, or document corpus with tools that encapsulate query and fetch. Cloud drives, knowledge bases, and code-search systems all land here. See RAG for the broader pattern this fits inside.
  • Code-execution environments. Expose a sandboxed runtime (Python, JavaScript, notebooks) with tools to run code, manipulate a virtual filesystem, and return results. Anthropic's Code execution with MCP post by Jones and Kelly (November 2025) argues this shape lets the agent "read tool definitions on-demand, rather than reading them all up-front," which keeps the model's context budget bounded.
  • Orchestrators. A meta-server that fans out to other MCP servers or external systems, exposing higher-level workflow tools ("file a bug and post to the channel"). Often built on frameworks like mcp-agent, which combines MCP with durable workflow execution.

The reference catalog skews toward single-responsibility servers. Multi-responsibility servers exist but trade clarity for surface area.

By statefulness

  • Stateless tool wrappers. Each tool call is an independent RPC. State lives in the underlying system, not in the server. The default for pure API facades, query proxies, and similar adapters. Horizontal scaling is straightforward.
  • Session-scoped state. The server holds transient state per MCP session (caches, handles, workflow progress). State clears on disconnect or restart. The pattern fits multi-step operations and long-running tasks. The MCP roadmap (as of mid-2026) names async-operations work that appears to assume this shape.
  • Persistent state. The server maintains state across sessions and restarts, usually backed by a database. Agent memory, project context, durable workflow state all land here. Persistent-state servers are the closest MCP analog to a traditional backend service.

Tool-design patterns

Tool design is where the most concrete guidance lives. Anthropic's Writing tools for AI agents post and the awslabs/mcp design guidelines both name these patterns. The patterns apply regardless of which responsibility shape the server lives in:

  • Intent-centric tools. Group functionality by what the user is trying to accomplish, not by underlying API endpoint. A create_issue tool that accepts title, body, and labels in one call beats three separate tools for the same workflow. Avoids the "god tool" anti-pattern and the tool-proliferation anti-pattern at the same time.
  • Handle-passing for large results. Tools that produce large payloads return identifiers (a document ID, a result handle) rather than the full payload. A separate tool dereferences the handle when the model needs the contents. The Anthropic code-execution post calls this out explicitly: keeping intermediate results in the execution environment, surfacing summaries and handles rather than full data, keeps context budget bounded.
  • Two-step retrieval. Pair a search tool with a get tool. The model discovers candidates first, then fetches detail on a chosen subset. Reduces tokens compared to a single tool that returns everything matching a query.
  • Progressive disclosure. Tools accept a detail_level parameter (summary, full, raw) so the agent trades verbosity against context cost based on need. Anthropic's code-execution post recommends this directly for a search_tools tool: "a detail level parameter... that allows the agent to select the level of detail required (such as name only, name and description, or the full definition with schemas)."
  • Schema-first design. Tool input and output schemas carry rich descriptions, tight type constraints, enums, and defaults. Tool definitions deserve as much attention as prompts. The model reads them on every turn the tool is available.
  • Safety-constrained tools. Destructive or irreversible operations are either absent, narrowly constrained, or gated through confirmation. A tool that takes raw shell commands without constraints is a vulnerability waiting to land. The awslabs design guidelines reinforce this: tool naming, validation layers, and security scanning belong in the build pipeline.

The patterns compose. A production retrieval connector usually combines intent-centric tools, two-step retrieval, handle-passing, and progressive disclosure. The combination is often what separates a usable MCP server from a noisy one.

Security considerations

MCP servers run code on behalf of the user, and tool definitions land in the model's context window. Both surfaces matter.

A few patterns worth carrying:

  • Consent boundaries belong at the host. The host application controls which servers connect, which tools the model invokes without confirmation, and which require an explicit prompt before execution. The protocol itself does not encode policy, so the host is the enforcement point.
  • Tool descriptions are model input. A tool whose description contradicts its behavior misleads the model. A tool whose description contains hidden instructions becomes a prompt-injection vector. See Prompt Injection for the broader pattern.
  • Server identity matters. A malicious server returns plausible-looking resource content that contains adversarial instructions. The host has no built-in way to distinguish a trustworthy server from a hostile one beyond what the user configured. Treat third-party servers the way you treat third-party browser extensions.
  • Tool arguments are attacker-controllable through the model. If the model accepts user input and passes it to a tool, prompt injection or accidental confusion turns those arguments into a security vector. Validate at the server, not only at the host.

The ecosystem

A reference catalog of MCP servers lives at modelcontextprotocol.io/servers and at github.com/modelcontextprotocol/servers. The early catalog covers local filesystems, SQLite, Postgres, Google Drive, Slack, GitHub, Puppeteer, and similar building blocks. SaaS vendors increasingly publish first-party servers for their own products.

On the host side, Claude Desktop, Cursor, the Claude Code CLI, and several other agent harnesses ship MCP client support. The list grows. The protocol is open and any host able to speak JSON-RPC implements it.

When MCP is the right answer

MCP fits well when:

  • A host needs access to many data sources or tools, and per-source custom code would multiply.
  • The data source or tool is shared across multiple hosts (an internal documentation server reachable from both an IDE plugin and a chat application).
  • Long-running connections matter (a database server that holds connection state across many requests).

MCP fits less well when:

  • A single host needs a single integration and a hard-coded client call costs less than running a separate server process.
  • The interaction is purely one-shot retrieval that a direct HTTP call from inside the host handles with no per-request session overhead.
  • The model never needs to invoke the capability directly, in which case a plain library call inside the host code path stays simpler.

The protocol is one option in the design space, not a default. Hosts that already have first-class integration with a data source rarely benefit from re-routing through MCP.