Atlas / MCP servers / talvinder / Carrot AI PM

Carrot AI PMBLOCK

mcp/talvinder/carrot-ai-pm

Carrot auto-writes specs and catches AI code drift. MCP server for Cursor that AST-validates every commit.

Verdict
BLOCK
Grade
D
Trust score
62 /100
Exposed tools
53 43r · 8w · 2d
Transport
stdio · streamable-http
License
MIT
Stars
29
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://opensource.org/licenses/MIT) [](CONTRIBUTING.md) [](https://modelcontextprotocol.io)

Carrot generates specs, validates output, and keeps AI assistants aligned. ----

Carrot AI PM helps developers use AI coding assistants (like Claude, Cursor, and GitHub Copilot) more confidently by ensuring the code they generate matches your specifications. Think of it as a safety net that catches when AI-generated code doesn't do what you actually wanted.

Why "Carrot"?

Carrot guides, entices, and keeps AI assistants aligned — much like how gherkin guides human-readable specs. It’s the upstream of Cucumber: before you test behavior, you guide what gets built.

Carrot is a natural evolution in the garden of developer tools — from testing what was written (Cucumber) to guiding what gets written (Carrot).

🤔 The Problem

When using AI to write code, you might ask:

  • "Create a user login API"
  • "Build a product card component"
  • "Set up a database for my e-commerce site"

But how do you know if the AI understood correctly? How can you be sure the generated code:

  • Has proper error handling?
  • Includes all the features you need?
  • Follows security best practices?
  • Works with your existing code?

💡 How Carrot AI PM Helps

Carrot AI PM acts as your AI coding assistant's "project manager". It:

  1. Creates clear specifications before coding starts
  2. Checks if the code matches what was specified
  3. Suggests specific fixes when something's wrong
  4. Gives you confidence that AI-generated code is correct

🎯 Real-World Example

Instead of just asking your AI to "create a user API", you can:

  1. You say: "Create a specification for a user management A
