python-mcp-server-generator

Generate a complete MCP server project in Python with tools, resources, and proper configuration

By github · 10,357 installs

npx skills add github/awesome-copilot --skill python-mcp-server-generator

Source repository · Upstream listing

Python MCP Server Generator Create a Model Context Protocol (MCP) server in Python with the official [MCP Python SDK](https://github.com/modelcontextprotocol/python sdk) v2. SDK v2 supports the MCP specification revision [2026 07 28](https://modelcontextprotocol.io/specification/2026 07 28). The same server also serves clients that use earlier revisions. Workflow Copy this checklist and track your progress: [ ] Step 1: Create the project. [ ] Step 2: Write the server. [ ] Step 3: Write the tests. [ ] Step 4: Run the tests until they pass. [ ] Step 5: Configure the client. Step 1: Create the project Run these commands: Then delete main.py . The server goes in server.py . Without no package , uv makes a src/ package layout, and the tests cannot import server.py . uv init makes the .gitignore file. Do not write a different one. Step 2: Write the server Start from this template: Then change the template for the request of the user: 1. Replace divide with the tools that the user needs. 2. Give each tool full type hints and a docstring. The SDK makes the input schema from the type hints. The docstring becomes the tool description. 3. Return a Pydantic model or a TypedDict when the client needs machine readable data. The SDK makes the output schema from the return type. 4. Use async def for I/O. The SDK runs a sync tool on a worker thread. 5. Mark a read only tool with @mcp.tool(annotations=ToolAnnotations(read only hint=True)) (from mcp.types ). Use destructive hint=True for a destructive tool. 6. Add resources ( @mcp.resource("users://{user id}") ) and prompts ( @mcp.prompt() ) only when the user asks for them. Use stdio by default. Read [references/streamable http.md](references/streamable http.md) only when the user asks for a remote server or an HTTP server. Step 3: Write the tests Put test server.py next to server.py . Write a test for each tool and for each ToolError : The in memory Client needs no subprocess and no port. It connects with the 2026 07 28 revision. The mcp package installs anyio , which supplies the anyio marker. Do not add pytest asyncio . Step 4: Run the tests until they pass 1. Run uv run pytest . 2. If a test fails, read the error. Fix the server or the test. 3. Run uv run pytest again. 4. Continue only when all tests pass. Step 5: Configure the client For VS Code, write .vscode/mcp.json : For Claude Desktop, run uv run mcp install server.py . Tell the user these commands: uv run server.py starts the stdio server. The server waits for a host on stdin and prints nothing. uv run mcp dev server.py opens the MCP Inspector. The Inspector needs Node.js. Gotchas SDK v2 and the 2026 07 28 revision changed many SDK v1 patterns. Do not copy SDK v1 examples. SDK v2 removed FastMCP and mcp.server.fastmcp . Import the server class with from mcp.server import MCPServer . Import Context , Image , Audio , Resolve , Elicit , ElicitationResult , AcceptedElicitation , Message , UserMessage , and AssistantMessage from mcp.server.mcpserver . Give the server name as the first MCPServer argument. Give all other constructor arguments as keyword arguments. Their positional order changed in SDK v2. Set version . If you do not set it, the server reports an empty version. Give the transport options ( transport , host , port , json response , stateless http , transport security ) to run() , not to MCPServer(...) . The SDK v2 types use snake case fields, for example read only hint , structured content , and is error . Raise ToolError for an error that the model must read. For other exceptions, the model gets only a generic error message. Do not raise MCPError for a tool failure. The client gets a protocol error, not a tool result with is error . Many hosts do not show this error to the model. In a stdio server, stdout is the protocol channel. Do not call print() . Log to stderr with the logging module. Do not use ctx.elicit() . It fails on a 2026 07 28 connection. For user input during a tool call, annotate a parameter with Resolve(fn) . Return Elicit(message, Model) from fn . Send list change notifications with await ctx.notify tools changed() . A 2026 07 28 connection drops ctx.session.send tool list changed() . For stdio and HTTP, the lifespan runs one time, when the server starts. Each in memory Client(mcp) in a test runs the lifespan again. Read its object with ctx.request context.lifespan context . The 2026 07 28 revision deprecates these features ([SEP 2577](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2577)). Do not add them to a new server: Sampling ( ctx.session.create message() ): Call the LLM provider API directly. Protocol logging ( ctx.log() , ctx.info() , and similar methods): Use the standard logging module. Roots ( ctx.session.list roots() ): Get paths from tool parameters, resource URIs, or the server configuration. The 2026 07 28 revision has no SSE transport. Use Streamable HTTP.