FAQ
What MCP is, and what it isn't
Is MCP a library, an SDK, or a specification — and why does pip install mcp exist? It is a specification: a document defining JSON-RPC methods and their meanings. mcp is one implementation, in one language, and you could implement the protocol without it. This matters because when the SDK does not expose something, the spec is where the answer is, and because a Python server and a TypeScript client interoperate without either knowing the other exists.
I already have tool calling. What does MCP actually buy me? Distribution and reuse. If your tools serve one application you control, with one model provider, MCP buys you very little and costs you a process boundary — plain tool definitions are the better engineering choice, and you should make it. MCP earns its keep when the same capability must be reached from several applications, by several teams, or by users bringing their own client. The question is not which is more sophisticated; it is whether anything other than your own code will ever call this.
Does connecting a server give a model access to my machine, or bypass my authentication? Two halves, and both are true. No: the model sees only the tools your server defines, MCP adds no authority, and a server behind an API still faces that API's permissions. But: a local stdio server is a program running with your user's permissions, so it can do anything you can do — that risk is real and comes from running the software, not from the protocol. Treat a local server as an installation, not a setting.
Is this an Anthropic thing? Will it work with other models? Created by Anthropic, released November 2024 under MIT, now community-governed with a public proposal process. The protocol does not mention a model vendor anywhere; a server you write works with any client, whatever model is behind it.
Things that used to be true
Every tutorial I've read uses FastMCP. Is my code wrong? No, it is out of date by one rename. from mcp.server.fastmcp import FastMCP became from mcp.server import MCPServer in SDK v2, ClientSession became Client, McpError became MCPError, and every field moved to snake_case. Change the imports and the field names and everything else you learned still applies.
The docs I found describe initialize and a session. Why does my server never see one? Because initialize is gone. Spec 2026-07-28 made MCP stateless; server/discover replaced the handshake and clients are not obliged to call it. The practical consequence for a server author is that you cannot keep per-connection state and cannot assume any setup call happened — everything a request needs rides in that request's _meta.
Sampling was perfect for my use case. What now? This is the uncomfortable one. Sampling let your server borrow the client's model, so you needed no API key. It is deprecated, and the replacement is to call an LLM provider's API from your server directly — which is more work: you now own a key, a bill and a model choice you did not have before. The trade was made because sampling required the server to speak first, which a stateless protocol cannot support, and because so few clients implemented it that servers depending on it worked almost nowhere.
Roots are gone. How does my server know which directory to work in? Pass the path as a tool argument and validate it. Roots were always advisory — the spec said servers should respect them, never must — so they were never a security boundary, and a mechanism that looks like one but is not is worse than none. Validate the path against an allowlist you control.
My logging either broke the connection or vanished entirely. Two causes, one symptom. If the connection broke, you wrote to stdout on a stdio server, and stdout is the protocol channel — use logging, which writes to stderr. If it vanished, you used notifications/message, which is deprecated; log to stderr or use OpenTelemetry.
Design questions with no obvious answer
Why can't my server just ask the user a question mid-call? Because there is no open channel to ask down. The server returns an InputRequiredResult carrying the question, the client collects the answer, and the client calls the tool again with inputResponses attached. Your handler therefore runs more than once for one logical operation, which means it must be safe to re-enter — do the irreversible thing after the questions, not before.
Can I collect an API key with a form elicitation? No — the specification says must not, for passwords, keys, tokens and payment credentials. The reason is not the transport; it is that a form answer passes through the client and into the model's context, and contexts get logged, cached and retained. Use elicit_url, which sends the user out of band and returns only whether they consented.
Should this be a tool or a resource — and why do some clients ignore my resources? The design answer is who decides: the model decides to call a tool, the application decides to load a resource. The practical answer is that tool support is universal and resource support is not, so a correctly-designed resource can be one nobody can reach. When the data genuinely matters, ship both — the resource, and a thin read-only tool over the same function.
What to take into the next lesson
MCP is a specification, it grants no authority the model did not already have, and it is worth adopting when something other than your own code will call your tools. The 2026-07-28 removals all share one cause: the server may no longer speak first. And two rules are absolute — never write to stdout on stdio, and never put a credential in a form. Next: where to look when this course goes out of date.