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.
Files changed (40) 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.3.0/PKG-INFO +141 -0
  4. cann_gitcode_mcp-0.3.0/README.md +112 -0
  5. cann_gitcode_mcp-0.3.0/docs/pipeline-tools-research.md +210 -0
  6. cann_gitcode_mcp-0.3.0/docs/repo-application.md +102 -0
  7. cann_gitcode_mcp-0.3.0/docs/token-antipatterns-todo.md +162 -0
  8. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/pyproject.toml +5 -1
  9. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/__init__.py +1 -1
  10. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/server.py +2 -0
  11. cann_gitcode_mcp-0.3.0/src/cann_gitcode_mcp/tools/pipeline.py +300 -0
  12. cann_gitcode_mcp-0.3.0/src/cann_gitcode_mcp/tools/pull_request.py +323 -0
  13. cann_gitcode_mcp-0.3.0/tests/fixtures/comment_pull_request.json +13 -0
  14. cann_gitcode_mcp-0.3.0/tests/fixtures/create_pull_request.json +99 -0
  15. cann_gitcode_mcp-0.3.0/tests/fixtures/get_pull_request.json +108 -0
  16. cann_gitcode_mcp-0.3.0/tests/fixtures/get_pull_request_files.json +39 -0
  17. cann_gitcode_mcp-0.3.0/tests/fixtures/list_pull_request_comments.json +16 -0
  18. cann_gitcode_mcp-0.3.0/tests/fixtures/list_pull_requests.json +147 -0
  19. cann_gitcode_mcp-0.3.0/tests/fixtures/merge_pull_request.json +5 -0
  20. cann_gitcode_mcp-0.3.0/tests/fixtures/pipeline_get_pull_request.json +433 -0
  21. cann_gitcode_mcp-0.3.0/tests/fixtures/pipeline_list_comments.json +46 -0
  22. cann_gitcode_mcp-0.3.0/tests/test_pipeline_tools.py +301 -0
  23. cann_gitcode_mcp-0.3.0/tests/test_pull_request_tools.py +389 -0
  24. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/tests/test_server.py +8 -8
  25. cann_gitcode_mcp-0.3.0/tests/test_token_budget.py +397 -0
  26. cann_gitcode_mcp-0.3.0/tests/test_tool_definition_budget.py +65 -0
  27. cann_gitcode_mcp-0.1.0/AGENTS.md +0 -133
  28. cann_gitcode_mcp-0.1.0/CLAUDE.md +0 -132
  29. cann_gitcode_mcp-0.1.0/PKG-INFO +0 -149
  30. cann_gitcode_mcp-0.1.0/README.md +0 -120
  31. cann_gitcode_mcp-0.1.0/src/cann_gitcode_mcp/tools/pull_request.py +0 -173
  32. cann_gitcode_mcp-0.1.0/tests/test_pull_request_tools.py +0 -184
  33. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/.gitignore +0 -0
  34. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/LICENSE +0 -0
  35. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/docs/gitcode_mcp_design.md +0 -0
  36. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/__main__.py +0 -0
  37. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/client.py +0 -0
  38. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/src/cann_gitcode_mcp/tools/__init__.py +0 -0
  39. {cann_gitcode_mcp-0.1.0 → cann_gitcode_mcp-0.3.0}/tests/__init__.py +0 -0
  40. {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,5 @@
1
+ # CLAUDE.md
2
+
3
+ <!-- 本项目开发指南统一维护在 AGENTS.md,避免重复 -->
4
+
5
+ See [AGENTS.md](AGENTS.md) for all project guidelines.
@@ -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
+ [![PyPI version](https://img.shields.io/pypi/v/cann-gitcode-mcp)](https://pypi.org/project/cann-gitcode-mcp/)
33
+ [![Python](https://img.shields.io/pypi/pyversions/cann-gitcode-mcp)](https://pypi.org/project/cann-gitcode-mcp/)
34
+ [![License](https://img.shields.io/pypi/l/cann-gitcode-mcp)](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
+ [![PyPI version](https://img.shields.io/pypi/v/cann-gitcode-mcp)](https://pypi.org/project/cann-gitcode-mcp/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/cann-gitcode-mcp)](https://pypi.org/project/cann-gitcode-mcp/)
5
+ [![License](https://img.shields.io/pypi/l/cann-gitcode-mcp)](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`