Read from source at commit 88fee54646deOBSERVED · 2026-10-08
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add carrot-ai-pm --env GITHUB_TOKEN=${GITHUB_TOKEN} -- npx -y [email protected]
claude-desktop
{
  "mcpServers": {
    "carrot-ai-pm": {
      "command": "npx",
      "args": [
        "-y",
        "[email protected]"
      ],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}
03

Exposed tools (53)

43 read · 8 write · 2 destructive. Blast radius: 2 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.

ToolRiskDescription
README.mdreadRepository documentation
activereadPressed/clicked state
add_routewrite
check_spec_complianceread
cleanreadClean build artifacts
commit_changeswrite
defaultreadNormal interactive state
delete_playlist_successdestructiveSuccessfully delete user\
delete_playlist_unauthorizeddestructiveAttempt to delete another user\
disabledreadNon-interactive disabled state
documentationreadComprehensive documentation for Carrot features and APIs
enforce_foreign_keysreadAll foreign key constraints must be enforced
errorreadInput has validation error
focusreadKeyboard focus state
format_coderead
general_errorreadGeneral error occurred
get_playlist_not_foundreadAttempt to get non-existent playlist
get_playlist_unauthorizedreadAttempt to access another user\
get_user_playlist_successreadSuccessfully retrieve user\
grow_cli_specread
grow_db_specread
grow_specread
grow_ui_specread
hoverreadMouse hover state
inputreadInput file or directory
interruptedreadCommand was interrupted by user
invalid_requestreadTest invalid request handling
jsonreadMachine-readable JSON output
loadingreadProcessing/loading state
multi-task-specsreadSupport for defining complex tasks with multiple subtasks and dependencies
onBlurreadFired when button loses focus
onChangereadFired when input value changes
onClickreadFired when button is clicked
onFocusreadFired when button receives focus
productionwriteDeploy to production environment
refine-spec-toolreadTool for iteratively refining and updating task specifications
run_testswrite
search_coderead
setup_carrotread
sourcereadSource directory to build
stagingwriteDeploy to staging environment
successreadCommand completed successfully
successful_requestreadTest successful request handling
task-metadatareadExtended metadata for task tracking, visualization, and management
textreadHuman-readable text output
update_playlist_invalid_datawriteAttempt to update with invalid data
update_playlist_partialwriteSuccessfully update only playlist name
update_playlist_successwriteSuccessfully update playlist name and description
usage_errorreadInvalid command line usage
user-notificationsreadSystem for notifying users about task status changes and events
vibe.yamlreadOpenAPI specification for the API
watchreadWatch for changes and rebuild
yamlreadYAML formatted output
04

Trust audit

BLOCKgrade D · trust 62/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfaceWARN
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
UNDECLARED (2 observation(s))
Network
declared (2 observation(s))
Shell
declared (4 observation(s))
Dependencies
not all pinned
Secrets in source
none-found

Findings (12)

HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
src/tools/add_route.ts:421
spec = yaml.load(fs.readFileSync(vibeYamlPath, 'utf8')) as any;
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
src/tools/check_spec_compliance.ts:366
return yaml.load(content);
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
src/tools/check_spec_compliance.ts:372
return yaml.load(content);
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
HIGHCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
src/tools/check_spec_compliance_universal.ts:746
return yaml.load(content);
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
MEDIUMFilesystem / path · mcp.destructive_tools · CWE-22, CWE-59
delete_playlist_success, delete_playlist_unauthorized
Why it matters. 2 tool(s) can delete or overwrite
Fix. prefer a read-only mode or scoped tokens; the page states the blast radius
LOWCode injection · code.deserialize · CWE-78, CWE-94, CWE-95
src/tools/grow_spec.ts:69
existingYaml = yaml.load(fs.readFileSync(vibeYamlPath, 'utf8')) as any;
Why it matters. deserialises untrusted bytes into live objects
Fix. use json or yaml.safe_load
LOWFilesystem / path · fs.system_paths · CWE-22, CWE-59
src/tools/grow_cli_spec.ts:333
locations: ['~/.config/app', './config', '/etc/app'],
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
src/tools/compliance/storage.ts:558
const packageJsonPath = path.join(__dirname, '../../../package.json');
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/development/simpleStreamableHttp.js:1
import { Client } from '../../client/index.js';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/development/simpleStreamableHttp.js:2
import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js';
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/development/simpleStreamableHttp.js:4
import { ListToolsResultSchema, CallToolResultSchema, ListPromptsResultSchema, GetPromptResultSchema, ListResourcesResultSchema, LoggingMessageNotificationSchema, ResourceListChangedNotificationSchema
LOWSupply chain · supply.unpinned · CWE-829, CWE-1357
package.json
@modelcontextprotocol/sdk, @types/express, @types/js-yaml, @types/node, @types/node-fetch, child_process, express, fs
Why it matters. 17 dependency range(s) float
Fix. pin exact versions or ship a lockfile

Gates applied: no_behavioural_pass.

Audited 2026-10-08 · audit v0.4.1 · source sha 88fee54646defull audit observations/trust-audit/mcp-server/talvinder__carrot-ai-pm.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-0888fee54646deBLOCKD62first audit
06

Questions

What is the Carrot AI PM MCP server?

Carrot auto-writes specs and catches AI code drift. MCP server for Cursor that AST-validates every commit.

What tools does Carrot AI PM expose?

53 in total: 43 read-only, 8 that write, and 2 that can delete or overwrite (delete_playlist_success, delete_playlist_unauthorized). Every one is listed on this page with its risk.

Is Carrot AI PM safe to connect to an agent?

No — not without reading the findings first. The audit graded it D (62/100) and found 4 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 2 of its tools can destroy data, so scope the token you give it to what you actually need.

What credentials does Carrot AI PM need?

It reads GITHUB_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does Carrot AI PM run?

It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as carrot-ai-pm at 1.0.0.

How current is this page?

The grade is for one exact copy of the source (88fee54646de), read on 2026-10-08. The repository is watched and re-audited when it changes.

Advertisement