8e41fd12af
Registers gitea_request in AVAILABLE_TOOLS with write_operation=False (deliberate: a static flag cannot describe a read-or-write tool; the handler authorizes writes per-method) and maps the tool name to raw_api_request_tool in the server handler registry. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
762 lines
26 KiB
Python
762 lines
26 KiB
Python
"""MCP protocol models and tool registry."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, ConfigDict, 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(
|
|
...,
|
|
alias="inputSchema",
|
|
serialization_alias="inputSchema",
|
|
description="JSON schema describing input arguments",
|
|
)
|
|
write_operation: bool = Field(default=False, description="Whether tool mutates data")
|
|
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
|
|
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 argument payload")
|
|
correlation_id: str | None = Field(default=None, description="Request correlation ID")
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class MCPToolCallResponse(BaseModel):
|
|
"""Response returned from MCP tool invocation."""
|
|
|
|
success: bool = Field(..., description="Whether invocation succeeded")
|
|
result: Any | None = Field(default=None, description="Tool result payload")
|
|
error: str | None = Field(default=None, description="Error message for failed request")
|
|
correlation_id: str = Field(..., description="Correlation ID for request tracing")
|
|
|
|
|
|
class MCPListToolsResponse(BaseModel):
|
|
"""Response listing available tools."""
|
|
|
|
tools: list[MCPTool] = Field(..., description="Available tool definitions")
|
|
|
|
|
|
def _tool(
|
|
name: str, description: str, schema: dict[str, Any], write_operation: bool = False
|
|
) -> MCPTool:
|
|
"""Construct tool metadata entry."""
|
|
return MCPTool(
|
|
name=name,
|
|
description=description,
|
|
inputSchema=schema,
|
|
write_operation=write_operation,
|
|
)
|
|
|
|
|
|
AVAILABLE_TOOLS: list[MCPTool] = [
|
|
_tool(
|
|
"list_repositories",
|
|
"List repositories visible to the authenticated Gitea API token.",
|
|
{"type": "object", "properties": {}, "required": []},
|
|
),
|
|
_tool(
|
|
"get_repository_info",
|
|
"Get metadata for a repository.",
|
|
{
|
|
"type": "object",
|
|
"properties": {"owner": {"type": "string"}, "repo": {"type": "string"}},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_file_tree",
|
|
"Get repository tree at a selected ref.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"ref": {"type": "string", "default": "main"},
|
|
"recursive": {"type": "boolean", "default": False},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_file_contents",
|
|
"Read a repository file with size-limited content.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"filepath": {"type": "string"},
|
|
"ref": {"type": "string", "default": "main"},
|
|
},
|
|
"required": ["owner", "repo", "filepath"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"search_code",
|
|
"Search code in a repository.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"query": {"type": "string"},
|
|
"ref": {"type": "string", "default": "main"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 25},
|
|
},
|
|
"required": ["owner", "repo", "query"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_commits",
|
|
"List commits for a repository ref.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"ref": {"type": "string", "default": "main"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 25},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_commit_diff",
|
|
"Get commit metadata and file diffs.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"sha": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "sha"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"compare_refs",
|
|
"Compare two repository refs.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"base": {"type": "string"},
|
|
"head": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "base", "head"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_issues",
|
|
"List repository issues.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"state": {"type": "string", "enum": ["open", "closed", "all"], "default": "open"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 25},
|
|
"labels": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_issue",
|
|
"Get repository issue details.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
},
|
|
"required": ["owner", "repo", "issue_number"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_pull_requests",
|
|
"List repository pull requests.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"state": {"type": "string", "enum": ["open", "closed", "all"], "default": "open"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 25},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_pull_request",
|
|
"Get pull request details.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"pull_number": {"type": "integer", "minimum": 1},
|
|
},
|
|
"required": ["owner", "repo", "pull_number"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_labels",
|
|
"List labels defined on a repository.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_tags",
|
|
"List repository tags.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_releases",
|
|
"List repository releases.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 25},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_pull_request_files",
|
|
"List files changed in a pull request.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"pull_number": {"type": "integer", "minimum": 1},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo", "pull_number"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_pull_request_commits",
|
|
"List commits in a pull request.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"pull_number": {"type": "integer", "minimum": 1},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo", "pull_number"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_issue_comments",
|
|
"List comments on an issue or pull request.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo", "issue_number"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_branches",
|
|
"List repository branches.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_branch",
|
|
"Get a single branch.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"branch": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "branch"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_release",
|
|
"Get a release by id.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"release_id": {"type": "integer", "minimum": 1},
|
|
},
|
|
"required": ["owner", "repo", "release_id"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_latest_release",
|
|
"Get the latest published release.",
|
|
{
|
|
"type": "object",
|
|
"properties": {"owner": {"type": "string"}, "repo": {"type": "string"}},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_milestones",
|
|
"List repository milestones.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"state": {"type": "string", "enum": ["open", "closed", "all"], "default": "open"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_commit_status",
|
|
"Get the combined commit status for a ref or sha.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"sha": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "sha"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_org_repositories",
|
|
"List repositories belonging to an organization.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"org": {"type": "string"},
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": ["org"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_organizations",
|
|
"List organizations the authenticated user belongs to.",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"page": {"type": "integer", "minimum": 1, "default": 1},
|
|
"limit": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50},
|
|
},
|
|
"required": [],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"get_repo_languages",
|
|
"Get the language breakdown for a repository.",
|
|
{
|
|
"type": "object",
|
|
"properties": {"owner": {"type": "string"}, "repo": {"type": "string"}},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"list_repo_topics",
|
|
"List the topics assigned to a repository.",
|
|
{
|
|
"type": "object",
|
|
"properties": {"owner": {"type": "string"}, "repo": {"type": "string"}},
|
|
"required": ["owner", "repo"],
|
|
"additionalProperties": False,
|
|
},
|
|
),
|
|
_tool(
|
|
"create_issue",
|
|
"Create a repository issue (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"title": {"type": "string"},
|
|
"body": {"type": "string", "default": ""},
|
|
"labels": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
"assignees": {"type": "array", "items": {"type": "string"}, "default": []},
|
|
"milestone": {
|
|
"type": ["integer", "string"],
|
|
"description": "Milestone id or title to assign the issue to",
|
|
},
|
|
},
|
|
"required": ["owner", "repo", "title"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"update_issue",
|
|
"Update issue title/body/state/milestone (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
"title": {"type": "string"},
|
|
"body": {"type": "string"},
|
|
"state": {"type": "string", "enum": ["open", "closed"]},
|
|
"milestone": {
|
|
"type": ["integer", "string"],
|
|
"description": "Milestone id or title to assign; 0 clears the milestone",
|
|
},
|
|
},
|
|
"required": ["owner", "repo", "issue_number"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_issue_comment",
|
|
"Create issue comment (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
"body": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "issue_number", "body"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_pr_comment",
|
|
"Create pull request comment (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"pull_number": {"type": "integer", "minimum": 1},
|
|
"body": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "pull_number", "body"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"add_labels",
|
|
"Add labels to an issue or PR (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
"labels": {"type": "array", "items": {"type": "string"}, "minItems": 1},
|
|
},
|
|
"required": ["owner", "repo", "issue_number", "labels"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"assign_issue",
|
|
"Assign users to issue or PR (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
"assignees": {"type": "array", "items": {"type": "string"}, "minItems": 1},
|
|
},
|
|
"required": ["owner", "repo", "issue_number", "assignees"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_label",
|
|
"Create a repository label (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"name": {"type": "string"},
|
|
"color": {"type": "string", "description": "Hex color, e.g. #00aabb"},
|
|
"description": {"type": "string", "default": ""},
|
|
"exclusive": {"type": "boolean", "default": False},
|
|
},
|
|
"required": ["owner", "repo", "name", "color"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"update_label",
|
|
"Update an existing repository label, located by its current name (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"name": {"type": "string", "description": "Current label name"},
|
|
"new_name": {"type": "string"},
|
|
"color": {"type": "string", "description": "Hex color, e.g. #00aabb"},
|
|
"description": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "name"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"remove_labels",
|
|
"Remove labels (by name) from an issue or pull request (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"issue_number": {"type": "integer", "minimum": 1},
|
|
"labels": {"type": "array", "items": {"type": "string"}, "minItems": 1},
|
|
},
|
|
"required": ["owner", "repo", "issue_number", "labels"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_pull_request",
|
|
"Open a pull request from head into base (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"title": {"type": "string"},
|
|
"head": {"type": "string", "description": "Source branch"},
|
|
"base": {"type": "string", "description": "Target branch"},
|
|
"body": {"type": "string", "default": ""},
|
|
},
|
|
"required": ["owner", "repo", "title", "head", "base"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_release",
|
|
"Create a release for a tag (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"tag_name": {"type": "string"},
|
|
"name": {"type": "string", "default": ""},
|
|
"body": {"type": "string", "default": ""},
|
|
"draft": {"type": "boolean", "default": False},
|
|
"prerelease": {"type": "boolean", "default": False},
|
|
"target": {"type": "string", "description": "Target commitish/branch"},
|
|
},
|
|
"required": ["owner", "repo", "tag_name"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"edit_release",
|
|
"Edit an existing release (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"release_id": {"type": "integer", "minimum": 1},
|
|
"name": {"type": "string"},
|
|
"body": {"type": "string"},
|
|
"draft": {"type": "boolean"},
|
|
"prerelease": {"type": "boolean"},
|
|
},
|
|
"required": ["owner", "repo", "release_id"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_branch",
|
|
"Create a branch, optionally from an existing branch (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"new_branch_name": {"type": "string"},
|
|
"old_branch_name": {"type": "string", "description": "Source branch (optional)"},
|
|
},
|
|
"required": ["owner", "repo", "new_branch_name"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"create_milestone",
|
|
"Create a repository milestone (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"title": {"type": "string"},
|
|
"description": {"type": "string", "default": ""},
|
|
"due_on": {"type": "string", "description": "ISO8601 due date (optional)"},
|
|
},
|
|
"required": ["owner", "repo", "title"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"edit_issue_comment",
|
|
"Edit an existing issue or PR comment (write-mode only).",
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"owner": {"type": "string"},
|
|
"repo": {"type": "string"},
|
|
"comment_id": {"type": "integer", "minimum": 1},
|
|
"body": {"type": "string"},
|
|
},
|
|
"required": ["owner", "repo", "comment_id", "body"],
|
|
"additionalProperties": False,
|
|
},
|
|
write_operation=True,
|
|
),
|
|
_tool(
|
|
"gitea_request",
|
|
(
|
|
"Generic escape hatch that calls an arbitrary Gitea REST endpoint "
|
|
"(method + path). Prefer the dedicated tools; use this only for "
|
|
"endpoints they do not cover. Subject to policy, write-mode and the "
|
|
"sensitive-path denylist. Methods other than GET/HEAD are writes and "
|
|
"require write-mode plus a whitelisted repository."
|
|
),
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"method": {
|
|
"type": "string",
|
|
"enum": ["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE"],
|
|
},
|
|
"path": {
|
|
"type": "string",
|
|
"description": "Gitea REST path, e.g. /repos/{owner}/{repo}/pulls/1/merge",
|
|
},
|
|
"query": {"type": "object", "description": "Optional query-string parameters"},
|
|
"body": {"type": "object", "description": "Optional JSON request body"},
|
|
},
|
|
"required": ["method", "path"],
|
|
"additionalProperties": False,
|
|
},
|
|
# write_operation is intentionally False: a static flag cannot describe a
|
|
# tool that is read OR write depending on the method. Setting it True
|
|
# would force the central write-mode gate on GETs and break reads. The
|
|
# handler is authoritative via its own per-method authorize() call.
|
|
write_operation=False,
|
|
),
|
|
]
|
|
|
|
|
|
def get_tool_by_name(tool_name: str) -> MCPTool | None:
|
|
"""Get tool definition by name."""
|
|
for tool in AVAILABLE_TOOLS:
|
|
if tool.name == tool_name:
|
|
return tool
|
|
return None
|