docs(python-mcp): update skill, instructions, agent, and plugin for MCP Python SDK v2 🤖🤖🤖 (#4737)

* docs(python-mcp-server-generator): rewrite skill for MCP Python SDK v2

- Target MCP Python SDK v2 (MCPServer) and MCP specification 2026-07-28
- Replace FastMCP imports with `from mcp.server import MCPServer`
- Rewrite the description with explicit triggers and exclusions
- Add the compatibility field (uv, Python 3.10+, npx for the Inspector)
- Add a five-step workflow checklist: create, write, test, validate, configure
- Pin the SDK with `uv add "mcp[cli]>=2,<3"` and use a flat uv app layout
- Add server and in-memory Client test templates
- Add a test-fix-retest validation loop with `uv run pytest`
- Add a Gotchas section for SDK v1 to v2 changes and deprecated features
- Move Streamable HTTP guidance to references/streamable-http.md
- Remove generic guidance that the model already knows

* docs(python-mcp-server): update instructions for MCP Python SDK v2

- Target MCP Python SDK v2 (MCPServer) and MCP specification 2026-07-28
- Replace FastMCP imports with MCPServer and mcp.server.mcpserver imports
- Move transport options from the constructor to run() and streamable_http_app()
- Use Resolve and Elicit for user input instead of ctx.elicit()
- Use ctx.notify_tools_changed() for list change notifications
- Explain ToolError and MCPError behavior for tool failures
- Mark sampling, protocol logging, and roots as deprecated
- Add transport security, CORS, and multi-worker guidance
- Add an in-memory Client test pattern
- Rewrite the text in ASD-STE100 Simplified Technical English
- Use single-quoted frontmatter values

* docs(python-mcp-expert): update agent for MCP Python SDK v2

- Target MCP Python SDK v2 (MCPServer) and MCP specification 2026-07-28
- Replace the retired GPT-4.1 model with GPT-6 Sol
- Replace FastMCP guidance with MCPServer guidance
- Add guidance for transport options, Resolve and Elicit, and notify_tools_changed()
- Explain ToolError and MCPError behavior for tool failures
- Mark sampling, protocol logging, and roots as deprecated
- Add SDK v1 to v2 migration as a supported scenario
- Rewrite the text in ASD-STE100 Simplified Technical English
- Use single-quoted frontmatter values

* chore(python-mcp-development): update plugin metadata for MCP Python SDK v2

- Remove FastMCP from the plugin description and README
- Describe the actual plugin contents: one skill and one agent
- Replace the fastmcp keyword with mcp-python-sdk
- Bump the plugin version to 2.0.0
- Regenerate marketplace.json and docs/README.plugins.md

* fix(python-mcp-server-generator): correct transport security, lifespan, and SSE notes

* fix(python-mcp-server): remove invalid structured_output advice and align with skill

* fix(python-mcp-expert): add missing SDK v2 rules and remove repeated guidance

* fix(python-mcp-expert): remove the retired model from frontmatter

* fix(python-mcp-server-generator): state Node.js as the MCP Inspector prerequisite
This commit is contained in:
Burak Kaygusuz
2026-10-09 12:00:23 +11:00
committed by GitHub
parent a32e48e7b7
commit 3fb8ae0f2c
10 changed files with 396 additions and 257 deletions
+132 -86
View File
@@ -1,105 +1,151 @@
---
name: python-mcp-server-generator
description: 'Generate a complete MCP server project in Python with tools, resources, and proper configuration'
description: 'Use this skill when the user wants to create a new Model Context Protocol (MCP) server in Python. Also use it to expose Python functions, an API, or a database to AI clients as MCP tools. The skill makes a uv project with the MCP Python SDK v2 (MCPServer), typed tools, in-memory tests, and client configuration. Do not use it for an MCP client or for a server in another language.'
compatibility: 'Requires uv, Python 3.10 or later, and network access to install packages. The MCP Inspector also requires Node.js.'
---
# Generate Python MCP Server
# Python MCP Server Generator
Create a complete Model Context Protocol (MCP) server in Python with the following specifications:
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.
## Requirements
## Workflow
1. **Project Structure**: Create a new Python project with proper structure using uv
2. **Dependencies**: Include mcp[cli] package with uv
3. **Transport Type**: Choose between stdio (for local) or streamable-http (for remote)
4. **Tools**: Create at least one useful tool with proper type hints
5. **Error Handling**: Include comprehensive error handling and validation
Copy this checklist and track your progress:
## Implementation Details
- [ ] 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.
### Project Setup
- Initialize with `uv init project-name`
- Add MCP SDK: `uv add "mcp[cli]"`
- Create main server file (e.g., `server.py`)
- Add `.gitignore` for Python projects
- Configure for direct execution with `if __name__ == "__main__"`
### Step 1: Create the project
### Server Configuration
- Use `FastMCP` class from `mcp.server.fastmcp`
- Set server name and optional instructions
- Choose transport: stdio (default) or streamable-http
- For HTTP: optionally configure host, port, and stateless mode
Run these commands:
### Tool Implementation
- Use `@mcp.tool()` decorator on functions
- Always include type hints - they generate schemas automatically
- Write clear docstrings - they become tool descriptions
- Use Pydantic models or TypedDicts for structured outputs
- Support async operations for I/O-bound tasks
- Include proper error handling
```bash
uv init --app --no-package project-name
cd project-name
uv add "mcp[cli]>=2,<3"
uv add --dev pytest
```
### Resource/Prompt Setup (Optional)
- Add resources with `@mcp.resource()` decorator
- Use URI templates for dynamic resources: `"resource://{param}"`
- Add prompts with `@mcp.prompt()` decorator
- Return strings or Message lists from prompts
Then delete `main.py`. The server goes in `server.py`.
### Code Quality
- Use type hints for all function parameters and returns
- Write docstrings for tools, resources, and prompts
- Follow PEP 8 style guidelines
- Use async/await for asynchronous operations
- Implement context managers for resource cleanup
- Add inline comments for complex logic
- 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.
## Example Tool Types to Consider
- Data processing and transformation
- File system operations (read, analyze, search)
- External API integrations
- Database queries
- Text analysis or generation (with sampling)
- System information retrieval
- Math or scientific calculations
### Step 2: Write the server
## Configuration Options
- **For stdio Servers**:
- Simple direct execution
- Test with `uv run mcp dev server.py`
- Install to Claude: `uv run mcp install server.py`
- **For HTTP Servers**:
- Port configuration via environment variables
- Stateless mode for scalability: `stateless_http=True`
- JSON response mode: `json_response=True`
- CORS configuration for browser clients
- Mounting to existing ASGI servers (Starlette/FastAPI)
Start from this template:
## Testing Guidance
- Explain how to run the server:
- stdio: `python server.py` or `uv run server.py`
- HTTP: `python server.py` then connect to `http://localhost:PORT/mcp`
- Test with MCP Inspector: `uv run mcp dev server.py`
- Install to Claude Desktop: `uv run mcp install server.py`
- Include example tool invocations
- Add troubleshooting tips
```python
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
## Additional Features to Consider
- Context usage for logging, progress, and notifications
- LLM sampling for AI-powered tools
- User input elicitation for interactive workflows
- Lifespan management for shared resources (databases, connections)
- Structured output with Pydantic models
- Icons for UI display
- Image handling with Image class
- Completion support for better UX
mcp = MCPServer("Demo", version="0.1.0")
## Best Practices
- Use type hints everywhere - they're not optional
- Return structured data when possible
- Log to stderr (or use Context logging) to avoid stdout pollution
- Clean up resources properly
- Validate inputs early
- Provide clear error messages
- Test tools independently before LLM integration
Generate a complete, production-ready MCP server with type safety, proper error handling, and comprehensive documentation.
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide a by b."""
if b == 0:
raise ToolError("b must not be zero.")
return a / b
if __name__ == "__main__":
mcp.run() # stdio is the default transport
```
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`:
```python
import pytest
from mcp import Client
from server import mcp
@pytest.mark.anyio
async def test_divide():
async with Client(mcp) as client:
result = await client.call_tool("divide", {"a": 6, "b": 3})
assert result.structured_content == {"result": 2.0}
@pytest.mark.anyio
async def test_divide_by_zero():
async with Client(mcp) as client:
result = await client.call_tool("divide", {"a": 1, "b": 0})
assert result.is_error
assert "must not be zero" in result.content[0].text
```
- 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`:
```json
{
"servers": {
"demo": {
"type": "stdio",
"command": "uv",
"args": ["--directory", "/absolute/path/to/project", "run", "server.py"]
}
}
}
```
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.
@@ -0,0 +1,46 @@
# Streamable HTTP Servers
Use this transport only for a remote server. A local server uses stdio.
## Run the server
Replace `mcp.run()` in `server.py`:
```python
import os
if __name__ == "__main__":
mcp.run(
transport="streamable-http",
host=os.environ.get("HOST", "127.0.0.1"),
port=int(os.environ.get("PORT", "8000")),
)
```
Clients connect to `http://HOST:PORT/mcp`. For VS Code, write `.vscode/mcp.json`:
```json
{
"servers": {
"demo": {
"type": "http",
"url": "http://localhost:8000/mcp"
}
}
}
```
## Mount the server in an ASGI app
1. Use `mcp.streamable_http_app()` to mount the server in a Starlette or FastAPI app.
2. Give the transport options to `streamable_http_app()`. This method has no `port` option.
3. Make the lifespan of the host app enter `mcp.session_manager.run()`.
## Gotchas
- Requests on the 2026-07-28 revision have no session. Any replica can answer a request.
- `stateless_http=True` changes only how the server serves clients of earlier revisions.
- `json_response=True` sends one JSON body for each request. In this mode, the server cannot send progress notifications during the request.
- If you do not set `transport_security`, the SDK checks the `Host` and `Origin` headers only when the host is `127.0.0.1`, `localhost`, or `::1`. For all other hosts, for example `0.0.0.0` or a public host name, the server does no check. For these hosts, give `transport_security=TransportSecuritySettings(allowed_hosts=[...], allowed_origins=[...])` (from `mcp.server.transport_security`) to `run()` or `streamable_http_app()`.
- For browser clients, add CORS to the host app. Allow the `Mcp-*` request headers. Expose the `Mcp-Session-Id` response header.
- For more than one worker, set `request_state_security=RequestStateSecurity(keys=[...])` (from `mcp.server.mcpserver`) on `MCPServer`. Use the same keys and the same server name on all workers.