generated from personal-projects/leo-claude-mktplace
feat(tools): add label and milestone operations
- Create labels.py with gitea_list_labels and gitea_create_label tools - Integrate milestone tools from milestones.py into server - Update tools/__init__.py with all tool exports - Update server.py to handle label and milestone tool calls Closes #4, Closes #5 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,10 +2,13 @@
|
||||
|
||||
from .issues import get_issue_tools, handle_issue_tool
|
||||
from .labels import get_label_tools, handle_label_tool
|
||||
from .milestones import get_milestone_tools, handle_milestone_tool
|
||||
|
||||
__all__ = [
|
||||
"get_issue_tools",
|
||||
"handle_issue_tool",
|
||||
"get_label_tools",
|
||||
"handle_label_tool",
|
||||
"get_milestone_tools",
|
||||
"handle_milestone_tool",
|
||||
]
|
||||
|
||||
170
src/gitea_mcp/tools/labels.py
Normal file
170
src/gitea_mcp/tools/labels.py
Normal file
@@ -0,0 +1,170 @@
|
||||
"""Gitea label operations MCP tools."""
|
||||
|
||||
from mcp.types import Tool, TextContent
|
||||
|
||||
from ..client import GiteaClient, GiteaClientError
|
||||
|
||||
|
||||
def get_label_tools() -> list[Tool]:
|
||||
"""Get label operation tool definitions.
|
||||
|
||||
Returns:
|
||||
list: Tool definitions for label operations.
|
||||
"""
|
||||
return [
|
||||
Tool(
|
||||
name="gitea_list_labels",
|
||||
description="List all labels in a Gitea repository",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"description": "Repository owner (user or organization)",
|
||||
},
|
||||
"repo": {
|
||||
"type": "string",
|
||||
"description": "Repository name",
|
||||
},
|
||||
},
|
||||
"required": ["owner", "repo"],
|
||||
},
|
||||
),
|
||||
Tool(
|
||||
name="gitea_create_label",
|
||||
description="Create a new label in a Gitea repository",
|
||||
inputSchema={
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"owner": {
|
||||
"type": "string",
|
||||
"description": "Repository owner (user or organization)",
|
||||
},
|
||||
"repo": {
|
||||
"type": "string",
|
||||
"description": "Repository name",
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Label name",
|
||||
},
|
||||
"color": {
|
||||
"type": "string",
|
||||
"description": "Label color (hex without #, e.g., 'ff0000' for red)",
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Label description (optional)",
|
||||
},
|
||||
},
|
||||
"required": ["owner", "repo", "name", "color"],
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
async def handle_label_tool(
|
||||
client: GiteaClient, name: str, arguments: dict
|
||||
) -> list[TextContent]:
|
||||
"""Handle label tool execution.
|
||||
|
||||
Args:
|
||||
client: Gitea client instance.
|
||||
name: Tool name.
|
||||
arguments: Tool arguments.
|
||||
|
||||
Returns:
|
||||
list: Tool response content.
|
||||
"""
|
||||
try:
|
||||
async with client:
|
||||
if name == "gitea_list_labels":
|
||||
return await _list_labels(client, arguments)
|
||||
elif name == "gitea_create_label":
|
||||
return await _create_label(client, arguments)
|
||||
else:
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text=f"Unknown label tool: {name}",
|
||||
)
|
||||
]
|
||||
except GiteaClientError as e:
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text=f"Gitea API error: {e}",
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
async def _list_labels(client: GiteaClient, arguments: dict) -> list[TextContent]:
|
||||
"""List labels in a repository.
|
||||
|
||||
Args:
|
||||
client: Gitea client instance.
|
||||
arguments: Tool arguments with owner and repo.
|
||||
|
||||
Returns:
|
||||
list: Label listing response.
|
||||
"""
|
||||
owner = arguments["owner"]
|
||||
repo = arguments["repo"]
|
||||
|
||||
labels = await client.get(f"/repos/{owner}/{repo}/labels")
|
||||
|
||||
if not labels:
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text=f"No labels found in {owner}/{repo}",
|
||||
)
|
||||
]
|
||||
|
||||
# Format labels for display
|
||||
lines = [f"Labels in {owner}/{repo}:", ""]
|
||||
for label in labels:
|
||||
color = label.get("color", "")
|
||||
desc = label.get("description", "")
|
||||
desc_text = f" - {desc}" if desc else ""
|
||||
lines.append(f" • {label['name']} (#{color}){desc_text}")
|
||||
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text="\n".join(lines),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
async def _create_label(client: GiteaClient, arguments: dict) -> list[TextContent]:
|
||||
"""Create a new label.
|
||||
|
||||
Args:
|
||||
client: Gitea client instance.
|
||||
arguments: Tool arguments with owner, repo, name, color, and optional description.
|
||||
|
||||
Returns:
|
||||
list: Creation response.
|
||||
"""
|
||||
owner = arguments["owner"]
|
||||
repo = arguments["repo"]
|
||||
name = arguments["name"]
|
||||
color = arguments["color"].lstrip("#") # Remove # if present
|
||||
description = arguments.get("description", "")
|
||||
|
||||
payload = {
|
||||
"name": name,
|
||||
"color": color,
|
||||
}
|
||||
if description:
|
||||
payload["description"] = description
|
||||
|
||||
label = await client.post(f"/repos/{owner}/{repo}/labels", payload)
|
||||
|
||||
return [
|
||||
TextContent(
|
||||
type="text",
|
||||
text=f"Created label '{label['name']}' (#{label['color']}) in {owner}/{repo}",
|
||||
)
|
||||
]
|
||||
Reference in New Issue
Block a user