code-repo-mcp
by janstuemmel
README.md
# code-repo-mcp
An MCP server that exposes `glob`, `grep` and `list_repos` tools over a folder
containing multiple git repositories. Point it at a directory where you mount
(or check out) several repos side by side, and any MCP client can search
across them by name — without needing local filesystem/shell access itself.
Runs as a single npm bin and serves the [MCP Streamable HTTP
transport](https://modelcontextprotocol.io/) (stateless mode), so it works
equally well as a personal local tool or as a small shared service.
## Install & run
```bash
npm install -g code-repo-mcp
code-repo-mcp --root /path/to/repos
```
Or without installing globally:
```bash
npx code-repo-mcp --root /path/to/repos
```
### Options
| Flag/env var | Default | Description |
| ---------------------------- | ----------- | ---------------------------------------------- |
| `--root` / `CODE_REPO_ROOT` | *(required)* | Folder containing git repos as subdirectories |
| `--port` / `PORT` | `3900` | Port to listen on |
| `--host` / `HOST` | `127.0.0.1` | Host to bind to |
The server exposes a single MCP endpoint at `http://<host>:<port>/mcp`, plus
`GET /healthz` for a basic liveness check.
## Repo layout
`--root` should point at a folder whose immediate subdirectories are git
repositories (i.e. each contains a `.git` directory or file), e.g.:
```
/path/to/repos/
├── service-a/ (git repo)
├── service-b/ (git repo)
└── shared-lib/ (git repo)
```
Only these first-level subdirectories are considered repos; other files or
non-git directories under `--root` are ignored by `list_repos` and rejected
by `glob`/`grep`.
## Tools
- **`list_repos`** — no arguments. Returns the names of all git repos found
directly under `--root`. Use these names as the `repo` argument for the
other tools.
- **`glob`** — `{ repo, pattern, ignore?, dot?, limit? }`. Runs a
[fast-glob](https://github.com/mrmlnc/fast-glob) pattern scoped to that
repo and returns matching relative file paths.
- **`grep`** — `{ repo, pattern, glob?, caseInsensitive?, fixedStrings?, contextLines?, maxMatches? }`.
Runs [ripgrep](https://github.com/BurntSushi/ripgrep) (bundled via
`@vscode/ripgrep`, no system install required) scoped to that repo and
returns `{ file, line, text }` matches.
All repo access is confined to the resolved repo directory: repo names must
be a single path segment (no `/`, `..`), and results that would resolve
outside the repo are filtered out as defense in depth.
## Connecting a client
Point any MCP-over-HTTP client at `http://127.0.0.1:3900/mcp`. For example,
in Claude Code's MCP config:
```json
{
"mcpServers": {
"code-repo-mcp": {
"type": "http",
"url": "http://127.0.0.1:3900/mcp"
}
}
}
```
## Docker
Prebuilt images are published to GitHub Container Registry on every push to
`main` and on version tags (see
[.github/workflows/docker-publish.yml](.github/workflows/docker-publish.yml)):
```bash
docker pull ghcr.io/janstuemmel/code-repo-mcp:latest
```
Or build it yourself:
```bash
docker build -t code-repo-mcp .
docker run -d --name code-repo-mcp \
-p 3900:3900 \
-v /path/to/repos:/repos:ro \
code-repo-mcp
```
The image mounts the repo folder at `/repos` by default (override with
`--root`/`CODE_REPO_ROOT` if you need a different path inside the container).
Mounting it `:ro` is recommended — the server only ever reads. It binds to
`0.0.0.0:3900` inside the container so `-p <host-port>:3900` is all you need;
override `HOST`/`PORT` env vars if you need something else.
Note: the image is based on `node:22-slim` (glibc), not Alpine — the bundled
ripgrep binary is a glibc build and won't run under musl.
## Development
```bash
npm install
npm run dev -- --root /path/to/repos # run from source via tsx
npm run build # compile to dist/
npm start -- --root /path/to/repos # run the compiled build
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues