sten 6 implementation

This commit is contained in:
John Lancaster
2026-06-20 14:31:24 -05:00
parent 3885774e5b
commit 467e1d3c35
7 changed files with 119 additions and 68 deletions
+1 -1
View File
@@ -55,7 +55,7 @@ Rules:
- No underscores, spaces, dots, or uppercase characters. - No underscores, spaces, dots, or uppercase characters.
- Directory name should equal `skill-id` in each committed revision. - Directory name should equal `skill-id` in each committed revision.
- Frontmatter `id` should equal directory name in each committed revision. - Frontmatter `id` should equal directory name in each committed revision.
- Prefer keeping `skill-id` stable, but renames are allowed when needed if mappings are updated together. - Treat `skill-id` as immutable after release; any rename is a breaking replacement and clients must move to the new id.
Example valid ids: Example valid ids:
+5 -36
View File
@@ -72,16 +72,6 @@ Contract intent:
- Resolves only inside `docs/`. - Resolves only inside `docs/`.
- This surface is markdown-only in end state (`.md` files). - This surface is markdown-only in end state (`.md` files).
### Legacy URI Policy (Current-to-Target Transition)
Current catalog URIs in this repo (`resource://catalog/patterns`, `resource://catalog/patterns_by_id`, `resource://catalog/skills_details`) are treated as compatibility aliases during migration.
Rules:
- Keep aliases only when needed for active clients.
- Prefer simple canonical URIs for new clients.
- Remove aliases once consumers have moved.
### URI Versioning Policy ### URI Versioning Policy
Default rule: Default rule:
@@ -91,30 +81,14 @@ Default rule:
Breaking-change rule: Breaking-change rule:
- If clients are already using an older shape, provide either: - Breaking changes use direct replacement of the canonical URI family.
- a short-lived alias, or - No compatibility aliases or dual URI families are maintained in this greenfield phase.
- a versioned URI family such as `resource://catalog/v2/...`.
- Choose the lightest migration path that minimizes maintenance overhead.
FastMCP version metadata usage: FastMCP version metadata usage:
- Resource `version` metadata MAY be used for implementation/version discovery. - Resource `version` metadata MAY be used for implementation/version discovery.
- URI readability and maintainability remain the primary contract. - URI readability and maintainability remain the primary contract.
### Deprecation Policy For URIs
When deprecating a URI:
1. Document the replacement URI in changelog/docs.
2. Optionally return deprecation metadata while an alias exists.
3. Remove deprecated aliases when no active client needs them.
Recommended deprecation metadata fields in resource responses:
- `deprecated: true`
- `replacement_uri: <uri>`
- `sunset_at: <ISO-8601 timestamp>`
### Reference ID Compatibility Policy ### Reference ID Compatibility Policy
`ref_id` is the public identifier for a reference document, separate from file path. `ref_id` is the public identifier for a reference document, separate from file path.
@@ -123,19 +97,14 @@ Rules:
- Prefer keeping `ref_id` stable when practical. - Prefer keeping `ref_id` stable when practical.
- File paths may change without URI churn as long as the mapped `ref_id` resolves. - File paths may change without URI churn as long as the mapped `ref_id` resolves.
- If a reference is renamed, introduce a new `ref_id`; keep an alias only if clients depend on the old id. - If a reference is renamed, introduce a new `ref_id` and treat the old one as retired.
- Avoid reusing retired `ref_id` values for unrelated content. - Avoid reusing retired `ref_id` values for unrelated content.
Alias behavior for renamed references:
- If alias is kept, old `ref_id` continues to resolve and points to the replacement.
- Remove old alias as soon as migration is complete.
### Invariants This Contract Guarantees ### Invariants This Contract Guarantees
- One canonical URI pattern per core capability surface. - One canonical URI pattern per core capability surface.
- Fast, low-friction URI evolution with optional compatibility aliases. - Fast, low-friction URI evolution through direct replacement of canonical URIs.
- Explicit migration path for catalog URI consolidation when needed. - A single canonical catalog URI family with no alias maintenance overhead.
- Reference mappings can evolve with minimal churn. - Reference mappings can evolve with minimal churn.
### Non-goals For Step 3 ### Non-goals For Step 3
+17 -14
View File
@@ -50,17 +50,19 @@ Rules:
### Tool Fallback Surface (Normative) ### Tool Fallback Surface (Normative)
The minimal read-only fallback tool set is: The fallback tool surface includes:
1. `search_patterns` 1. `list_resources`
2. `get_pattern_by_id` 2. `read_resource`
3. `get_skill_document_by_id` 3. `search_patterns`
4. `get_pattern_by_id`
5. `get_skill_document_by_id`
Fallback order: Fallback order:
1. call `search_patterns` to find likely skills 1. call `list_resources` to inspect canonical static/template resource surfaces
2. call `get_pattern_by_id` for one selected id when detail is needed 2. call `read_resource` for catalog URIs and selected skill URIs
3. call `get_skill_document_by_id` only for selected skill(s) 3. use thin catalog tools only when additional metadata-first narrowing is needed
Tool behavior requirements: Tool behavior requirements:
@@ -71,14 +73,14 @@ Tool behavior requirements:
### Resources-As-Tools Compatibility Layer ### Resources-As-Tools Compatibility Layer
Step 6 may include a resources-as-tools compatibility layer for clients that can call tools but not attach resources. Step 6 includes a resources-as-tools compatibility layer for clients that can call tools but not attach resources.
Rules: Rules:
1. If enabled, it wraps canonical resource reads rather than re-implementing content transforms. 1. It wraps canonical resource reads rather than re-implementing content transforms.
2. It preserves canonical URIs and metadata semantics. 2. It preserves canonical URIs and metadata semantics.
3. It does not replace the minimal catalog tools listed above. 3. It does not replace the minimal catalog tools listed above.
4. It remains optional and interoperability-driven. 4. It is interoperability-driven and remains read-only.
### Resource/Tool Parity Contract ### Resource/Tool Parity Contract
@@ -144,10 +146,11 @@ Separation-of-concerns rule:
Step 6 is complete when all are true: Step 6 is complete when all are true:
1. Resource-first discovery remains the documented and implemented default path. 1. Resource-first discovery remains the documented and implemented default path.
2. The fallback tool set is minimal, read-only, and schema-aligned. 2. `list_resources` and `read_resource` are available for tool-only clients.
3. Fallback tool outputs map to canonical skill identities and URIs. 3. Thin catalog tools remain minimal, read-only parity surfaces.
4. Context loading is bounded and clarifying-question behavior is documented for low-confidence cases. 4. Fallback tool outputs map to canonical skill identities and URIs.
5. No second content source is introduced; resources and tools resolve the same authored markdown. 5. Context loading is bounded and clarifying-question behavior is documented for low-confidence cases.
6. No second content source is introduced; resources and tools resolve the same authored markdown.
### Non-goals for Step 6 ### Non-goals for Step 6
+25 -9
View File
@@ -61,14 +61,20 @@ Use this sequence to confirm behavior:
2. fetch only selected skill documents for context 2. fetch only selected skill documents for context
3. keep slash commands for deterministic fallback flows 3. keep slash commands for deterministic fallback flows
When resource attachment is unavailable in the active session, use thin catalog discovery tools as operational fallback: When resource attachment is unavailable in the active session, use ResourcesAsTools first, then thin catalog discovery tools as parity fallback:
1. `search_patterns` 1. `list_resources`
2. `get_pattern_by_id` 2. `read_resource`
3. `get_skill_document_by_id` 3. `search_patterns`
4. `get_pattern_by_id`
5. `get_skill_document_by_id`
The first two are generated from the canonical resource surface and should be preferred in tool-only clients.
These should stay read-only, minimal, and schema-aligned with catalog resources. These should stay read-only, minimal, and schema-aligned with catalog resources.
For very large tool catalogs, server operators can optionally enable tool search mode (`regex` or `bm25`) while keeping `list_resources` and `read_resource` pinned as always-visible fallback tools.
## What To Type In Copilot Chat ## What To Type In Copilot Chat
Use prompts that tell Copilot which MCP feature path to take. Use prompts that tell Copilot which MCP feature path to take.
@@ -91,7 +97,15 @@ I attached personal-mcp catalog resources first. Use them to identify the best m
### If only tools are available ### If only tools are available
Ask Copilot to explicitly use the catalog tools. Ask Copilot to explicitly use resource-backed tools first.
Example resource-backed prompt:
```text
Use personal-mcp tool fallback by first calling list_resources, then read_resource for resource://catalog/skills_index and the selected resource://skills/<skill-id>/document URI. Use only that loaded skill context in your answer.
```
If needed, use the thin catalog tools.
Example discovery prompt: Example discovery prompt:
@@ -128,7 +142,7 @@ When a task may benefit from personal-mcp skills, use this sequence:
1. Start with personal-mcp catalog discovery when the task appears to match documented implementation patterns. 1. Start with personal-mcp catalog discovery when the task appears to match documented implementation patterns.
2. Prefer MCP resources when the chat surface exposes resource attachment. 2. Prefer MCP resources when the chat surface exposes resource attachment.
3. If MCP resource attachment is unavailable, use catalog tools instead. 3. If MCP resource attachment is unavailable, use `list_resources`/`read_resource` first, then thin catalog tools if needed.
4. Load only the most relevant skill document or at most 2 skill documents. 4. Load only the most relevant skill document or at most 2 skill documents.
5. Treat skill documents as guidance, then reconcile them with the actual repository code before making changes. 5. Treat skill documents as guidance, then reconcile them with the actual repository code before making changes.
@@ -141,9 +155,11 @@ Preferred discovery order:
Tool fallback order: Tool fallback order:
1. `search_patterns` 1. `list_resources`
2. `get_pattern_by_id` 2. `read_resource`
3. `get_skill_document_by_id` 3. `search_patterns`
4. `get_pattern_by_id`
5. `get_skill_document_by_id`
If confidence is low after catalog discovery, ask one clarifying question before loading more skill documents. If confidence is low after catalog discovery, ask one clarifying question before loading more skill documents.
``` ```
+25 -7
View File
@@ -72,7 +72,7 @@ In this project, "automatic loading" should be read as a preference you express
In practice, there are two reliable ways to make skill content available in chat: In practice, there are two reliable ways to make skill content available in chat:
1. explicit resource attachment through `Add Context > MCP Resources` or `MCP: Browse Resources` 1. explicit resource attachment through `Add Context > MCP Resources` or `MCP: Browse Resources`
2. MCP tool invocation such as `search_patterns` followed by `get_skill_document_by_id` 2. MCP tool invocation using `list_resources`/`read_resource` (ResourcesAsTools), with thin catalog tools as parity fallback
Instruction quality and metadata quality still matter, because they influence whether Copilot recognizes that the MCP server is relevant and chooses the tool path well. Instruction quality and metadata quality still matter, because they influence whether Copilot recognizes that the MCP server is relevant and chooses the tool path well.
@@ -146,6 +146,21 @@ Weak metadata reduces Copilot match quality and increases wrong context injectio
If you skip the catalog/index step, behavior is less predictable and may either miss relevant skills or pull too much context. If you skip the catalog/index step, behavior is less predictable and may either miss relevant skills or pull too much context.
## Optional Tool Search Mode
When tool catalogs grow, FastMCP search transforms can reduce tool-list noise for tool-only clients.
Runtime switches:
1. `PERSONAL_MCP_TOOL_SEARCH=none|regex|bm25` (default `none`)
2. `PERSONAL_MCP_TOOL_SEARCH_MAX_RESULTS=<positive int>` (default `5`)
Behavior:
1. `regex` uses deterministic regex matching for targeted queries.
2. `bm25` uses ranked natural-language matching.
3. `list_resources` and `read_resource` stay visible so resource-backed fallback remains primary.
## Copilot Instruction Pattern ## Copilot Instruction Pattern
If you want Copilot to use `personal-mcp` skill content more reliably, the instruction file should describe three things clearly: If you want Copilot to use `personal-mcp` skill content more reliably, the instruction file should describe three things clearly:
@@ -170,7 +185,7 @@ When a task may match a documented implementation pattern from `personal-mcp`:
1. Start with catalog-first discovery. 1. Start with catalog-first discovery.
2. Prefer MCP resources when the chat surface exposes resource attachment. 2. Prefer MCP resources when the chat surface exposes resource attachment.
3. If MCP resource attachment is unavailable, use catalog tools instead. 3. If MCP resource attachment is unavailable, use `list_resources`/`read_resource` first, then thin catalog tools if needed.
4. Load only the most relevant skill document, or at most 2 skill documents. 4. Load only the most relevant skill document, or at most 2 skill documents.
5. Reconcile loaded skill guidance with the actual repository code before making changes. 5. Reconcile loaded skill guidance with the actual repository code before making changes.
@@ -183,9 +198,11 @@ Preferred resource order:
Preferred tool fallback order: Preferred tool fallback order:
1. `search_patterns` 1. `list_resources`
2. `get_pattern_by_id` 2. `read_resource`
3. `get_skill_document_by_id` 3. `search_patterns`
4. `get_pattern_by_id`
5. `get_skill_document_by_id`
If confidence is low after discovery, ask one clarifying question before loading more context. If confidence is low after discovery, ask one clarifying question before loading more context.
``` ```
@@ -225,8 +242,9 @@ Suggested instruction policy text:
1. Start with catalog-first discovery. 1. Start with catalog-first discovery.
2. Prefer MCP resources when the chat surface exposes resource attachment. 2. Prefer MCP resources when the chat surface exposes resource attachment.
3. Otherwise use catalog tools to search and load one or two likely skill documents. 3. Otherwise use tool fallback to load one or two likely skill documents.
4. If confidence is low, ask one clarifying question before loading more. 4. Prefer `list_resources`/`read_resource` first when operating in tool-only clients.
5. If confidence is low, ask one clarifying question before loading more.
## Summary ## Summary
+45
View File
@@ -4,6 +4,8 @@ import os
from typing import Any from typing import Any
from fastmcp import FastMCP from fastmcp import FastMCP
from fastmcp.server.transforms import ResourcesAsTools
from fastmcp.server.transforms.search import BM25SearchTransform, RegexSearchTransform
from personal_mcp.catalog.server import ( from personal_mcp.catalog.server import (
build_skill_detail_payload, build_skill_detail_payload,
@@ -20,6 +22,8 @@ from personal_mcp.skills.document_loader import (
) )
DOCS_ROOT = os.getenv("PERSONAL_MCP_DOCS_ROOT", "../../docs") DOCS_ROOT = os.getenv("PERSONAL_MCP_DOCS_ROOT", "../../docs")
TOOL_SEARCH_MODE = os.getenv("PERSONAL_MCP_TOOL_SEARCH", "none").strip().lower()
TOOL_SEARCH_MAX_RESULTS = os.getenv("PERSONAL_MCP_TOOL_SEARCH_MAX_RESULTS", "5")
REGISTRY: DocsRegistry = load_docs_registry( REGISTRY: DocsRegistry = load_docs_registry(
package_anchor="personal_mcp", package_anchor="personal_mcp",
docs_root=DOCS_ROOT, docs_root=DOCS_ROOT,
@@ -28,6 +32,44 @@ REGISTRY: DocsRegistry = load_docs_registry(
mcp = FastMCP("personal-mcp", on_duplicate="error") mcp = FastMCP("personal-mcp", on_duplicate="error")
def _parse_positive_int(value: str, *, env_name: str) -> int:
try:
parsed = int(value)
except ValueError as exc:
raise ValueError(f"{env_name} must be an integer") from exc
if parsed <= 0:
raise ValueError(f"{env_name} must be greater than zero")
return parsed
def _install_tool_fallback_transforms() -> None:
# Expose list_resources/read_resource for tool-only clients.
mcp.add_transform(ResourcesAsTools(mcp))
if TOOL_SEARCH_MODE in {"", "none"}:
return
max_results = _parse_positive_int(
TOOL_SEARCH_MAX_RESULTS,
env_name="PERSONAL_MCP_TOOL_SEARCH_MAX_RESULTS",
)
kwargs: dict[str, Any] = {
"max_results": max_results,
"always_visible": ["list_resources", "read_resource"],
}
if TOOL_SEARCH_MODE == "regex":
mcp.add_transform(RegexSearchTransform(**kwargs))
return
if TOOL_SEARCH_MODE == "bm25":
mcp.add_transform(BM25SearchTransform(**kwargs))
return
raise ValueError(
"PERSONAL_MCP_TOOL_SEARCH must be one of: none, regex, bm25"
)
def _ro_annotations() -> dict[str, bool]: def _ro_annotations() -> dict[str, bool]:
return { return {
"readOnlyHint": True, "readOnlyHint": True,
@@ -141,3 +183,6 @@ def get_skill_document_by_id(skill_id: str) -> dict[str, Any]:
"found": True, "found": True,
"document": read_skill_document(REGISTRY, skill_id), "document": read_skill_document(REGISTRY, skill_id),
} }
_install_tool_fallback_transforms()
+1 -1
View File
@@ -92,7 +92,7 @@ nav = [
{ "Arch" = "skills/nicegui/references/architecture.md" }, { "Arch" = "skills/nicegui/references/architecture.md" },
{ "Sources" = "skills/nicegui/references/source-documentation.md" }, { "Sources" = "skills/nicegui/references/source-documentation.md" },
] }, ] },
{ "NiceGUI UI" = [ { "NiceGUI Fine-Tuning" = [
{ "Overview" = "skills/nicegui-ui-customization/SKILL.md" }, { "Overview" = "skills/nicegui-ui-customization/SKILL.md" },
{ "Style" = "skills/nicegui-ui-customization/references/architecture-and-styling.md" }, { "Style" = "skills/nicegui-ui-customization/references/architecture-and-styling.md" },
{ "Flows" = "skills/nicegui-ui-customization/references/interaction-patterns.md" }, { "Flows" = "skills/nicegui-ui-customization/references/interaction-patterns.md" },