Browse Source

✨ feat: 新增仓库列表mcp

Pchen. 3 months ago
parent
commit
90bb62001c
2 changed files with 28 additions and 113 deletions
  1. 1 1
      mcp_/client.py
  2. 27 112
      mcp_/server.py

+ 1 - 1
mcp_/client.py

@@ -8,7 +8,7 @@ from http import HTTPStatus
 from mcp import ClientSession, StdioServerParameters
 from mcp.client.stdio import stdio_client
 from dashscope import Application
-from base_config import mcp_key, mcp_app_id
+from base_config import mcp_key, mcp_app_id, path as REPO_BASE_PATH
 # from dotenv import load_dotenv
 
 # load_dotenv()

+ 27 - 112
mcp_/server.py

@@ -2,6 +2,7 @@ import logging
 from pathlib import Path
 from typing import Optional
 from enum import Enum
+from base_config import path as REPO_BASE_PATH
 
 import git
 from mcp.types import TextContent
@@ -210,16 +211,33 @@ mcp = FastMCP("git")
 
 # --- Tool Definitions using @mcp_.tool() ---
 
-# @mcp.tool()
-# async def init_tool(repo_path: str) -> list[TextContent]:
-#     """Initializes a Git repository at the specified path.
+@mcp.tool()
+async def list_repos_tool(uuid: str) -> list[TextContent]:
+    """
+    列出指定用户在 GitNexus 平台上的所有仓库名称(即 repo 文件夹名)。
+
+    Args:
+        uuid: 用户的唯一标识,用于定位其仓库根路径。
+    """
+    user_path = Path(REPO_BASE_PATH) / uuid
+    logger.info(f"Executing tool: list_repos_tool for user {uuid}")
 
-#     Args:
-#         repo_path: The file system path where the Git repository should be initialized. Parent directories will be created if they don't exist.
-#     """
-#     logger.info(f"Executing tool: {GitTools.INIT} for path {repo_path}")
-#     result = git_init(repo_path)
-#     return [TextContent(type="text", text=result)]
+    if not user_path.exists() or not user_path.is_dir():
+        return [TextContent(type="text", text=f"用户还没有可用的Git仓库")]
+
+    try:
+        repo_names = [
+            f.name for f in user_path.iterdir()
+            if f.is_dir() and (f / ".git").exists()
+        ]
+        if not repo_names:
+            return [TextContent(type="text", text="当前没有可用的仓库。")]
+
+        result = "您当前拥有以下仓库:\n" + "\n".join(f"- {name}" for name in repo_names)
+        return [TextContent(type="text", text=result)]
+    except Exception as e:
+        logger.exception("Error while listing repositories")
+        return [TextContent(type="text", text=f"获取仓库列表时出错:{e}")]
 
 @mcp.tool()
 async def status_tool(repo_path: str) -> list[TextContent]:
@@ -237,38 +255,6 @@ async def status_tool(repo_path: str) -> list[TextContent]:
         result = str(e)
     return [TextContent(type="text", text=result)]
 
