prompts and resources as tools
This commit is contained in:
@@ -16,7 +16,7 @@ Copilot interacts with MCP servers through independently exposed lanes:
|
|||||||
2. resources attached as read-only context
|
2. resources attached as read-only context
|
||||||
3. server-provided prompts
|
3. server-provided prompts
|
||||||
|
|
||||||
This server publishes skills as native `skill://` resources, general docs as `resource://docs/{path*}` resources, and workflows as native MCP prompt objects. It intentionally publishes no compatibility tools that mirror resources or prompts.
|
This server publishes skills as native `skill://` resources, general docs as `resource://docs/{path*}` resources, and workflows as native MCP prompt objects. It also publishes four compatibility tools generated by FastMCP's resource and prompt transforms, so tool-only chat surfaces can reach the same content without relying on resource or prompt UI support.
|
||||||
|
|
||||||
## VS Code Feature Coverage
|
## VS Code Feature Coverage
|
||||||
|
|
||||||
@@ -25,12 +25,12 @@ The server uses every FastMCP feature that applies to its read-only guidance wor
|
|||||||
| Feature | Usage |
|
| 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. |
|
| Server identity | The initialize response includes a stable name, usage instructions, and a self-contained icon for VS Code's MCP server UI. |
|
||||||
| Tools | No tools are published for this documentation-only server surface. Resource and prompt operations stay on native MCP capabilities. |
|
| Tools | `list_resources` and `read_resource` expose skills and docs; `list_prompts` and `get_prompt` expose prompt discovery and rendering. All four are generated by FastMCP transforms and delegate to the native server surfaces. |
|
||||||
| Resources | Documentation and skills use native resources and wildcard resource templates with explicit Markdown MIME types. |
|
| 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. |
|
| Prompts | Declarative workflows use native prompt objects with descriptions, display titles, typed arguments, and explicit `/<server>.<prompt>` invocation in VS Code chat. |
|
||||||
| Argument completion | Prompt arguments with authored `choices` are returned through `completion/complete` as the user types. |
|
| 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.
|
[FastMCP server identity](https://gofastmcp.com/servers/server), [resource tools](https://gofastmcp.com/servers/transforms/resources-as-tools), [prompt tools](https://gofastmcp.com/servers/transforms/prompts-as-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:
|
The following capabilities are conditional rather than useful by default:
|
||||||
|
|
||||||
@@ -73,6 +73,21 @@ For autonomous agents:
|
|||||||
|
|
||||||
For manual context attachment, browse the server's resources and attach the same bounded set of files.
|
For manual context attachment, browse the server's resources and attach the same bounded set of files.
|
||||||
|
|
||||||
|
## Tool Fallbacks
|
||||||
|
|
||||||
|
When a chat surface cannot browse or attach MCP resources:
|
||||||
|
|
||||||
|
1. Call `list_resources` to see every skill and docs resource, including manifests and supporting-file templates.
|
||||||
|
2. Call `read_resource` with the exact `uri` (or a filled-in template such as `skill://<name>/<path>`) to fetch content.
|
||||||
|
|
||||||
|
When an agent needs to discover or render prompts without explicit slash-command invocation:
|
||||||
|
|
||||||
|
1. Call `list_prompts` to get each prompt's name, description, and required or optional arguments.
|
||||||
|
2. Call `get_prompt` with the prompt `name` and an optional `arguments` object.
|
||||||
|
3. Treat the returned JSON `messages` array as the rendered workflow context.
|
||||||
|
|
||||||
|
These tools route through the same native resource and prompt surfaces, so provider validation, middleware, visibility, and live prompt discovery still apply.
|
||||||
|
|
||||||
## Prompt Examples
|
## Prompt Examples
|
||||||
|
|
||||||
Resource attachment:
|
Resource attachment:
|
||||||
@@ -111,7 +126,11 @@ Instructions steer behavior but do not force VS Code to attach resources automat
|
|||||||
|
|
||||||
## Prompt Objects
|
## Prompt Objects
|
||||||
|
|
||||||
Prompts remain separate from skills. When the client supports MCP prompt APIs, use prompt listing and `get_prompt` for parameterized workflows. Each authored `PROMPT.md` is the complete source of truth for its metadata, arguments, and prose; changes are loaded on the next prompt request.
|
Prompts remain separate from skills. VS Code presents native MCP prompts as explicit `/<server>.<prompt>` commands that users select in chat; this is the preferred path for a user intentionally starting a known parameterized workflow. Native prompt argument completion uses the authored choices where available.
|
||||||
|
|
||||||
|
The compatibility tools cover the autonomous path: an agent can call `list_prompts`, select a workflow by its description, and call `get_prompt` with matching arguments. `get_prompt` returns the same rendered prompt as JSON containing its ordered MCP messages rather than starting a second chat request itself.
|
||||||
|
|
||||||
|
Each authored `PROMPT.md` is the complete source of truth for metadata, arguments, and prose. Both native prompt requests and compatibility-tool calls resolve through the same provider, so changes are loaded on the next request.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ flowchart TD
|
|||||||
B --> G[FastMCP]
|
B --> G[FastMCP]
|
||||||
D --> G
|
D --> G
|
||||||
F --> G
|
F --> G
|
||||||
|
G --> I[ResourcesAsTools]
|
||||||
|
G --> J[PromptsAsTools]
|
||||||
|
I --> N[list_resources / read_resource]
|
||||||
|
J --> O[list_prompts / get_prompt]
|
||||||
G --> H[MCP Transport]
|
G --> H[MCP Transport]
|
||||||
H --> K[FastAPI Application]
|
H --> K[FastAPI Application]
|
||||||
L[Pre-built site] --> M[Static /docs Mount]
|
L[Pre-built site] --> M[Static /docs Mount]
|
||||||
@@ -81,12 +85,12 @@ No runtime Markdown-to-HTML conversion occurs.
|
|||||||
2. Skill supporting files map to `skill://<skill-id>/<path>`.
|
2. Skill supporting files map to `skill://<skill-id>/<path>`.
|
||||||
3. Declarative prompt documents map to native MCP prompt names.
|
3. Declarative prompt documents map to native MCP prompt names.
|
||||||
4. General `src/personal_mcp/docs/<path>.md` maps to `resource://docs/{path*}`.
|
4. General `src/personal_mcp/docs/<path>.md` maps to `resource://docs/{path*}`.
|
||||||
|
5. FastMCP's `ResourcesAsTools` transform projects every registered resource and template onto two compatibility tools, `list_resources` and `read_resource`, for tool-only clients.
|
||||||
The server publishes no tool projections of resources or prompts.
|
6. FastMCP's `PromptsAsTools` transform projects every registered prompt onto `list_prompts` and `get_prompt`; rendering still routes through the native prompt provider.
|
||||||
|
|
||||||
## Public Surface Policy
|
## Public Surface Policy
|
||||||
|
|
||||||
Canonical provider and protocol surfaces are the only public interfaces.
|
Native resources and prompts remain the source of truth. Generated compatibility tools delegate to those surfaces instead of maintaining parallel catalogs or rendering logic.
|
||||||
|
|
||||||
## Static Mount Expectations
|
## Static Mount Expectations
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from fastmcp import FastMCP
|
from fastmcp import FastMCP
|
||||||
|
from fastmcp.server.transforms import PromptsAsTools
|
||||||
|
from fastmcp.server.transforms import ResourcesAsTools
|
||||||
from mcp_types import Icon
|
from mcp_types import Icon
|
||||||
|
|
||||||
from .prompts.provider import prompt_lifespan
|
from .prompts.provider import prompt_lifespan
|
||||||
@@ -10,8 +12,9 @@ from .skills import skill_lifespan
|
|||||||
|
|
||||||
_SERVER_INSTRUCTIONS = """Personal development guidance exposed as native MCP resources and prompts.
|
_SERVER_INSTRUCTIONS = """Personal development guidance exposed as native MCP resources and prompts.
|
||||||
|
|
||||||
Use prompts for parameterized workflows. For task-specific guidance, browse native skill resources,
|
Use prompts for parameterized workflows; tool-only agents can discover and render them with
|
||||||
select one skill://<name>/SKILL.md resource, and read its manifest only when supporting detail is needed.
|
list_prompts and get_prompt. For task-specific guidance, browse native skill resources, select one
|
||||||
|
skill://<name>/SKILL.md resource, and read its manifest only when supporting detail is needed.
|
||||||
"""
|
"""
|
||||||
_SERVER_ICON = Icon(
|
_SERVER_ICON = Icon(
|
||||||
src=(
|
src=(
|
||||||
@@ -59,6 +62,10 @@ def create_mcp() -> FastMCP:
|
|||||||
def docs_markdown(path: str) -> dict[str, str]:
|
def docs_markdown(path: str) -> dict[str, str]:
|
||||||
return read_docs_markdown_path(registry, path)
|
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
|
return mcp
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from fastmcp import Client
|
from fastmcp import Client
|
||||||
|
from mcp_types import TextContent
|
||||||
from mcp_types import TextResourceContents
|
from mcp_types import TextResourceContents
|
||||||
|
|
||||||
|
|
||||||
@@ -6,8 +7,9 @@ async def assert_server_contract(client: Client) -> None:
|
|||||||
resources = {str(resource.uri) for resource in await client.list_resources()}
|
resources = {str(resource.uri) for resource in await client.list_resources()}
|
||||||
templates = {str(template.uri_template) for template in await client.list_resource_templates()}
|
templates = {str(template.uri_template) for template in await client.list_resource_templates()}
|
||||||
prompts = {prompt.name for prompt in await client.list_prompts()}
|
prompts = {prompt.name for prompt in await client.list_prompts()}
|
||||||
|
tools = {tool.name for tool in await client.list_tools()}
|
||||||
|
|
||||||
assert await client.list_tools() == []
|
assert tools == {"get_prompt", "list_prompts", "list_resources", "read_resource"}
|
||||||
assert "skill://pytesting/SKILL.md" in resources
|
assert "skill://pytesting/SKILL.md" in resources
|
||||||
assert "resource://docs/{path*}" in templates
|
assert "resource://docs/{path*}" in templates
|
||||||
assert "skill://pytesting/{path*}" in templates
|
assert "skill://pytesting/{path*}" in templates
|
||||||
@@ -20,3 +22,13 @@ async def assert_server_contract(client: Client) -> None:
|
|||||||
assert "# Pytesting" in skill_content[0].text
|
assert "# Pytesting" in skill_content[0].text
|
||||||
assert isinstance(docs_content[0], TextResourceContents)
|
assert isinstance(docs_content[0], TextResourceContents)
|
||||||
assert '"format": "markdown"' in docs_content[0].text
|
assert '"format": "markdown"' in docs_content[0].text
|
||||||
|
|
||||||
|
listed = await client.call_tool("list_resources")
|
||||||
|
listed_content = listed.content[0]
|
||||||
|
assert isinstance(listed_content, TextContent)
|
||||||
|
assert "skill://pytesting/SKILL.md" in listed_content.text
|
||||||
|
|
||||||
|
read = await client.call_tool("read_resource", {"uri": "skill://pytesting/SKILL.md"})
|
||||||
|
read_content = read.content[0]
|
||||||
|
assert isinstance(read_content, TextContent)
|
||||||
|
assert "# Pytesting" in read_content.text
|
||||||
|
|||||||
Reference in New Issue
Block a user