Cursor CLI delegation for verified bulk reads and reference-driven code generation.
mcp-portal is a stdio Model Context Protocol server that lets a frontier agent (Claude Code, Codex, Cursor, or any MCP host) delegate two jobs to the Cursor CLI on its own quota: bounded bulk_read (read explicitly selected files, answer with verified quotes) and code_write (generate boilerplate from a reference file + spec; the server writes the target file). Python stdlib only—no Node runtime and no MCP SDK dependency.
On 2026-09-08, composer-2.5-fast generated roughly 5× faster than a frontier model on the same brief (line-rate measurement). Cursor quota is separate from the host model's.
uvx mcp-portal
Also available as pipx install mcp-portal / pip install mcp-portal, and listed in the
MCP Registry as io.github.apollion69/mcp-portal.
To run the development head instead of the release:
uvx --from git+https://github.com/apollion69/mcp-portal mcp-portal
Requirements: Python 3.10+, the Cursor CLI (cursor-agent) installed and logged in.
Doctor (CLI inventory, no model call):
mcp-portal-doctor
claude mcp add --scope user mcp-portal -- uvx mcp-portal
~/.codex/config.toml)[mcp_servers.mcp-portal]
command = "uvx"
args = ["mcp-portal"]
tool_timeout_sec = 150
~/.cursor/mcp.json){
"mcpServers": {
"mcp-portal": {
"command": "uvx",
"args": ["mcp-portal"]
}
}
}
.vscode/mcp.json, servers key){
"servers": {
"mcp-portal": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-portal"]
}
}
}
mcpServers JSON{
"mcpServers": {
"mcp-portal": {
"command": "uvx",
"args": ["mcp-portal"]
}
}
}
Environment (optional):
| Variable | Purpose |
|---|---|
MCP_PORTAL_HOME | Cache, receipts, evidence (default ~/.cache/mcp-portal) |
MCP_PORTAL_CLI | Path to cursor-agent / agent |
bulk_read| Argument | Required | Description |
|---|---|---|
paths | yes | 1–16 file paths (relative to root or absolute) |
question | yes | Question answered only from those files |
root | no | Common root; default = longest common parent of paths |
model | no | Override model; policy applies when omitted |
Returns status, run_id, answer.findings[] (file, start, end, quote, fact), gaps[], metrics, model_decision.
code_write| Argument | Required | Description |
|---|---|---|
spec | yes | What to generate |
reference_path | yes | Style/context reference file |
target_path | no | If set, server writes this path |
model | no | Override model |
Returns generated code, optional bytes_written, run_id, metrics.
statusNo arguments. Returns CLI path, auth hint, default model, policy summary, cache location, receipt counters.
Shipped in model-policy.json (package data). Defaults:
composer-2.5, then cursor-grok-*)-fast suffixes (never auto-select fast variants)cursor-agent --list-modelsOverride by editing model-policy.json in the installed package or setting policy fields via a custom file at MCP_PORTAL_HOME (future) — today, replace the package file or patch preferred in your fork. Each tool result includes model_decision.reason (default_preferred, fast_suffix_stripped, cursor_native_explicit, explicit_other_vendor, requested_unavailable_fallback).
CURSOR_CONFIG_DIR, deny-all permissions, --mode ask, sandbox enabled.quote in bulk_read answers must appear verbatim in the cited line range; bad citations are dropped or fail closed.MCP_PORTAL_HOME/runs/<run_id>/ with manifest (hashes, metrics; not full source).On Windows, the delegate uses a local Cursor CLI run when either:
MCP_PORTAL_CLI points at an executable (including test stubs), orcursor-agent / agent is found on PATH and is a real file.Otherwise it falls back to the wsl.exe bridge into Ubuntu/WSL (python3 -m mcp_portal.delegate --worker). Force either mode with MCP_PORTAL_BACKEND=local or MCP_PORTAL_BACKEND=wsl.
uvx mcp-portal when the CLI is on PATH, or wsl.exe + uvx mcp-portal when it is notclients/windows/ (delegate.ps1, parse_read.ps1)MCP_PORTAL_WORKER overrides the default WSL worker commandMCP_PORTAL_WSL_CD sets the WSL working directory (default ~)Install read gate + skill (generic, transactional):
python3 -m mcp_portal.install_router prepare --client claude --python python3 \
--state-root ~/.cache/mcp-portal/router-tx --shell bash --command-shell bash
# then apply with the printed transaction id
See docs/skills/cursor-bulk-reader/SKILL.md for agent-facing guidance. The router blocks or warns on large full-file reads (>350 lines or >128 KiB) and points agents at bulk_read.
Repo-level MCP registration helper:
python3 -m mcp_portal.install plan
python3 -m mcp_portal.install apply --target claude-mcp
See SECURITY.md. Summary: you choose which files leave the machine; the CLI runs read-only with tools denied; quotes are verified server-side. Not a substitute for secret hygiene.
Several Node-based bridges expose Cursor via MCP (different tradeoffs: SDK/Node stack, varying isolation and verification):
mcp-portal focuses on stdlib Python, hash-pinned manifests, quote verification, server-side writes for code_write, model policy, and WSL-first Windows support.
MIT — see LICENSE.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
uvx mcp-portalMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-apollion69-mcp-portal": {
"command": "uvx",
"args": [
"mcp-portal"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referencemcp-portalpypiio.github.apollion69/mcp-portal works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.