Install
$ agentstack add mcp-edmmy-codebase-bridge-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
codebase-bridge-mcp
A read-only MCP server that lets a Claude chat — in the desktop or web app — explore your local repository and answer questions about it, returning synthesized answers with file:line references. No copy-pasting files, no giving the chat write access to your machine.
ask_codebase runs headless Claude Code (claude -p) inside your repo with an exclusive read-only tool set (Read Grep Glob — no Edit, Write, Bash, agents, or MCP) and a hook that confines reads to the target repo, so a disposable agent explores the code and returns a synthesized, file:line answer. See [Security](#security) for exactly what is and isn't enforced.
Claude client --MCP--> codebase-bridge --> claude -p (Read/Grep/Glob only)
└─ explores /path/to/your/repo
Why I built this
I do my best thinking about a problem in a conversational Claude chat, not in a coding agent — the back-and-forth on an idea tends to go deeper there. But every time I wanted to ask about a specific part of my code, I had to go hunting for the right file, find the relevant section, and paste it in by hand — every single question. It broke the flow exactly when I wanted to think freely.
I went looking for something to close the gap and found the existing codebase tools all point the wrong way: filesystem and repo-packing servers (like Repomix) feed a coding agent that already has your repo, and structural-index servers (like codebase-memory-mcp) need a coding agent to be the brain. Nothing brought a finished, read-only answer about my code into the chat where I was actually thinking. So I built it: it shells out to a headless, read-only Claude scoped to a single repo (Read/Grep/Glob only — no Write, no Bash), and hands the synthesized answer back to my chat. I can interrogate my codebase mid-conversation without ever leaving the thinking.
Requirements
- Claude Code (
claude) installed and authenticated. uv(runs the server with zero install — deps are
declared inline in server.py).
- For the optional
httptransport:cloudflared
or any HTTPS tunnel.
Tools
| Tool | What it does | | ---- | ------------ | | ask_codebase(question, thread="", model="", effort="", show_steps=False) | Explore the repo read-only and answer. | | bridge_cost() | Return the per-thread + grand-total cost ledger for this server process. | | bridge_forget(thread="") | Drop a thread's session (or all threads) so the next call starts fresh. |
ask_codebase parameters:
thread— a friendly name (e.g."auth-investigation"). Reuse the same name
to keep one Claude Code session alive — turn-based steering: each follow-up keeps prior context, so you redirect it and it stays cheap (prompt-cache hits, measured 45% → 95% → 99% cache-read across turns). Omit for a one-off fresh session.
model— e.g."sonnet"/"opus". Binds to a thread on its first call; a
different model on an existing thread is refused with a note, because switching models forces a full-context reprocess. Start a new thread for a different model.
effort— reasoning effort:low,medium,high,xhigh,max. Per-call
(safe to vary within a thread — unlike model it doesn't invalidate the cache). Lower = cheaper/faster; raise it for hard cross-file reasoning. Unknown values are ignored with a note.
show_steps— append the exploration trail so you see how it reached the
answer and can steer the next turn.
Example answer:
Auth is enforced in app/middleware.py:42 (verify_token), called from the
@requires_auth decorator in app/security.py:18.
[bridge] explored via 2 step(s):
1. grep 'verify_token'
2. read app/middleware.py
--
[bridge] model=opus-4-8 | call=$0.0383 | cache 58k read / 19 fresh (100% cached)
[bridge] thread 'auth' total=$0.81 over 3 call(s) -- reuse this thread for cheap follow-ups
Install / run
stdio (recommended — Claude Desktop & Claude Code)
stdio is launched as a local subprocess by the client: no URL, no tunnel, no token.
Claude Code:
claude mcp add codebase-bridge -- uv run --script /ABS/PATH/server.py --repo /ABS/PATH/your-repo
Claude Desktop: edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) — see [examples/claude_desktop_config.json](examples/claudedesktopconfig.json):
{
"mcpServers": {
"codebase-bridge": {
"command": "/opt/homebrew/bin/uv",
"args": ["run", "--script", "/ABS/PATH/server.py", "--repo", "/ABS/PATH/your-repo"]
}
}
}
Use the absolute path to uv (which uv) — Claude Desktop doesn't inherit your shell PATH. Restart Desktop after editing. Then ask: "Use askcodebase on thread 'auth', showsteps: how does login work?"
http (only for claude.ai web)
claude.ai reaches servers from Anthropic's cloud, so it needs a public URL + token:
export BRIDGE_TOKEN=$(openssl rand -hex 16); echo "token: $BRIDGE_TOKEN"
uv run --script server.py --transport http --repo /ABS/PATH/your-repo # 127.0.0.1:8765
cloudflared tunnel --url http://localhost:8765 # new terminal
http transport refuses to start without BRIDGE_TOKEN (pass --insecure-no-auth to deliberately run an open server, e.g. when you front it with your own auth). It binds 127.0.0.1 by default — the tunnel connects to localhost; set --host 0.0.0.0 only if you really need other interfaces. The token check is constant-time.
Add https://.trycloudflare.com/mcp (no trailing slash) as a custom connector in claude.ai with the bearer token.
Configuration
All knobs have CLI flags and/or env vars:
| Env | CLI | Default | Meaning | | --- | --- | ------- | ------- | | BRIDGE_REPO | --repo | current dir | repo Claude Code explores | | BRIDGE_TRANSPORT | --transport | stdio | stdio or http | | BRIDGE_TOKEN | — | unset | http bearer token (http refuses to start unless set or --insecure-no-auth) | | BRIDGE_HOST | --host | 127.0.0.1 | http bind address | | BRIDGE_PORT | — | 8765 | http listen port | | BRIDGE_TIMEOUT | — | 240 | per-call wall-clock cap (seconds) | | BRIDGE_MODEL | — | Claude Code default | default model for new threads / ephemeral calls | | BRIDGE_MAX_CONCURRENT | — | 4 | cap on concurrent claude subprocesses (DoS/cost guard) | | BRIDGE_THREAD_TTL | — | 1800 | idle seconds before a thread session is dropped (0 = never) | | BRIDGE_MAX_THREADS | — | 256 | live-thread cap before LRU eviction | | BRIDGE_CONFINE_READS | — | 1 | PreToolUse hook confines reads to --repo (0 = read anywhere) | | — | --insecure-no-auth | off | allow http without a token (explicit opt-in; refused on non-loopback host) |
Security
This project has not been independently security-audited. It is hardened, and the guarantees below are enforced and were verified empirically — but read this before exposing it to untrusted input.
What is enforced (default), at Claude's tool-dispatch layer:
- Exclusive read-only tool set. The agent is launched with `--tools "Read Grep
Glob" — the *exclusive* built-in tool flag (unlike --allowedTools, which is merely additive and lets unlisted tools still run). The agent literally has **no Bash, Edit, Write, agent/subagent, or MCP tool** — verified: it reports only Read/Grep/Glob`.
- Reads confined to
--repo. APreToolUsehook (this script, registered via
--settings) runs host-side before every tool call and denies any read whose path resolves outside the target repo (absolute paths, ../, /proc/self/environ, etc.) — verified: reading /etc/hosts is rejected with "outside the target repo". This is the one thing no claude flag does (Read accepts absolute paths by design). Disable with BRIDGE_CONFINE_READS=0 for trusted local cross-repo use.
- No shell injection / no flag injection. Argv list (no shell); the question is
passed after a -- end-of-options separator so it can't be reparsed as a flag.
- The server's own secrets aren't inherited.
BRIDGE_*env vars (incl.
BRIDGE_TOKEN) are stripped from the child env, and /proc/self/environ is outside the repo so the read hook blocks it too.
- http transport. Refuses to start without
BRIDGE_TOKEN(override with
--insecure-no-auth, itself refused on a non-loopback host), binds 127.0.0.1, constant-time token compare, concurrent subprocesses capped (BRIDGE_MAX_CONCURRENT).
The honest caveats:
- This is policy enforcement, not a kernel sandbox. The tool restriction and read
hook are evaluated by Claude Code host-side and are deterministic (the model can't reason around them), but they are not an OS-level boundary. For a fully untrusted client (e.g. exposed over a public tunnel), additionally wrap the process in an OS sandbox (sandbox-exec on macOS, bubblewrap on Linux, or a container) so even a hypothetical claude/Node compromise can't escape. (code.claude.com/docs/sandboxing.)
- **Files inside the repo are readable** — including any secrets committed there
(.env, keys). Point it at repos you trust to expose.
- Prompt injection. Untrusted content inside repo files could try to misdirect the
agent; the read-confinement hook limits the blast radius to the repo itself.
Known limitations
- State is in-memory and per-process. Thread sessions and the cost ledger reset on
restart; there is no cross-restart persistence (by design for now). Idle threads are dropped after BRIDGE_THREAD_TTL and evicted by LRU past BRIDGE_MAX_THREADS.
- No mid-flight cancellation. Cancelling the MCP request does not kill the running
claude subprocess; it finishes (bounded by BRIDGE_TIMEOUT).
- Depends on the
claudeCLI's output schema. It parses `--output-format
stream-json`; a future CLI change could require an update (the smoke test guards the tool surface, not the parser).
- Not independently security-audited. Reviewed adversarially (incl. by separate AI
reviewers) but not professionally audited.
Cost model
Each ask_codebase call spins up a fresh headless Claude Code agent, so dollar cost varies with how much it explores. The win from thread reuse shows as a climbing cache-hit rate and cheap short follow-ups — not a strictly lower price every call. State is in-memory per server process; restarting resets threads and the ledger.
Development
uv run tests/smoke.py # MCP handshake + tool-surface check (no API key needed)
uv build # build wheel + sdist
CI runs both on every push/PR (.github/workflows/ci.yml).
License
MIT — see [LICENSE](LICENSE).
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: EDMMY
- Source: EDMMY/codebase-bridge-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.