sten 6 implementation
This commit is contained in:
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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" },
|
||||||
|
|||||||
Reference in New Issue
Block a user