Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/humcp/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

from src.humcp.decorator import RegisteredTool
from src.humcp.schemas import (
CategoryInfo,
CategorySummary,
GetCategoryResponse,
GetToolResponse,
InputSchema,
ListCategoriesResponse,
ListToolsResponse,
SkillFull,
SkillMetadata,
Expand Down Expand Up @@ -96,6 +98,27 @@ async def get_tool(category: str, tool_name: str) -> GetToolResponse:
output_schema=reg.tool.output_schema,
)

@app.get("/categories", tags=["Info"], response_model=ListCategoriesResponse)
async def list_categories() -> ListCategoriesResponse:
category_list = [
CategoryInfo(
name=cat,
tool_count=len(items),
skill=SkillFull(
name=skills[cat].name,
description=skills[cat].description,
content=skills[cat].content,
)
if cat in skills
else None,
)
for cat, items in sorted(categories.items())
]
return ListCategoriesResponse(
total_categories=len(category_list),
categories=category_list,
)


def _add_tool_route(app: FastAPI, reg: RegisteredTool) -> None:
"""Add POST /tools/{name} endpoint for a tool."""
Expand Down
16 changes: 16 additions & 0 deletions src/humcp/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,19 @@ class GetToolResponse(BaseModel):
output_schema: dict[str, Any] | None = Field(
description="JSON schema for tool output", default=None
)


# GET /categories response
class CategoryInfo(BaseModel):
"""Information about a category."""

name: str = Field(..., description="Category name")
tool_count: int = Field(..., description="Number of tools in category")
Comment thread
GuanyiLi-Craig marked this conversation as resolved.
skill: SkillFull | None = Field(None, description="Skill information if available")


class ListCategoriesResponse(BaseModel):
"""Response schema for GET /categories."""

total_categories: int = Field(..., description="Total number of categories")
categories: list[CategoryInfo] = Field(..., description="List of categories")
21 changes: 21 additions & 0 deletions tests/humcp/test_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,24 @@ def test_tool_execution(self, sample_registrations, tmp_path):
resp = client.post("/tools/test_tool_two", json={"a": 5})
assert resp.status_code == 200
assert resp.json()["result"]["data"]["result"] == 15

def test_categories_endpoint(self, sample_registrations, tmp_path):
app = FastAPI()
register_routes(app, tmp_path, sample_registrations)
client = TestClient(app)

resp = client.get("/categories")
assert resp.status_code == 200
data = resp.json()
assert data["total_categories"] == 2
assert len(data["categories"]) == 2
# Check categories are sorted
names = [c["name"] for c in data["categories"]]
assert names == ["other", "test"]
# Check tool counts and skill field
test_cat = next(c for c in data["categories"] if c["name"] == "test")
assert test_cat["tool_count"] == 2
assert test_cat["skill"] is None # No SKILL.md in tmp_path
other_cat = next(c for c in data["categories"] if c["name"] == "other")
assert other_cat["tool_count"] == 1
assert other_cat["skill"] is None # No SKILL.md in tmp_path