cann-gitcode-mcp 0.1.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.
- cann_gitcode_mcp-0.3.0/AGENTS.md +179 -0
- cann_gitcode_mcp-0.3.0/CLAUDE.md +5 -0
- cann_gitcode_mcp-0.3.0/PKG-INFO +141 -0
- cann_gitcode_mcp-0.3.0/README.md +112 -0
- cann_gitcode_mcp-0.3.0/docs/pipeline-tools-research.md +210 -0
- cann_gitcode_mcp-0.3.0/docs/repo-application.md +102 -0
- cann_gitcode_mcp-0.3.0/docs/token-antipatterns-todo.md +162 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/pyproject.toml +5 -1
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/__init__.py +1 -1
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/server.py +2 -0
- cann_gitcode_mcp-0.3.0/src/cann_gitcode_mcp/tools/pipeline.py +300 -0
- cann_gitcode_mcp-0.3.0/src/cann_gitcode_mcp/tools/pull_request.py +323 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/comment_pull_request.json +13 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/create_pull_request.json +99 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/get_pull_request.json +108 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/get_pull_request_files.json +39 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/list_pull_request_comments.json +16 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/list_pull_requests.json +147 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/merge_pull_request.json +5 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/pipeline_get_pull_request.json +433 -0
- cann_gitcode_mcp-0.3.0/tests/fixtures/pipeline_list_comments.json +46 -0
- cann_gitcode_mcp-0.3.0/tests/test_pipeline_tools.py +301 -0
- cann_gitcode_mcp-0.3.0/tests/test_pull_request_tools.py +389 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/tests/test_server.py +8 -8
- cann_gitcode_mcp-0.3.0/tests/test_token_budget.py +397 -0
- cann_gitcode_mcp-0.3.0/tests/test_tool_definition_budget.py +65 -0
- cann_gitcode_mcp-0.1.0/AGENTS.md +0 -133
- cann_gitcode_mcp-0.1.0/CLAUDE.md +0 -132
- cann_gitcode_mcp-0.1.0/PKG-INFO +0 -149
- cann_gitcode_mcp-0.1.0/README.md +0 -120
- cann_gitcode_mcp-0.1.0/src/cann_gitcode_mcp/tools/pull_request.py +0 -173
- cann_gitcode_mcp-0.1.0/tests/test_pull_request_tools.py +0 -184
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/.gitignore +0 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/LICENSE +0 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/docs/gitcode_mcp_design.md +0 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/__main__.py +0 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/client.py +0 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/tools/__init__.py +0 -0
- {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/tests/__init__.py +0 -0
- {cann_gitcode_mcp-0.1.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,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cann-gitcode-mcp
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: CANN GitCode MCP Server - GitCode platform tools for CANN developers
|
|
5
|
+
Project-URL: Homepage, https://gitcode.com/shengnan666/cann-gitcode-mcp
|
|
6
|
+
Project-URL: Repository, https://gitcode.com/shengnan666/cann-gitcode-mcp
|
|
7
|
+
Project-URL: Issues, https://gitcode.com/shengnan666/cann-gitcode-mcp/issues
|
|
8
|
+
Author-email: shengnan <shengnan1126@yeah.net>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cann,gitcode,mcp,model-context-protocol
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: httpx>=0.27
|
|
22
|
+
Requires-Dist: mcp>=1.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: twine>=6.0; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# cann-gitcode-mcp
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/cann-gitcode-mcp/)
|
|
33
|
+
[](https://pypi.org/project/cann-gitcode-mcp/)
|
|
34
|
+
[](https://github.com/shengnan666/cann-gitcode-mcp/blob/main/LICENSE)
|
|
35
|
+
|
|
36
|
+
CANN 社区的代码托管在 [GitCode](https://gitcode.com/) 平台。`cann-gitcode-mcp` 将 GitCode API 封装为 [MCP](https://modelcontextprotocol.io/) 工具,让 CANN 开发者在 Claude Code 等 AI 助手中直接操作仓库的 Pull Request、Issue、流水线等,无需离开对话界面。
|
|
37
|
+
|
|
38
|
+
## 快速开始
|
|
39
|
+
|
|
40
|
+
### 1. 安装
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install cann-gitcode-mcp
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. 配置 Claude Code
|
|
47
|
+
|
|
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`:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"cann-gitcode": {
|
|
75
|
+
"command": "cann-gitcode-mcp",
|
|
76
|
+
"env": {
|
|
77
|
+
"GITCODE_API_TOKEN": "your_token_here"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
> **注意**:`.mcp.json` 若提交到版本库,其他协作者也会加载该 MCP 配置,但每人需在自己机器上安装 `cann-gitcode-mcp` 并填写自己的 Token。如果 Token 因人而异,可将 `.mcp.json` 加入 `.gitignore`,或仅配置不含 Token 的部分,通过其他方式注入环境变量。
|
|
85
|
+
|
|
86
|
+
重启 Claude Code 即可使用。
|
|
87
|
+
|
|
88
|
+
> **环境变量说明**:Token 通过 MCP 配置的 `env` 字段传入即可,无需手动 `export`。如需覆盖 API 地址,可额外设置 `GITCODE_API_BASE_URL`(默认 `https://gitcode.com/api/v5`)。
|
|
89
|
+
|
|
90
|
+
## 可用工具
|
|
91
|
+
|
|
92
|
+
### Pull Request
|
|
93
|
+
|
|
94
|
+
| 工具名 | 说明 |
|
|
95
|
+
|--------|------|
|
|
96
|
+
| `create_pull_request` | 创建 Pull Request |
|
|
97
|
+
| `list_pull_requests` | 列出仓库的 Pull Request(支持状态、排序等过滤) |
|
|
98
|
+
| `get_pull_request` | 获取指定 PR 的详细信息 |
|
|
99
|
+
| `merge_pull_request` | 合并 Pull Request |
|
|
100
|
+
| `comment_pull_request` | 在 PR 上发表评论 |
|
|
101
|
+
| `get_pull_request_files` | 获取 PR 的变更文件列表 |
|
|
102
|
+
| `list_pull_request_comments` | 获取 PR 的所有评论 |
|
|
103
|
+
|
|
104
|
+
### Pipeline(流水线)
|
|
105
|
+
|
|
106
|
+
| 工具名 | 说明 |
|
|
107
|
+
|--------|------|
|
|
108
|
+
| `trigger_pr_pipeline` | 向 PR 发送 `compile` 评论以触发 CI/CD 流水线 |
|
|
109
|
+
| `get_pr_pipeline_summary` | 获取 PR 的 CI/CD 流水线摘要(解析 cann-robot 评论) |
|
|
110
|
+
|
|
111
|
+
`trigger_pr_pipeline` 通过在 PR 下发表 `compile` 评论来触发 cann-robot 启动流水线。**注意**:重复触发会中止当前运行的流水线并重新启动,请勿多次调用。
|
|
112
|
+
|
|
113
|
+
`get_pr_pipeline_summary` 从 PR 评论中解析 cann-robot 发布的流水线结果,返回每个任务的名称、状态(SUCCESS/FAILED/ABORTED)、日志链接、构建产物下载链接,以及整体 CI 结论。无需 openLiBing token,仅使用 GitCode API。
|
|
114
|
+
|
|
115
|
+
## 路线图
|
|
116
|
+
|
|
117
|
+
当前处于早期开发阶段(`0.x`),已实现 PR 工具集和流水线摘要。后续将按 CANN 社区实际研发流程的优先级逐步扩展:
|
|
118
|
+
|
|
119
|
+
1. **Issue 工具** — Issue 增删改查、评论管理(CANN 社区日常协作最频繁的场景)
|
|
120
|
+
2. **仓库工具** — 分支管理、文件读取、提交历史
|
|
121
|
+
3. **流水线详情(Level 2)** — 通过 openLiBing API 获取 stage/job/step 级别的详细信息和错误消息
|
|
122
|
+
|
|
123
|
+
欢迎在 [Issue](https://gitcode.com/shengnan666/cann-gitcode-mcp/issues) 中提出需求或反馈。
|
|
124
|
+
|
|
125
|
+
## 开发
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# 安装开发依赖
|
|
129
|
+
pip install -e ".[dev]"
|
|
130
|
+
|
|
131
|
+
# 运行测试
|
|
132
|
+
pytest
|
|
133
|
+
|
|
134
|
+
# 构建与发布
|
|
135
|
+
python -m build
|
|
136
|
+
twine upload dist/*
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## 许可证
|
|
140
|
+
|
|
141
|
+
[Apache License 2.0](LICENSE)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# cann-gitcode-mcp
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/cann-gitcode-mcp/)
|
|
4
|
+
[](https://pypi.org/project/cann-gitcode-mcp/)
|
|
5
|
+
[](https://github.com/shengnan666/cann-gitcode-mcp/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
CANN 社区的代码托管在 [GitCode](https://gitcode.com/) 平台。`cann-gitcode-mcp` 将 GitCode API 封装为 [MCP](https://modelcontextprotocol.io/) 工具,让 CANN 开发者在 Claude Code 等 AI 助手中直接操作仓库的 Pull Request、Issue、流水线等,无需离开对话界面。
|
|
8
|
+
|
|
9
|
+
## 快速开始
|
|
10
|
+
|
|
11
|
+
### 1. 安装
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install cann-gitcode-mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. 配置 Claude Code
|
|
18
|
+
|
|
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`:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"cann-gitcode": {
|
|
46
|
+
"command": "cann-gitcode-mcp",
|
|
47
|
+
"env": {
|
|
48
|
+
"GITCODE_API_TOKEN": "your_token_here"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> **注意**:`.mcp.json` 若提交到版本库,其他协作者也会加载该 MCP 配置,但每人需在自己机器上安装 `cann-gitcode-mcp` 并填写自己的 Token。如果 Token 因人而异,可将 `.mcp.json` 加入 `.gitignore`,或仅配置不含 Token 的部分,通过其他方式注入环境变量。
|
|
56
|
+
|
|
57
|
+
重启 Claude Code 即可使用。
|
|
58
|
+
|
|
59
|
+
> **环境变量说明**:Token 通过 MCP 配置的 `env` 字段传入即可,无需手动 `export`。如需覆盖 API 地址,可额外设置 `GITCODE_API_BASE_URL`(默认 `https://gitcode.com/api/v5`)。
|
|
60
|
+
|
|
61
|
+
## 可用工具
|
|
62
|
+
|
|
63
|
+
### Pull Request
|
|
64
|
+
|
|
65
|
+
| 工具名 | 说明 |
|
|
66
|
+
|--------|------|
|
|
67
|
+
| `create_pull_request` | 创建 Pull Request |
|
|
68
|
+
| `list_pull_requests` | 列出仓库的 Pull Request(支持状态、排序等过滤) |
|
|
69
|
+
| `get_pull_request` | 获取指定 PR 的详细信息 |
|
|
70
|
+
| `merge_pull_request` | 合并 Pull Request |
|
|
71
|
+
| `comment_pull_request` | 在 PR 上发表评论 |
|
|
72
|
+
| `get_pull_request_files` | 获取 PR 的变更文件列表 |
|
|
73
|
+
| `list_pull_request_comments` | 获取 PR 的所有评论 |
|
|
74
|
+
|
|
75
|
+
### Pipeline(流水线)
|
|
76
|
+
|
|
77
|
+
| 工具名 | 说明 |
|
|
78
|
+
|--------|------|
|
|
79
|
+
| `trigger_pr_pipeline` | 向 PR 发送 `compile` 评论以触发 CI/CD 流水线 |
|
|
80
|
+
| `get_pr_pipeline_summary` | 获取 PR 的 CI/CD 流水线摘要(解析 cann-robot 评论) |
|
|
81
|
+
|
|
82
|
+
`trigger_pr_pipeline` 通过在 PR 下发表 `compile` 评论来触发 cann-robot 启动流水线。**注意**:重复触发会中止当前运行的流水线并重新启动,请勿多次调用。
|
|
83
|
+
|
|
84
|
+
`get_pr_pipeline_summary` 从 PR 评论中解析 cann-robot 发布的流水线结果,返回每个任务的名称、状态(SUCCESS/FAILED/ABORTED)、日志链接、构建产物下载链接,以及整体 CI 结论。无需 openLiBing token,仅使用 GitCode API。
|
|
85
|
+
|
|
86
|
+
## 路线图
|
|
87
|
+
|
|
88
|
+
当前处于早期开发阶段(`0.x`),已实现 PR 工具集和流水线摘要。后续将按 CANN 社区实际研发流程的优先级逐步扩展:
|
|
89
|
+
|
|
90
|
+
1. **Issue 工具** — Issue 增删改查、评论管理(CANN 社区日常协作最频繁的场景)
|
|
91
|
+
2. **仓库工具** — 分支管理、文件读取、提交历史
|
|
92
|
+
3. **流水线详情(Level 2)** — 通过 openLiBing API 获取 stage/job/step 级别的详细信息和错误消息
|
|
93
|
+
|
|
94
|
+
欢迎在 [Issue](https://gitcode.com/shengnan666/cann-gitcode-mcp/issues) 中提出需求或反馈。
|
|
95
|
+
|
|
96
|
+
## 开发
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# 安装开发依赖
|
|
100
|
+
pip install -e ".[dev]"
|
|
101
|
+
|
|
102
|
+
# 运行测试
|
|
103
|
+
pytest
|
|
104
|
+
|
|
105
|
+
# 构建与发布
|
|
106
|
+
python -m build
|
|
107
|
+
twine upload dist/*
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 许可证
|
|
111
|
+
|
|
112
|
+
[Apache License 2.0](LICENSE)
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# Pipeline Tools 前期调研与架构设计
|
|
2
|
+
|
|
3
|
+
> 调研日期: 2026-03-29
|
|
4
|
+
|
|
5
|
+
## 1. 背景
|
|
6
|
+
|
|
7
|
+
CANN 的 CI/CD 流水线托管在 openLiBing (www.openlibing.com)。需要通过 MCP 工具查看流水线结果(编译结果、用例执行结果等)。
|
|
8
|
+
|
|
9
|
+
## 2. openLiBing 平台调研
|
|
10
|
+
|
|
11
|
+
### 2.1 平台概况
|
|
12
|
+
|
|
13
|
+
- **URL**: https://www.openlibing.com
|
|
14
|
+
- **性质**: MaJun 平台上的 CI/CD 服务,用于华为开源生态
|
|
15
|
+
- **登录方式**: 通过 GitCode 账号 OAuth 授权登录
|
|
16
|
+
- **公开 API**: 无。无公开文档、无 SDK、无 CLI
|
|
17
|
+
- **内部接口**: 有,Web UI 背后通过 JSON 接口获取数据
|
|
18
|
+
|
|
19
|
+
### 2.2 已确认的内部接口
|
|
20
|
+
|
|
21
|
+
**Pipeline Run Detail(流水线运行详情)**
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
GET /gateway/openlibing-cicd/project/pipeline/pipeline-run/detail
|
|
25
|
+
?projectId={projectId}
|
|
26
|
+
&pipelineId={pipelineId}
|
|
27
|
+
&pipelineRunId={pipelineRunId}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- Host: `www.openlibing.com`
|
|
31
|
+
- 认证方式: JWT Token,通过 Cookie 和 Header 双重传递
|
|
32
|
+
- Cookie: `token={jwt}; csrf-token-open-li-bing={jwt}`
|
|
33
|
+
- Header: `Csrf-Token-Open-Li-Bing: {jwt}`
|
|
34
|
+
- Token 有效期: 30 分钟(`Max-Age=1800`),响应 Set-Cookie 自动续期
|
|
35
|
+
- JWT Payload 含: accountId, accountLogin, accountPlatform("gitcode"), exp 等
|
|
36
|
+
|
|
37
|
+
### 2.3 流水线数据没有列表接口
|
|
38
|
+
|
|
39
|
+
用户确认:openLiBing 没有通过 pipelineId 查询运行列表的接口。每次流水线的入口是从 GitCode PR 上 bot 评论中的链接点进去的。
|
|
40
|
+
|
|
41
|
+
## 3. GitCode PR Bot 评论分析
|
|
42
|
+
|
|
43
|
+
### 3.1 Bot 信息
|
|
44
|
+
|
|
45
|
+
- **Bot 用户**: `cann-robot` (login: `cann-robot`)
|
|
46
|
+
- **评论 API**: `GET /api/v5/repos/{owner}/{repo}/pulls/{number}/comments`
|
|
47
|
+
- **认证**: `Authorization: Bearer {GITCODE_API_TOKEN}`(注意是 Bearer 不是 token 前缀)
|
|
48
|
+
|
|
49
|
+
### 3.2 Bot 评论结构
|
|
50
|
+
|
|
51
|
+
Bot 发两条评论:
|
|
52
|
+
|
|
53
|
+
**评论 1**: PR 审批状态(CLA签名、lgtm/approve 进度)
|
|
54
|
+
|
|
55
|
+
**评论 2**: 流水线结果(关键),包含:
|
|
56
|
+
|
|
57
|
+
1. **触发信息**: "流水线任务触发成功"
|
|
58
|
+
2. **openLiBing 链接**:
|
|
59
|
+
```
|
|
60
|
+
https://www.openlibing.com/apps/pipelineDetail
|
|
61
|
+
?pipelineId={pipelineId}
|
|
62
|
+
&pipelineRunId={pipelineRunId}
|
|
63
|
+
&projectName=CANN
|
|
64
|
+
```
|
|
65
|
+
3. **HTML 表格**,每行一个任务:
|
|
66
|
+
- 任务名称: `Check_Pr`, `Compile_X86_compiler`, `UT_Test_dflow` 等
|
|
67
|
+
- 状态: `SUCCESS` / `FAILED` / `ABORTED`
|
|
68
|
+
- 日志链接: openLiBing 详情页链接
|
|
69
|
+
- 下载链接: `ascend-ci.obs.cn-north-4.myhuaweicloud.com` 上的构建产物
|
|
70
|
+
4. **结论**: `CI执行失败` 或 `CI执行成功`
|
|
71
|
+
|
|
72
|
+
### 3.3 Bot 评论示例(关键部分)
|
|
73
|
+
|
|
74
|
+
```html
|
|
75
|
+
流水线任务触发成功
|
|
76
|
+
任务链接 [<a href='https://www.openlibing.com/apps/pipelineDetail?pipelineId=xxx&pipelineRunId=yyy&projectName=CANN'>yyy</a>]
|
|
77
|
+
<table>
|
|
78
|
+
<tr><th>任务名称</th><th>状态</th><th>日志</th><th>下载链接</th></tr>
|
|
79
|
+
<tr>
|
|
80
|
+
<td><strong>Compile_X86_compiler</strong></td>
|
|
81
|
+
<td>❌ FAILED</td>
|
|
82
|
+
<td><a href=https://www.openlibing.com/apps/pipelineDetail?...>>>>>></a></td>
|
|
83
|
+
<td><a href=></a></td>
|
|
84
|
+
</tr>
|
|
85
|
+
<tr>
|
|
86
|
+
<td><strong>Compile_X86_executor</strong></td>
|
|
87
|
+
<td>✅ SUCCESS</td>
|
|
88
|
+
<td><a href=...>>>>>></a></td>
|
|
89
|
+
<td><a href=https://ascend-ci.obs.cn-north-4.myhuaweicloud.com/ge/package/1601/cann-ge-executor_linux-x86_64.run>>>>>></a></td>
|
|
90
|
+
</tr>
|
|
91
|
+
...
|
|
92
|
+
</table>
|
|
93
|
+
[2026-03-28 16:45:30] CI执行失败
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 4. openLiBing Pipeline Run Detail 数据结构
|
|
97
|
+
|
|
98
|
+
从实际抓包获得的 JSON 结构(以 cann_ge pipeline #7071 为例):
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Pipeline Run
|
|
102
|
+
├── id, pipeline_id, name("cann_ge"), status("FAILED")
|
|
103
|
+
├── executor_name, trigger_type("Note"), run_number(7071)
|
|
104
|
+
├── start_time, end_time (epoch ms)
|
|
105
|
+
├── sources[] — 代码来源信息
|
|
106
|
+
│ └── git_type("gitcode"), repo_name("ge"), build_params(MR信息)
|
|
107
|
+
├── artifacts[] — 构建产物列表
|
|
108
|
+
│ └── name, packageType, version
|
|
109
|
+
└── stages[] — 流水线阶段列表
|
|
110
|
+
├── 阶段_1 (sequence:0) — 解析CI分支, COMPLETED
|
|
111
|
+
├── Image (sequence:1) — 解析镜像版本, COMPLETED
|
|
112
|
+
├── 编译构建 (sequence:2) — 14个并行Job, FAILED
|
|
113
|
+
│ └── jobs[]
|
|
114
|
+
│ ├── name, identifier, status, condition
|
|
115
|
+
│ ├── message (失败时有错误信息)
|
|
116
|
+
│ └── steps[]
|
|
117
|
+
│ ├── name, task, business_type, status, message
|
|
118
|
+
│ └── inputs[] (key/value配置)
|
|
119
|
+
├── LLT (sequence:3) — UT/ST测试 + codecheck等, 23个Job, INIT(未执行)
|
|
120
|
+
├── lcov (sequence:4) — 覆盖率报告, INIT
|
|
121
|
+
└── 后处理阶段 (sequence:5) — last_comment + Resource Clean, FAILED
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 4.1 Stage 依赖关系
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
阶段_1 → Image → 编译构建 → LLT → lcov
|
|
128
|
+
└→ 后处理阶段 (run_always:true)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 4.2 Job 状态枚举
|
|
132
|
+
|
|
133
|
+
- `COMPLETED` — 成功
|
|
134
|
+
- `FAILED` — 失败(message 字段含错误信息)
|
|
135
|
+
- `INIT` — 未执行(因前置阶段失败)
|
|
136
|
+
- `ABORTED` — 被中止
|
|
137
|
+
|
|
138
|
+
### 4.3 典型错误信息
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{"errorMessage":" 构建任务执行失败!","errorCode":"DEV-CODECI-35002"}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 5. 架构设计方案
|
|
145
|
+
|
|
146
|
+
### 5.1 分层设计(已与用户达成共识)
|
|
147
|
+
|
|
148
|
+
**Level 1: PR 评论解析 + 触发(纯 GitCode API)** ✅ 已实现
|
|
149
|
+
- 不依赖 openLiBing,只用 GITCODE_API_TOKEN
|
|
150
|
+
- 工具 1: `get_pr_pipeline_summary(owner, repo, pr_number)` — 解析 cann-robot 评论提取任务状态表,通过 PR labels 判断流水线状态(running/passed/failed),支持分页获取所有评论确保取到最后一次 pipeline 结果
|
|
151
|
+
- 工具 2: `trigger_pr_pipeline(owner, repo, pr_number)` — 在 PR 中发 `compile` 评论触发流水线
|
|
152
|
+
|
|
153
|
+
**Level 2: openLiBing 详情(需 openLiBing JWT)**
|
|
154
|
+
- 获取 stage/job/step 级别的详细信息和错误消息
|
|
155
|
+
- 工具: `get_pipeline_run_detail(pipeline_id, pipeline_run_id)`
|
|
156
|
+
- 需要解决 JWT 获取和续期问题
|
|
157
|
+
- **后续实现**,用于获取失败的详细信息
|
|
158
|
+
|
|
159
|
+
### 5.2 流水线状态判断
|
|
160
|
+
|
|
161
|
+
通过 PR labels 判断流水线状态(比解析评论更准确):
|
|
162
|
+
|
|
163
|
+
| PR Label | pipeline_status |
|
|
164
|
+
|----------|----------------|
|
|
165
|
+
| `ci-pipeline-running` | `running` |
|
|
166
|
+
| `ci-pipeline-passed` | `passed` |
|
|
167
|
+
| `ci-pipeline-failed` | `failed` |
|
|
168
|
+
| 都没有 | `unknown` |
|
|
169
|
+
|
|
170
|
+
### 5.3 职责划分
|
|
171
|
+
|
|
172
|
+
| 职责 | 归属 | 原因 |
|
|
173
|
+
|------|------|------|
|
|
174
|
+
| 发 `compile` 评论触发流水线 | MCP 工具 | 原子操作 |
|
|
175
|
+
| 查询最新 pipeline 结果 | MCP 工具 | 原子操作 |
|
|
176
|
+
| 等待流水线完成(轮询) | 调用方(Claude Code / 用户) | 等待时间分钟~几十分钟级 |
|
|
177
|
+
| 判断是否需要重新触发 | 调用方 | 业务决策 |
|
|
178
|
+
|
|
179
|
+
### 5.4 代码结构
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
src/cann_gitcode_mcp/
|
|
183
|
+
├── client.py # 现有 GitCodeClient (Bearer token auth)
|
|
184
|
+
├── openlibing_client.py # 待实现: OpenLiBingClient (JWT + CSRF auth, auto-refresh)
|
|
185
|
+
└── tools/
|
|
186
|
+
├── pull_request.py # 7 个 PR 工具(含 list_pull_request_comments)
|
|
187
|
+
└── pipeline.py # 2 个 pipeline 工具(trigger + summary)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 5.5 环境变量
|
|
191
|
+
|
|
192
|
+
| 变量 | 用途 | Level |
|
|
193
|
+
|------|------|-------|
|
|
194
|
+
| `GITCODE_API_TOKEN` | GitCode API 认证 | Level 1 |
|
|
195
|
+
| `OPENLIBING_TOKEN` | openLiBing JWT token | Level 2 |
|
|
196
|
+
|
|
197
|
+
## 6. 待确认/待探索
|
|
198
|
+
|
|
199
|
+
- [ ] openLiBing 是否有获取单个 Job 日志的接口(需要用户在 Web UI 上抓包)
|
|
200
|
+
- [ ] openLiBing JWT 的自动获取方案(OAuth flow 还是手动提供)
|
|
201
|
+
- [ ] 是否有其他 openLiBing 接口(如项目列表、流水线列表等)
|
|
202
|
+
|
|
203
|
+
## 7. 参考
|
|
204
|
+
|
|
205
|
+
- GitCode PR 评论 API: `GET /api/v5/repos/{owner}/{repo}/pulls/{number}/comments`
|
|
206
|
+
- openLiBing Pipeline Detail: `GET /gateway/openlibing-cicd/project/pipeline/pipeline-run/detail`
|
|
207
|
+
- 示例 PR: https://gitcode.com/cann/ge/pull/1601
|
|
208
|
+
- 示例 Pipeline Run ID: `aaa5c9122dbb44b0bbdd2890218a92f2`
|
|
209
|
+
- 示例 Pipeline ID: `8033cdebd5e5420e9165181589392a80`
|
|
210
|
+
- Project ID: `300033`, Project Name: `CANN`
|