Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Bootstrap MCP server with Python SDK, transport configuration, tool/resource handlers, and proper project structure.
.claude/skills/a5c-ai-mcp-sdk-python-bootstrapper/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 5% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 44% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 36% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 40% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 6% | 0% |
Bootstrap a complete MCP server using the Python SDK with proper project structure.
Invoke this skill when you need to:
| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | projectName | string | Yes | Name of the MCP server project | | description | string | Yes | Description of the server | | tools | array | No | List of tools to implement | | resources | array | No | List of resources to expose | | transport | string | No | Transport type: stdio, sse (default: stdio) |
json{ "tools": [ { "name": "search_files", "description": "Search for files matching a pattern", "parameters": { "pattern": { "type": "string", "description": "Search pattern" }, "path": { "type": "string", "description": "Base path", "default": "." } } } ] }
<projectName>/
├── pyproject.toml
├── README.md
├── .gitignore
├── src/
│ └── <package>/
│ ├── __init__.py
│ ├── __main__.py # Entry point
│ ├── server.py # MCP server setup
│ ├── tools/
│ │ ├── __init__.py
│ │ └── search.py # Tool implementations
│ ├── resources/
│ │ ├── __init__.py
│ │ └── files.py # Resource providers
│ └── types/
│ ├── __init__.py
│ └── schemas.py # Pydantic models
└── tests/
└── test_tools.pypythonimport asyncio from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, Resource from .tools import register_tools from .resources import register_resources # Create server instance server = Server("<projectName>") # Register handlers register_tools(server) register_resources(server) async def main(): """Run the MCP server.""" async with stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, server.create_initialization_options() ) def run(): """Entry point for the server.""" asyncio.run(main())
pythonfrom typing import Any from pydantic import BaseModel, Field from mcp.server import Server from mcp.types import Tool, TextContent class SearchFilesInput(BaseModel): """Input schema for search_files tool.""" pattern: str = Field(description="Search pattern (glob)") path: str = Field(default=".", description="Base path to search") def register(server: Server) -> None: """Register the search_files tool.""" @server.list_tools() async def list_tools() -> list[Tool]: return [ Tool( name="search_files", description="Search for files matching a pattern", inputSchema=SearchFilesInput.model_json_schema() ) ] @server.call_tool() async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]: if name != "search_files": raise ValueError(f"Unknown tool: {name}") # Validate input input_data = SearchFilesInput(**arguments) # Execute search from pathlib import Path matches = list(Path(input_data.path).glob(input_data.pattern)) return [ TextContent( type="text", text="\n".join(str(m) for m in matches) ) ]
pythonfrom mcp.server import Server from mcp.types import Resource, TextResourceContents def register(server: Server) -> None: """Register file resources.""" @server.list_resources() async def list_resources() -> list[Resource]: return [ Resource( uri="file:///config", name="Configuration", description="Server configuration", mimeType="application/json" ) ] @server.read_resource() async def read_resource(uri: str) -> TextResourceContents: if uri == "file:///config": return TextResourceContents( uri=uri, mimeType="application/json", text='{"version": "1.0.0"}' ) raise ValueError(f"Unknown resource: {uri}")
toml[tool.poetry.dependencies] python = ">=3.10" mcp = "^1.0.0" pydantic = "^2.0.0" [tool.poetry.group.dev.dependencies] pytest = "^8.0.0" pytest-asyncio = "^0.23.0"
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 21,107 | 20,699 | -2% | 1 | 1 | 0% | 4,991 | 5,264 | +5% | 0 | 0 | — |
case-02 | fail→pass | 14,159 | 13,449 | -5% | 1 | 1 | 0% | 3,161 | 4,546 | +44% | 0 | 0 | — |
case-03 | fail→pass | 17,186 | 16,549 | -4% | 1 | 1 | 0% | 3,950 | 5,369 | +36% | 0 | 0 | — |
case-04 | fail→fail | 9,636 | 9,877 | +3% | 1 | 1 | 0% | 1,895 | 3,050 | +61% | 0 | 0 | — |
case-05 | fail→fail | 11,774 | 9,688 | -18% | 1 | 1 | 0% | 2,652 | 3,587 | +35% | 0 | 0 | — |
case-06 | fail→fail | 20,951 | 23,457 | +12% | 1 | 1 | 0% | 4,423 | 5,382 | +22% | 0 | 0 | — |
case-07 | fail→pass | 10,363 | 6,867 | -34% | 1 | 1 | 0% | 2,026 | 2,832 | +40% | 0 | 0 | — |
case-08 | fail→fail | 14,884 | 8,430 | -43% | 1 | 1 | 0% | 2,549 | 3,261 | +28% | 0 | 0 | — |
case-09 | fail→fail | 9,913 | 7,250 | -27% | 1 | 1 | 0% | 2,029 | 2,806 | +38% | 0 | 0 | — |
case-10 | fail→pass | 15,780 | 8,689 | -45% | 1 | 1 | 0% | 3,014 | 3,187 | +6% | 0 | 0 | — |
case-11 | fail→fail | 9,003 | 3,464 | -62% | 1 | 1 | 0% | 1,751 | 2,060 | +18% | 0 | 0 | — |
case-12 | fail→fail | 13,640 | 6,797 | -50% | 1 | 1 | 0% | 2,989 | 2,818 | -6% | 0 | 0 | — |
case-13 | fail→fail | 7,873 | 6,151 | -22% | 1 | 1 | 0% | 1,479 | 2,585 | +75% | 0 | 0 | — |
case-14 | fail→fail | 7,426 | 6,068 | -18% | 1 | 1 | 0% | 1,384 | 2,688 | +94% | 0 | 0 | — |
case-15 | fail→fail | 8,433 | 5,106 | -39% | 1 | 1 | 0% | 1,702 | 2,468 | +45% | 0 | 0 | — |
case-16 | fail→fail | 4,663 | 3,757 | -19% | 1 | 1 | 0% | 932 | 2,073 | +122% | 0 | 0 | — |
case-17 | fail→fail | 6,196 | 4,480 | -28% | 1 | 1 | 0% | 1,240 | 2,286 | +84% | 0 | 0 | — |
case-18 | fail→pass | 14,113 | 4,672 | -67% | 1 | 1 | 0% | 2,616 | 2,437 | -7% | 0 | 0 | — |
case-19 | fail→fail | 11,130 | 6,660 | -40% | 1 | 1 | 0% | 2,018 | 2,664 | +32% | 0 | 0 | — |
case-20 | fail→fail | 11,484 | 6,467 | -44% | 1 | 1 | 0% | 2,317 | 2,765 | +19% | 0 | 0 | — |
case-21 | fail→fail | 4,818 | 3,655 | -24% | 1 | 1 | 0% | 993 | 2,080 | +109% | 0 | 0 | — |
case-22 | pass→pass | 8,289 | 4,399 | -47% | 1 | 1 | 0% | 1,616 | 2,174 | +35% | 0 | 0 | — |
case-23 | fail→pass | 14,384 | 12,637 | -12% | 1 | 1 | 0% | 2,435 | 3,646 | +50% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +30 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.