Files

3.2 KiB

name, description
name description
new-mcp-server 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

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.

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

[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

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

"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