cann-gitcode-mcp 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. cann_gitcode_mcp-0.3.0/AGENTS.md +179 -0
  2. cann_gitcode_mcp-0.3.0/CLAUDE.md +5 -0
  3. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/PKG-INFO +29 -3
  4. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/README.md +28 -2
  5. cann_gitcode_mcp-0.3.0/docs/repo-application.md +102 -0
  6. cann_gitcode_mcp-0.3.0/docs/token-antipatterns-todo.md +162 -0
  7. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/pyproject.toml +5 -1
  8. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/__init__.py +1 -1
  9. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/tools/pipeline.py +53 -26
  10. cann_gitcode_mcp-0.3.0/src/cann_gitcode_mcp/tools/pull_request.py +323 -0
  11. cann_gitcode_mcp-0.3.0/tests/fixtures/comment_pull_request.json +13 -0
  12. cann_gitcode_mcp-0.3.0/tests/fixtures/create_pull_request.json +99 -0
  13. cann_gitcode_mcp-0.3.0/tests/fixtures/get_pull_request.json +108 -0
  14. cann_gitcode_mcp-0.3.0/tests/fixtures/get_pull_request_files.json +39 -0
  15. cann_gitcode_mcp-0.3.0/tests/fixtures/list_pull_request_comments.json +16 -0
  16. cann_gitcode_mcp-0.3.0/tests/fixtures/list_pull_requests.json +147 -0
  17. cann_gitcode_mcp-0.3.0/tests/fixtures/merge_pull_request.json +5 -0
  18. cann_gitcode_mcp-0.3.0/tests/fixtures/pipeline_get_pull_request.json +433 -0
  19. cann_gitcode_mcp-0.3.0/tests/fixtures/pipeline_list_comments.json +46 -0
  20. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/tests/test_pipeline_tools.py +10 -5
  21. cann_gitcode_mcp-0.3.0/tests/test_pull_request_tools.py +389 -0
  22. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/tests/test_server.py +3 -8
  23. cann_gitcode_mcp-0.3.0/tests/test_token_budget.py +397 -0
  24. cann_gitcode_mcp-0.3.0/tests/test_tool_definition_budget.py +65 -0
  25. cann_gitcode_mcp-0.2.0/AGENTS.md +0 -137
  26. cann_gitcode_mcp-0.2.0/CLAUDE.md +0 -133
  27. cann_gitcode_mcp-0.2.0/src/cann_gitcode_mcp/tools/pull_request.py +0 -210
  28. cann_gitcode_mcp-0.2.0/tests/test_pull_request_tools.py +0 -213
  29. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/.gitignore +0 -0
  30. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/LICENSE +0 -0
  31. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/docs/gitcode_mcp_design.md +0 -0
  32. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/docs/pipeline-tools-research.md +0 -0
  33. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/__main__.py +0 -0
  34. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/client.py +0 -0
  35. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/server.py +0 -0
  36. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/tools/__init__.py +0 -0
  37. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/tests/__init__.py +0 -0
  38. {cann_gitcode_mcp-0.2.0 → cann_gitcode_mcp-0.3.0}/tests/test_client.py +0 -0
