Skip to content

Commit 0b7a406

Browse files
committed
mcp
1 parent f23793f commit 0b7a406

9 files changed

Lines changed: 1612 additions & 6 deletions

File tree

‎mcp.md‎

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# CodeAnt MCP Server
2+
3+
The CodeAnt CLI ships an MCP (Model Context Protocol) server that exposes CodeAnt's scan/review/PR data as tools Claude (and any other MCP client) can call directly.
4+
5+
- **Entrypoint:** `codeant mcp` — stdio transport, single subcommand registered in [src/index.js](src/index.js).
6+
- **Server:** [src/mcp/server.js](src/mcp/server.js) — uses `@modelcontextprotocol/sdk` and registers tools via `server.registerTool(...)`.
7+
- **Bundle:** the [mcpb/](mcpb/) directory + [scripts/build-mcpb.mjs](scripts/build-mcpb.mjs) produce a `.mcpb` Desktop Extension bundle (`dist/codeant.mcpb`).
8+
9+
## Tools registered
10+
11+
| Name | Read/Write | What it does |
12+
|------|------------|--------------|
13+
| `codeant_scans_orgs` | read | List authenticated CodeAnt orgs. |
14+
| `codeant_scans_repos` | read | List repos in an org. |
15+
| `codeant_scans_history` | read | Recent scan runs for a repo. |
16+
| `codeant_scans_get` | read | Severity/category summary for one scan. |
17+
| `codeant_scans_results` | read | Full findings (SAST, SCA, secrets, IaC, …) for one scan. |
18+
| `codeant_scans_dismissed` | read | Dismissed alerts for a repo. |
19+
| `codeant_pr_list` | read | List PRs/MRs across GitHub, GitLab, Bitbucket, Azure DevOps. |
20+
| `codeant_pr_get` | read | Detail for a PR/MR. |
21+
| `codeant_pr_comments` | read | Comments on a PR, filtered. |
22+
| `codeant_comments_search` | read | Free-text search across CodeAnt review comments. |
23+
| `codeant_review_local` | read | Run a CodeAnt review on local working-copy changes. |
24+
| `codeant_scans_start` | **write** | Trigger a new scan. Gated. |
25+
| `codeant_pr_resolve` | **write** | Resolve a PR conversation thread. Gated. |
26+
27+
Write tools are only registered when `CODEANT_READ_ONLY=0`. Default = read-only.
28+
29+
Every tool carries MCP annotations (`title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) so the client can decide whether to auto-approve calls.
30+
31+
## Configuration (env vars)
32+
33+
| Var | Purpose | Default |
34+
|-----|---------|---------|
35+
| `CODEANT_API_TOKEN` | API token (CodeAnt account → settings → API). Required. | — |
36+
| `CODEANT_API_URL` | API base URL. Override for self-hosted. | `https://api.codeant.ai` |
37+
| `CODEANT_READ_ONLY` | `1` to hide write tools, `0` to expose them. | `1` |
38+
39+
The CLI also reads these from `~/.codeant/config.json` when not set in env. For MCP usage prefer env — it keeps per-client config explicit.
40+
41+
---
42+
43+
## Install paths
44+
45+
### A — Claude Code CLI (terminal / VS Code extension)
46+
47+
```bash
48+
claude mcp add codeant -s user -e CODEANT_READ_ONLY=1 -- codeant mcp
49+
```
50+
51+
`-s user` puts it in your user-scope config so it works in every project. Use `-s project` to scope it to one repo (writes a `.mcp.json` at the repo root).
52+
53+
For a single project, you can instead drop this `.mcp.json` next to the project root:
54+
55+
```json
56+
{
57+
"mcpServers": {
58+
"codeant": {
59+
"command": "codeant",
60+
"args": ["mcp"],
61+
"env": { "CODEANT_READ_ONLY": "1" }
62+
}
63+
}
64+
}
65+
```
66+
67+
Verify with `/mcp` inside a Claude Code session.
68+
69+
### B — Claude Desktop (manual config)
70+
71+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the equivalent on Windows and add a `codeant` block:
72+
73+
```json
74+
{
75+
"mcpServers": {
76+
"codeant": {
77+
"command": "codeant",
78+
"args": ["mcp"],
79+
"env": { "CODEANT_READ_ONLY": "1" }
80+
}
81+
}
82+
}
83+
```
84+
85+
Requires the `codeant` CLI to be on the desktop app's PATH. If you hit "command not found" in `~/Library/Logs/Claude/mcp-server-codeant.log`, swap `"command": "codeant"` for `"command": "node"` with `"args": ["<absolute-path-to>/codeant-cli/src/index.js", "mcp"]`.
86+
87+
Quit Claude Desktop (Cmd-Q — not just close the window) and relaunch. The server appears under **Settings → Connectors**.
88+
89+
### C — Claude Desktop (MCPB double-click)
90+
91+
The MCPB bundle is the only path that does not assume the user has the CodeAnt CLI installed — it ships everything in the bundle. This is what we submit to the Anthropic directory.
92+
93+
```bash
94+
npm run mcpb:build
95+
open -a Claude dist/codeant.mcpb
96+
```
97+
98+
Claude pops an install dialog asking for the `user_config` fields:
99+
- **CodeAnt API token** (sensitive, required)
100+
- **API base URL** (defaults to `https://api.codeant.ai`)
101+
- **Read-only mode** (defaults to on)
102+
103+
After install, manage it in **Settings → Connectors**.
104+
105+
If you also have a manual `claude_desktop_config.json` entry from path B, you'll see `codeant` listed twice — remove one to avoid duplicate tool listings.
106+
107+
---
108+
109+
## Packaging the MCPB bundle
110+
111+
### What gets bundled
112+
113+
```
114+
codeant.mcpb (zip)
115+
├── manifest.json # from mcpb/manifest.json, version pinned to package.json
116+
├── icon.png # 256×256, from mcpb/icon.png
117+
├── server/
118+
│ └── index.js # thin entry wrapper, calls startMcpServer()
119+
├── src/ # the entire CLI source tree
120+
├── node_modules/ # production deps only (npm install --omit=dev)
121+
└── package.json # trimmed: only name/version/type/dependencies
122+
```
123+
124+
The bundle is self-contained — Claude Desktop ships its own Node runtime, so no global install is required on the user's machine.
125+
126+
### Build it
127+
128+
```bash
129+
npm run mcpb:build
130+
```
131+
132+
Under the hood this runs [scripts/build-mcpb.mjs](scripts/build-mcpb.mjs):
133+
134+
1. Clean `dist/mcpb-stage/` and `dist/codeant.mcpb`.
135+
2. Copy `src/` and `mcpb/server/` into the staging dir.
136+
3. Write a trimmed `package.json` containing only production deps.
137+
4. Run `npm install --omit=dev` inside the staging dir.
138+
5. Copy `mcpb/manifest.json` (with `version` overridden from the root `package.json`) and `mcpb/icon.png`.
139+
6. Zip the staging dir as `dist/codeant.mcpb`.
140+
141+
Result is typically ~11 MB. Verify the bundled server speaks MCP:
142+
143+
```bash
144+
cd dist/mcpb-stage
145+
(printf '%s\n' \
146+
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
147+
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
148+
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}'; sleep 1) | node server/index.js
149+
```
150+
151+
Expect 11 tools in the `tools/list` response (or 13 if `CODEANT_READ_ONLY=0`).
152+
153+
### Bumping the version
154+
155+
Edit `version` in [package.json](package.json). The build script pins the manifest's `version` field from there, so you do not need to touch [mcpb/manifest.json](mcpb/manifest.json) for normal bumps.
156+
157+
### Replacing the icon
158+
159+
`mcpb/icon.png` should be a 256×256 PNG. The current one was rasterized from `../vscode-build/assets/Logo.svg` via `qlmanage`. To regenerate from a new SVG:
160+
161+
```bash
162+
qlmanage -t -s 256 -o /tmp /path/to/Logo.svg
163+
cp /tmp/Logo.svg.png mcpb/icon.png
164+
npm run mcpb:build
165+
```
166+
167+
---
168+
169+
## Submitting to the Anthropic directory
170+
171+
CodeAnt's MCP server uses stdio + a packaged bundle, so the submission route is **Desktop Extensions (MCPB)**, not the remote-connector form.
172+
173+
- **Submission URL:** https://clau.de/desktop-extention-submission
174+
- **Bundle:** upload `dist/codeant.mcpb`
175+
- **Required metadata:** already in [mcpb/manifest.json](mcpb/manifest.json) — display name, description, author, homepage, documentation, repository, license, keywords, `privacy_policies`, `tools` static listing, `user_config` schema.
176+
177+
Reviewer notes worth preparing:
178+
179+
- **Auth model.** CodeAnt uses a user-scoped API token entered into `user_config.api_token`. The token never leaves the user's machine — the bundle talks to `api.codeant.ai` (or the user's self-hosted URL) directly. No third-party OAuth flow needed.
180+
- **Sandbox creds.** Provide a test account + token so reviewers can exercise the read tools.
181+
- **Write tools.** Gated behind `user_config.read_only` (defaults to on). Reviewers can toggle off to test `codeant_scans_start` / `codeant_pr_resolve`.
182+
183+
---
184+
185+
## Troubleshooting
186+
187+
| Symptom | Where to look |
188+
|---|---|
189+
| Server fails to start in Claude Desktop | `~/Library/Logs/Claude/mcp-server-codeant.log` |
190+
| Tool calls return errors | Same log — server stderr is captured there. |
191+
| Tool not listed at all | Check `CODEANT_READ_ONLY` — write tools are hidden when set to `1`. |
192+
| Auth errors on every tool | Confirm `CODEANT_API_TOKEN` is set in the MCP env (not just in `~/.codeant/config.json`). |
193+
| MCPB install dialog never appears | Open `.mcpb` with `open -a Claude dist/codeant.mcpb` to force the desktop app to handle it. |

