mcp-portal
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.
Quick start
Until the first PyPI release lands, install straight from GitHub:
uvx --from git+https://github.com/apollion69/mcp-portal mcp-portal
After the PyPI release the short forms work:
uvx mcp-portal
pipx install mcp-portal
pip install mcp-portal
Requirements: Python 3.10+, the Cursor CLI (cursor-agent) installed and logged in.
Doctor (CLI inventory, no model call):
mcp-portal-doctor
Configure per host
Claude Code
claude mcp add --scope user mcp-portal -- uvx mcp-portal
Codex (~/.codex/config.toml)
[mcp_servers.mcp-portal]
command = "uvx"
args = ["mcp-portal"]
tool_timeout_sec = 150
Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"mcp-portal": {
"command": "uvx",
"args": ["mcp-portal"]
}
}
}
VS Code (.vscode/mcp.json, servers key)
{
"servers": {
"mcp-portal": {
"type": "stdio",
"command": "uvx",
"args": ["mcp-portal"]
}
}
}
Generic 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 |
Tools
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.
status
No arguments. Returns CLI path, auth hint, default model, policy summary, cache location, receipt counters.
Model policy
Shipped in model-policy.json (package data). Defaults:
- Prefer Cursor-native models (
composer-2.5, thencursor-grok-*) - Strip
-fastsuffixes (never auto-select fast variants) - Other vendors only when explicitly requested and listed by
cursor-agent --list-models
Override 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).
How it works
- Authorize — Server reads only listed paths; blocks credential-like paths and secret patterns.
- Manifest — Request JSON includes per-file SHA-256 hashes.
- Isolate — Cursor CLI runs with fresh
CURSOR_CONFIG_DIR, deny-all permissions,--mode ask, sandbox enabled. - Verify — Every
quoteinbulk_readanswers must appear verbatim in the cited line range; bad citations are dropped or fail closed. - Evidence — Per-run directory under
MCP_PORTAL_HOME/runs/<run_id>/with manifest (hashes, metrics; not full source). - Budgets — 16 files, 128 KiB combined input, 90s timeout, bounded stdio frames.
Windows
On Windows, the delegate uses a local Cursor CLI run when either:
MCP_PORTAL_CLIpoints at an executable (including test stubs), orcursor-agent/agentis found onPATHand 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.
- MCP config can use native
uvx mcp-portalwhen the CLI is on PATH, orwsl.exe+uvx mcp-portalwhen it is not - Helpers in
clients/windows/(delegate.ps1,parse_read.ps1) MCP_PORTAL_WORKERoverrides the default WSL worker commandMCP_PORTAL_WSL_CDsets the WSL working directory (default~)
Optional Claude Code routing hook
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
Security
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.
Related projects
Several Node-based bridges expose Cursor via MCP (different tradeoffs: SDK/Node stack, varying isolation and verification):
- lipey1/cursor-agent-mcp
- andreilungeanu/cursor-delegate-mcp
- sailay1996/cursor-agent-mcp
- ai-nuke/cursor-agent-mcp
- JaimeJunr/cursor-mcp-bridge
mcp-portal focuses on stdlib Python, hash-pinned manifests, quote verification, server-side writes for code_write, model policy, and WSL-first Windows support.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_portal-0.1.0.tar.gz.
File metadata
- Download URL: mcp_portal-0.1.0.tar.gz
- Upload date:
- Size: 50.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
344ec306691afd00ff3e9b0c3ccec8f077c9c9ffc29147a11075d02c90ce20df
|
|
| MD5 |
32bf40fede749dda8d86c76aaea1ee32
|
|
| BLAKE2b-256 |
1aacd117da9d6a9fbfdeb73a54d91f0224f6396c44f31b1ca46978790d6893ed
|
Provenance
The following attestation bundles were made for mcp_portal-0.1.0.tar.gz:
Publisher:
publish.yml on apollion69/mcp-portal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_portal-0.1.0.tar.gz -
Subject digest:
344ec306691afd00ff3e9b0c3ccec8f077c9c9ffc29147a11075d02c90ce20df - Sigstore transparency entry: 2792860460
- Sigstore integration time:
-
Permalink:
apollion69/mcp-portal@14f3af2516450ba89c41ebf20841aebe1f1ed554 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/apollion69
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@14f3af2516450ba89c41ebf20841aebe1f1ed554 -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcp_portal-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mcp_portal-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96ea3fc6af8f96df74611d5ec322b28c3205c21f7252d6102efa0437eec29da8
|
|
| MD5 |
8df2d8187aaca694afe0f5091ee1e530
|
|
| BLAKE2b-256 |
447d4239d03e531787a091f3a32896b5822102cd134610dda62ded0a706b4c08
|
Provenance
The following attestation bundles were made for mcp_portal-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on apollion69/mcp-portal
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_portal-0.1.0-py3-none-any.whl -
Subject digest:
96ea3fc6af8f96df74611d5ec322b28c3205c21f7252d6102efa0437eec29da8 - Sigstore transparency entry: 2792860521
- Sigstore integration time:
-
Permalink:
apollion69/mcp-portal@14f3af2516450ba89c41ebf20841aebe1f1ed554 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/apollion69
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@14f3af2516450ba89c41ebf20841aebe1f1ed554 -
Trigger Event:
push
-
Statement type: