From 9be7c27410f65d63cede20ea39472943343a004d Mon Sep 17 00:00:00 2001 From: John Lancaster <32917998+jsl12@users.noreply.github.com> Date: Sat, 8 Aug 2026 00:05:58 -0500 Subject: [PATCH] better vscode integration --- src/personal_mcp/docs/copilot.md | 53 +++++++++++---- src/personal_mcp/docs/index.md | 2 +- .../references/ecosystem-and-tooling.md | 2 + .../mcp-details/references/sdk-and-fastmcp.md | 7 ++ src/personal_mcp/docs/usage.md | 7 +- src/personal_mcp/mcp.py | 65 ++++++++++++++++++- src/personal_mcp/prompts/models.py | 1 + 7 files changed, 120 insertions(+), 17 deletions(-) diff --git a/src/personal_mcp/docs/copilot.md b/src/personal_mcp/docs/copilot.md index 206e230..51593fd 100644 --- a/src/personal_mcp/docs/copilot.md +++ b/src/personal_mcp/docs/copilot.md @@ -16,7 +16,32 @@ Copilot interacts with MCP servers through independently exposed lanes: 2. resources attached as read-only context 3. server-provided prompts -This server publishes skills as native `skill://` resources and prompts as native MCP prompt objects. +This server publishes skills as native `skill://` resources and prompts as native MCP prompt objects. It also exposes generic `list_resources` and `read_resource` tools for agents whose tool catalog does not include direct MCP resource operations. + +## VS Code Feature Coverage + +The server uses every FastMCP feature that applies to its read-only guidance workload: + +| Feature | Usage | +| --- | --- | +| Server identity | The initialize response includes a stable name, usage instructions, and a self-contained icon for VS Code's MCP server UI. | +| Tools | Compatibility tools have display titles, structured output schemas, and read-only, idempotent, closed-world annotations. FastMCP's default schema dereferencing remains enabled for clients such as VS Code that require flat schemas. | +| Resources | Documentation and skills use native resources and wildcard resource templates with explicit Markdown MIME types. | +| Prompts | Declarative workflows use native prompt objects with descriptions, display titles, typed arguments, and slash-command access. | +| Argument completion | Prompt arguments with authored `choices` are returned through `completion/complete` as the user types. | + +[FastMCP server identity](https://gofastmcp.com/servers/server), [component icons](https://gofastmcp.com/servers/icons), [tool metadata](https://gofastmcp.com/servers/tools), and [argument completion](https://gofastmcp.com/servers/completions) define the implementation details. [VS Code's MCP documentation](https://code.visualstudio.com/docs/agent-customization/mcp-servers) describes how tools, resources, prompts, and MCP Apps appear in the client. + +The following capabilities are conditional rather than useful by default: + +1. MCP Apps require an interactive tool result such as a form or visualization; this server returns guidance and structured resource data only. +2. Sampling is appropriate only when server-side work must ask VS Code to run an LLM. The current server retrieves authored content and does not generate it. +3. Elicitation is appropriate only when a running operation needs additional user input. Prompt arguments already collect all required input before execution. +4. Progress, client logging, and background tasks require long-running operations. Current reads and prompt rendering are bounded local operations. +5. Client roots matter only when server behavior depends on client filesystem roots. This server reads packaged content and never traverses a client workspace. +6. `website_url` requires a canonical public deployment URL. None is configured, so the server does not advertise a guessed address. + +Add one of these capabilities when a concrete workflow needs it, then cover its negotiated capability and protocol response in the HTTP MCP smoke tests. See the [FastMCP Apps overview](https://gofastmcp.com/apps/overview), [sampling](https://gofastmcp.com/servers/sampling), [elicitation](https://gofastmcp.com/servers/elicitation), [progress reporting](https://gofastmcp.com/servers/progress), and [MCP context](https://gofastmcp.com/servers/context) for the activation criteria. ## Native Skill Resources @@ -26,7 +51,7 @@ For every skill, Copilot can discover: 2. `skill:///_manifest` 3. `skill:///{path*}` supporting-file template -The main resource description comes from `SKILL.md`. The manifest discloses supporting paths, sizes, and SHA256 hashes. This is the only skill discovery contract; there is no parallel skill catalog. +The main resource description comes from `SKILL.md`. The manifest discloses supporting paths, sizes, and SHA256 hashes. Native resources remain the only skill content and discovery contract; the generic tools delegate to that same resource surface rather than maintaining a parallel catalog. ## Resource Picker Availability @@ -39,10 +64,15 @@ A successful `resources/list` response does not guarantee the picker appears in ## Recommended Workflow -1. browse the server's resources -2. attach one relevant `skill:///SKILL.md` -3. attach `_manifest` only if supporting detail may be needed -4. attach only selected supporting files +For autonomous agents: + +1. call `list_resources` +2. compare main skill names and descriptions +3. call `read_resource` for one relevant `skill:///SKILL.md` +4. read `_manifest` only if supporting detail may be needed +5. read only selected supporting files + +For manual context attachment, browse the server's resources and attach the same bounded set of files. ## Prompt Examples @@ -72,13 +102,13 @@ A repo-level instruction should name the native retrieval order and context budg When a task matches a personal-mcp skill: 1. Prefer an already attached native skill resource. -2. Otherwise browse MCP resources and select one `skill:///SKILL.md` resource by description. -3. Read `_manifest` only when supporting material is needed. +2. Otherwise call `list_resources` and select one `skill:///SKILL.md` resource by description. +3. Call `read_resource` for the selected skill and read `_manifest` only when supporting material is needed. 4. Load at most two candidate main files and only the relevant supporting paths. 5. Reconcile guidance with the current repository before editing. ``` -Instructions steer behavior but do not force VS Code to attach resources automatically. +Instructions steer behavior but do not force VS Code to attach resources automatically. The generic tools provide an agent-callable fallback when direct resource operations are absent from the deferred-tool catalog. ## Prompt Objects @@ -88,8 +118,9 @@ Prompts remain separate from skills. When the client supports MCP prompt APIs, u 1. Use `MCP: List Servers` to confirm the server is enabled. 2. Use `MCP: Browse Resources` to confirm native skill resources exist. -3. Restart the MCP server after changing skill files because production uses `reload=False`. -4. Reload the VS Code window if the server is healthy but the resource picker remains stale. +3. Confirm `list_resources` and `read_resource` appear in the chat tool picker when autonomous retrieval is required. +4. Restart the MCP server after changing skill files because production uses `reload=False`. +5. Reload the VS Code window if the server is healthy but the resource or tool picker remains stale. ## Further Reading diff --git a/src/personal_mcp/docs/index.md b/src/personal_mcp/docs/index.md index f47737d..179676a 100644 --- a/src/personal_mcp/docs/index.md +++ b/src/personal_mcp/docs/index.md @@ -25,7 +25,7 @@ uv sync Run the app locally with the static docs rebuilt first, using [Uvicorn factory mode](https://www.uvicorn.org/settings/#application): ```bash -uv run zensical build && uv run uvicorn personal_mcp.main:create_app --factory --host 127.0.0.1 --port 8765 +uv run zensical build && uv run uvicorn personal_mcp.web.app:create_app --factory --host 127.0.0.1 --port 8765 ``` Build and run the Docker image with the same exposed port: diff --git a/src/personal_mcp/docs/skills/mcp-details/references/ecosystem-and-tooling.md b/src/personal_mcp/docs/skills/mcp-details/references/ecosystem-and-tooling.md index 142ab87..43126ee 100644 --- a/src/personal_mcp/docs/skills/mcp-details/references/ecosystem-and-tooling.md +++ b/src/personal_mcp/docs/skills/mcp-details/references/ecosystem-and-tooling.md @@ -7,6 +7,8 @@ Use this page for MCP client setup, operational tools, and integration reference !!! info "VS Code MCP docs" - [VS Code MCP servers overview](https://code.visualstudio.com/docs/agent-customization/mcp-servers) - [VS Code MCP configuration reference](https://code.visualstudio.com/docs/agents/reference/mcp-configuration) + - [VS Code MCP developer guide](https://code.visualstudio.com/docs/agents/guides/mcp-developer-guide) + - [VS Code MCP Apps support](https://code.visualstudio.com/blogs/2026/01/26/mcp-apps-support) - [VS Code Copilot customization overview](https://code.visualstudio.com/docs/copilot/customization/overview) ## Debugging and Inspection diff --git a/src/personal_mcp/docs/skills/mcp-details/references/sdk-and-fastmcp.md b/src/personal_mcp/docs/skills/mcp-details/references/sdk-and-fastmcp.md index 1b7ed82..987826e 100644 --- a/src/personal_mcp/docs/skills/mcp-details/references/sdk-and-fastmcp.md +++ b/src/personal_mcp/docs/skills/mcp-details/references/sdk-and-fastmcp.md @@ -13,6 +13,13 @@ Use this page for implementation-oriented links across MCP SDKs and FastMCP. !!! info "FastMCP sources" - [FastMCP project documentation](https://gofastmcp.com/) + - [FastMCP server identity and behavior](https://gofastmcp.com/servers/server) + - [FastMCP tools and annotations](https://gofastmcp.com/servers/tools) + - [FastMCP resources and templates](https://gofastmcp.com/servers/resources) + - [FastMCP prompts](https://gofastmcp.com/servers/prompts) + - [FastMCP argument completion](https://gofastmcp.com/servers/completions) + - [FastMCP component icons](https://gofastmcp.com/servers/icons) + - [FastMCP Apps](https://gofastmcp.com/apps/overview) - [FastMCP GitHub repository](https://github.com/jlowin/fastmcp) - [FastMCP examples directory](https://github.com/jlowin/fastmcp/tree/main/examples) - [FastMCP PyPI package](https://pypi.org/project/fastmcp/) diff --git a/src/personal_mcp/docs/usage.md b/src/personal_mcp/docs/usage.md index d97a5b5..275bf8d 100644 --- a/src/personal_mcp/docs/usage.md +++ b/src/personal_mcp/docs/usage.md @@ -53,14 +53,15 @@ These utilities operate directly on the native `skill://` contract and require n In VS Code, skills can arrive through: 1. explicit attachment from `Add Context > MCP Resources` or `MCP: Browse Resources` -2. a slash-command prompt that names a specific native skill URI +2. the generic `list_resources` and `read_resource` tools for autonomous agents +3. a slash-command prompt that names a specific native skill URI -Instructions can steer retrieval, but they do not guarantee automatic resource attachment in every chat surface. +Instructions can steer retrieval, but they do not guarantee automatic resource attachment in every chat surface. When the deferred-tool catalog omits direct MCP resource operations, use the generic tools; they delegate to the native providers and do not duplicate skill metadata or content. A reliable prompt is: ```text -Browse personal-mcp resources and select the best matching skill://.../SKILL.md resource. Read one selected skill, inspect its _manifest only if supporting detail is needed, and reconcile the guidance with this workspace. +Call list_resources and select the best matching skill://.../SKILL.md resource. Use read_resource for one selected skill, inspect its _manifest only if supporting detail is needed, and reconcile the guidance with this workspace. ``` ## Thin Shim Pattern diff --git a/src/personal_mcp/mcp.py b/src/personal_mcp/mcp.py index 26f74ee..47ff492 100644 --- a/src/personal_mcp/mcp.py +++ b/src/personal_mcp/mcp.py @@ -1,24 +1,53 @@ from __future__ import annotations from fastmcp import FastMCP +from mcp.types import CompletionArgument +from mcp.types import CompletionContext +from mcp.types import Icon +from mcp.types import PromptReference from personal_mcp.prompts import create_prompts_provider +from personal_mcp.prompts.models import MarkdownPrompt +from personal_mcp.prompts.provider import MarkdownPromptsProvider from personal_mcp.registry.load import get_docs_registry from personal_mcp.registry.load import read_docs_markdown_path from personal_mcp.registry.models import DocsRegistry from personal_mcp.skills import create_skills_provider +_SERVER_INSTRUCTIONS = """Personal development guidance exposed as native MCP resources and prompts. + +Use prompts for parameterized workflows. For task-specific guidance, list resources, select one +skill:///SKILL.md by description, and read its manifest only when supporting detail is needed. +Read-only compatibility tools expose the same resource catalog to clients without native resource access. +""" +_SERVER_ICON = Icon( + src=( + "data:image/svg+xml;base64," + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NCA2NCI+" + "PHJlY3Qgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiByeD0iOCIgZmlsbD0iIzE2N0Q4RCIvPjxwYXRoIGQ9" + "Ik0xOCAxNmgyMGw4IDh2MjRIMTh6IiBmaWxsPSJub25lIiBzdHJva2U9IndoaXRlIiBzdHJva2Utd2lk" + "dGg9IjQiLz48cGF0aCBkPSJNMzggMTZ2MTBoOE0yNSAzM2gxNE0yNSA0MGgxNCIgZmlsbD0ibm9uZSIg" + "c3Ryb2tlPSJ3aGl0ZSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PC9zdmc+" + ), + mime_type="image/svg+xml", + sizes=["64x64"], +) + def _ro_annotations() -> dict[str, bool]: return { "readOnlyHint": True, "idempotentHint": True, + "openWorldHint": False, } def _register_components(mcp: FastMCP, registry: DocsRegistry) -> None: @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=_ro_annotations(), @@ -30,6 +59,7 @@ def _register_components(mcp: FastMCP, registry: DocsRegistry) -> None: def _register_resource_tools(mcp: FastMCP) -> None: @mcp.tool( name="list_resources", + title="List Resources", description=( "List available MCP resources and URI templates. Use before read_resource to discover skill guidance." ), @@ -61,6 +91,7 @@ def _register_resource_tools(mcp: FastMCP) -> None: @mcp.tool( name="read_resource", + title="Read Resource", description="Read a resource URI returned by list_resources, including skill files, manifests, and references.", annotations=_ro_annotations(), ) @@ -69,11 +100,41 @@ def _register_resource_tools(mcp: FastMCP) -> None: return result.model_dump(mode="json", exclude_none=True) +def _register_prompt_completions(mcp: FastMCP, provider: MarkdownPromptsProvider) -> None: + @mcp.completion + async def complete_prompt_argument( + ref: object, + argument: CompletionArgument, + context: CompletionContext | None, + ) -> list[str] | None: + del context + if not isinstance(ref, PromptReference): + return None + + prompt = await provider.get_prompt(ref.name) + if not isinstance(prompt, MarkdownPrompt): + return None + + definition = prompt.definitions.get(argument.name) + if definition is None or definition.choices is None: + return None + + prefix = argument.value.casefold() + return [choice for choice in definition.choices if choice.casefold().startswith(prefix)] + + def create_mcp() -> FastMCP: registry = get_docs_registry() - mcp = FastMCP("personal-mcp", on_duplicate="error") + mcp = FastMCP( + "personal-mcp", + instructions=_SERVER_INSTRUCTIONS, + icons=[_SERVER_ICON], + on_duplicate="error", + ) _register_components(mcp, registry) - mcp.add_provider(create_prompts_provider()) + prompts_provider = create_prompts_provider() + mcp.add_provider(prompts_provider) mcp.add_provider(create_skills_provider()) _register_resource_tools(mcp) + _register_prompt_completions(mcp, prompts_provider) return mcp diff --git a/src/personal_mcp/prompts/models.py b/src/personal_mcp/prompts/models.py index 298af8e..188c496 100644 --- a/src/personal_mcp/prompts/models.py +++ b/src/personal_mcp/prompts/models.py @@ -65,6 +65,7 @@ class MarkdownPrompt(Prompt): metadata = definition.metadata return cls( name=definition.prompt_id, + title=definition.prompt_id.replace("-", " ").title(), version=metadata.version, description=metadata.description, tags=set(metadata.tags),