‎mcpb/icon.png‎

1.71 KB
Loading

‎mcpb/manifest.json‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
{
2+
"manifest_version": "0.3",
3+
"name": "codeant",
4+
"display_name": "CodeAnt AI",
5+
"version": "0.5.0",
6+
"description": "Drive CodeAnt AI security scans and code review from Claude — org-wide secret triage, cross-repo SAST/SCA findings, on-demand scans, and local PR review.",
7+
"long_description": "CodeAnt AI inside Claude. Ask things like \"how many critical SAST findings do I have across my org?\", \"show every exposed secret in payments-service\", or \"review my staged changes\" — Claude calls the CodeAnt API directly via this MCP server.\n\nIncludes 11 read-only tools (orgs, repos, scan history, scan metadata, findings, dismissed alerts, PRs, comments, comment search, local review) and 2 opt-in write tools (trigger a scan, resolve a PR conversation) gated behind a setting.\n\nRequires a CodeAnt account. Sign up at https://codeant.ai and grab an API key from your settings page.",
8+
"author": {
9+
"name": "CodeAnt AI",
10+
"email": "support@codeant.ai",
11+
"url": "https://codeant.ai"
12+
},
13+
"homepage": "https://codeant.ai",
14+
"documentation": "https://docs.codeant.ai/cli/claude-code-plugin",
15+
"support": "https://docs.codeant.ai/support",
16+
"repository": {
17+
"type": "git",
18+
"url": "https://github.com/CodeAnt-AI/codeant-cli"
19+
},
20+
"license": "MIT",
21+
"keywords": [
22+
"code-review",
23+
"security",
24+
"secrets",
25+
"sast",
26+
"sca",
27+
"static-analysis",
28+
"pull-requests"
29+
],
30+
"privacy_policies": [
31+
"https://codeant.ai/privacy"
32+
],
33+
"icon": "icon.png",
34+
"server": {
35+
"type": "node",
36+
"entry_point": "server/index.js",
37+
"mcp_config": {
38+
"command": "node",
39+
"args": ["${__dirname}/server/index.js"],
40+
"env": {
41+
"CODEANT_API_TOKEN": "${user_config.api_token}",
42+
"CODEANT_API_URL": "${user_config.base_url}",
43+
"CODEANT_READ_ONLY": "${user_config.read_only}"
44+
}
45+
}
46+
},
47+
"compatibility": {
48+
"runtimes": {
49+
"node": ">=18.0.0"
50+
}
51+
},
52+
"tools_generated": false,
53+
"tools": [
54+
{ "name": "codeant_scans_orgs", "description": "List the CodeAnt organizations the current user is authenticated to." },
55+
{ "name": "codeant_scans_repos", "description": "List repositories connected to CodeAnt for an organization." },
56+
{ "name": "codeant_scans_history", "description": "Show recent scan runs for a single repository." },
57+
{ "name": "codeant_scans_get", "description": "Get summary metadata for a single scan (no findings)." },
58+
{ "name": "codeant_scans_results", "description": "Fetch full findings (SAST, SCA, secrets, IaC, etc.) for a scan." },
59+
{ "name": "codeant_scans_dismissed", "description": "List dismissed alerts for a repository." },
60+
{ "name": "codeant_pr_list", "description": "List pull requests / merge requests across GitHub, GitLab, Bitbucket, Azure DevOps." },
61+
{ "name": "codeant_pr_get", "description": "Fetch detailed information for a single PR/MR." },
62+
{ "name": "codeant_pr_comments", "description": "List comments on a PR/MR with optional filters." },
63+
{ "name": "codeant_comments_search", "description": "Search across CodeAnt review comments by free-text query." },
64+
{ "name": "codeant_review_local", "description": "Run a CodeAnt AI review on local working-copy changes." },
65+
{ "name": "codeant_scans_start", "description": "Trigger a new scan run (write — gated behind read_only=false)." },
66+
{ "name": "codeant_pr_resolve", "description": "Resolve a PR conversation thread (write — gated behind read_only=false)." }
67+
],
68+
"user_config": {
69+
"api_token": {
70+
"type": "string",
71+
"title": "CodeAnt API token",
72+
"description": "Find this in your CodeAnt account settings at app.codeant.ai. Required.",
73+
"required": true,
74+
"sensitive": true
75+
},
76+
"base_url": {
77+
"type": "string",
78+
"title": "API base URL",
79+
"description": "Override only if you are on a self-hosted CodeAnt instance.",
80+
"required": false,
81+
"default": "https://api.codeant.ai"
82+
},
83+
"read_only": {
84+
"type": "boolean",
85+
"title": "Read-only mode",
86+
"description": "When enabled, write tools (trigger scan, resolve PR thread) are hidden. Recommended.",
87+
"required": false,
88+
"default": true
89+
}
90+
}
91+
}

‎mcpb/server/index.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env node
2+
// MCPB bundle entry point. The build script (scripts/build-mcpb.mjs) copies
3+
// the entire `src/` tree alongside this file so the relative import below resolves.
4+
import { startMcpServer } from '../src/mcp/server.js';
5+
6+
startMcpServer().catch((err) => {
7+
// stderr is forwarded to mcp-server-codeant.log in Claude Desktop.
8+
console.error('[codeant-mcpb] fatal:', err);
9+
process.exit(1);
10+
});

0 commit comments

Comments
 (0)