This commit is contained in:
2026-01-29 19:53:36 +01:00
parent 1bda2013bb
commit a9708b33e2
27 changed files with 3745 additions and 4 deletions

View File

@@ -0,0 +1,156 @@
"""MCP protocol implementation for AegisGitea."""
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Field
class MCPTool(BaseModel):
"""MCP tool definition."""
name: str = Field(..., description="Unique tool identifier")
description: str = Field(..., description="Human-readable tool description")
input_schema: Dict[str, Any] = Field(..., description="JSON Schema for tool input")
class MCPToolCallRequest(BaseModel):
"""Request to invoke an MCP tool."""
tool: str = Field(..., description="Name of the tool to invoke")
arguments: Dict[str, Any] = Field(default_factory=dict, description="Tool arguments")
correlation_id: Optional[str] = Field(None, description="Request correlation ID")
class MCPToolCallResponse(BaseModel):
"""Response from an MCP tool invocation."""
success: bool = Field(..., description="Whether the tool call succeeded")
result: Optional[Any] = Field(None, description="Tool result data")
error: Optional[str] = Field(None, description="Error message if failed")
correlation_id: str = Field(..., description="Request correlation ID")
class MCPListToolsResponse(BaseModel):
"""Response listing available MCP tools."""
tools: List[MCPTool] = Field(..., description="List of available tools")
# Tool definitions for AegisGitea MCP
TOOL_LIST_REPOSITORIES = MCPTool(
name="list_repositories",
description="List all repositories visible to the AI bot user. "
"Only repositories where the bot has explicit read access will be returned. "
"This respects Gitea's dynamic authorization model.",
input_schema={
"type": "object",
"properties": {},
"required": [],
},
)
TOOL_GET_REPOSITORY_INFO = MCPTool(
name="get_repository_info",
description="Get detailed information about a specific repository, "
"including description, default branch, language, and metadata. "
"Requires the bot user to have read access.",
input_schema={
"type": "object",
"properties": {
"owner": {
"type": "string",
"description": "Repository owner username or organization",
},
"repo": {
"type": "string",
"description": "Repository name",
},
},
"required": ["owner", "repo"],
},
)
TOOL_GET_FILE_TREE = MCPTool(
name="get_file_tree",
description="Get the file tree structure for a repository at a specific ref. "
"Returns a list of files and directories. "
"Non-recursive by default for safety (max depth: 1 level).",
input_schema={
"type": "object",
"properties": {
"owner": {
"type": "string",
"description": "Repository owner username or organization",
},
"repo": {
"type": "string",
"description": "Repository name",
},
"ref": {
"type": "string",
"description": "Branch, tag, or commit SHA (defaults to 'main')",
"default": "main",
},
"recursive": {
"type": "boolean",
"description": "Whether to recursively fetch entire tree (use with caution)",
"default": False,
},
},
"required": ["owner", "repo"],
},
)
TOOL_GET_FILE_CONTENTS = MCPTool(
name="get_file_contents",
description="Read the contents of a specific file in a repository. "
"File size is limited to 1MB by default for safety. "
"Returns base64-encoded content for binary files.",
input_schema={
"type": "object",
"properties": {
"owner": {
"type": "string",
"description": "Repository owner username or organization",
},
"repo": {
"type": "string",
"description": "Repository name",
},
"filepath": {
"type": "string",
"description": "Path to file within repository (e.g., 'src/main.py')",
},
"ref": {
"type": "string",
"description": "Branch, tag, or commit SHA (defaults to 'main')",
"default": "main",
},
},
"required": ["owner", "repo", "filepath"],
},
)
# Registry of all available tools
AVAILABLE_TOOLS: List[MCPTool] = [
TOOL_LIST_REPOSITORIES,
TOOL_GET_REPOSITORY_INFO,
TOOL_GET_FILE_TREE,
TOOL_GET_FILE_CONTENTS,
]
def get_tool_by_name(tool_name: str) -> Optional[MCPTool]:
"""Get tool definition by name.
Args:
tool_name: Name of the tool to retrieve
Returns:
Tool definition or None if not found
"""
for tool in AVAILABLE_TOOLS:
if tool.name == tool_name:
return tool
return None