-# @mcp.tool()
-# async def diff_unstaged_tool(repo_path: str) -> list[TextContent]:
-#     """Shows changes in the working directory that are not staged for commit.
-
-#     Args:
-#         repo_path: The file system path to the Git repository.
-#     """
-#     logger.info(f"Executing tool: {GitTools.DIFF_UNSTAGED} for repo {repo_path}")
-#     try:
-#         repo = _get_repo(repo_path)
-#         diff = git_diff_unstaged(repo)
-#         result = f"Unstaged changes (working directory vs index) in '{repo_path}':\n{diff or 'No unstaged changes.'}"
-#     except ValueError as e:
-#         result = str(e)
-#     return [TextContent(type="text", text=result)]
-
-# @mcp.tool()
-# async def diff_staged_tool(repo_path: str) -> list[TextContent]:
-#     """Shows changes that are staged for the next commit (compared to HEAD).
-
-#     Args:
-#         repo_path: The file system path to the Git repository.
-#     """
-#     logger.info(f"Executing tool: {GitTools.DIFF_STAGED} for repo {repo_path}")
-#     try:
-#         repo = _get_repo(repo_path)
-#         diff = git_diff_staged(repo)
-#         result = f"Staged changes (index vs HEAD) in '{repo_path}':\n{diff or 'No staged changes.'}"
-#     except ValueError as e:
-#         result = str(e)
-#     return [TextContent(type="text", text=result)]
-
 @mcp.tool()
 async def diff_tool(repo_path: str, target: str) -> list[TextContent]:
     """Shows differences between the current HEAD and a specified target (e.g., a branch, tag, or commit hash).
@@ -288,60 +274,6 @@ async def diff_tool(repo_path: str, target: str) -> list[TextContent]:
         result = f"Error running git diff against '{target}': {e.stderr or e.stdout}"
     return [TextContent(type="text", text=result)]
 
-# @mcp.tool()
-# async def add_tool(repo_path: str, files: list[str]) -> list[TextContent]:
-#     """Adds specified file contents to the staging area (index) for the next commit.
-
-#     Args:
-#         repo_path: The file system path to the Git repository.
-#         files: A list of file paths (relative to the repository root) to stage. Use '.' to stage all changes.
-#     """
-#     logger.info(f"Executing tool: {GitTools.ADD} for repo {repo_path}, files: {files}")
-#     if not files:
-#         return [TextContent(type="text", text="Error: No files specified to add.")]
-#     try:
-#         repo = _get_repo(repo_path)
-#         result = git_add(repo, files)
-#     except ValueError as e: # Catches errors from _get_repo
-#         result = str(e)
-#     except Exception as e: # Catch other potential errors during add
-#         result = f"An unexpected error occurred during add: {str(e)}"
-#     return [TextContent(type="text", text=result)]
-
-# @mcp.tool()
-# async def commit_tool(repo_path: str, message: str) -> list[TextContent]:
-#     """Records changes staged in the index to the repository history.
-
-#     Args:
-#         repo_path: The file system path to the Git repository.
-#         message: The commit message describing the changes.
-#     """
-#     logger.info(f"Executing tool: {GitTools.COMMIT} for repo {repo_path}")
-#     try:
-#         repo = _get_repo(repo_path)
-#         # The check is now inside git_commit for cleaner tool function
-#         result = git_commit(repo, message)
-#     except ValueError as e: # Catches errors from _get_repo
-#         result = str(e)
-#     except Exception as e: # Catch other potential errors
-#         result = f"An unexpected error occurred during commit: {str(e)}"
-#     return [TextContent(type="text", text=result)]
-
-# @mcp.tool()
-# async def reset_tool(repo_path: str) -> list[TextContent]:
-#     """Resets the staging area (index) to match the current HEAD commit, effectively unstaging all changes. Does not modify the working directory.
-
-#     Args:
-#         repo_path: The file system path to the Git repository.
-#     """
-#     logger.info(f"Executing tool: {GitTools.RESET} for repo {repo_path}")
-#     try:
-#         repo = _get_repo(repo_path)
-#         result = git_reset(repo)
-#     except ValueError as e:
-#         result = str(e)
-#     return [TextContent(type="text", text=result)]
-
 @mcp.tool()
 async def log_tool(repo_path: str, max_count: int = 10) -> list[TextContent]:
     """Shows the commit history log for the current branch.
@@ -362,23 +294,6 @@ async def log_tool(repo_path: str, max_count: int = 10) -> list[TextContent]:
         result = str(e)
     return [TextContent(type="text", text=result)]
 
-# @mcp.tool()
-# async def create_branch_tool(repo_path: str, branch_name: str, base_branch: Optional[str] = None) -> list[TextContent]:
-#     """Creates a new branch.
-
-#     Args:
-#         repo_path: The file system path to the Git repository.
-#         branch_name: The name for the new branch.
-#         base_branch: Optional. The existing branch or commit hash to base the new branch on. If omitted, defaults to the current HEAD.
-#     """
-#     logger.info(f"Executing tool: {GitTools.CREATE_BRANCH} for repo {repo_path}, branch: {branch_name}, base: {base_branch}")
-#     try:
-#         repo = _get_repo(repo_path)
-#         result = git_create_branch(repo, branch_name, base_branch)
-#     except ValueError as e:
-#         result = str(e)
-#     return [TextContent(type="text", text=result)]
-
 @mcp.tool()
 async def checkout_tool(repo_path: str, branch_name: str) -> list[TextContent]:
     """Switches the working directory to a different branch.