Browse · Writeups
Writeup

MCP: From Copy-Paste Friction to Composable AI Applications

Why Model Context Protocol separates tools, resources, and prompts—and how client support, transport, authorization, and governance shape what developers can build.

Source and teaching reviews passed · Human editorial review pending.

The gap between Claude Desktop and an editor

David Soria Parra kept copying material between Claude Desktop and his editor. Desktop had artifacts he enjoyed using, but no way to extend its capabilities. His editor could work with the filesystem but lacked the same artifact experience. Around July 2024, while working on internal developer tooling at Anthropic, he began looking for a way to connect these applications to integrations he could build himself.

[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) addresses that problem by giving AI applications a common interface to external capabilities. The application connects as a client; an integration exposes functionality as a server, filling a role similar to a plugin. Its target is the application surrounding the model. In the Latent Space conversation published April 3, 2025, the creators explain how this boundary grew from a practical frustration into a protocol.

David recognized an M × N integration problem: many applications each needed many integrations. A shared protocol could let application developers and integration authors implement their respective sides once. He pitched the idea to Justin, who handled much of the initial Claude Desktop integration while David explored editor implementations.

Work began around July, followed by weeks to months of groundwork on clients, servers, and software development kits (SDKs). David’s first editor implementation appeared publicly in Zed about a month and a half before the official release, under a different name. At an internal hackathon roughly a month before release, a server controlling a 3D printer made the promise tangible: an AI application could reach beyond its existing interface into the physical world.

A shared boundary, different application experiences

The main inspiration was Language Server Protocol (LSP), which separates language-specific support from the editor that presents it. Language specialists can build language servers while editor developers focus on their applications. MCP applies the same division of labor to AI integrations and borrows JSON-RPC for communication.

A subtler inheritance was presentation-focused design: capabilities with overlapping behavior may deserve separate representations because applications should expose them differently. From an application developer’s perspective, receiving a function to call, a document to attach, and a reusable prompt are different needs. Tool calling alone does not express all three.

The designers examined criticisms of LSP and avoided copying its particular JSON-RPC approach wholesale. Their strategy was to keep foundational choices conventional and concentrate innovation in the protocol’s primitives. Making that design usable still required SDK work in TypeScript, Python, and Rust—the last for Zed—and reliable launching of local server subprocesses.

Tools, resources, and prompts

MCP began with three core primitives: - Tools expose functions for the model to select and invoke. - Resources expose data or context that an application can bring into a conversation. - Prompts supply user-invoked text or messages, comparable to macros or editor slash commands. The protocol distinguishes these interactions while leaving their interface to the application developer. Shared integrations can support distinct application experiences.

The first Zed implementation supported prompts. A server could retrieve a backtrace from Sentry or another crash tracker and insert it into context before the user asked the model to act. This gave the user direct control over the material in the conversation. Servers could also include prompts demonstrating how to use their tools.

Resources support a different separation: a collection can exceed the model’s context window without being loaded in full. One envisioned application would build a retrieval-augmented generation index over documents or database content exposed by a server, retrieving relevant material for the model. This remained a desired application pattern at the time of the conversation.

A database makes the distinction concrete. Letting the model choose to run a SQL query fits a tool. Exposing table schemas that an application can list and read fits resources. A user could attach a schema, or an application could discover the appropriate one automatically. Each resource has a unique URI, an identifier that a server can interpret to retrieve its content. Many clients still lacked resource support, limiting these interactions in practice.

Zed did use resources to populate its prompt library at startup, with both sides agreeing on the identifier and data formats. A prompt could therefore be distributed as a resource when the application was loading a library: the interaction determined the primitive. The conversation also raised a broader requirement for prompt sharing—support for dynamic, multistep conversations, beyond isolated snippets.

How much should a server shape its data?

The Google Maps example server exposed a familiar API-wrapper problem: its author selected which fields reached the user, making omitted fields unavailable. At that point, MCP tool results deliberately carried text, images, or other messages for direct model consumption, without requiring a structured JSON result matching an output schema.

