code-graph-mcp
by attaxr
README.md
<div align="center">
<img src="docs/assets/logo.png" alt="Code Graph" width="180">
# Code Graph MCP
**Stop your coding agent from grepping. Give it a graph of the codebase instead.**
[](LICENSE)
[](https://modelcontextprotocol.io)
[](https://go.dev)
[](https://docs.docker.com/compose/)
[](https://neo4j.com)
Semantic code search, call graphs, control and data flow, impact analysis.
Served to AI coding agents over MCP.
</div>
---
## Overview
Code Graph turns a repository into a **queryable graph**: every file, symbol,
call, import, control-flow branch and variable, indexed with semantic
embeddings and served to AI coding agents through the Model Context Protocol.
Instead of guessing keywords and reading whole files, an agent asks structural
questions and gets structural answers, with the real source attached.
<p align="center">
<img src="docs/assets/grep-vs-graph.svg" alt="Answering "how does a repository get indexed?": six grep calls and still guessing, versus one explain_feature call returning 4 entry points, 6 call chains, 9 files, the relationship subgraph and the source of each one." width="920">
</p>
---
## Search your codebase in the browser
<p align="center">
<img src="docs/assets/demo.gif" alt="The web app: a plain-language search expands into a subgraph of files and symbols on the canvas, with the source of the selected node in the side panel." width="880">
</p>
The web app at `http://localhost:8989` is for you, not your agent. Search the
codebase by intent, expand what comes back, and follow the calls and imports
across the canvas. The graph it draws is the one the server built, so it is
also a quick way to check the index is healthy before you rely on it.
**Everything runs locally.** Parsing, embedding and storage happen in
containers on your machine. No code leaves it.
---
## Quick start
**Prerequisites:** Docker Engine 24+ with Compose v2, or Docker Desktop.
Nothing else. Go and Node are only needed for native development.
```sh
git clone https://github.com/attaxr/code-graph-mcp.git
cd code-graph-mcp/deploy
./deploy.sh up # Windows PowerShell: .\deploy.ps1 up
./deploy.sh index # one-shot index of the mounted repo
```
Open <http://localhost:8989>. The MCP endpoint is
<http://localhost:8989/mcp>.
Two things to expect on the first run:
- **The first start is slow.** The embedding container downloads its model
before it can serve requests, which takes about two minutes. Every start
after that is quick, and re-indexing is incremental.
- **The graph holds one repository at a time.** It is keyed by repo-relative
paths, so pointing it at a new project clears the previous one instead of
merging two codebases.
### Point it at your own project
Install the [`codegraph` CLI](#the-codegraph-cli) and run one command from
inside the project you want indexed. No compose edits, no restart:
```sh
cd /path/to/your/project
codegraph init
```
Your agent can do the same thing mid-conversation by calling
`initialize_project`.
To set the target permanently instead, name it in `deploy/.env`:
```sh
echo "TARGET_REPO=/absolute/path/to/your/project" >> deploy/.env
./deploy.sh up # `up`, not `restart`: restart reuses containers
./deploy.sh index
```
---
## The codegraph CLI
`codegraph` is a terminal front-end for the server. It points the server at a
repository, builds the graph, keeps it in sync, and reports on it, from any
directory, without editing docker-compose or reaching for curl.
### Install
```sh
go install github.com/attaxr/code-graph-mcp/apps/code-graph-cli/cmd/codegraph@latest
```
That drops `codegraph` in `$GOBIN` (usually `~/go/bin`, or `%USERPROFILE%\go\bin`
on Windows). Make sure it is on your `PATH`.
No Go toolchain? Every [release](https://github.com/attaxr/code-graph-mcp/releases)
ships prebuilt archives for Linux, macOS and Windows on amd64 and arm64. Unpack
one and put `codegraph` on your `PATH`.
### Usage
**Index a codebase.** Run this from inside the project you want indexed. It
resolves the git checkout root, switches the server to that repository, and
follows the index run to completion:
```sh
cd /path/to/your/project
codegraph init
```
**Keep the graph in sync after edits.** Only changed files are re-parsed and
re-embedded, so this takes seconds:
```sh
codegraph sync
```
**Rebuild from scratch** after large moves, renames, or an embedding model
change:
```sh
codegraph rebuild
```
**Check what the server is pointed at**, whether a run is in flight, and what
the graph holds:
```sh
codegraph status
```
**Index a different project without leaving this one**, and do it in the
background:
```sh
codegraph init ../other-project --no-wait
```
**Work against a remote or token-protected server:**
```sh
codegraph --server https://codegraph.example.com --token <token> status
codegraph login # verify the token once and store it
```
**When something is wrong**, `diagnose` checks reachability, auth, the health
endpoint, index status and graph stats, printing a pass or fail line for each:
```sh
codegraph diagnose
```
Prefer a menu? `codegraph tui` runs the same operations interactively.
### Commands
| Command | What it does |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `codegraph init [path]` | Point the server at a repository and build its graph. `path` defaults to the current directory and resolves to its git checkout root. Clears the previous graph |
| `codegraph sync` | Re-index the active project. Incremental: only changed files are re-parsed and re-embedded |
| `codegraph rebuild` | Full re-index that re-embeds every file. Alias: `codegraph reindex` |
| `codegraph status` | Active project, index run state, and graph stats (files, symbols, edges, calls, unresolved, languages) |
| `codegraph logs` | The most recent index run: repo, counts, unresolved ratio, duration. Server process logs are not exposed over the API, so use `./deploy.sh logs` for those |
| `codegraph diagnose` | Health checks with pass or fail per check, and advice on each failure. Exits non-zero if any check fails |
| `codegraph login` | Verify the API token against the server and store it in the config file |
| `codegraph config` | Show the effective configuration. Subcommands below |
| `codegraph tui` | Interactive menu for the common operations. Requires a terminal |
| `codegraph version` | Version, commit, build date, and Go toolchain |
| `codegraph completion <shell>` | Shell completion script for bash, zsh, fish or powershell |
| `codegraph help [command]` | Help for any command. Same as `--help` |
`config` on its own prints the effective configuration. Four subcommands manage
the file, and the only keys are `server` and `token`:
| Subcommand | What it does |
| ------------------------------------ | ------------------------------------------------------- |
| `codegraph config` | Print the config file path, server URL and masked token |
| `codegraph config path` | Print the config file path only |
| `codegraph config get [key]` | Print the effective configuration |
| `codegraph config set <key> <value>` | Write `server` or `token` to the config file |
| `codegraph config unset <key>` | Remove `server` or `token` from the config file |
### Flags
Every flag is global, so it can be passed to any command.
| Flag | Value | Default | Description |
| -------------- | ------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `--server` | URL | `http://localhost:8989` | Base URL of the Code Graph server. Overrides `CODE_GRAPH_URL` and the config file |
| `--token` | string | none | API token, sent as `Authorization: Bearer`. Overrides `CODE_GRAPH_TOKEN` and `API_TOKEN` |
| `--config` | path | OS config dir | Use a different config file instead of the default location |
| `--force` | boolean | `false` | Re-embed every file, ignoring content hashes. Applies to `init` and `sync`; `rebuild` always forces |
| `--no-wait` | boolean | `false` | Start the index run and exit instead of following it. Poll `codegraph status` for progress. Applies to `init`, `sync` and `rebuild` |
| `--no-tui` | boolean | `false` | Print plain text instead of the interactive progress UI. Applied automatically when stdout is not a terminal |
| `-h`, `--help` | boolean | `false` | Help for the command |
### Configuration and tokens
Settings are resolved in this order, with the first match winning:
1. Flags: `--server`, `--token`
2. Environment: `CODE_GRAPH_URL`, then `CODE_GRAPH_TOKEN`, then `API_TOKEN`
3. Config file: `~/.config/code-graph/config.json` on Linux and macOS,
`%AppData%\code-graph\config.json` on Windows. Written by `codegraph login`
and `codegraph config set`, with user-only permissions
4. Default: `http://localhost:8989`, no token
If no token is found in any of those, the CLI looks inside the current
repository, first at `deploy/.env` for `API_TOKEN=`, then at `.mcp.json` for an
`Authorization: Bearer` header. That means a checkout that already talks to a
protected server needs no extra setup.
### Migrating from the init scripts
`codegraph` replaces the old `scripts/code-graph-init.sh` and
`scripts/code-graph-init.ps1` (now removed). The mapping is direct:
| Old script | New command |
| ------------------------------------------------ | --------------------------------- |
| `./code-graph-init.sh` / `.\code-graph-init.ps1` | `codegraph init` |
| `./code-graph-init.sh ../other-project` | `codegraph init ../other-project` |
| `-Url http://host:port` / `--url URL` | `--server URL` |
| `-Token X` / `--token X` | `--token X` |
| `-NoWait` / `--no-wait` | `--no-wait` |
Environment variables are unchanged: `CODE_GRAPH_URL`, `CODE_GRAPH_TOKEN` and
`API_TOKEN` all still work, as does the automatic token discovery from
`deploy/.env` and `.mcp.json`. Anything that piped the scripts through
`irm | iex` or `curl | sh` becomes one `go install` plus `codegraph init`.
### Indexing without the CLI
`deploy.sh` still drives a one-shot index inside the running container:
```sh
cd deploy
./deploy.sh index # Windows PowerShell: .\deploy.ps1 index
./deploy.sh index -force # re-embed everything
```
Either way, the repository named in `TARGET_REPO` (`deploy/.env`, default `..`,
your repo root) is mounted **read-only** at `/workspace`, so your source is
never modified. The graph lives in Neo4j. To verify a run finished, use
`codegraph status`, poll `curl -s http://localhost:8989/api/stats` until `files`
and `symbols` are non-zero, or open <http://localhost:8989>.
---
## Connect your AI agent
Two steps: register the server, then install the skills that teach your agent
when to use it.
### 1. Register the MCP server
The endpoint is always `http://localhost:8989/mcp`, the transport is streamable
HTTP, and the server name is `code-graph`. Everything below is those three
values in a different file.
| Agent | Where the config goes |
| ------------------------------ | --------------------------------------------------- |
| Claude Code | `.mcp.json` in the project |
| VS Code, GitHub Copilot | `.mcp.json` in the project, or the `code` CLI below |
| Cursor | `.cursor/mcp.json` in the project |
| Zed | `settings.json` |
| OpenCode | `opencode.json` in the project |
| Gemini CLI, Codex CLI | their own MCP configuration |
| Windsurf, Cline, Roo, Continue | their MCP server settings panel |
Most of them take this shape:
```json
{
"mcpServers": {
"code-graph": {
"type": "http",
"url": "http://localhost:8989/mcp"
}
}
}
```
Zed and OpenCode nest it under `mcp` instead, and OpenCode calls the transport
`remote`:
```json
{
"mcp": {
"code-graph": {
"type": "remote",
"url": "http://localhost:8989/mcp",
"enabled": true
}
}
}
```
Zed applies the change live. Restart it only if the tools do not appear.
VS Code can register the server from the command line instead of a file:
```sh
code --add-mcp '{
"name": "code-graph",
"type": "http",
"url": "http://localhost:8989/mcp"
}'
```
This repo also ships a root `.mcp.json`, which Claude Code, VS Code and Copilot
read automatically for project-level MCP servers.
### 2. Install the skills
The skills teach your agent **which tool answers which question**, and to stop
reaching for grep. One command works on every agent:
```sh
cd /path/to/your/project
npx skills add attaxr/code-graph-mcp --all -y
```
To target a single agent, pass `-a <agent>`:
```sh
npx skills add attaxr/code-graph-mcp -a claude-code -g -y
```
The bundle contains eight skills: `code-graph` (the router), plus
`code-graph-onboarding`, `code-graph-references`, `code-graph-tracing`,
`code-graph-impact`, `code-graph-reuse`, `code-graph-cypher` and
`code-graph-indexing`.
Claude Code can install them as a plugin instead:
```sh
claude plugin marketplace add attaxr/code-graph-mcp
claude plugin install code-graph@code-graph
```
Gemini CLI takes them as an extension:
```sh
gemini extensions install https://github.com/attaxr/code-graph-mcp
```
For any other agent, copy the `skills/*/SKILL.md` playbooks from this repo into
its skills or rules directory.
### Or let the agent set it up
Paste this into any MCP-capable coding agent. It does the whole setup and
verifies it.
```text
Set up the Code Graph MCP Server for this project and use it instead of grep from now on.
1. START
Clone https://github.com/attaxr/code-graph-mcp to ../code-graph-mcp (git pull if it already
exists). In its deploy/ dir, set TARGET_REPO in .env to MY project's absolute path, then run
`./deploy.sh up` (PowerShell: `.\deploy.ps1 up`) and `./deploy.sh index`. The first run
downloads an embedding model, so allow a few minutes. Poll
`curl -s http://localhost:8989/api/stats` until files and symbols are non-zero.
2. SKILLS
Run `npx skills add attaxr/code-graph-mcp --all -y` in MY project. If that CLI is unavailable,
install the skills from the clone's skills/ directory into whatever mechanism you support.
3. CONNECT
Register a server named `code-graph` at http://localhost:8989/mcp (streamable HTTP) using your
usual MCP configuration. If you don't know your config format, print the exact JSON for me to
paste instead of writing to a guessed path.
4. VERIFY: show me the real output, not a summary
a) confirm the code-graph tools are connected (reload/restart first if needed)
b) index_status()
c) explain_feature("<the main thing this project does>")
5. REPORT
Tell me: clone path, index stats, what you configured where, and anything that failed.
From now on, use the code-graph tools instead of grep/ripgrep/find to locate code, trace
relationships or understand an implementation, and run search_code before writing any new
function. Keep text search for non-code text only.
```
If the stack is already running, paste steps 2 to 5 alone.
---
## Running the stack
The whole stack (Neo4j, the embedding server, the Go MCP/HTTP backend and the
web app) is defined in `deploy/docker-compose.yml`. Two scripts drive it with
identical commands, one per platform:
- `deploy/deploy.sh` for Linux, macOS, WSL and Git Bash.
- `deploy/deploy.ps1` for Windows PowerShell.
Run every command **from the `deploy/` directory**, where `.env` and the
compose file live. The first `up` copies `deploy/.env.example` to `deploy/.env`
automatically.
```sh
cd deploy
./deploy.sh up # build images and start the stack detached
./deploy.sh ps # container state (alias: status)
./deploy.sh logs -f # tail logs (`logs -f nginx` for one service)
./deploy.sh restart # restart all services
./deploy.sh down # stop and remove containers (`-v` drops volumes)
```
What `up` starts:
| Container | Service | Published port | Purpose |
| ---------------- | ------------ | -------------------- | ------------------------------------------------ |
| `cgm-web` | `nginx` | `:8989` (`WEB_PORT`) | Single public entry point: SPA, `/api/*`, `/mcp` |
| `cgm-server` | `mcp-server` | none | HTTP API and streamable MCP backend |
| `cgm-neo4j` | `neo4j` | none | Graph store and vector indexes |
| `cgm-embeddings` | `embeddings` | none | Local embedding model (TEI) |
Only nginx publishes a port. The rest live on the internal compose network.
To update to the latest version:
```sh
git pull
./deploy.sh rebuild # rebuild images and restart the stack
# or: ./deploy.sh pull && ./deploy.sh up # pull images without rebuilding
# `rebuild --no-cache` forces a clean build
```
Named volumes (`neo4j-data`, `neo4j-logs`, `hf-cache`) survive `down` and
`restart`. Only `down -v` deletes them.
---
## Configuration
On first start, `deploy.sh up` copies `deploy/.env.example` to `deploy/.env`.
Edit that file, then re-run `./deploy.sh up`. Do not use `restart`: it does not
recreate containers, so new values are not picked up.
| Variable | Default | Required | Description |
| ----------------------- | ----------------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `TARGET_REPO` | `..` (repo root) | Yes | Repository mounted read-only at `/workspace`. Point this at your own project |
| `PROJECTS_DIR` | `../..` (clone parent) | No | Directory of checkouts mounted read-only at `/projects`, which lets `initialize_project` switch repos |
| `NEO4J_PASSWORD` | `codegraph123` | No | Neo4j password (the user is always `neo4j`) |
| `EMBEDDING_MODEL` | `BAAI/bge-base-en-v1.5` | No | Embedding model served by TEI. 768-dim models only, since `EMBEDDING_DIM` is fixed |
| `WEB_PORT` | `8989` | No | Host port published by nginx |
| `LOG_LEVEL` | `info` | No | `mcp-server` log level |
| `API_TOKEN` | _(empty)_ | No | Optional static token guarding `/api/*` and `/mcp`. See [Authentication](#authentication) |
| `EMBED_QUERY_PREFIX` | _(commented out)_ | No | Retrieval query prefix. Keep it quoted; it ends in a space |
| `EMBED_DOCUMENT_PREFIX` | _(commented out)_ | No | Document prefix. Keep it quoted; it ends in a space |
> **Trailing-space warning.** `EMBED_QUERY_PREFIX` and `EMBED_DOCUMENT_PREFIX`
> end in a space, which the compose `.env` parser trims from unquoted values.
> If you enable them, keep them quoted exactly as in `.env.example`.
---
## Authentication
Auth is **opt-in**. Leave `API_TOKEN` empty (the default) for a
trust-your-localhost setup. Set it to require a token on **every** `/api/*` and
`/mcp` request.
```sh
echo "API_TOKEN=<a-long-random-token>" >> deploy/.env
cd deploy && ./deploy.sh up # recreate containers so they pick it up
```
How it works:
- Compose delivers the token to the `mcp-server` and `nginx` containers at
runtime via `env_file`. It is never baked into an image.
- The server guards the **whole HTTP surface**. Every request must present the
token as `Authorization: Bearer <token>` or `X-API-Key: <token>`. Anything
else gets a `401` with `WWW-Authenticate: Bearer realm="code-graph"`. Tokens
are compared in constant time, so a wrong token cannot be told from a correct
one by timing.
- The web UI keeps working with auth on. The nginx entrypoint writes the token
into `/config.js` at container start, and the SPA sends it automatically.
- After changing the token, re-run `./deploy.sh up`. `restart` will not pick it
up.
Check that both surfaces are guarded:
```sh
# REST API: 401 without the token, 200 with it
curl -i http://localhost:8989/api/health
curl -i \
-H "Authorization: Bearer <token>" \
http://localhost:8989/api/health
# MCP endpoint: same 401, same 200 once the header is added
curl -i -X POST http://localhost:8989/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "curl", "version": "0" }
}
}'
```
The CLI takes the token as a flag, or finds it itself in `deploy/.env` or
`.mcp.json` when you run inside the checkout:
```sh
codegraph --token <token> status
codegraph login # verify once and store it for later commands
```
### Sending the token from an MCP client
Every client config in [Connect your AI agent](#connect-your-ai-agent) accepts
a `headers` field:
```jsonc
// VS Code / Cursor: .mcp.json
{
"mcpServers": {
"code-graph": {
"type": "http",
"url": "http://localhost:8989/mcp",
"headers": { "Authorization": "Bearer <token>" },
},
},
}
```
```jsonc
// Zed: settings.json
{
"mcp": {
"code-graph": {
"url": "http://localhost:8989/mcp",
"headers": { "Authorization": "Bearer <token>" },
},
},
}
```
For OpenCode, add the same `headers` entry to `opencode.json` under
`mcp.code-graph`. Plugin-based clients such as Claude Code and Gemini CLI take
the token in their MCP server settings. It is the same
`Authorization: Bearer <token>` header on the same URL.
---
## How it works
<!-- TODO: drop the demo GIF at docs/assets/code-graph-demo.gif and link it here -->
`./deploy.sh up` starts four services behind a single nginx entry point at
`http://localhost:8989`:
```
nginx (:8989) ── / static web app
├── /api/* ──> mcp-server :7788
└── /mcp ──> mcp-server :7788 (streamable MCP)
mcp-server ──> neo4j graph store + vector indexes
mcp-server ──> embeddings local embedding model
```
An index pass parses every file with tree-sitter, resolves symbols and edges,
and stores them in Neo4j with semantic embeddings. Your agent's MCP tools
(`explain_feature`, `find_callers` and the rest) query that graph and get the
real source back. The web app reads the same graph over `/api/*`, which is how
you search and explore it yourself.
---
## Bug reports
[](https://github.com/attaxr/code-graph-mcp/issues/new)
Found a bug? Open a
[new issue](https://github.com/attaxr/code-graph-mcp/issues/new) and include:
- **What you did.** Steps to reproduce.
- **What you expected, and what happened instead.**
- **Index stats** if relevant: `curl -s http://localhost:8989/api/stats`, or the
output of `index_status()`.
- **Container logs** if the stack is involved: `./deploy.sh logs`.
---
## Contributing
Contributions are welcome: code, docs, skills and issues all count.
- **Set up for development.** `./deploy.sh --dev up` runs the stack with Vite
HMR. The Go server lives in `services/mcp-server/`, the web app in
`apps/web/`.
- **Graph schema.** The single source of truth is
`services/mcp-server/internal/graph/schema.go`. The TypeScript mirror in
`packages/graph-schema/src/generated.ts` is generated from it, so edit the Go
file and run `go generate ./internal/graph`. Never edit the generated file.
- **Open a pull request** from a fork with a clear description of what and why.
Tests and a re-index of your change (`./deploy.sh index`) are appreciated.
### Contributors
[](https://github.com/attaxr/code-graph-mcp/graphs/contributors)

---
## License
Released under the [MIT License](LICENSE). Copyright 2026 Code Graph MCP
contributors.
MIT is a permissive open-source license: you may use, copy, modify, merge,
publish, distribute, sublicense and sell the software, provided the copyright
notice and permission text are included in all copies or substantial portions.
The software is provided **as is**, without warranty of any kind.
See [LICENSE](LICENSE) for the full text.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessSyncing