Skip to main content
Glama

Bicameral MCP — Decision Ledger for Your Codebase

Every software team makes hundreds of verbal decisions per week — in meetings, PRDs, Slack threads, and huddles. None of those decisions are linked to the code that implements (or fails to implement) them.

Bicameral MCP is a local MCP server that ingests meeting transcripts and PRDs, builds a structured graph of decisions mapped to code symbols, and continuously tracks whether those decisions are reflected, drifting, or lost as the codebase evolves.

One-liner: A provenance-aware decision layer for your codebase — paste a transcript, get a living map of what was decided and what was actually built.


The Problem: 5 SDLC Friction Points

Smell

What Happens

Fix

CONSTRAINT_LOST

A rate limit or compliance rule surfaces mid-sprint instead of at design time

bicameral.search — pre-flight context before coding

CONTEXT_SCATTERED

The "why" behind a decision is split across Slack, Notion, and someone's memory

bicameral.ingest — normalizes intent from any source into a unified graph

DECISION_UNDOCUMENTED

A verbal "let's do X" never lands in a ticket or ADR

bicameral.status — tracks what was decided vs what was built

REPEATED_EXPLANATION

Same context tax paid twice — once to design, once to engineering

bicameral.search + get_neighbors — retrieves full decision provenance

TRIBAL_KNOWLEDGE

Only one person knows why the system works the way it does

bicameral.drift — surfaces institutional memory tied to code

General-purpose AI can shred a PRD into user stories, but it goes deaf the moment code hits production. Bicameral's wedge is post-commit drift detection — knowing that a decision made three weeks ago is now inconsistent with what actually shipped.


Quickstart

One-command setup

uvx bicameral-mcp setup

This launches an interactive wizard that:

  1. Detects your repo (from cwd or prompts you)

  2. Installs the MCP config into Claude Code and/or Claude Desktop automatically

That's it. The server builds its code index on first tool call.

Manual config

If you prefer to configure manually, add to your MCP config:

{
  "mcpServers": {
    "bicameral": {
      "command": "uvx",
      "args": ["bicameral-mcp"],
      "env": {
        "REPO_PATH": "/path/to/your/repo"
      }
    }
  }
}

Local development

cd pilot/mcp
pip install -e ".[test]"
bicameral-mcp setup           # interactive config
bicameral-mcp --smoke-test    # verify tools
bicameral-mcp                 # start MCP server (stdio)

No LLM provider credentials needed — all retrieval is deterministic.


9 MCP Tools

Decision Ledger (5 tools)

Tool

Purpose

Auto-triggers

bicameral.ingest

Ingest a normalized source payload (transcript, PRD, Slack export) and advance the source cursor

bicameral.status

Surface implementation status of all tracked decisions (reflected / drifted / pending / ungrounded)

bicameral.search

Pre-flight: find past decisions relevant to a feature before writing code

link_commit(HEAD)

bicameral.drift

Code review: surface decisions that touch symbols in a file, flagging divergence

link_commit(HEAD)

bicameral.link_commit

Sync a commit into the ledger — updates content hashes, re-evaluates drift

Code Locator (4 tools)

Tool

Purpose

Requires

validate_symbols

Fuzzy-match candidate symbol names against the codebase index (rapidfuzz + SQLite)

Indexed repo

search_code

BM25 text search + structural graph traversal, ranked via RRF fusion

Indexed repo

get_neighbors

1-hop graph traversal around a symbol (callers, callees, imports, inheritance)

Indexed repo

extract_symbols

Tree-sitter symbol extraction from a source file


How the Tools Compose

Pre-flight (before coding)

bicameral.search("add rate limiting") → surfaces prior constraints
validate_symbols(["RateLimiter"]) → confirms code entities exist
search_code("rate limit middleware") → locates relevant code
get_neighbors(symbol_id) → understands blast radius

Code review (before merging)

bicameral.drift("payments/processor.py") → surfaces decisions touching this file
extract_symbols("payments/processor.py") → enumerates current symbols
bicameral.status(filter="drifted") → full drift report

Ingestion (after a meeting)

bicameral.ingest(transcript_payload) → extracts intents, maps to code
bicameral.link_commit("HEAD") → syncs latest commit state
bicameral.status(since="2026-03-20") → shows what's reflected vs pending

Architecture

Host Model (Claude Code / Cursor / Claude Desktop)
  │  MCP stdio transport
  ▼
server.py — 9 tools, tool dispatch
  ├── handlers/          ← 5 ledger tool handlers
  │   ├── ingest.py
  │   ├── decision_status.py
  │   ├── search_decisions.py
  │   ├── detect_drift.py
  │   └── link_commit.py
  ├── adapters/          ← adapter layer
  │   ├── ledger.py      → SurrealDBLedgerAdapter (singleton)
  │   └── code_locator.py → RealCodeLocatorAdapter (lazy init)
  ├── ledger/            ← SurrealDB v2 embedded
  │   ├── adapter.py, client.py, queries.py
  │   ├── schema.py      ← canonical table/index definitions
  │   └── status.py      ← content-hash drift derivation
  └── code_locator/      ← deterministic retrieval
      ├── tools/          (validate, search, neighbors)
      ├── indexing/       (tree-sitter, SQLite, graph builder)
      ├── retrieval/      (BM25, sqlite-vec)
      └── fusion/         (RRF)

Storage: SurrealDB v2 embedded (surrealkv:// persistent or memory:// for tests) + SQLite (symbol index, BM25, graph edges). No external server required.

Zero nested LLM calls. The host model orchestrates tool calls directly. All retrieval is deterministic: tree-sitter + BM25 + graph traversal.


Status Derivation

Decision status is a pure function computed at query time — never stored:

Condition

Status

Meaning

No code_region mapped

ungrounded

Intent captured but no matching code found

Symbol absent at git ref

pending

Code not yet written

content_hash differs

drifted

Code changed since decision was recorded

content_hash matches

reflected

Code matches intent

This makes Bicameral immune to rebase, squash, and cherry-pick — status is always re-derivable from (intent, git_ref).


Environment Variables

Var

Default

Purpose

REPO_PATH

.

Path to the repo being analyzed

SURREAL_URL

surrealkv://~/.bicameral/ledger.db

SurrealDB URL. Use memory:// for tests.

CODE_LOCATOR_SQLITE_DB

$REPO_PATH/.bicameral/code-graph.db

Override code index location


Tests & CI

Tests run via GitHub Actions on PRs to main (pilot/mcp/** paths). All phases use real adapters with SURREAL_URL=memory://.

cd pilot/mcp && source .venv/bin/activate
pytest tests/ -v   # run everything locally

Phase

Tests

What

Phase 1

test_phase1_code_locator.py

Code locator tools against real indexed repo

Phase 2

test_phase2_ledger.py

SurrealDB ledger adapter with memory://

Phase 3

test_phase3_integration.py

Full E2E structured around 5 SDLC failure modes

Phase 3 tests produce JSON artifacts (test-results/e2e/) with full tool responses and SurrealDB graph dumps for qualitative review. These are uploaded as CI artifacts and embedded in the HTML test report.


Visual Documentation

See visual-plan/plans/ for rendered architecture docs:

-
security - not tested
F
license - not found
-
quality - not tested

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BicameralAI/bicameral-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server