Codacy MCP Server
A Model Context Protocol server for Codacy, reimagined with the Vurb.ts framework to provide structured perception for AI agents, featuring grouped tool exposition, guardrails, and prompt templates.
README
Codacy MCP Server โ Vurb.ts Edition
The official Codacy MCP Server reimagined with the Vurb.ts framework โ structured perception for AI agents.
11 Tools - 44 actions available on-demand
<img width="538" height="111" alt="image" src="https://github.com/user-attachments/assets/903fd134-6ebe-4dc2-92eb-fc70aea917e7" />
3 Prompts MCP prompts โ code-review, security-audit, repo-health
<img width="337" height="239" alt="image" src="https://github.com/user-attachments/assets/428a84c3-3a66-49c2-be71-8a0127d3d982" />
<br> <br>
[!IMPORTANT]
๐ค Zero lines of human code.
An AI agent (Antigravity, Opus 4.6) read a framework's
llms.txtand a 488-line skill file. That's all it knew about Vurb.ts. From that, it built a complete production codebase from scratch: 11 tools ยท 44 actions ยท 12 models ยท 11 presenters ยท 3 prompts ยท 105 tests No human wrote a single line.
The thesis of Vurb.ts: if an AI agent can learn a framework from its llms.txt and produce production-grade code on the first attempt โ the framework is doing its job.
[!NOTE]
๐ Designed for agents, not for humans.
Traditional frameworks optimize for human ergonomics โ tutorials, documentation, months of learning curve. Vurb.ts inverts this entirely. Its fluent API,
llms.txt, and skill system were designed so that an AI agent can become productive in a single context window. The learning curve isn't short โ it's zero. The agent reads the spec, understands the patterns, and ships. This codebase is the proof.
Why Vurb.ts?
The original Codacy MCP Server is a solid, production-grade implementation. This edition rebuilds it using the Vurb.ts MVA (Model ยท View ยท Agent) pattern โ a framework designed specifically for MCP servers that gives AI agents structured, high-fidelity perception instead of raw JSON dumps.
Key advantages of the Vurb.ts approach:
- ๐ง Structured Perception โ Presenters transform raw API data into optimized, LLM-readable formats with semantic annotations, HATEOAS navigation links, and severity-based suggestions
- ๐ก๏ธ Guardrails โ Middleware (
requireAuth), egress limits, idempotent mutation markers, and DLP redaction (secrets are stripped before reaching the wire) - ๐ Prompt Templates โ First-class support for MCP prompts (
code-review,security-audit,repo-health) with dynamic argument injection - ๐ State Sync โ Declarative cache invalidation policies ensure mutations automatically refresh dependent queries
- ๐งฉ Fluent API โ Each tool action is defined as a composable, type-safe chain โ no manual JSON schemas or handler wiring
- ๐ฆ Zero Code Generation โ No auto-generated OpenAPI client; a lightweight typed HTTP client is all that's needed
- ๐๏ธ Grouped Exposition โ 44 actions exposed as 11 namespace tools, avoiding context window explosion
Capability Matrix
| Capability | Original | Vurb.ts |
|---|---|---|
| Security & DLP | ||
| Auth middleware with self-healing errors | โ | โ |
| Secret redaction before wire (DLP) | โ | โ |
| Egress size limits per action | โ | โ |
Safe process execution (execFileSync) for analysis |
โ | โ |
| Determinism & Guardrails | ||
| Typed input schemas (Zod) | โ | โ |
| Idempotent mutation markers | โ | โ |
| Declarative cache invalidation | โ | โ |
.instructions() with common-mistake guardrails |
โ | โ |
| Tool-redirection hints (cross-agent navigation) | โ | โ |
| LLM Optimization | ||
| Grouped tool exposition (โ78% context tokens) | โ | โ |
| HATEOAS navigation links in responses | โ | โ |
| Severity-aware action suggestions | โ | โ |
| Presenter-formatted tables (vs raw JSON) | โ | โ |
| MCP Protocol | ||
tools/list |
โ | โ |
tools/call |
โ | โ |
prompts/list + prompts/get |
โ | โ |
| State sync / cache control headers | โ | โ |
| Developer Experience | ||
| Auto-discovery (zero manual imports) | โ | โ |
| Fluent builder API | โ | โ |
| Test suite (105 tests) | โ | โ |
| Hot-reload dev server | โ | โ |
Grouped Tool Exposition โ Solving Context Explosion
This is the single most important architectural difference between the two implementations.
The Problem
The original server registers 24 flat tools in the MCP tools/list response. Every one of them โ with its full name, description, and JSON Schema โ is injected into the LLM's system prompt at the start of every conversation. This means the model must process ~4,000 tokens of tool definitions before the user even types a word.
At 44 actions, a flat approach would be even worse โ ~7,000+ tokens consumed permanently just by tool schemas, leaving less room for actual conversation and reasoning.
The Solution: toolExposition: 'grouped'
Vurb.ts introduces grouped tool exposition. Instead of exposing 44 individual tools, the MCP server advertises only 11 namespace routers:
Original (flat) Vurb.ts (grouped)
โโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโ
codacy_list_organizations codacy_organizations โ 2 actions
codacy_list_organization_repos codacy_repositories โ 3 actions
codacy_list_repository_issues codacy_issues โ 7 actions
codacy_search_org_srm_items codacy_security โ 6 actions
codacy_search_repo_srm_items codacy_tools โ 6 actions
codacy_list_files codacy_files โ 4 actions
codacy_get_file_issues codacy_pull_requests โ 6 actions
codacy_get_file_coverage codacy_commits โ 3 actions
codacy_get_file_clones codacy_overview โ 2 actions
codacy_get_file_with_analysis codacy_quality โ 3 actions
codacy_list_repository_pull_reqs codacy_cli โ 2 actions
codacy_get_repository_pull_req โโโโโโโโโโโโโโโโโโโโโโ
codacy_list_pull_request_issues 11 tools in system prompt
44 actions available on-demand
codacy_get_pr_files_coverage
codacy_get_pr_git_diff
codacy_get_repository_analysis
codacy_list_tools
codacy_list_repo_tools
codacy_get_pattern
codacy_list_repo_tool_patterns
codacy_get_issue
codacy_setup_repository
codacy_cli_analyze
codacy_cli_install
โโโโโโโโโโโโโโโโโโโโโ
24 tools in system prompt
How the LLM Navigates
The model interacts with the 11 namespace tools using an action parameter. It works like a progressive disclosure pattern:
Step 1 โ Discovery. The LLM sees 11 high-level tools with concise descriptions. Each tool's schema has an action enum listing available actions:
codacy_security โ actions: [search_org, search_repo, dashboard, sbom_search, ossf_scorecard, ignore]
Step 2 โ Selection. When the user asks "show me security vulnerabilities in my repo", the LLM picks codacy_security with action: "search_repo". The remaining 43 action schemas are never loaded into context.
Step 3 โ Navigation. Presenters include HATEOAS-style links in their response, guiding the LLM to the next logical tool:
๐ Next steps: codacy_issues.list (for code quality) ยท codacy_security.dashboard (for summary)
Context Window Impact
| Metric | Original (flat) | Vurb.ts (grouped) |
|---|---|---|
Tools in tools/list |
24 | 11 |
| Actions available | 24 | 44 (+83%) |
| JSON Schema surface (tool definitions) | 29,316 chars across 718 lines | Derived from fluent chain โ no hand-written schemas |
Fewer tools in the system prompt means the LLM spends less context budget on tool schemas and more on actual reasoning โ a critical advantage for models with limited context windows.
Developer Experience โ Side by Side
The same security search tool in both implementations:
<table> <tr> <th>โ Without Vurb.ts โ 3 files, ~160 lines</th> <th>โ With Vurb.ts โ 1 file, 26 lines</th> </tr> <tr> <td>
// tools/searchSecurityItemsTool.ts (124 lines)
export const searchRepositorySecurityItemsTool = {
name: toolNames.CODACY_LIST_REPOSITORY_SRM_ITEMS,
description: `Tool to list security...
\n ${rules}
\n ${generalRepositoryMistakes}`,
inputSchema: {
type: 'object',
properties: {
...repositorySchema,
...getPaginationWithSorting('...'),
options: {
type: 'object',
properties: {
priorities: {
type: 'array',
items: { type: 'string',
enum: ['Low','Medium','High','Critical']
},
},
scanTypes: { /* ... 20 more lines */ },
categories: { /* ... 15 more lines */ },
statuses: { /* ... 8 more lines */ },
},
},
},
required: ['provider','organization','repository'],
},
};
// handlers/security.ts (35 lines)
export const handler = async (args: any) => {
const { provider, organization, repository,
cursor, limit, sort, direction, options
} = args;
return await SecurityService.searchSecurityItems(
provider, organization,
cursor, limit, sort, direction,
{ ...options, repositories: [repository] }
);
};
// index.ts โ manual tool registration
codacy_search_repository_srm_items: {
tool: Tools.searchRepositorySecurityItemsTool,
handler: Handlers.searchRepoSecurityItemsHandler,
},
</td> <td>
// codacy_security.tool.ts โ complete
export const searchRepo = security
.query('search_repo')
.describe('Search security findings within a repository.')
.instructions(`Repo-level security search.
Uses the organization-level API filtered by repo.
Scan types: SAST, SCA, Secrets, IaC, CICD.
DAST and PenTesting are org-level only.`)
.fromModel(CodacyScopeModel, 'repo')
.withOptionalEnum('priority', SEVERITY_LEVELS)
.withOptionalEnum('category', SECURITY_CATEGORIES)
.withOptionalEnum('scanType', REPO_SCAN_TYPES)
.withOptionalEnum('status', SECURITY_STATUSES)
.withOptionalNumber('cursor')
.withOptionalNumber('limit')
.egress(1 * 1024 * 1024)
.returns(SecurityPresenter)
.handle(async (input, ctx) => {
const body = { repositories: [input.repository] };
if (input.priority) body.priorities = [input.priority];
if (input.category) body.categories = [input.category];
return ctx.client.post(
`organizations/${input.provider}/${input.organization}/security/search`,
body,
{ cursor: input.cursor, limit: input.limit ?? 50 },
);
});
</td> </tr> </table>
What you don't write with Vurb.ts:
- โ No JSON Schema objects โ input types derived from fluent chain
- โ No handler wiring โ
autoDiscover()replaces manual registration - โ No OpenAPI codegen โ lightweight HTTP client replaces 3,000+ generated lines
- โ No
anytypes โ full type inference from model to presenter
๐ What Reaches the LLM โ The Security Gap
The original server sends every API field directly to the LLM provider via JSON.stringify (index.ts:172). No filtering, no size limit, no redaction.
Here is what happens to each field from a Secrets detection scan:
| API Field | โ Without Vurb.ts | โ With Vurb.ts | How |
|---|---|---|---|
title |
"Hardcoded AWS Secret Key" โ sent to LLM |
"Hardcoded AWS Secret Key" โ sent to LLM |
โ |
priority |
"Critical" โ sent to LLM |
๐ด Crit โ semantic badge |
Presenter |
apiToken |
โ ๏ธ "cda_tk_9f8e7d6c5b4a3..." โ sent to LLM |
[REDACTED] |
redactPII |
internalId |
โ ๏ธ 948271 โ sent to LLM |
Gone โ never serialized | Schema stripping |
orgId |
โ ๏ธ "org_5f8a2b1d" โ sent to LLM |
Gone โ never serialized | Schema stripping |
suggestion.patchUrl |
โ ๏ธ "/api/v3/internal/patches/..." โ sent to LLM |
Gone โ never serialized | Schema stripping |
_links |
โ ๏ธ Full internal API surface โ sent to LLM | Gone โ never serialized | Schema stripping |
| 247 findings | All 247 dumped (1,000+ lines) | Top results only | agentLimit: 100 |
| Response size | Unbounded | Max 1 MB | .egress(1 * 1024 * 1024) |
| Next action | LLM must guess | โ codacy_security.ignore |
suggestActions() |
Architecture Comparison
<table> <thead> <tr> <th></th> <th>Original (codacy-mcp-server)</th> <th>Vurb.ts Edition (codacy-vurb)</th> </tr> </thead> <tbody> <tr> <td><strong>Pattern</strong></td> <td>Imperative โ monolithic handler registry</td> <td>MVA โ Model ยท View (Presenter) ยท Agent</td> </tr> <tr> <td><strong>Tool Definition</strong></td> <td>Manual JSON Schema objects per tool</td> <td>Fluent builder API (<code>.withString()</code>, <code>.withOptionalEnum()</code>)</td> </tr> <tr> <td><strong>Tool Registration</strong></td> <td>190-line <code>index.ts</code> mapping tools โ handlers</td> <td><code>autoDiscover()</code> โ zero manual imports</td> </tr> <tr> <td><strong>Tool Exposition</strong></td> <td>Flat โ 24 individual tools in <code>tools/list</code></td> <td>Grouped โ 11 namespace routers, 44 actions via <code>action</code> param (54% fewer tools in system prompt)</td> </tr> <tr> <td><strong>API Client</strong></td> <td>Auto-generated OpenAPI client (~3,000+ lines)</td> <td>Lightweight typed HTTP client (123 lines)</td> </tr> <tr> <td><strong>Response Format</strong></td> <td>Raw <code>JSON.stringify(result)</code></td> <td>Presenters with semantic tables, HATEOAS links, severity badges, and action suggestions</td> </tr> <tr> <td><strong>Auth Handling</strong></td> <td><code>noAuth</code> boolean flag + inline <code>if</code> check</td> <td><code>requireAuth</code> middleware with self-healing error messages</td> </tr> <tr> <td><strong>Security</strong></td> <td>No DLP or output sanitization</td> <td>DLP-ready: <code>SecurityPresenter</code> redacts secrets before wire</td> </tr> <tr> <td><strong>Prompts</strong></td> <td>Not supported</td> <td>3 MCP prompts โ <code>code-review</code>, <code>security-audit</code>, <code>repo-health</code></td> </tr> <tr> <td><strong>Cache / State Sync</strong></td> <td>Not supported</td> <td>Declarative invalidation policies (mutations auto-refresh queries)</td> </tr> <tr> <td><strong>Egress Control</strong></td> <td>Not supported</td> <td>Per-action egress limits (e.g., 1 MB for issue lists, 2 MB for patches)</td> </tr> <tr> <td><strong>LLM Instructions</strong></td> <td>Embedded in tool <code>description</code> field</td> <td>Separate <code>.instructions()</code> with common mistakes, redirection rules, and guardrails</td> </tr> <tr> <td><strong>Mutation Safety</strong></td> <td>No markers</td> <td><code>.idempotent()</code> marker + <code>.invalidates()</code> cache busting</td> </tr> <tr> <td><strong>Tests</strong></td> <td>No test suite</td> <td>105 tests (prompts, presenters, structural invariants)</td> </tr> <tr> <td><strong>Dependencies</strong></td> <td>11 (including codegen, node-fetch, ESLint, Prettier, Husky)</td> <td>4 (<code>@vurb/core</code>, <code>@modelcontextprotocol/sdk</code>, <code>fast-redact</code>, <code>zod</code>)</td> </tr> </tbody> </table>
Metrics (verified)
Every number below was measured directly from the source code.
| Metric | Original | Vurb.ts | Diff |
|---|---|---|---|
| Source files (hand-written) | 45 | 42 | โ3 |
Tool definitions (src/tools/) |
718 lines | โ | โ |
Handlers (src/handlers/) |
424 lines | โ | โ |
Agents (src/agents/ โ tool + handler in one file) |
โ | 763 lines | โ33% vs tools+handlers |
Tools in tools/list response |
24 | 11 | โ54% |
| Actions available to the LLM | 24 | 44 | +83% |
| MCP Prompts | 0 | 3 | +3 |
| Test cases | 0 | 105 | +105 |
| Runtime dependencies | 6 | 4 | โ33% |
| Dev dependencies | 9 | 3 | โ67% |
Tool Actions (44)
codacy_organizations (2)
| Action | Description |
|---|---|
list |
List organizations the authenticated user belongs to |
list_repos |
List repositories in an organization |
codacy_repositories (3)
| Action | Description |
|---|---|
get |
Get repository details with analysis metrics |
list_branches |
List branches of a repository |
setup |
Add or follow a repository (multi-step orchestration) |
codacy_issues (7)
| Action | Description |
|---|---|
list |
Search and filter code quality issues |
get |
Get detailed issue information |
file_issues |
Get issues for a specific file |
pr_issues |
Get issues in a pull request |
quickfix_patch |
Download auto-fix patches |
ignore |
Mark an issue as ignored |
bulk_ignore |
Batch ignore multiple issues |
codacy_security (6)
| Action | Description |
|---|---|
search_org |
Search org-level security findings |
search_repo |
Search repo-specific security findings |
dashboard |
Get security dashboard summary |
sbom_search |
Search SBOM dependencies |
ossf_scorecard |
Get OSSF Scorecard for a package/repo |
ignore |
Ignore a security finding |
codacy_tools (6)
| Action | Description |
|---|---|
list |
List all analysis tools available |
repo_tools |
List tools configured for a repository |
get_pattern |
Get a specific code pattern definition |
repo_patterns |
List patterns for a tool in a repository |
configure |
Enable/disable a tool for a repository |
update_patterns |
Enable/disable specific patterns |
codacy_files (4)
| Action | Description |
|---|---|
list |
List files with analysis metrics |
get |
Get file details with metrics |
coverage |
Get line-by-line coverage |
clones |
Get code duplication blocks |
codacy_pull_requests (6)
| Action | Description |
|---|---|
list |
List PRs with analysis status |
get |
Get PR details with quality results |
coverage |
Get file-level PR coverage |
diff |
Get the Git diff |
trigger_ai_review |
Trigger AI-powered code review |
bypass |
Bypass the quality gate |
codacy_commits (3)
| Action | Description |
|---|---|
list |
List commits with analysis status |
get |
Get commit details with delta statistics |
issues |
Get issues introduced by a commit |
codacy_overview (2)
| Action | Description |
|---|---|
issues |
Aggregated issue overview with charts |
categories |
Issue count breakdown by category |
codacy_quality (3)
| Action | Description |
|---|---|
get_settings |
Get quality gate thresholds for a repository |
list_policies |
List gate policies for an organization |
get_policy |
Get details of a specific gate policy |
codacy_cli (2)
| Action | Description |
|---|---|
analyze |
Run local analysis via CLI |
install |
Install the CLI |
Setup
Requirements
- Node.js โฅ 18
- A Codacy Account API Token
Configuration
Add to your MCP client configuration (Cursor, VS Code, Claude Desktop, etc.):
{
"mcpServers": {
"codacy": {
"command": "node",
"args": ["dist/server.js"],
"env": {
"CODACY_ACCOUNT_TOKEN": "<YOUR_TOKEN>"
}
}
}
}
Development
npm install
npm run build # Compile TypeScript
npm run dev # Vurb dev server (hot-reload)
npm test # Run 105 tests
npm run inspect # MCP Inspector
Project Structure
src/
โโโ agents/ # Tool definitions (Fluent API)
โ โโโ codacy_organizations.tool.ts
โ โโโ codacy_repositories.tool.ts
โ โโโ codacy_issues.tool.ts
โ โโโ codacy_security.tool.ts
โ โโโ codacy_tools.tool.ts
โ โโโ codacy_files.tool.ts
โ โโโ codacy_pull_requests.tool.ts
โ โโโ codacy_commits.tool.ts
โ โโโ codacy_overview.tool.ts
โ โโโ codacy_quality.tool.ts
โ โโโ codacy_cli.tool.ts
โโโ models/ # Zod schemas (data contracts)
โโโ views/ # Presenters (LLM-optimized output)
โโโ middleware/ # Auth, validation
โโโ prompts/ # MCP prompt templates
โโโ utils/ # Constants, rules, types
โโโ context.ts # API client + context factory
โโโ index.ts # Registry
โโโ server.ts # Entry point
Usage (MCP stdio)
This server runs as a stdio MCP transport โ the AI client launches it as a subprocess and communicates via stdin/stdout.
Cursor / Windsurf / Claude Desktop
Add to your MCP configuration file:
- Cursor:
.cursor/mcp.json - Windsurf:
.codeium/windsurf/mcp_config.json - Claude Desktop:
claude_desktop_config.json
{
"mcpServers": {
"codacy": {
"command": "node",
"args": ["/absolute/path/to/codacy-vurb/dist/server.js"],
"env": {
"CODACY_ACCOUNT_TOKEN": "<YOUR_TOKEN>"
}
}
}
}
VS Code (Copilot)
Add to your settings.json (Ctrl+Shift+P โ Preferences: Open User Settings (JSON)):
{
"mcp": {
"servers": {
"codacy": {
"command": "node",
"args": ["/absolute/path/to/codacy-vurb/dist/server.js"],
"env": {
"CODACY_ACCOUNT_TOKEN": "<YOUR_TOKEN>"
}
}
}
}
}
Get your token
- Go to Codacy Account โ Access Management
- Generate an Account API Token
- Paste it in the
CODACY_ACCOUNT_TOKENfield above
Build & run
npm install
npm run build
# The server starts automatically when the MCP client launches it via stdio
License
Apache 2.0 โ see LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
E2B
Using MCP to run code via e2b.