@@ -0,0 +1,179 @@
1
+ # AGENTS.md — cann-gitcode-mcp
2
+
3
+ ## Project Overview
4
+
5
+ `cann-gitcode-mcp` is an MCP server that exposes GitCode REST API (v5, base `https://gitcode.com/api/v5`) as MCP tools for CANN developers. Package: `cann-gitcode-mcp`; module: `cann_gitcode_mcp`.
6
+
7
+ ## Quick Reference
8
+
9
+ ```bash
10
+ uv pip install -e ".[dev]" # Install (or: pip install -e ".[dev]")
11
+ pytest -v # Run tests
12
+ python -m cann_gitcode_mcp # Start MCP server (stdio)
13
+ ```
14
+
15
+ | Env Variable | Required | Description |
16
+ |---|---|---|
17
+ | `GITCODE_API_TOKEN` | Yes | Personal access token from GitCode |
18
+ | `GITCODE_API_BASE_URL` | No | Override API base (default: `https://gitcode.com/api/v5`) |
19
+
20
+ ## Architecture
21
+
22
+ ```
23
+ src/cann_gitcode_mcp/
24
+ ├── __init__.py # Package metadata
25
+ ├── __main__.py # python -m entry → server.main()
26
+ ├── server.py # FastMCP instance; wires all tool modules
27
+ ├── client.py # GitCodeClient (async httpx wrapper)
28
+ └── tools/
29
+ ├── __init__.py
30
+ ├── pull_request.py # 7 PR tools
31
+ └── pipeline.py # 2 pipeline tools (trigger + summary)
32
+ ```
33
+
34
+ - **`server.py`** — creates `FastMCP("gitcode")`, calls every `register_*_tools(mcp)`. Single wiring point.
35
+ - **`client.py`** — `GitCodeClient` reads `GITCODE_API_TOKEN` from env, provides async `get/post/patch/put/delete`. Raises `ValueError` if token unset, `RuntimeError` on non-2xx.
36
+ - **`tools/`** — each file owns one domain. Tools registered via `@mcp.tool()` inside `register_*_tools(mcp)`.
37
+
38
+ ## Code Rules
39
+
40
+ 1. **Python 3.11+** — `from __future__ import annotations` at top of every file.
41
+ 2. **Async** — all tool functions must be `async def`.
42
+ 3. **Type hints** — all parameters and return types annotated.
43
+ 4. **Return `str`** — `json.dumps(data, ensure_ascii=False)`, no `indent`.
44
+ 5. **Docstrings** — first line = MCP tool description; `Args:` for params.
45
+ 6. **Registration** — tools via `@mcp.tool()` inside `register_*_tools(mcp)`, never at module import time.
46
+ 7. **No bare exceptions** — let errors propagate; MCP framework surfaces them.
47
+ 8. **No global state beyond `_client`** — the singleton is reset between tests via `patch`.
48
+
49
+ ## Adding a New Tool
50
+
51
+ ### 1. Create `src/cann_gitcode_mcp/tools/<domain>.py`
52
+
53
+ ```python
54
+ from __future__ import annotations
55
+ import json
56
+ from mcp.server.fastmcp import FastMCP
57
+ from cann_gitcode_mcp.client import GitCodeClient
58
+
59
+ _client: GitCodeClient | None = None
60
+
61
+ def _get_client() -> GitCodeClient:
62
+ global _client
63
+ if _client is None:
64
+ _client = GitCodeClient()
65
+ return _client
66
+
67
+ def register_<domain>_tools(mcp: FastMCP) -> None:
68
+
69
+ @mcp.tool()
70
+ async def get_thing(owner: str, repo: str, number: int) -> str:
71
+ """One-line description for MCP.
72
+
73
+ Args:
74
+ owner: Repository namespace
75
+ repo: Repository name
76
+ number: Item number
77
+ """
78
+ client = _get_client()
79
+ result = await client.get(f"/repos/{owner}/{repo}/things/{number}")
80
+ return json.dumps(result, ensure_ascii=False)
81
+ ```
82
+
83
+ ### 2. Register in `server.py`
84
+
85
+ ```python
86
+ from cann_gitcode_mcp.tools.<domain> import register_<domain>_tools
87
+ register_<domain>_tools(mcp)
88
+ ```
89
+
90
+ ### 3. Add tests in `tests/test_<domain>.py`
91
+
92
+ ```python
93
+ import pytest
94
+ from unittest.mock import AsyncMock, patch
95
+ from mcp.server.fastmcp import FastMCP
96
+
97
+ @pytest.fixture
98
+ def mcp_server():
99
+ server = FastMCP("test")
100
+ with patch("cann_gitcode_mcp.tools.<domain>._client", None), \
101
+ patch.dict("os.environ", {"GITCODE_API_TOKEN": "test-token"}):
102
+ register_<domain>_tools(server)
103
+ yield server
104
+
105
+ async def test_get_thing(mcp_server):
106
+ tool_fn = mcp_server._tool_manager._tools["get_thing"].fn
107
+ with patch("cann_gitcode_mcp.tools.<domain>.GitCodeClient.get",
108
+ new_callable=AsyncMock, return_value={"id": 1}):
109
+ result = await tool_fn(owner="org", repo="repo", number=1)
110
+ assert '"id": 1' in result
111
+ ```
112
+
113
+ ### 4. Verify
114
+
115
+ ```bash
116
+ pytest tests/ -v # All tests must pass before committing
117
+ ```
118
+
119
+ ## Token Budget Rules
120
+
121
+ MCP tool tokens directly squeeze LLM context. Rules split into **input side** (tool definitions, fixed cost per turn) and **output side** (tool responses, variable cost per call).
122
+
123
+ ### Input Side — Tool Definitions (Fixed Cost)
124
+
125
+ | # | Rule | Practice | Anti-pattern |
126
+ |---|---|---|---|
127
+ | I1 | 合并同域工具 | 相关操作合并为一个工具 + `action` 参数路由 | 一个 API endpoint = 一个 tool |
128
+ | I2 | 描述只写决策信息 | 一行说"做什么",`Args:` 只写参数含义 | 写示例、教程、实现细节、重复 schema 约束 |
129
+ | I3 | enum 优先于 oneOf | `Literal["a","b"]` 生成 `enum` | `oneOf` 每个值一个 object,2-4x 膨胀 |
130
+ | I4 | 预算守护 | `test_tool_definition_budget.py` 断言工具 ≤ 4、定义 ≤ 1300 tokens | 加工具不跑预算测试 |
131
+ | I5 | 描述中不重复 schema | type/default/min/max 已在 JSON Schema,不再重复 | `"page: Page number (integer, minimum 1, default 1)"` |
132
+
133
+ ### Output Side — Tool Responses (Variable Cost)
134
+
135
+ | # | Rule | Practice | Anti-pattern |
136
+ |---|---|---|---|
137
+ | O1 | 字段裁剪 | 只返回决策字段,用 `_slim_*`。丢弃 `_links`, `permissions`, `avatar_url` | 透传原始 API 响应(70-90% 冗余) |
138
+ | O2 | 紧凑 JSON | `json.dumps(data, ensure_ascii=False)` 不加缩进 | `indent=2` 增加 30-40% token |
139
+ | O3 | 摘要/详情分级 | `detail="summary"\|"full"` 参数;列表默认 key fields | 列表接口返回完整 body |
140
+ | O4 | 大内容截断 | diff/日志设上限 `_MAX_DIFF_LINES`,超出截断 | 无限制返回大 diff/日志 |
141
+ | O5 | 失败详细 / 成功折叠 | 失败项保留名称+状态+日志链接;成功项折叠为计数 | 成功失败全量输出 |
142
+ | O6 | 写操作返回确认 | create/merge/comment 只返回 id + url | 返回完整创建对象 |
143
+ | O7 | 公共前缀提取 | 多 URL 共享前缀时提取 `base_url` + 相对路径 | 每条记录完整 URL |
144
+ | O8 | structuredContent 不双送 | `content` 和 `structuredContent` 只送一份 | 两者相同但都发送 |
145
+
146
+ ### Test Guards
147
+
148
+ | Test | Responsibility |
149
+ |---|---|
150
+ | `test_tool_definition_budget.py` | 工具数量和定义 token 总量不超预算 |
151
+ | `test_token_budget.py` | 每个工具响应 token ≤ 预算 |
152
+ | `TestTokenReductionReport` | raw vs slim token 对比(信息性) |
153
+
154
+ Token approximation: `len(text) // 4` (conservative for mixed CJK/English).
155
+
156
+ ### Current Baseline (2026-03-31)
157
+
158
+ | Metric | Value |
159
+ |---|---|
160
+ | Tool count | 4 (2 PR + 2 pipeline) |
161
+ | Definition tokens | ~1263 (budget: 1300) |
162
+ | Max response budget | 600 tokens (`get_pr_pipeline_summary`) |
163
+ | Response trimming | 87-95% vs raw API |
164
+
165
+ ### Scaling (When Tools > 8)
166
+
167
+ Not needed at 4 tools, but plan ahead:
168
+
169
+ - **Toolset filtering**: `--toolsets` flag, users enable only needed groups
170
+ - **Lazy loading**: expose name + one-line summary, load full schema on demand (91% input savings)
171
+ - **JSON `$ref`**: shared params defined once via `$ref`
172
+ - **Code Mode**: sandbox replaces N tools (98%+ savings, per Anthropic/Cloudflare)
173
+
174
+ ## GitCode API Reference
175
+
176
+ - Base URL: `https://gitcode.com/api/v5`
177
+ - Auth: `Authorization: Bearer <token>`
178
+ - PR endpoints: `/repos/{owner}/{repo}/pulls[/{number}[/merge|comments|files]]`
179
+ - Pipeline data: extracted from cann-robot PR comments (no dedicated API); see `docs/pipeline-tools-research.md`
@@ -0,0 +1,5 @@
1
+ # CLAUDE.md
2
+
3
+ <!-- 本项目开发指南统一维护在 AGENTS.md,避免重复 -->
4
+
5
+ See [AGENTS.md](AGENTS.md) for all project guidelines.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cann-gitcode-mcp
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: CANN GitCode MCP Server - GitCode platform tools for CANN developers
5
5
  Project-URL: Homepage, https://gitcode.com/shengnan666/cann-gitcode-mcp
