arko-mcp
v0.3.2
Published
ARKO Model Context Protocol server — brings the ARKO security control engine into Claude Code, Cursor, and any MCP-compatible AI coding agent.
Maintainers
Readme
arko-mcp
ARKO's security control engine as a Model Context Protocol (MCP) server — so Claude Code, Cursor, and any MCP-compatible AI coding agent can scan code, validate fixes, and remediate findings directly in their loop.
It is a thin client over the live ARKO API (https://arko.devsecai.io). No scanning logic lives here: every tool call is an authenticated request to the existing plugin / control-plane API, so the 5-layer decision engine, tenant isolation, and the audit trail are all inherited unchanged.
Enterprise model in one line
A developer signs in once with their work email. The backend resolves their enterprise tenant from the email domain (e.g. @acme-corp.com → the Acme Corp tenant), so every scan that developer's agent runs is tagged to that tenant and shows up in the organisation's Control Plane — same findings, same audit trail as the IDE plugin. Non-enterprise domains fall back to the free tier. Same binary, no per-user config.
write code → arko_scan_code → fix the finding → arko_validate_fix → done
↓ every call authenticated as the real user
results land in that enterprise's Control Plane (app.arko.devsecai.io)Authentication — automatic on first use
One-time login. Run npx -y arko-mcp login once — your browser opens to sign in (Authorization Code + PKCE — no secret stored). The refresh token is cached in ~/.arko/credentials.json (0600) and silently refreshed, so it never asks again. Until you log in, tools fail fast with the exact command to run.
Sign in with your work email → the backend resolves your enterprise tenant from the domain → results appear in that organisation's Control Plane. The agent is the only UI; findings show up in the existing Control Plane.
Optional commands — run them through npx (there is no globally-installed arko-mcp binary; the package only runs via your agent or npx):
npx -y arko-mcp login --email [email protected] # sign in ahead of time (skips the first-use prompt)
npx -y arko-mcp whoami # identity, tier, enterprise tenant
npx -y arko-mcp logout # clear cached credentials
npx -y arko-mcp init [--with-gate] # set up the current repo (see below)
npx -y arko-mcp gate --changed # scan changed files; exit 2 when the gate failsSet up a repository — one command
npx -y arko-mcp init --with-gateIdempotent; run it once per repo. It does three things:
- Registers the MCP server in
.mcp.json(project-scoped — every developer's agent in this repo gets the Arko tools automatically). - Adds the security-loop instructions to every standard agent file so any tool picks them up:
CLAUDE.md(Claude Code) andAGENTS.md(the cross-tool open standard — Cursor, Codex, Jules…) are always written, plus a Cursor rule (.cursor/rules/arko.mdc) when the repo already uses Cursor. All between<!-- arko:start/end -->markers so re-runs never duplicate. This is what makes agents scan reliably, not just when the model remembers. --with-gateinstalls a Claude Code Stop hook (.claude/settings.json) that runsarko-mcp gate --changedbefore the agent may finish a turn. Deterministic enforcement: the gate scans the changed files and, on findings at or above the threshold, exits 2 — the findings are fed back to the agent, which fixes them and tries again.--dry-runpreviews all writes.
The gate
arko-mcp gate --changed scans the working tree's modified + untracked code files (capped and logged) through the live Arko API and exits 0 (pass) or 2 (fail, findings on stderr). Threshold via ARKO_GATE=critical|high|medium|off (default critical) or --min-severity. It is fail-open by default — offline, signed-out, or a still-running scan never blocks a developer; pass --strict in CI to fail closed. Fixes are applied by the developer's own agent in the working tree — Arko never opens a pull request or changes code unless asked.
The --email is optional — npx -y arko-mcp login on its own opens the browser and you sign in there; the tenant is resolved from your email domain either way.
Headless / CI: set ARKO_TOKEN=<jwt> to skip the browser entirely.
One-time activation by DevSecAI: register the loopback redirect
http://localhost:8765/callbackon the Cognito app client — contact DevSecAI to enable your organisation.
Tools
| Tool | Endpoint | Use |
|------|----------|-----|
| arko_scan_code | POST /analyze | Scan code you just wrote/changed (SAST, 5-layer engine). |
| arko_validate_fix | POST /vulnerabilities/check-remediation | Confirm a fix actually closed the finding. |
| arko_fix_all | POST /analyze → plan | Scan + a prioritised plan to remediate every finding; "make this secure" in one call, then validate. |
| arko_scan_project | POST /scan/build (+ poll) | Dependency / SCA scan of package manifests (CVEs). |
| arko_raise_fix_pr | POST /org/findings/{id}/create-pr | Open an Arko AutoFix pull request for a finding on a GitHub-connected repository; returns the PR link. |
Scan and fix tools operate only on code the caller provides; they don't read the organisation's dashboard. The control-plane read tools (org findings / score / policy in the IDE) are temporarily withdrawn pending an admin-granted access gate.
Wiring your agent
Full guide: AGENT-GUIDELINES.md (ships in the npm package). The short version:
1. Give the agent a standing instruction (e.g. CLAUDE.md in the project root, or a Kiro steering file):
After material code changes run arko_scan_code. If the output begins GATE: FAIL, fix using arko_fix_all, apply the fixes, then arko_validate_fix — do not conclude while the gate fails.
2. The gate line. arko_scan_code and arko_fix_all lead their output with a machine-readable gate line — GATE: FAIL — 3 critical, 2 high (threshold: high) or GATE: PASS — so an agent can key off line 1. Configure the threshold with ARKO_GATE:
| ARKO_GATE | Behaviour |
|-------------|-----------|
| critical (default) | Fails only on critical findings. |
| high | Fails on high or critical findings. |
| medium | Fails on medium, high, or critical findings. |
| off | No gate line is emitted. |
3. The loop: scan (arko_scan_code) → fix (arko_fix_all, apply the plan) → validate (arko_validate_fix, repeat until nothing is still open) → on a GitHub-connected repository, arko_raise_fix_pr with a finding id opens an AutoFix pull request for review and returns the PR link.
4. Register the server. Claude Code — .mcp.json in the project root:
{
"mcpServers": {
"arko": {
"command": "npx",
"args": ["-y", "arko-mcp"],
"env": { "ARKO_GATE": "high" }
}
}
}Kiro — .kiro/settings/mcp.json:
{
"mcpServers": {
"arko": {
"command": "npx",
"args": ["-y", "arko-mcp"],
"env": { "ARKO_GATE": "high" },
"disabled": false,
"autoApprove": ["arko_scan_code", "arko_validate_fix"]
}
}
}Install & build (local, pre-publish)
cd packages/mcp
npm install
npm run build # tsc → dist/
npm run smoke # MCP handshake + assert all scan/fix tools register
npm run authtest # PKCE / authorize-URL / loopback / credential checks (no live Cognito)Install in Claude Code — one line
claude mcp add arko -- npx -y arko-mcpThat's the whole install. Run npx -y arko-mcp login once to sign in; every scan after that is automatic.
Local build (pre-publish):
claude mcp add arko -- node /ABS/PATH/packages/mcp/dist/index.js
Team distribution — commit a project-scope .mcp.json (a project-scope .mcp.json with the npx -y arko-mcp command below); every developer who opens the repo in Claude Code inherits Arko; each developer runs arko-mcp login once with their work email — their findings route to the org's Control Plane:
{
"mcpServers": {
"arko": {
"command": "npx",
"args": ["-y", "arko-mcp"],
"env": { "ARKO_API_BASE_URL": "https://arko.devsecai.io" }
}
}
}No token in the config — auth is the per-developer arko-mcp login.
Other clients (same binary)
- Cursor —
.cursor/mcp.json, samemcpServersshape. - VS Code (Copilot agent mode) —
.vscode/mcp.json, top-level keyservers.
Configuration
| Env var | Default | Purpose |
|---------|---------|---------|
| ARKO_API_BASE_URL | https://arko.devsecai.io | API origin. |
| ARKO_TOKEN | (unset) | Static bearer JWT — overrides interactive login (CI/headless). |
| ARKO_OAUTH_CLIENT_ID | central pool SPA client | Cognito app client used for login. |
| ARKO_COGNITO_DOMAIN | central pool Hosted UI | Cognito Hosted UI origin. |
| ARKO_OAUTH_PORT | 8765 | Loopback callback port (must be registered on the client). |
| ARKO_CREDENTIALS_PATH | ~/.arko/credentials.json | Where the refresh token is cached. |
| ARKO_TIMEOUT_MS | 120000 | Per-request timeout. |
| ARKO_SCAN_WAIT_MS | 240000 | Max wait for a large async scan. |
| ARKO_GATE | critical | Gate threshold for the GATE: line (critical / high / medium / off). |
Roadmap
- Phase 1 — local stdio (default): browser-OAuth login (
arko-mcp login), tenant routed by email domain. Works in Claude Code, Cursor, VS Code agent today. - Phase 2 — remote Streamable HTTP (
arko-mcp serve-http): Claude Code runs the OAuth itself (MCP-native auth, RFC 9728 discovery → Cognito); no local login. Server code + auth gate + discovery are built and tested (npm run httpsmoke); deploy + JWKS hardening are gated.
# Phase 2, once deployed behind TLS:
claude mcp add --transport http arko https://mcp.arko.devsecai.io/mcpLayout
packages/mcp/
├── src/
│ ├── index.ts # entry: dispatch CLI vs MCP server
│ ├── cli.ts # login / logout / whoami
│ ├── config.ts # env + OAuth/Cognito config
│ ├── client.ts # thin ARKO API HTTP client (token-provider backed)
│ ├── tools.ts # the five MCP tool registrations
│ ├── version.ts
│ └── auth/
│ ├── pkce.ts # PKCE S256
│ ├── cognito.ts # Hosted UI authorize + token + refresh
│ ├── loopback.ts # one-shot localhost callback listener
│ ├── credentials.ts # ~/.arko store (0600)
│ ├── tokenProvider.ts # cached access token → silent refresh
│ └── login.ts # interactive flow + identity/tenant lookup
├── scripts/ smoke-test.mjs · auth-test.mjs
├── examples/ .mcp.json · vscode.mcp.json · .env.example
├── AGENT-GUIDELINES.md # wiring an agent: gate line, ARKO_GATE, the fix loop
├── ENTERPRISE-SETUP.md
└── README.md