Servers describe themselves
After a short handshake, tools/list returns each tool's name, description and input schema. Nothing is hard-coded in the app: connect a new server and its tools simply appear.
The Model Context Protocol is a standard way for an AI app to ask a server what it can do, and then to ask it to do it. The model chooses; the app makes the calls; the server does the work.
Two small servers and four tools. Messages follow the MCP specification (JSON-RPC 2.0, version 2025-06-18); the model's choices are fixed per question so every run is repeatable.
The host starts a files server and its MCP client says hello: initialize, the server's capabilities, initialized. Then tools/list. The model knows nothing about this server until those tool descriptions are put in its prompt.
Ready. A host with a model and no servers. The model has no tools at all.
| server | message | |
|---|---|---|
| – | (nothing yet) |
After a short handshake, tools/list returns each tool's name, description and input schema. Nothing is hard-coded in the app: connect a new server and its tools simply appear.
The model only reads tool descriptions and asks for a call. The host holds the connections, sends tools/call and returns the result. That's where permissions belong.
A server written once works in any MCP host: chat apps, IDEs, agents. Without a standard, every app had to write its own integration for every tool.
Live: the latest message on the wire
$ (no messages yet)Live: the tools the model is shown
$ prompt --tools
(no tools: no servers connected)Live: the conversation, with tool results
$ conversation
(no question yet)Every MCP message is a JSON-RPC 2.0 object. Requests have an id and a method, and their reply carries the same id. Notifications, like notifications/initialized, have no id and get no reply.
Two transports carry them. With stdio, the host starts the server as a child process and writes to its stdin, which is how most local servers run. With Streamable HTTP, the server runs somewhere else and the client POSTs to one endpoint, with authorization on top.
Tools are one of three things a server can offer. Resources are data the app can read into context, like a file or a database row, and prompts are reusable templates the user can pick. The handshake's capabilities say which ones a server supports.
A tool that fails should say so in its result, with isError: true and a useful message. The model can then try something else. A server that crashes or hangs leaves it nothing to work with.
The protocol can mark a tool as read-only or destructive, but it's the host that decides whether to ask. An app that allows every call lets the model book, send and delete on a guess.
A tool's description goes straight into the model's prompt. A malicious server can hide instructions there, and a local stdio server runs with your permissions. Install servers like you install software.
A host connects a files server and a calendar server. The model asks to call list_events. Who sends the request to the calendar server?
The model asks for read_file on a file that doesn't exist. What does it get back?
Here the model's choices are scripted. A real model picks from the descriptions it's given, so vague names and descriptions lead to wrong or missed calls. Writing them well is most of the work of building a server.
Every tool definition takes up space in the prompt. With dozens of servers that adds up, so hosts let users switch servers off, or load tool definitions only when they're needed.
Servers can send notifications too, such as notifications/tools/list_changed when their tools change. They can also ask the host for things, like asking its model for a completion (sampling) or asking the user for input.
Remote servers use OAuth so a user can grant an app access to their account without handing over a password. Local stdio servers usually read credentials from environment variables the host passes in.