115 lines
3.2 KiB
Markdown
115 lines
3.2 KiB
Markdown
---
|
|
name: new-mcp-server
|
|
description: Scaffolds a new FastMCP server following pi_mcps conventions. Use this skill when creating any new MCP server in the pi_mcps monorepo — produces the full directory structure with server.py, pyproject.toml, tests, and README in one pass.
|
|
---
|
|
|
|
# New MCP Server
|
|
|
|
## When to use
|
|
- Creating a new MCP server in `pi_mcps/mcp/{name}/`
|
|
- Bootstrapping a server scaffold before filling in tool logic
|
|
|
|
## When NOT to use
|
|
- Adding tools to an existing server (edit `src/server.py` directly)
|
|
- Non-MCP Python projects
|
|
|
|
## Inputs required
|
|
- **Server name** — e.g., `homelab-docker` (will become `mcp-homelab-docker`)
|
|
- **Purpose** — one sentence description
|
|
- **Tools list** — names + brief descriptions
|
|
- **Dependencies** — any Python packages beyond fastmcp
|
|
- **Environment variables** — any auth/config env vars needed
|
|
|
|
## Workflow
|
|
|
|
### Step 1 — Create directory structure
|
|
```bash
|
|
mkdir -p mcp/{name}/src
|
|
mkdir -p mcp/{name}/tests
|
|
touch mcp/{name}/src/__init__.py
|
|
```
|
|
|
|
### Step 2 — Write `mcp/{name}/src/server.py`
|
|
|
|
**Convention:** All tool parameters **must** use `Annotated[type, Field(description="...")]` for
|
|
descriptions. Do **not** use docstring `Args:` sections — FastMCP reads `Field` metadata directly
|
|
to expose parameter descriptions in the MCP schema.
|
|
|
|
```python
|
|
from typing import Annotated
|
|
from fastmcp import FastMCP
|
|
from pydantic import Field
|
|
|
|
mcp = FastMCP("mcp-{name}")
|
|
|
|
@mcp.tool()
|
|
def {tool_name}(
|
|
param: Annotated[str, Field(description="What this parameter controls")],
|
|
) -> str:
|
|
"""One-line tool description (no Args: section needed)."""
|
|
# implementation
|
|
...
|
|
|
|
if __name__ == "__main__":
|
|
mcp.run()
|
|
```
|
|
|
|
> Optional parameters with defaults: `param: Annotated[int, Field(description="...")] = 10`
|
|
|
|
### Step 3 — Write `mcp/{name}/pyproject.toml`
|
|
```toml
|
|
[project]
|
|
name = "mcp-{name}"
|
|
version = "0.1.0"
|
|
requires-python = ">=3.11"
|
|
dependencies = [
|
|
"fastmcp>=0.1.0",
|
|
# add other deps here
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
test = ["pytest", "pytest-mock", "pytest-cov"]
|
|
|
|
[build-system]
|
|
requires = ["hatchling"]
|
|
build-backend = "hatchling.build"
|
|
```
|
|
|
|
### Step 4 — Write `mcp/{name}/tests/conftest.py`
|
|
```python
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
|
|
```
|
|
|
|
### Step 5 — Write `mcp/{name}/tests/test_server.py`
|
|
- Import each tool function directly
|
|
- Mock all external calls with `pytest-mock`
|
|
- Cover: happy path, error path, edge cases
|
|
- Run: `cd mcp/{name} && uv run pytest tests/ -v`
|
|
|
|
### Step 6 — Write `mcp/{name}/README.md`
|
|
Include: purpose, tools table, env vars, usage example, test command
|
|
|
|
### Step 7 — Wire into `.roo/mcp.json`
|
|
```json
|
|
"mcp-{name}": {
|
|
"command": "uv",
|
|
"args": ["--directory", "/home/pplate/pi_mcps/mcp/{name}", "run", "src/server.py"],
|
|
"env": {
|
|
"ENV_VAR": "${ENV_VAR}"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Step 8 — Store in BigMind
|
|
```
|
|
memory_store_fact("codebase", "mcp/{name} has N tools: [tool1, tool2]. Stack: fastmcp + X. Env vars: Y.")
|
|
```
|
|
|
|
## Troubleshooting
|
|
- **FastMCP import error:** Run `uv sync` in the server directory first
|
|
- **Tool not showing in IDE:** Restart the MCP server via IDE settings
|
|
- **Test isolation:** Each test should monkeypatch env vars to avoid cross-test pollution
|