68 lines
2.5 KiB
Python
68 lines
2.5 KiB
Python
from importlib.resources import files
|
|
from importlib.resources.abc import Traversable
|
|
|
|
import pytest
|
|
import yaml
|
|
from fastmcp import Client
|
|
from fastmcp import FastMCP
|
|
from fastmcp.utilities.skills import get_skill_manifest
|
|
from fastmcp.utilities.skills import list_skills
|
|
|
|
from personal_mcp.skills import create_skills_provider
|
|
|
|
pytestmark = pytest.mark.unit
|
|
|
|
SKILLS_ROOT = files("personal_mcp").joinpath("docs", "skills")
|
|
|
|
|
|
def skill_directories() -> list[Traversable]:
|
|
return [
|
|
directory
|
|
for directory in SKILLS_ROOT.iterdir()
|
|
if directory.is_dir() and directory.joinpath("SKILL.md").is_file()
|
|
]
|
|
|
|
|
|
class TestSkillsProvider:
|
|
"""Covers native FastMCP skill discovery and retrieval."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_discovers_authored_skills(self) -> None:
|
|
"""Ensures each authored skill is exposed with its description."""
|
|
expected_names = {directory.name for directory in skill_directories()}
|
|
mcp = FastMCP("skills-test")
|
|
mcp.add_provider(create_skills_provider())
|
|
|
|
async with Client(mcp) as client:
|
|
skills = await list_skills(client)
|
|
|
|
assert {skill.name for skill in skills} == expected_names
|
|
assert all(skill.description for skill in skills)
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_reads_manifest_and_supporting_file(self) -> None:
|
|
"""Ensures manifests disclose hashed files that remain directly readable."""
|
|
mcp = FastMCP("skills-test")
|
|
mcp.add_provider(create_skills_provider())
|
|
|
|
async with Client(mcp) as client:
|
|
manifest = await get_skill_manifest(client, "mcp-details")
|
|
reference = next(file for file in manifest.files if file.path.startswith("references/"))
|
|
contents = await client.read_resource(f"skill://mcp-details/{reference.path}")
|
|
|
|
assert any(file.path == "SKILL.md" for file in manifest.files)
|
|
assert all(file.hash.startswith("sha256:") for file in manifest.files)
|
|
assert reference.size > 0
|
|
assert contents
|
|
|
|
def test_frontmatter_names_match_directories(self) -> None:
|
|
"""Ensures provider identity and authored skill names remain aligned."""
|
|
for directory in skill_directories():
|
|
skill_file = directory.joinpath("SKILL.md")
|
|
raw = skill_file.read_text(encoding="utf-8")
|
|
frontmatter = yaml.safe_load(raw.split("---", 2)[1])
|
|
|
|
assert set(frontmatter) == {"name", "description"}
|
|
assert frontmatter["name"] == directory.name
|
|
assert frontmatter["description"]
|