Skip to main content
Glama
README.md
# project-mcp

A small, **read-only** MCP server that lets Claude read the source code of
your projects. You keep your projects in one folder; Claude can then read the
*current* version of your files instead of relying on pasted snippets.

## The simple mental model

1. There is a `projects/` folder.
2. You create one sub-folder per project inside it.
3. Claude can read the code in those sub-folders. That's it.

```
project-mcp/
  project_mcp.toml        <- one line of config
  projects/               <- you create this
    some-project/         <- project
```

Drop a new folder into `projects/` and it shows up automatically — no config
change needed.

## Setup

```bash
cd project-mcp
python3 -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -e .

mkdir projects                     # your projects live here
cp project_mcp.example.toml project_mcp.toml
```

The default `project_mcp.toml` needs a single line:

```toml
projects_root = "projects"
```

A relative path is resolved next to the config file, so this means "the
`projects/` folder next to this config". Done.

> **MCP version note:** this server pins `mcp>=1.2,<2`. The official SDK is now
> at 2.0, which removed the `from mcp.server.fastmcp import FastMCP` import that
> this server (and research-mcp) use. The pin keeps it working and consistent
> with research-mcp.

## Connect it to Claude Desktop

Add an entry to `claude_desktop_config.json`. Using the venv's Python by
absolute path is the most robust:

```json
{
  "mcpServers": {
    "project-mcp": {
      "command": "/absolute/path/to/project-mcp/.venv/bin/python",
      "args": ["-m", "project_mcp"],
      "env": {
        "PROJECT_MCP_CONFIG": "/absolute/path/to/project-mcp/project_mcp.toml"
      }
    }
  }
}
```

(On Windows use `...\.venv\Scripts\python.exe`.) Restart Claude Desktop;
`project-mcp` then appears next to `research-mcp` in the tool list. A good
first check: ask Claude to run `list_projects`.

## Tools (all read-only)

| Tool | Purpose |
|------|---------|
| `list_projects()` | the projects Claude can see + how many readable files each has |
| `list_files(project)` | readable files in a project (exclusions already applied) |
| `read_code(project, path, max_chars=100000)` | read one file |
| `search_code(query, project=None, max_results=50)` | substring search across readable files |

No writing, no deleting — for "review my code" reading is enough and much
safer.

## Security model

The config **is** the policy, and it is enforced in code — the server cannot
read anything the policy forbids, regardless of what a request says. Two
boundaries are checked, in order:

1. The named project must be visible (either auto-discovered under
   `projects_root`, or on the `include_projects` allow-list if you set one).
2. The file must resolve to a path *inside that project* (containment is
   checked **after** `Path.resolve()`, so `..` segments and symlinks are
   collapsed first and then rejected), must not sit in an excluded directory,
   must have an allowed suffix, and must not match an excluded glob (e.g.
   `.env`, `*secret*`).

By default any folder you place in `projects/` is readable. If you want tighter
control — say you keep NDA/company code around — set `include_projects` to an
explicit allow-list so a project is only visible when you name it on purpose.
Either way, the secret-file exclusions (`.env`, `*.key`, `*secret*`, …) always
apply.

## Tests

```bash
pytest      # 13 tests, focused on path confinement:
            # .. escapes, symlink escape, allow-list, exclusions, suffixes,
            # and auto-discovery
```

## Project structure

```
project-mcp/
  project_mcp.example.toml   config template
  pyproject.toml
  src/project_mcp/
    config.py    load config (projects_root, optional allow-list, exclusions)
    safe_io.py   security core: safe_resolve + read / list / search
    server.py    FastMCP server + the four tools
  tests/test_safe_io.py
```

TDQS

A4.5/5.0

Scored across 4 tools

Disambiguation5/5

Each tool targets a distinct action and resource: listing projects, listing files, reading a file, and searching code. No overlap or ambiguity between them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: list_projects, list_files, read_code, search_code. The style is uniform and predictable.

Tool Count5/5

With 4 tools, the set is well-scoped for a read-only code exploration server. Each tool serves a necessary function and there is no bloat.

Completeness5/5

The toolset covers the full workflow of browsing projects: discover projects, list their files, read file contents, and search across them. No significant gaps for the intended domain.

Maintenance

ActivitySlowing
ResponsivenessNo issues