128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
MCP-Server für Gitea (Issues + Datei-Inhalt via API).
|
|
|
|
Cursor: in den MCP-Einstellungen dieses Skript starten (siehe MCP_SETUP.md).
|
|
Transport: stdio (Standard FastMCP).
|
|
|
|
Abhängigkeit: pip install "mcp>=1.2.0" (siehe requirements-mcp.txt)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
|
|
from gitea_lib import (
|
|
issues_comment,
|
|
issues_create,
|
|
issues_get,
|
|
issues_list_all,
|
|
issues_list_page,
|
|
issues_patch,
|
|
load_dotenv,
|
|
repo_file_content,
|
|
repo_root,
|
|
require_config,
|
|
)
|
|
|
|
from mcp.server.fastmcp import FastMCP # noqa: E402
|
|
|
|
mcp = FastMCP(
|
|
"mitai-gitea",
|
|
instructions=(
|
|
"Gitea-Tools für das Repo aus GITEA_OWNER/GITEA_REPO. "
|
|
"Schließe Issues nur nach klarer Code-Verifikation; sonst Kommentar mit offenen Punkten."
|
|
),
|
|
)
|
|
|
|
|
|
def _cfg():
|
|
load_dotenv(repo_root())
|
|
return require_config()
|
|
|
|
|
|
def _json(obj) -> str:
|
|
return json.dumps(obj, indent=2, ensure_ascii=False)
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_list_issues(
|
|
state: str = "open",
|
|
limit_per_page: int = 50,
|
|
fetch_all_pages: bool = False,
|
|
) -> str:
|
|
"""Listet Issues. state: open | closed | all. fetch_all_pages=true holt alle Seiten (kann langsam sein)."""
|
|
base, token, owner, repo = _cfg()
|
|
if fetch_all_pages:
|
|
items = issues_list_all(
|
|
base, token, owner, repo, state=state, limit=limit_per_page
|
|
)
|
|
return _json(
|
|
[{"number": i.get("number"), "title": i.get("title"), "state": i.get("state")} for i in items]
|
|
)
|
|
_, items = issues_list_page(
|
|
base, token, owner, repo, state=state, page=1, limit=limit_per_page
|
|
)
|
|
return _json(
|
|
[{"number": i.get("number"), "title": i.get("title"), "state": i.get("state")} for i in items]
|
|
)
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_get_issue(issue_number: int) -> str:
|
|
"""Holt ein Issue inkl. Body, Labels, State (JSON)."""
|
|
base, token, owner, repo = _cfg()
|
|
st, payload = issues_get(base, token, owner, repo, issue_number)
|
|
return _json({"http_status": st, "issue": payload})
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_create_issue(title: str, body: str = "", labels: str = "") -> str:
|
|
"""Legt ein Issue an. labels: kommagetrennte Namen, z.B. \"bug,backend\"."""
|
|
base, token, owner, repo = _cfg()
|
|
lab = [x.strip() for x in labels.split(",") if x.strip()]
|
|
st, payload = issues_create(
|
|
base, token, owner, repo, title=title, body=body, labels=lab
|
|
)
|
|
return _json({"http_status": st, "result": payload})
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_comment_issue(issue_number: int, body: str) -> str:
|
|
"""Kommentar an ein Issue anhängen."""
|
|
base, token, owner, repo = _cfg()
|
|
st, payload = issues_comment(base, token, owner, repo, issue_number, body)
|
|
return _json({"http_status": st, "result": payload})
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_close_issue(issue_number: int) -> str:
|
|
"""Issue schließen (state=closed)."""
|
|
base, token, owner, repo = _cfg()
|
|
st, payload = issues_patch(
|
|
base, token, owner, repo, issue_number, {"state": "closed"}
|
|
)
|
|
return _json({"http_status": st, "result": payload})
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_reopen_issue(issue_number: int) -> str:
|
|
"""Geschlossenes Issue wieder öffnen."""
|
|
base, token, owner, repo = _cfg()
|
|
st, payload = issues_patch(
|
|
base, token, owner, repo, issue_number, {"state": "open"}
|
|
)
|
|
return _json({"http_status": st, "result": payload})
|
|
|
|
|
|
@mcp.tool()
|
|
def gitea_get_repo_file(path: str, git_ref: str = "") -> str:
|
|
"""Liest eine Datei aus dem Repo über die Gitea-API (Standard: Default-Branch)."""
|
|
base, token, owner, repo = _cfg()
|
|
st, payload = repo_file_content(base, token, owner, repo, path, ref=git_ref)
|
|
return _json({"http_status": st, "payload": payload})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mcp.run()
|