MCP Server Basics
8 examples to get you started with Building MCP Servers - 5 basic and 3 intermediate.
Search across all documentation pages
8 examples to get you started with Building MCP Servers - 5 basic and 3 intermediate.
pip install mcp.npm install @modelcontextprotocol/sdk.The smallest possible MCP server: create an instance and run it over stdio.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("demo-server")
if __name__ == "__main__":
mcp.run(transport="stdio")FastMCP is the high-level server class in the Python SDK; it handles the connection and capability negotiation stages for you."demo-server" is the server's name, which a client may display when listing connected servers.mcp.run(transport="stdio") starts the event loop and blocks, reading requests from stdin and writing responses to stdout.Add a callable tool using the @mcp.tool() decorator.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
@mcp.tool()
def get_weather(city: str) -> str:
"""Return a short weather summary for a city."""
return f"It is sunny in {city}."
if __name__ == "__main__":
mcp.run(transport="stdio")get_weather in the server's capability manifest, so it appears during negotiation.city: str) becomes the tool's input schema, the client uses this to know what arguments to send.Expose read-only content at a URI using @mcp.resource().
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("config-server")
@mcp.resource("config://settings")
def get_settings() -> str:
return "theme=dark\ntimezone=UTC"config://) is arbitrary, choose one that describes what the resource represents.Provide a reusable prompt template with @mcp.prompt().
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("prompt-server")
@mcp.prompt()
def summarize_request(topic: str) -> str:
return f"Please summarize the latest updates about {topic} in three bullet points."Start the server as a subprocess a client can spawn.
python server.pyRelated: stdio vs HTTP/SSE MCP Deployment Comparison - when to move beyond stdio
Combine all three capability types in one server, mirroring a small real deployment.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("tickets-server")
TICKETS = {"T-1": "Open: printer offline", "T-2": "Closed: VPN issue"}
@mcp.tool()
def get_ticket(ticket_id: str) -> str:
"""Look up a support ticket by ID."""
return TICKETS.get(ticket_id, "Ticket not found.")
@mcp.resource("tickets://open")
def list_open_tickets() -> str:
return "\n".join(k for k, v in TICKETS.items() if v.startswith("Open"))
@mcp.prompt()
def triage_prompt(ticket_id: str) -> str:
return f"Review ticket {ticket_id} and suggest a next action."
if __name__ == "__main__":
mcp.run(transport="stdio")get_ticket performs a lookup, so it's a tool. list_open_tickets is read-only data, so it's a resource.TICKETS dict is fine for a demo, a production server would back this with a real datastore.The same tool-registration pattern using the official TypeScript SDK.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({ name: "weather-server", version: "1.0.0" });
server.tool(
"get_weather",
{ city: z.string() },
async ({ city }) => ({
content: [{ type: "text", text: `It is sunny in ${city}.` }],
})
);
await server.connect(new StdioServerTransport());McpServer plays the same role as FastMCP, it manages connection and negotiation for you.zod schemas define the tool's input shape, the TypeScript equivalent of Python's type hints.server.connect(new StdioServerTransport()) is the TypeScript SDK's version of mcp.run(transport="stdio").Related: Building an MCP Server with the TypeScript SDK - full walkthrough of the TypeScript SDK
A quick manual check that your server negotiates correctly before wiring it into a real client.
npx @modelcontextprotocol/inspector python server.pyRelated: How MCP Servers Handle Requests - the lifecycle this inspection is checking | Testing MCP Servers Before Deployment - automated tests for the same handlers
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the current Model Context Protocol Python/TypeScript SDKs. Model names, SDK versions, and the MCP spec move quickly - verify current specifics at platform.claude.com/docs and modelcontextprotocol.io before relying on them.
Reviewed by Chris St. John·Last updated Jul 18, 2026