from __future__ import annotations from fastmcp import FastMCP from fastmcp.server.transforms import PromptsAsTools from fastmcp.server.transforms import ResourcesAsTools from mcp_types import Icon from .prompts.provider import prompt_lifespan from .registry.load import get_docs_registry from .registry.load import read_docs_markdown_path from .skills import skill_lifespan _SERVER_INSTRUCTIONS = """Personal development guidance exposed as native MCP resources and prompts. Use prompts for parameterized workflows; tool-only agents can discover and render them with list_prompts and get_prompt. For task-specific guidance, browse native skill resources, select one skill:///SKILL.md resource, and read its manifest only when supporting detail is needed. """ _SERVER_ICON = Icon( src=( "data:image/svg+xml;base64," "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCI+" "PHJlY3Qgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiByeD0iOCIgZmlsbD0iIzE2N0Q4RCIvPjxwYXRoIGQ9" "Ik0xOCAxNmgyMGw4IDh2MjRIMTh6IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lk" "dGg9IjQiLz48cGF0aCBkPSJNMzggMTZ2MTBoOE0yNSAzM2gxNE0yNSA0MGgxNCIgZmlsbD0ibm9uZSIg" "c3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PC9zdmc+" ), mime_type="image/svg+xml", sizes=["64x64"], ) def run_stdio() -> None: """Create the MCP server and expose it over stdio""" create_mcp().run() def create_mcp() -> FastMCP: mcp = FastMCP( "personal-mcp", instructions=_SERVER_INSTRUCTIONS, icons=[_SERVER_ICON], on_duplicate="error", lifespan=skill_lifespan | prompt_lifespan, ) registry = get_docs_registry() @mcp.resource( "resource://docs/{path*}", name="docs_markdown", title="Documentation Markdown", description="Read a packaged documentation page by its path relative to the docs root.", mime_type="text/markdown", tags={"docs"}, annotations={ "readOnlyHint": True, "idempotentHint": True, "openWorldHint": False, }, ) def docs_markdown(path: str) -> dict[str, str]: return read_docs_markdown_path(registry, path) # Bridges tool-only clients that cannot browse native resources or prompts directly. mcp.add_transform(ResourcesAsTools(mcp)) mcp.add_transform(PromptsAsTools(mcp)) return mcp if __name__ == "__main__": run_stdio()