6
6
  Project-URL: Repository, https://gitcode.com/shengnan666/cann-gitcode-mcp
@@ -45,12 +45,33 @@ pip install cann-gitcode-mcp
45
45
 
46
46
  ### 2. 配置 Claude Code
47
47
 
48
- 先在 [GitCode 用户设置](https://gitcode.com/setting/token-classic) 中生成个人访问令牌,然后在 Claude Code 的 MCP 配置文件(`~/.claude/settings.json` 或项目级 `.mcp.json`)中添加:
48
+ 先在 [GitCode 用户设置](https://gitcode.com/setting/token-classic) 中生成个人访问令牌,然后按需选择配置范围:
49
+
50
+ **方式一:当前用户范围(对本用户的所有项目生效)**
51
+
52
+ 编辑 `~/.claude.json`,在顶层添加 `mcpServers` 字段:
53
+
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "cann-gitcode": {
58
+ "command": "cann-gitcode-mcp",
59
+ "env": {
60
+ "GITCODE_API_TOKEN": "your_token_here"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ ```
66
+
67
+ **方式二:仅当前工程生效(可提交到版本库,团队共享)**
68
+
69
+ 在项目根目录创建或编辑 `.mcp.json`:
49
70
 
50
71
  ```json
51
72
  {
52
73
  "mcpServers": {
53
- "gitcode": {
74
+ "cann-gitcode": {
54
75
  "command": "cann-gitcode-mcp",
55
76
  "env": {
56
77
  "GITCODE_API_TOKEN": "your_token_here"
@@ -60,6 +81,8 @@ pip install cann-gitcode-mcp
60
81
  }
61
82
  ```
62
83
 
84
+ > **注意**:`.mcp.json` 若提交到版本库,其他协作者也会加载该 MCP 配置,但每人需在自己机器上安装 `cann-gitcode-mcp` 并填写自己的 Token。如果 Token 因人而异,可将 `.mcp.json` 加入 `.gitignore`,或仅配置不含 Token 的部分,通过其他方式注入环境变量。
85
+
63
86
  重启 Claude Code 即可使用。
64
87
 
65
88
  > **环境变量说明**:Token 通过 MCP 配置的 `env` 字段传入即可,无需手动 `export`。如需覆盖 API 地址,可额外设置 `GITCODE_API_BASE_URL`(默认 `https://gitcode.com/api/v5`)。
@@ -82,8 +105,11 @@ pip install cann-gitcode-mcp
82
105
 
83
106
  | 工具名 | 说明 |
84
107
  |--------|------|
108
+ | `trigger_pr_pipeline` | 向 PR 发送 `compile` 评论以触发 CI/CD 流水线 |
85
109
  | `get_pr_pipeline_summary` | 获取 PR 的 CI/CD 流水线摘要(解析 cann-robot 评论) |
86
110
 
111
+ `trigger_pr_pipeline` 通过在 PR 下发表 `compile` 评论来触发 cann-robot 启动流水线。**注意**:重复触发会中止当前运行的流水线并重新启动,请勿多次调用。
112
+
87
113
  `get_pr_pipeline_summary` 从 PR 评论中解析 cann-robot 发布的流水线结果,返回每个任务的名称、状态(SUCCESS/FAILED/ABORTED)、日志链接、构建产物下载链接,以及整体 CI 结论。无需 openLiBing token,仅使用 GitCode API。
88
114
 
89
115
  ## 路线图
@@ -16,12 +16,33 @@ pip install cann-gitcode-mcp
16
16
 
17
17
  ### 2. 配置 Claude Code
18
18
 
19
- 先在 [GitCode 用户设置](https://gitcode.com/setting/token-classic) 中生成个人访问令牌,然后在 Claude Code 的 MCP 配置文件(`~/.claude/settings.json` 或项目级 `.mcp.json`)中添加:
19
+ 先在 [GitCode 用户设置](https://gitcode.com/setting/token-classic) 中生成个人访问令牌,然后按需选择配置范围:
20
+
21
+ **方式一:当前用户范围(对本用户的所有项目生效)**
22
+
23
+ 编辑 `~/.claude.json`,在顶层添加 `mcpServers` 字段:
24
+
25
+ ```json
26
+ {
27
+ "mcpServers": {
28
+ "cann-gitcode": {
29
+ "command": "cann-gitcode-mcp",
30
+ "env": {
31
+ "GITCODE_API_TOKEN": "your_token_here"
32
+ }
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ **方式二:仅当前工程生效(可提交到版本库,团队共享)**
39
+
40
+ 在项目根目录创建或编辑 `.mcp.json`:
20
41
 
21
42
  ```json
22
43
  {
23
44
  "mcpServers": {
24
- "gitcode": {
45
+ "cann-gitcode": {
25
46
  "command": "cann-gitcode-mcp",
26
47
  "env": {
27
48
  "GITCODE_API_TOKEN": "your_token_here"
@@ -31,6 +52,8 @@ pip install cann-gitcode-mcp
31
52
  }
32
53
  ```
33
54
 
55
+ > **注意**:`.mcp.json` 若提交到版本库,其他协作者也会加载该 MCP 配置,但每人需在自己机器上安装 `cann-gitcode-mcp` 并填写自己的 Token。如果 Token 因人而异,可将 `.mcp.json` 加入 `.gitignore`,或仅配置不含 Token 的部分,通过其他方式注入环境变量。
56
+
34
57
  重启 Claude Code 即可使用。
35
58
 
36
59
  > **环境变量说明**:Token 通过 MCP 配置的 `env` 字段传入即可,无需手动 `export`。如需覆盖 API 地址,可额外设置 `GITCODE_API_BASE_URL`(默认 `https://gitcode.com/api/v5`)。
@@ -53,8 +76,11 @@ pip install cann-gitcode-mcp
53
76
 
54
77
  | 工具名 | 说明 |
55
78
  |--------|------|
79
+ | `trigger_pr_pipeline` | 向 PR 发送 `compile` 评论以触发 CI/CD 流水线 |
56
80
  | `get_pr_pipeline_summary` | 获取 PR 的 CI/CD 流水线摘要(解析 cann-robot 评论) |
57
81
 
82
+ `trigger_pr_pipeline` 通过在 PR 下发表 `compile` 评论来触发 cann-robot 启动流水线。**注意**:重复触发会中止当前运行的流水线并重新启动,请勿多次调用。
83
+
58
84
  `get_pr_pipeline_summary` 从 PR 评论中解析 cann-robot 发布的流水线结果,返回每个任务的名称、状态(SUCCESS/FAILED/ABORTED)、日志链接、构建产物下载链接,以及整体 CI 结论。无需 openLiBing token,仅使用 GitCode API。
59
85
 
60
86
  ## 路线图
@@ -0,0 +1,102 @@
1
+ # cann-gitcode-mcp 建仓申请材料
2
+
3
+ ## 仓库名称
4
+
5
+ `cann-gitcode-mcp`
6
+
7
+ ## 一、仓库用途
8
+
9
+ 为 CANN 开发者提供 GitCode 平台的 MCP(Model Context Protocol)工具服务。将 GitCode REST API 封装为标准 MCP 工具,使 Claude Code 等 AI 编程助手能够在对话中直接执行 Pull Request 管理、CI/CD 流水线触发与状态查询等 GitCode 平台操作,消除开发者在 AI 助手与 GitCode Web 界面之间的频繁切换。
10
+
11
+ ## 二、建仓目的
12
+
13
+ CANN 社区的代码托管在 GitCode 平台,而当前主流 AI 编程助手(如 Claude Code)仅原生支持 GitHub。GitCode 官方尚未发布 MCP 服务,而 CANN 社区的 AI 辅助研发需求已经迫切,我们选择先行建设而非被动等待。
14
+
15
+ 本项目的定位**不是简单的 GitCode API 封装**,而是在 GitCode 基础能力之上,结合 CANN 社区特有的研发规范构建上层工具。项目包含两个层次的能力:
16
+
17
+ - **GitCode 平台能力**:PR 全生命周期管理(创建、查询、合并、评论、变更文件查看),为 AI 助手提供基础的平台操作能力。
18
+ - **CANN 研发规范工具**:基于 CANN 社区的 CI/CD 规范,实现 cann-robot 流水线触发、构建结果解析(任务状态、日志链接、构建产物),在对话中完成"提交→触发→查看结果"的闭环。这些工具与 CANN 构建体系深度绑定,是本仓的核心差异化价值。
19
+
20
+ > **与 GitCode 官方 MCP 的关系**:若 GitCode 官方未来发布 MCP 服务,本项目中 GitCode 平台能力部分可平滑切换至官方实现或将已有实现贡献给官方,CANN 研发规范工具不受影响,继续独立演进。
21
+
22
+ ## 三、仓库价值
23
+
24
+ 1. **降低工具切换成本**:开发者在 AI 助手中即可完成 GitCode 平台操作,减少上下文切换,提升研发效率。
25
+ 2. **补齐 AI 辅助研发短板**:GitCode 官方尚未提供 MCP 服务,本项目先行填补这一空白,使 CANN 社区不必等待即可用上 AI 辅助研发能力。
26
+ 3. **标准化协议,可扩展性强**:基于 MCP 开放协议实现,不绑定特定 AI 客户端,任何支持 MCP 的工具均可接入。
27
+ 4. **已发布可用**:当前版本(0.2.0)已发布至 PyPI,提供 9 个生产可用的工具函数,覆盖 PR 管理和流水线查询两大核心场景。
28
+
29
+ ## 四、未来演进
30
+
31
+ | 阶段 | 内容 | 说明 |
32
+ |------|------|------|
33
+ | 近期 | 多 Agent 客户端支持 | 适配 OpenCode、Codex 等更多 MCP 客户端,扩大工具覆盖面 |
34
+ | 中期 | 流水线详情(L2) | 对接 openLiBing API,获取 stage/job/step 级别的详细信息和错误定位 |
35
+ | 长期 | 更多 CANN 工具 | 根据社区研发规范扩展更多 CANN 专属工具, 例如触发 RDV 等 |
36
+ | 持续 | 与 GitCode 官方协同 | 官方发布 MCP 后,平台能力部分可切换至官方或贡献上游,CANN 工具独立演进 |
37
+
38
+ ## 五、技术栈
39
+
40
+ | 类别 | 技术选型 | 说明 |
41
+ |------|----------|------|
42
+ | 语言 | Python 3.11+ | 使用现代类型标注,全异步实现 |
43
+ | 核心协议 | MCP (Model Context Protocol) | Anthropic 主导的开放协议,`mcp>=1.0` SDK |
44
+ | HTTP 客户端 | httpx | 异步 HTTP 库,封装 GitCode REST API v5 调用 |
45
+ | 构建工具 | Hatchling | PEP 517 标准构建后端 |
46
+ | 测试框架 | pytest + pytest-asyncio | 异步测试,mock 网络层,无外部依赖 |
47
+ | 分发渠道 | PyPI | `pip install cann-gitcode-mcp` 即可安装 |
48
+ | 许可证 | Apache License 2.0 | 与 CANN 社区许可证保持一致 |
49
+
50
+ ## 附录:MCP 在 AI Agent 体系中的位置
51
+
52
+ > **一句话定位**:Agent 是大脑,Skill 是内功,MCP 是双手 —— Agent 负责理解与决策,Skill 定义做事的方法论,MCP 让 Agent 能操作外部世界。
53
+
54
+ ```
55
+ ┌───────────────────────────────┐
56
+ │ 开发者 (用户) │
57
+ └───────────────┬───────────────┘
58
+ │ 自然语言对话
59
+
60
+ ┌───────────────────────────────────────────────────┐
61
+ │ AI Agent (Claude Code) │
62
+ │ │
63
+ │ 理解意图 → 规划步骤 → 调度能力 → 交付结果 │
64
+ │ │
65
+ │ ┌─────────────┐ ┌──────────────────────┐ │
66
+ │ │ Skills │ │ MCP Clients │ │
67
+ │ │ (内置技能) │ │ (工具连接器) │ │
68
+ │ │ │ │ │ │
69
+ │ │ · 代码编辑 │ │ MCP 协议 (JSON-RPC) │ │
70
+ │ │ · 调试推理 │ │ │ │ │ │ │
71
+ │ │ · 测试驱动 │ │ ▼ ▼ ▼ │ │
72
+ │ │ · Git 操作 │ │ ┌──┐┌──┐┌──┐ │ │
73
+ │ │ · ... │ │ │S1││S2││S3│ │ │
74
+ │ └─────────────┘ │ └──┘└──┘└──┘ │ │
75
+ └──────────────────────────│─────────────────────┘ │
76
+ └───┬────┬────┬─────────┘
77
+ │ │ │
78
+ ┌──────────────┘ │ └──────────────┐
79
+ ▼ ▼ ▼
80
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
81
+ │ MCP Server S1 │ │ MCP Server S2 │ │ MCP Server S3 │
82
+ │ cann-gitcode-mcp│ │ (其他 MCP) │ │ (其他 MCP) │
83
+ │ │ │ │ │ │
84
+ │ · create_pr │ │ · 数据库查询 │ │ · 文档检索 │
85
+ │ · merge_pr │ │ · 消息通知 │ │ · 监控告警 │
86
+ │ · trigger_ci │ │ · ... │ │ · ... │
87
+ │ · ... │ │ │ │ │
88
+ └────────┬────────┘ └────────┬────────┘ └────────┬────────┘
89
+ │ │ │
90
+ ▼ ▼ ▼
91
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
92
+ │ GitCode API │ │ 外部服务 B │ │ 外部服务 C │
93
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
94
+ ```
95
+
96
+ **三者关系**:
97
+
98
+ | 概念 | 类比 | 职责边界 |
99
+ |------|------|----------|
100
+ | **Agent** | 大脑 | 理解用户意图,规划任务步骤,决定调用哪些能力 |
101
+ | **Skill** | 内功 | Agent 内置的方法论与工作流(如 TDD、调试策略),不涉及外部系统 |
102
+ | **MCP** | 双手 | 标准化的外部工具协议,让 Agent 能操作任意平台,本项目即通过 MCP 让 Agent 操作 GitCode |
@@ -0,0 +1,162 @@
1
+ # Token 反模式 TODO
2
+
3
+ 审计日期:2026-03-31
4
+ 对照规则:AGENTS.md "Token Budget Rules"
5
+
6
+ ## 反模式清单
7
+
8
+ ### AP-1: `pull_request_write(create)` 透传原始 API 响应 [违反 O1, O6]
9
+
10
+ **文件**: `src/cann_gitcode_mcp/tools/pull_request.py:281`
11
+
12
+ ```python
13
+ result = await client.post(f"/repos/{owner}/{repo}/pulls", json=payload)
14
+ return _text_result(result) # ← 原始 API 响应,未裁剪
15
+ ```
16
+
17
+ **问题**: create 返回完整 PR 对象(含 `_links`, `permissions`, `mergeable_state` 等 30+ 字段),写操作应只返回确认信息。
18
+
19
+ **修复**: 返回 `_slim_pr(result)` 或更精简的确认:`{"number": N, "html_url": "...", "action": "created"}`。
20
+
21
+ **预期节省**: ~200-400 tokens/次
22
+
23
+ **优先级**: P1
24
+
25
+ ---
26
+
27
+ ### AP-2: `pull_request_write(merge)` 透传原始 API 响应 [违反 O6]
28
+
29
+ **文件**: `src/cann_gitcode_mcp/tools/pull_request.py:292`
30
+
31
+ ```python
32
+ result = await client.put(..., json=payload)
33
+ return _text_result(result) # ← 原始 merge 响应
34
+ ```
35
+
36
+ **问题**: merge 响应可能包含冗余字段。写操作应返回精简确认。
37
+
38
+ **修复**: 只返回 `{"pr": "owner/repo#N", "action": "merged", "merge_method": "..."}`。
39
+
40
+ **预期节省**: ~50-100 tokens/次
41
+
42
+ **优先级**: P2
43
+
44
+ ---
45
+
46
+ ### AP-3: `trigger_pr_pipeline` 响应中 message 冗余 [违反 I2 精神]
47
+
48
+ **文件**: `src/cann_gitcode_mcp/tools/pipeline.py:197-201`
49
+
50
+ ```python
51
+ return _text_result({
52
+ "pr": f"{owner}/{repo}#{pr_number}",
53
+ "action": "pipeline_triggered",
54
+ "message": "Posted 'compile' comment. Pipeline will start shortly. "
55
+ "Use get_pr_pipeline_summary to check status.",
56
+ "comment_id": result.get("id"),
57
+ })
58
+ ```
59
+
60
+ **问题**: `message` 字段是给人看的指引文本,LLM 不需要被告知 "use tool X to do Y"。LLM 自己知道工具链。
61
+
62
+ **修复**: 删除 `message` 字段,或缩短为 `"status": "triggered"`。
63
+
64
+ **预期节省**: ~25 tokens/次
65
+
66
+ **优先级**: P3
67
+
68
+ ---
69
+
70
+ ### AP-4: CLAUDE.md 示例代码使用 `indent=2` [违反 O2]
71
+
72
+ **文件**: `CLAUDE.md:62`(已修复)
73
+
74
+ **问题**: 示例代码 `json.dumps(result, indent=2, ...)` 会误导新工具开发者加缩进。
75
+
76
+ **状态**: ✅ 已修复
77
+
78
+ ---
79
+
80
+ ### AP-5: AGENTS.md "Important Constraints" 也写了 `indent=2` [违反 O2]
81
+
82
+ **文件**: `AGENTS.md:126`(已修复)
83
+
84
+ **状态**: ✅ 已修复
85
+
86
+ ---
87
+
88
+ ### AP-6: `get_pr_pipeline_summary` 无结果时返回冗余 message [违反 O6 精神]
89
+
90
+ **文件**: `src/cann_gitcode_mcp/tools/pipeline.py:246-249`
91
+
92
+ ```python
93
+ return _text_result({
94
+ **base_result,
95
+ "pipeline_found": False,
96
+ "message": "No pipeline comments found from cann-robot",
97
+ })
98
+ ```
99
+
100
+ **问题**: `pipeline_found: False` 已经表达了含义,`message` 冗余。
101
+
102
+ **修复**: 删除 `message` 字段。
103
+
104
+ **预期节省**: ~15 tokens/次
105
+
106
+ **优先级**: P3
107
+
108
+ ---
109
+
110
+ ### AP-7: `pull_request_read(files)` 不支持 `detail="summary"` [违反 O3]
111
+
112
+ **文件**: `src/cann_gitcode_mcp/tools/pull_request.py:217-218`
113
+
114
+ **问题**: files action 忽略 `detail` 参数。summary 模式可以只返回 filename + status(不含 diff),显著减少 token。
115
+
116
+ **修复**: `detail="summary"` 时只返回 `{"filename": ..., "status": ..., "additions": N, "deletions": N}`,不含 diff。
117
+
118
+ **预期节省**: 50-80% per file(diff 是大头)
119
+
120
+ **优先级**: P2
121
+
122
+ ---
123
+
124
+ ### AP-8: `pull_request_read(comments)` 不支持 `detail="summary"` [违反 O3]
125
+
126
+ **文件**: `src/cann_gitcode_mcp/tools/pull_request.py:220-228`
127
+
128
+ **问题**: comments action 忽略 `detail` 参数。summary 模式可以只返回 user + created_at(不含 body),用于快速浏览。
129
+
130
+ **修复**: `detail="summary"` 时只返回 `{"id": ..., "user": ..., "created_at": ...}`。
131
+
132
+ **预期节省**: 40-60% per comment(body 通常最长)
133
+
134
+ **优先级**: P3
135
+
136
+ ---
137
+
138
+ ### AP-9: 缺少 `pull_request_write(create)` 的 token budget 测试 [违反测试要求]
139
+
140
+ **文件**: `tests/test_token_budget.py`
141
+
142
+ **问题**: BUDGETS 中没有 `pull_request_write:create` 的预算定义,也没有对应测试。create 返回原始 API 响应(AP-1),修复后需要加测试守护。
143
+
144
+ **修复**: 添加 fixture + budget + 测试。
145
+
146
+ **优先级**: P1(跟 AP-1 一起修复)
147
+
148
+ ---
149
+
150
+ ## 优先级总结
151
+
152
+ | 优先级 | 编号 | 描述 | 预期节省 |
153
+ |--------|------|------|----------|
154
+ | **P1** | AP-1 | create PR 透传原始响应 | ~200-400 tok |
155
+ | **P1** | AP-9 | create PR 缺 token budget 测试 | 守护 |
156
+ | **P2** | AP-2 | merge PR 透传原始响应 | ~50-100 tok |
157
+ | **P2** | AP-7 | files 不支持 summary 模式 | 50-80%/file |
158
+ | **P3** | AP-3 | trigger_pipeline 冗余 message | ~25 tok |
159
+ | **P3** | AP-6 | pipeline 无结果冗余 message | ~15 tok |
160
+ | **P3** | AP-8 | comments 不支持 summary 模式 | 40-60%/comment |
161
+ | ✅ | AP-4 | CLAUDE.md indent=2 示例 | 已修复 |
162
+ | ✅ | AP-5 | AGENTS.md indent=2 约束 | 已修复 |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cann-gitcode-mcp"
3
- version = "0.2.0"
3
+ dynamic = ["version"]
4
4
  description = "CANN GitCode MCP Server - GitCode platform tools for CANN developers"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -44,6 +44,10 @@ cann-gitcode-mcp = "cann_gitcode_mcp.server:main"
44
44
  requires = ["hatchling"]
45
45
  build-backend = "hatchling.build"
46
46
 
47
+ [tool.hatch.version]
48
+ source = "code"
49
+ path = "src/cann_gitcode_mcp/__init__.py"
50
+
47
51
  [tool.hatch.build.targets.wheel]
48
52
  packages = ["src/cann_gitcode_mcp"]
49
53
 
@@ -1,3 +1,3 @@
1
1
  """CANN GitCode MCP Server - GitCode platform tools for CANN developers."""
2
2
 
3
- __version__ = "0.2.0"
3
+ __version__ = "0.3.0"