Files
2026-06-19 00:24:08 -05:00

6.0 KiB

Hooking Up a New Skill

Use this checklist after generating a new skill under docs/skills/<slug>/.

Checklist

  1. Create the authored docs content. Add docs/skills/<slug>/SKILL.md and any companion files under docs/skills/<slug>/references/.

  2. Choose the three names up front. Use a docs slug like fastapi-uv-docker, a resource id like fastapi-uv-docker, and a Python package name like fastapi_uv_docker.

  3. Add the runtime package. Create src/personal_mcp/skills/<python_namespace>/ with __init__.py, server.py, and metadata.yaml.

  4. Expose the document resource in server.py. Follow the existing pattern: create a FastMCP instance, register resource://skills/<skill-id>/document, and return the shared loader result. For the default layout, load docs/skills/<slug>/SKILL.md. For special cases, set document_path in metadata.yaml to a repo-relative Markdown file and load from metadata instead of hardcoding a path in the server.

  5. Register the catalog metadata. In metadata.yaml, add the skill id, name, version, description, tags, capabilities, and depends_on. The capabilities list should include resource://skills/<skill-id>/document.

  6. Mount the skill in the root server. Import the new server in src/personal_mcp/mcp.py and add an mcp.mount(...) call with the Python namespace.

  7. Let the loader and catalog do the rest. The document loader reads canonical Markdown from docs/skills/<slug>/SKILL.md by default, or from metadata.yaml's optional document_path override when present. The catalog discovers metadata from src/personal_mcp/skills/*/metadata.yaml automatically.

  8. Rebuild and smoke-test. Run uv run zensical build to publish the docs site, then run a quick Python check or start the app to confirm the new resource loads.

Discovery Tool Policy

To keep behavior consistent across MCP clients and Copilot session types, follow this boundary:

  1. Keep per-skill servers resource-only.
  2. Keep discovery/query tools centralized in the catalog server.
  3. Keep canonical content in docs/skills/<slug>/SKILL.md and expose it through resource://skills/<skill-id>/document.

Do

  1. Add or update metadata.yaml fields (id, description, tags, capabilities) so catalog discovery quality stays high.
  2. Use document_path when a skill should expose a Markdown file outside docs/skills/<slug>/SKILL.md.
  3. Use catalog resources as the primary discovery surface.
  4. Add thin, read-only catalog tools only when client behavior needs a fallback path.

Don't

  1. Do not add duplicate discovery tools to each skill package.
  2. Do not duplicate canonical skill guidance in tool descriptions.
  3. Do not create mutating catalog tools for skill discovery.

Minimal Shape

  • Docs content: docs/skills/<slug>/SKILL.md
  • Optional references: docs/skills/<slug>/references/*.md
  • Runtime package: src/personal_mcp/skills/<python_namespace>/
  • Resource URI: resource://skills/<skill-id>/document

Quick Validation

  1. Confirm the Markdown document resolves through the loader. uv run python -c "from personal_mcp.skills.document_loader import load_skill_document; print(load_skill_document(skill_id='<skill-id>', skill_slug='<slug>')['source_path'])"

  2. Confirm the docs build still works. uv run zensical build

server.py Template

from fastmcp import FastMCP

from personal_mcp.skills.document_loader import load_skill_document

<python_namespace>_server = FastMCP("<skill-id>")


@<python_namespace>_server.resource("resource://skills/<skill-id>/document")
def skill_document() -> dict[str, str]:
    """Return the canonical Markdown document for this skill."""
    return load_skill_document(
        skill_id="<skill-id>",
        skill_slug="<slug>",
    )

metadata.yaml Template

id: <skill-id>
name: <Human Readable Name>
version: 1.0.0
description: <One sentence describing what the skill provides.>
tags:
  - <tag-one>
  - <tag-two>
document_path: <optional repo-relative path to a markdown file>
capabilities:
  - resource://skills/<skill-id>/document
depends_on: []

Omit document_path when the canonical document is docs/skills/<slug>/SKILL.md.

Root Mount Template

Add an import in src/personal_mcp/mcp.py:

from personal_mcp.skills.<python_namespace>.server import <python_namespace>_server

Add a mount call:

mcp.mount(<python_namespace>_server, namespace="<python_namespace>")

Example Scaffold

For a new skill called sqlmodel-patterns:

  1. Docs content lives in docs/skills/sqlmodel-patterns/SKILL.md.
  2. The Python package lives in src/personal_mcp/skills/sqlmodel_patterns/.
  3. The resource id is sqlmodel-patterns.

Example server.py:

from fastmcp import FastMCP

from personal_mcp.skills.document_loader import load_skill_document

sqlmodel_patterns_server = FastMCP("sqlmodel-patterns")


@sqlmodel_patterns_server.resource("resource://skills/sqlmodel-patterns/document")
def skill_document() -> dict[str, str]:
    """Return the canonical Markdown document for this skill."""
    return load_skill_document(
        skill_id="sqlmodel-patterns",
        skill_slug="sqlmodel-patterns",
    )

Example metadata.yaml:

id: sqlmodel-patterns
name: SQLModel Patterns
version: 1.0.0
description: Provide reusable patterns for building apps with SQLModel.
tags:
  - sqlmodel
  - python
  - patterns
capabilities:
  - resource://skills/sqlmodel-patterns/document
depends_on: []

Example mcp.py additions:

from personal_mcp.skills.sqlmodel_patterns.server import sqlmodel_patterns_server

mcp.mount(sqlmodel_patterns_server, namespace="sqlmodel_patterns")

Bootstrap Sequence

  1. Create docs/skills/<slug>/SKILL.md.
  2. Copy the server.py template into src/personal_mcp/skills/<python_namespace>/server.py.
  3. Copy the metadata.yaml template into src/personal_mcp/skills/<python_namespace>/metadata.yaml.
  4. Add __init__.py in the new package directory.
  5. Import and mount the server in src/personal_mcp/mcp.py.
  6. Run the validation commands above.