The proposed improvement was to pass through broader API output and let the model extract relevant information. Address formatting supplied a small example: the model could receive raw address data and format it for the user. Servers would still need to handle awkward encodings or representations. This was a recommendation for the Maps server, rather than its existing behavior.

The underlying bet was that improving models would benefit from broader access to information. Excessive response shaping could discard data they could use. MCP also reflected a larger expectation: access to outside data and the ability to take stateful actions might become major bottlenecks for capable models, making safety and user control around those interactions essential.

[OpenAPI](https://github.com/OAI/OpenAPI-Specification), which describes API endpoints, operates at a different level. The argument for MCP was that purpose-designed tools, resources, and prompts express richer application interactions. Its allowance for state also reflected expectations about future audio and video use. The creators nevertheless treated the approaches as complementary: a readable API specification could be sufficient, and community translators already exposed OpenAPI specifications as MCP servers.

Build one useful tool, then expand

The recommended starting sequence was small: 1. Choose a familiar language and an available SDK. 2. Implement one personally useful tool with a basic description. 3. Connect it to an application over standard input/output and observe the interaction. 4. Add tools, resources, and prompts as needed, then define evaluations and optimize against them. A simple prototype was described as achievable in roughly half an hour—an informal estimate, not a development benchmark.

AI-assisted development could shorten the initial implementation. One suggested approach was to place the SDK code in a model’s context, request a server, and refine the result. Starter servers were described as often taking 100–200 lines. For a language without an SDK, a specification subset plus another SDK could help generate a narrow implementation; a complete SDK remained a larger undertaking.

Servers could contribute behavior as well as API access. A memory server retained information across conversations. A sequential-thinking server offered a structured way to work through a problem without connecting to an external service. Its claimed reasoning benefits were not accompanied by measured results.

Sampling and recursive composition

A proposed morning-summary server illustrated the next step. Fetching posts from favorite subreddits would provide the data, but summarizing them would require a model. Sampling lets a server request a completion from the client managing the model interaction, receive the generated result, and continue its workflow. The server can remain model-independent without bringing its own model SDK or requiring a separate model-access setup.

The example used Cursor to illustrate how the client-selected model could perform the summary; it did not establish that Cursor supported sampling. Such workflows faced a practical adoption dependency: server authors needed capable clients, while client developers needed compelling servers to justify supporting more primitives.

Recursive composition lets an application serve an upstream MCP client while acting as a client of downstream servers. Components can form chains or graphs, and preserving that property was an explicit design goal. These arrangements were already possible, though SDK support for assembling them conveniently was still missing.

A component with both roles might simply proxy requests. One proposed distinction for an agent was an internal model loop that calls tools through downstream clients. MCP’s broader role remained open: representing agents, connecting them, or concentrating on AI applications. Expanding its scope too far risked weakening the abstractions that made it useful.

Tool selection, user control, and trust

There was no universal tool-count limit. Usable capacity depended on the model and the clarity of tool names and descriptions. GitHub and GitLab illustrated how overlapping functions could confuse selection. A respondent considered hundreds of tools plausible for Claude, but gave no model version, benchmark, or success criterion and did not extend the estimate to other models.

Applications could reduce the active tool set in several ways: - Filter tools in the client. - Use a smaller, faster model to select tools for a larger model. - Filter through an MCP proxy consuming other servers. An editor or chat application could also let users switch feature sets between tasks. Model-controlled invocation remains subject to application and user control: clients can filter tools and transform or enrich their descriptions.

The unit of composition was itself debated. One proposal would let servers group related tools, resources, and prompts; another favored separate servers that users could combine. For the ecosystem more broadly, a respondent preferred competing implementations and gradual convergence over a prescribed standard library. Vendor-maintained servers, such as Cloudflare’s for Workers, were expected to become natural choices for their products.

Popularity could not guarantee safety. A later update could compromise a package with strong download counts or reviews. A participant recommended mcp-inspector for examining traffic; registry security remained a software supply-chain problem. Shared vetting and reputation mechanisms were unresolved, and an Anthropic endorsement was discussed only hypothetically.

Small servers as experiments

Many launch servers originated at the internal hackathon. MCP let people prototype capabilities such as memory without access to Claude’s proprietary application code or expertise across the whole system. The memory example was described as roughly 300 lines: a useful starting point, with a more battle-tested implementation potentially needed at larger scale.

The filesystem server addressed the original frustration directly. It exposed file editing and let Claude interact with a local machine during game development, connecting the assistant to work that previously required moving between applications.

Sequential thinking offered branching and more space to work through a problem. A respondent knew of no common lineage with Anthropic’s think tool. The broader opportunity was to expose different thinking patterns through servers, prompts, or tools for different tasks, without prescribing one method for every application.

Some servers could serve as temporary bridges across model capability gaps: an external technique might take days to build while native model behavior required a longer research and training cycle. A hypothetical best-of-three server illustrated the flexibility—request three answers, then select one. No selection method or measured benefit was proposed.

Stateful sessions without permanent connections

Transport design had to reconcile an expectation of increasingly stateful AI interactions with the cost of keeping connections open. MCP’s original SSE transport required clients to remain connected indefinitely, making deployment and operation difficult at scale. The trade-off had been debated publicly for months and was contentious within the core team.

[Streamable HTTP](https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/transports/#streamable-http) offered a simpler baseline while retaining SSE for streaming. A server could expose one endpoint, accept HTTP POST requests, and return results, then add streaming responses and server-initiated requests. If both sides supported session resumption, they could disconnect and continue later. Session state could survive without an uninterrupted connection.

Authorization was evolving alongside transport. At recording time, the draft next revision focused on user-to-server authorization through OAuth 2.1 or a subset of modern OAuth. This would provide an authorization flow for an expected shift toward remote servers, reducing reliance on users manually supplying API keys. The design operated at the transport layer and required framing such as headers; browser-based local authorization and local HTTP remained options under discussion.

The preference was to cover practical cases with few mechanisms. A server could also act as an OAuth authorization server and present an API-key field on its /authorize page. The suggested flow had awkward ergonomics, but avoided adding another authorization method that every client and server would need to consider.

A questioner proposed finer-grained permissions, such as restricting email access to particular correspondents, and asked whether a model could filter the data. The response called for a concrete end-to-end case that existing implementations could not solve, followed by a prototype demonstrating a workable user experience. Another response suggested that a server needing authorization to 20 downstream systems might be better decomposed into smaller servers.

Protocol evolution and the unfinished wish list

Adding a protocol feature creates a lasting compatibility commitment. The maintainers preferred minimal solutions to demonstrated problems, letting extensions establish their usefulness before becoming core features. They acknowledged that authorization had followed a more top-down process than this usual approach.

Contributors were encouraged to start in the specification repository’s discussions and bring working examples or SDK implementations. With extraordinary discussion volume competing for limited attention, practical work carried more weight than opinions alone. The maintainers welcomed feedback while retaining responsibility for a coherent direction, including unpopular decisions; disagreement could also lead to other projects or forks.

A questioner raised working groups and foundation stewardship as governance possibilities. The creators wanted broad participation, including other AI labs, but worried that formal processes could slow development. Outside participation already included Shopify’s Streamable HTTP proposals, Pydantic contributors’ Python SDK commit access, and Block’s specification contributions. Microsoft handled C#, JetBrains Kotlin, and Spring AI Java, with SDK control distributed across organizations.

The closing requests were concrete: more sampling-capable clients to support model-independent summaries of Reddit threads or a week of EVE Online activity, and broader client support for the specification’s other primitives. Incremental adoption had made it possible to start small; fuller implementations would let server authors build richer workflows.

A Godot integration returned to the original game-development motivation: perhaps Claude could run and playtest the game as well as help build it. A participant also mentioned work on a Claude Plays Pokémon hackathon with David Hershey, floating MCP integration as a possibility without an existing plan to include it. The wish remained practical—connect the assistant to the environment where the work happens.

Latent Space

Join Latent Space.

Sign in with Google, or get the newsletter by email.

Loading Google sign-in…

or subscribe by email

Free. Unsubscribe any time.