promptdiet
v0.3.0
Published
Token-optimizing MCP server for Cursor. Give your AI IDE access to specialized code agents backed by AST skeletonization and Eco-Telemetry.
Maintainers
Readme
PromptDiet
Token-optimizing MCP server for Cursor. Give your AI IDE access to specialized code agents that review, refactor, generate, and test your code — without burning tokens on routing decisions or shipping full file contents to the API.
No API keys or external LLM calls — PromptDiet builds token-efficient skeleton + git context locally; use that output with Cursor or any model you choose.
The Problem
Every time you paste code into ChatGPT or Claude to refactor, review, or explain it, you pay twice:
- Routing cost — The model spends tokens figuring out what kind of task this is
- Context cost — Your entire file(s) get sent, including comments, whitespace, and boilerplate the model doesn't need
A single 500-line TypeScript file can burn 15,000–50,000 tokens per turn. Repeated across a sprint, that's real money and real latency.
The Solution
PromptDiet is an MCP server that:
- Zero-token routing — Cursor's AI parses your intent and calls the correct tool directly. No LLM is consulted for routing.
- AST skeletonization — Only class/function signatures, imports, and docstrings are sent (~85% token reduction)
- SQLite Agile board — Persistent Kanban state in
.promptdiet/state.db(sql.js, pure WebAssembly) - Depth-1 dependency traversal — Local imports are skeletonized to prevent LLM hallucinations about your data models
- Eco-Telemetry — Every call returns a token audit: naive vs. optimized count, cost savings, and water offset
Architecture
The Model Context Protocol (MCP) fundamentally changes how PromptDiet works. Instead of a CLI that parses commands, PromptDiet is a server that Cursor's AI talks to directly.
┌─────────────────────────────────────────────┐
│ CURSOR IDE │
│ │
│ @promptdiet refactor src/auth/middleware.ts │
└────────────────┬────────────────────────────┘
│
│ JSON-RPC (stdio)
▼
┌─────────────────────────────────────────────┐
│ PROMPTDIET MCP SERVER │
│ │
│ • Cursor sends natural language request │
│ • PromptDiet skeletonizes the code │
│ • PromptDiet assembles skeleton + git context │
│ • PromptDiet returns markdown handoff + eco-telemetry │
└────────────────┬────────────────────────────┘
│
│ JSON-RPC Response
▼
┌─────────────────────────────────────────────┐
│ CURSOR IDE (Native Rendering) │
│ │
│ • Use handoff in chat (no server apply) │
│ • Markdown explanation in chat │
│ • Eco-Telemetry table in chat │
└─────────────────────────────────────────────┘Installation
npm install -g promptdietRequirements: Node.js ≥ 18
Cursor Setup
- Open Cursor Settings → MCP
- Add a new MCP server:
{ "mcpServers": { "promptdiet": { "command": "npx", "args": ["-y", "promptdiet"] } } }
Usage
In Cursor Chat
Recommended: use flow for one freeform request; PromptDiet infers agent and operation (rule-based), assembles a markdown handoff (agent persona, repo rules, skeleton, git, telemetry), and optionally your job-board ticket. apply is ignored — PromptDiet never writes patches; you implement changes in Cursor.
@promptdiet flow --request "Refactor this for security" --target_path src/auth/middleware.ts@promptdiet flow --request "Audit this" --ticket_id <uuid> --target_path src/auth/middleware.ts@promptdiet run_agent --agent code-reviewer --target src/auth/middleware.ts --operation review@promptdiet get_board_state@promptdiet list_agents@promptdiet init_board@promptdiet create_ticket --type epic --title "My Epic" --description "Description" --tags auth,security@promptdiet update_ticket --ticket_id <id> --type story --state IN_PROGRESS@promptdiet delete_ticket --ticket_id <id> --type epicMCP Tools
flow
Recommended Cursor entrypoint: one freeform request, optional target_path, optional ticket_id, optional apply (legacy, ignored).
- Target path: use
target_path, or include a path inrequest(e.g.src/foo.ts). If no path exists yet, greenfield mode still returns a handoff with a placeholder skeleton. - Ticket: if
ticket_idis set, loads epic/story from.promptdiet/state.db; tags drive agent selection; title, description, and acceptance criteria are appended to instructions (truncated to ~2500 characters). - Routing: keyword/tag heuristics pick
agent_idandoperation— no routing LLM. - Ambiguity: if multiple agents tie, the tool returns a fenced question signal (JSON:
status,reason,options,instruction). Use Cursor’s question UI to clarify, then callflowagain. - Apply: always ignored; no filesystem writes from PromptDiet.
{
"request": "Refactor this module for clarity and add edge-case tests",
"target_path": "src/auth/middleware.ts",
"ticket_id": "optional-uuid",
"apply": false
}run_agent
Lower-level tool: explicit operation and path. Agent is auto-selected based on ticket_id tags if not specified.
Returns a markdown handoff (full systemPrompt, repo rules, skeleton, optional extra context from context_paths, git) plus eco-telemetry. apply is ignored. Use include_dependencies: true for depth-1 import skeletons on the primary file.
{
"agent_id": "code-reviewer",
"ticket_id": "optional-ticket-id",
"target_path": "src/auth/middleware.ts",
"operation": "review",
"instructions": "Focus on security vulnerabilities",
"greenfield": false,
"context_paths": ["src/types/auth.ts"],
"include_dependencies": false,
"apply": false
}Typical response shape:
explanation— Full handoff markdown for Cursor’s modeleco_telemetry— Token savings report (embedded in the markdown table)
init_board
Initialize a new PromptDiet Agile board in the current directory.
{
"force": false
}create_ticket
Create a new Epic or Story in the PromptDiet Agile board.
{
"type": "epic",
"title": "JWT Authentication",
"description": "Implement JWT-based authentication",
"tags": ["auth", "security"],
"effort_points": 5
}update_ticket
Update an existing Epic or Story.
{
"ticket_id": "<uuid>",
"type": "story",
"state": "IN_PROGRESS",
"tags": ["auth", "review"]
}delete_ticket
Delete an Epic or Story.
{
"ticket_id": "<uuid>",
"type": "epic"
}get_board_state
Read the current Agile board state.
{
"epic_id": "optional-filter-id",
"view": "kanban"
}Views: kanban (default), list, sprint
goal_orchestrate
Rule-based goal breakdown (keyword templates, no external LLM). Returns ordered epic/story plan as markdown. Set persist: true to create tickets in .promptdiet/state.db (requires init_board first).
{
"goal": "Ship a small calculator web app with tests",
"persist": false
}list_agents
List all available agents.
{}Core Concepts
Zero-Token Routing
Cursor's AI parses your intent. For most tasks, call the flow tool with a natural-language request; PromptDiet infers agent_id and operation locally. For explicit control, use run_agent with fixed arguments. No LLM is consulted for routing — zero tokens burned.
Tag-Based Agent Routing
When using ticket_id without agent_id, PromptDiet automatically selects the best agent based on ticket tags:
| Ticket Tags | Auto-Selected Agent |
|-------------|---------------------|
| auth, security, review, audit | code-reviewer |
| refactor, restructure, optimize | refactorer |
| tests, coverage, quality | test-writer |
| security, audit, compliance | security-scanner |
| perf, optimize, performance | perf-optimizer |
AST Skeletonization
Instead of sending full file contents:
// FULL FILE (what you'd paste into ChatGPT)
async function authenticateUser(req, res) {
// 50 lines of implementation, comments, etc.
// ...
}
// SKELETON (what PromptDiet sends)
async function authenticateUser(
req: Request,
res: Response
): Promise<AuthResult> { /* ... */ }Only signatures, parameter types, return types, decorators, and docstrings are extracted. Function bodies are excluded.
Depth-1 Dependency Traversal
For TypeScript/JavaScript files, PromptDiet also traverses local relative imports one hop deep:
src/auth/middleware.ts
└── imports ./models/User → parses src/models/User.ts
extracts: interface User { id, email, role }
blocks: node_modules, react, expressConventional Commit Git Context
Only meaningful commits are injected:
// Kept: feat:, fix:, refactor:, perf:
// Dropped: chore:, style:, docs:, ci:
gitContext = {
recentRelevantTags: ["feat: add JWT middleware", "refactor: extract auth util"],
modifiedFiles: [{ status: "M", path: "src/auth/middleware.ts" }]
}Eco-Telemetry
Every successful call returns a token audit rendered by Cursor in the chat:
═══════════════════════════════════════════
PromptDiet Eco-Telemetry
═══════════════════════════════════════════
Naive token estimate 31,204 tokens
Optimized token count 4,812 tokens
Tokens saved 26,392 tokens (84.6%)
Estimated cost saved $0.0023 (ref. $0.10/1K)
Water offset 0.087 mL (WUE: 0.0033 mL/token)
═══════════════════════════════════════════
*WUE heuristic based on Li et al. (2023) average datacenter metrics.
═══════════════════════════════════════════WUE Citation: Water offset is computed using the baseline from Li et al. (2023), "Making AI Less Thirsty: Characterizing and Estimating Data Center Water Usage for Large Language Models". The 0.0033 mL/token heuristic reflects average datacenter Water Usage Effectiveness (WUE) across Google's fleet.
Agent Catalog
Five agents ship by default:
| ID | Name | Tags | Operations |
|----|------|------|------------|
| code-reviewer | Code Reviewer | auth, security, review, audit | review, audit |
| refactorer | Refactorer | refactor, restructure, optimize | refactor, optimize |
| test-writer | Test Writer | tests, coverage, quality | write-tests |
| security-scanner | Security Scanner | security, audit, compliance | audit, security-scan |
| perf-optimizer | Performance Optimizer | perf, optimize, performance | optimize, profile |
Each agent is defined in agents.yaml with a systemPrompt, supportedOperations, and tags[].
Configuration
.promptdiet/ directory structure:
.promptdiet/
├── state.db # SQLite database (sql.js WebAssembly)
├── agents.yaml # Agent definitions (systemPrompt, tags, operations)
├── instructions.md # Optional — merged into handoffs (see repo rules)
└── .gitignore # (created by init)Repo rules (handoff): first file found among .promptdiet/instructions.md, PROMPTDIET_RULES.md (repo root), .cursorrules.
Environment variables:
PROMPTDIET_NO_ECHO=1 # Suppress eco-telemetry
PROMPTDIET_GIT_LOG_N=20 # Commits scanned for relevant messages (1–100, default 20)
PROMPTDIET_COMMIT_TAGS=feat:,fix: # Comma-separated lowercase prefixes to treat as “relevant” commitsDevelopment
See DEV_TESTING.md for detailed testing instructions.
Quick Test
npm run build # Compile TypeScript
npm run start:dev # Run dev mode testBuild
npm run build # Compile TypeScript
npm start # Run the MCP serverArchitecture (Internal)
MCP Server (src/server.ts)
│
├── MCP Handlers (src/mcp/handlers.ts)
│ ├── flow() ──▶ rule routing + run_agent handoff
│ ├── run_agent() ──▶ buildHandoffPrompt() (src/gemini/client.ts) — markdown only, no HTTP
│ │ ├── loadRepoRules() (src/promptdiet/repo-rules.ts)
│ │ ├── skeletonizeFile / skeletonizeWithDependencies (src/skeleton/)
│ │ ├── getGitContext() (src/git/)
│ │ └── calculateEcoTelemetry() (src/telemetry/)
│ ├── goal_orchestrate() ──▶ rule-based plan (src/mcp/goal-orchestrate.ts)
│ │
│ ├── init_board() ──▶ SQLite via sql.js
│ ├── create_ticket() ──▶ SQLite via sql.js
│ ├── update_ticket() ──▶ SQLite via sql.js
│ ├── delete_ticket() ──▶ SQLite via sql.js
│ ├── get_board_state() ──▶ SQLite via sql.js
│ │
│ └── list_agents() ──▶ agents.yaml parser (src/agents/)
│
└── MCP Resources (src/mcp/resources.ts)
├── file://.promptdiet/state.db
└── file://.promptdiet/agents.yamlExit Codes
| Code | Meaning |
|------|---------|
| 0 | Success |
| 1 | Non-retryable failure during agent run |
| 2 | Parse error (invalid file, unsupported language) |
| 3 | Ticket not found |
| 4 | Agent not found |
License
MIT
