test_resources.pyβ’3.86 kB
"""Test that resource metadata follows MCP specification."""
from pathlib import Path
from skillz import SkillRegistry
from skillz._server import register_skill_resources
def write_skill_with_resources(
    directory: Path, name: str = "TestSkill"
) -> Path:
    """Create a test skill with multiple resource types."""
    skill_dir = directory / name.lower()
    skill_dir.mkdir()
    # Create SKILL.md
    (skill_dir / "SKILL.md").write_text(
        f"""---
name: {name}
description: Test skill with resources
---
Test skill instructions.
""",
        encoding="utf-8",
    )
    # Create text file
    (skill_dir / "script.py").write_text("print('hello')", encoding="utf-8")
    # Create another text file
    (skill_dir / "README.md").write_text("# README", encoding="utf-8")
    # Create binary file
    (skill_dir / "data.bin").write_bytes(b"\x00\x01\x02\x03")
    return skill_dir
def test_resource_metadata_follows_mcp_spec(tmp_path: Path) -> None:
    """Resources should have uri, name, and mimeType (no description)."""
    write_skill_with_resources(tmp_path, name="TestSkill")
    registry = SkillRegistry(tmp_path)
    registry.load()
    skill = registry.get("testskill")
    # Get resource metadata
    from fastmcp import FastMCP
    mcp = FastMCP()
    metadata = register_skill_resources(mcp, skill)
    # Should have 3 resources (script.py, README.md, data.bin)
    # SKILL.md is NOT a resource - it's only returned from the tool
    assert len(metadata) == 3
    # Check each resource has required fields
    for resource in metadata:
        # Must have these fields according to MCP spec
        assert "uri" in resource
        assert "name" in resource
        assert "mime_type" in resource
        # Should NOT have these fields
        assert "description" not in resource
        assert "relative_path" not in resource
        # URI should follow MCP format: protocol://host/path
        assert resource["uri"].startswith("resource://skillz/testskill/")
        # Name should be path without protocol
        assert resource["name"].startswith("testskill/")
        assert not resource["name"].startswith("resource://")
        # SKILL.md should NOT be in resources
        assert "SKILL.md" not in resource["name"]
def test_resource_mime_types(tmp_path: Path) -> None:
    """MIME types should be detected correctly."""
    write_skill_with_resources(tmp_path, name="TestSkill")
    registry = SkillRegistry(tmp_path)
    registry.load()
    skill = registry.get("testskill")
    from fastmcp import FastMCP
    mcp = FastMCP()
    metadata = register_skill_resources(mcp, skill)
    # Create lookup by name
    resources_by_name = {r["name"]: r for r in metadata}
    # SKILL.md should NOT be in resources
    assert "testskill/SKILL.md" not in resources_by_name
    # Check MIME types for actual resources
    assert (
        resources_by_name["testskill/script.py"]["mime_type"]
        == "text/x-python"
    )
    assert (
        resources_by_name["testskill/README.md"]["mime_type"]
        == "text/markdown"
    )
    # Binary files may not have a detected MIME type
    assert resources_by_name["testskill/data.bin"]["mime_type"] in [
        None,
        "application/octet-stream",
    ]
def test_resource_uris_use_resource_protocol(tmp_path: Path) -> None:
    """Resource URIs should use resource:// protocol, not file://."""
    write_skill_with_resources(tmp_path, name="TestSkill")
    registry = SkillRegistry(tmp_path)
    registry.load()
    skill = registry.get("testskill")
    from fastmcp import FastMCP
    mcp = FastMCP()
    metadata = register_skill_resources(mcp, skill)
    # All URIs should use resource:// protocol
    for resource in metadata:
        assert resource["uri"].startswith("resource://")
        assert not resource["uri"].startswith("file://")