Add tags to meta

This commit is contained in:
Jeremiah Lowin 2025-07-28 17:38:18 -04:00
commit a41aba3486
6 changed files with 80 additions and 1 deletions

View file

@ -100,6 +100,7 @@ class Prompt(FastMCPComponent, ABC):
"description": self.description,
"arguments": arguments,
"title": self.title,
"_meta": self.get_meta(),
}
return MCPPrompt(**kwargs | overrides)

View file

@ -122,6 +122,7 @@ class Resource(FastMCPComponent, abc.ABC):
"mimeType": self.mime_type,
"title": self.title,
"annotations": self.annotations,
"_meta": self.get_meta(),
}
return MCPResource(**kwargs | overrides)

View file

@ -154,6 +154,7 @@ class ResourceTemplate(FastMCPComponent):
"mimeType": self.mime_type,
"title": self.title,
"annotations": self.annotations,
"_meta": self.get_meta(),
}
return MCPResourceTemplate(**kwargs | overrides)

View file

@ -145,6 +145,7 @@ class Tool(FastMCPComponent):
"outputSchema": self.output_schema,
"annotations": self.annotations,
"title": title,
"_meta": self.get_meta(),
}
return MCPTool(**kwargs | overrides)

View file

@ -36,7 +36,9 @@ class FastMCPComponent(FastMCPBaseModel):
default_factory=set,
description="Tags for the component.",
)
meta: dict[str, Any] = Field(
default_factory=dict, description="Meta information about the prompt"
)
enabled: bool = Field(
default=True,
description="Whether the component is enabled.",
@ -58,6 +60,10 @@ class FastMCPComponent(FastMCPBaseModel):
"""
return self._key or self.name
def get_meta(self) -> dict[str, Any]:
"""Get the meta information about the component."""
return {"tags": list(self.tags)} | self.meta
def with_key(self, key: str) -> Self:
return self.model_copy(update={"_key": key})

View file

@ -268,6 +268,21 @@ class TestToolTags:
result_2 = await client.call_tool("tool_2", {})
assert result_2.data == 2
async def test_tags_in_meta(self):
mcp = FastMCP()
@mcp.tool(tags={"tool-example", "test-tool-tag"})
def sample_tool(x: int) -> int:
"""A sample tool."""
return x * 2
async with Client(mcp) as client:
tools = await client.list_tools()
assert len(tools) == 1
tool = tools[0]
assert tool.meta is not None
assert set(tool.meta["tags"]) == {"tool-example", "test-tool-tag"}
class TestToolReturnTypes:
async def test_string(self):
@ -1544,6 +1559,26 @@ class TestResourceTags:
with pytest.raises(McpError, match="Unknown resource"):
await client.read_resource(AnyUrl("resource://1"))
async def test_tags_in_meta(self):
mcp = FastMCP()
@mcp.resource(
uri="test://resource", tags={"resource-example", "test-resource-tag"}
)
def sample_resource() -> str:
"""A sample resource."""
return "resource content"
async with Client(mcp) as client:
resources = await client.list_resources()
assert len(resources) == 1
resource = resources[0]
assert resource.meta is not None
assert set(resource.meta["tags"]) == {
"resource-example",
"test-resource-tag",
}
class TestResourceContext:
async def test_resource_with_context_annotation_gets_context(self):
@ -1972,6 +2007,26 @@ class TestResourceTemplatesTags:
result = await client.read_resource("resource://2/x")
assert result[0].text == "Template resource 2: x" # type: ignore[attr-defined]
async def test_tags_in_meta(self):
mcp = FastMCP()
@mcp.resource(
"test://template/{id}", tags={"template-example", "test-template-tag"}
)
def sample_template(id: str) -> str:
"""A sample resource template."""
return f"template content for {id}"
async with Client(mcp) as client:
templates = await client.list_resource_templates()
assert len(templates) == 1
template = templates[0]
assert template.meta is not None
assert set(template.meta["tags"]) == {
"template-example",
"test-template-tag",
}
class TestResourceTemplateContext:
async def test_resource_template_context(self):
@ -2339,6 +2394,20 @@ class TestPrompts:
prompt = prompts_dict["sample_prompt"]
assert prompt.tags == {"example", "test-tag"}
async def test_tags_in_meta(self):
mcp = FastMCP()
@mcp.prompt(tags={"example", "test-tag"})
def sample_prompt() -> str:
return "Hello, world!"
async with Client(mcp) as client:
prompts = await client.list_prompts()
assert len(prompts) == 1
prompt = prompts[0]
assert prompt.meta is not None
assert set(prompt.meta["tags"]) == {"example", "test-tag"}
class TestPromptEnabled:
async def test_toggle_enabled(self):