Synapse MCP
A structural code context server that connects your local repository to AI assistants via the Model Context Protocol.
Instead of copy-pasting files into a prompt, Synapse lets your AI assistant dynamically explore your codebase — pulling only the code it needs, when it needs it. The result: less context waste, smarter answers, and a workflow that scales to large projects — with no vector database or embedding API to set up.
AI Assistant ──MCP──► Synapse MCP ──fs/git──► Your Repository
(pulls) (server) (local)Status: Early-stage, actively developed. Contributions and bug reports are welcome — see Contributing.
Why Synapse?
Most AI coding tools already index files. Synapse solves a different problem: context quality at scale.
| Problem | Synapse solution |
|---|---|
| Reading an entire file when you only need its API surface | get_semantic_context with outline_only — signatures only, ≤ 50% of full content |
| AI doesn't know what files exist in an unfamiliar project | get_project_index — full symbol map at ≤ 40% of raw source size, one call |
| "Review my changes" requires pasting the diff manually | get_changed_files — structured git diff, git-aware by default |
| Dependency rabbit holes filling the context window | Configurable depth cap on import traversal |
The compression ratios above are enforced as automated test budgets — not marketing estimates.
Why not vector embeddings?
Most code-context MCP servers use semantic search backed by a vector database (e.g. Milvus, Qdrant) and an embedding API (OpenAI, VoyageAI). That gives them a real capability Synapse doesn't have: finding code by conceptual meaning ("find the authentication logic") rather than by structure or text.
Synapse trades that capability for a different set of properties:
- Zero external dependencies — no API keys, no vector database, no embedding provider to configure
- Zero recurring cost — no per-token embedding charges, no hosted database bill
- Fully local and deterministic — the same input always produces the same output, nothing leaves your machine, nothing to index ahead of time
- Instant on any repo — no indexing step before first use (see Performance: 120–257 ms on real repos)
If you need natural-language semantic search across millions of lines in many languages, a vector-backed server is the better tool. If you want structural context (signatures, dependency graphs, diffs) without standing up infrastructure, Synapse is built for that.
Tools
get_project_index
Returns a compressed semantic map of the entire project: all exported functions, classes, interfaces, types, enums, and top-level constants with their signatures — no bodies. The right first call when exploring an unfamiliar codebase.
# Project Index: my-app (47 files, 312 symbols)
## src/services/user-service.ts
UserService (class) [export]
constructor(db: Database)
findById(id: string): Promise<User | null>
create(data: CreateUserDto): Promise<User>
## src/models/user.ts
User (interface) [export]
id: string
email: string
createdAt: Date
createUser(data: Partial<User>): User [export]Parameters: file_pattern (glob to narrow scope), include_non_exported, output_format ("markdown" default · "json" for structured output)
Use output_format: "json" to get the raw symbol data as a structured object, which is easier to post-process programmatically:
{
"root": "/path/to/project",
"totalFiles": 47,
"totalSymbols": 312,
"files": [
{
"relativePath": "src/services/user-service.ts",
"language": "typescript",
"symbols": [...]
}
]
}Large projects: output grows linearly with the number of exported symbols. For monorepos or projects with 500+ files, use
file_patternto scope the index to one area at a time — e.g."src/services/**/*.ts".
get_semantic_context
Returns a file's content alongside its local dependency graph — everything the AI needs to understand the code in context.
Add outline_only: true to get signatures without implementation bodies. Output is enforced by the benchmark suite to be ≤ 50% of full content length, while preserving full structural understanding.
Parameters: file_path (required), depth (import hops, default: 2), outline_only, output_format ("markdown" default · "json" for structured output)
get_changed_files
Lists files changed since a git ref, grouped by status (Added / Modified / Deleted / Renamed), with optional line counts and full unified diff.
Changed files since `main` (8 files):
**Added (2):**
src/services/payment.ts (+120 −0)
tests/unit/payment.test.ts (+89 −0)
**Modified (5):**
src/models/order.ts (+14 −3)
...
**Summary:** +245 −18 linesParameters: base_ref (default: HEAD~1), include_diff, file_pattern
get_project_tree
Structured view of the repository, respecting .gitignore rules.
Parameters: path, max_depth, show_hidden
search_codebase
Fast text or regex search across the project, returning matches with file paths and line numbers. Uses ripgrep when available, falls back to a pure Node.js scanner.
Parameters: query (required), file_pattern, is_regex, max_results
Language support
Synapse uses ts-morph (TypeScript compiler API) for deep analysis of TypeScript and JavaScript. For other languages, it applies regex-based extraction of function and class names.
| Feature | TypeScript / JS | Python · Go · Rust | Other |
|---|---|---|---|
get_project_tree | ✓ | ✓ | ✓ |
search_codebase | ✓ | ✓ | ✓ |
get_semantic_context — full source | ✓ | ✓ | ✓ |
get_semantic_context — dependency graph | ✓ | — | — |
get_semantic_context outline_only | ✓ full signatures | ✓ names only | — |
get_project_index | ✓ full signatures | ✓ names only | — |
Dependency graph traversal (following import/require chains) is TypeScript/JavaScript only. For all other languages, Synapse still reads and searches files normally — it just won't walk the import graph.
Note: dependency graph traversal follows both relative imports (
./foo,../bar) and path aliases configured viatsconfig.jsoncompilerOptions.paths(e.g.@/components/Foo), as long as atsconfig.jsonis present at the project root. Projects without atsconfig.jsonfall back to relative-only resolution.
Installation
Global install (recommended):
npm install -g synapse-code-mcpRun without installing:
npx synapse-code-mcp --root /path/to/your/projectSetup
Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"synapse": {
"command": "npx",
"args": ["synapse-code-mcp", "--root", "/absolute/path/to/your/project"]
}
}
}Claude Code (CLI)
claude mcp add synapse -- npx synapse-code-mcp --root /path/to/your/projectOr add directly to ~/.claude/settings.json:
{
"mcpServers": {
"synapse": {
"command": "npx",
"args": ["synapse-code-mcp", "--root", "/path/to/your/project"]
}
}
}Cursor
Add to .cursor/mcp.json in your home directory or project root:
{
"mcpServers": {
"synapse": {
"command": "npx",
"args": ["synapse-code-mcp", "--root", "/path/to/your/project"]
}
}
}Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"synapse": {
"command": "npx",
"args": ["synapse-code-mcp", "--root", "/path/to/your/project"]
}
}
}Tip: Replace
/path/to/your/projectwith the absolute path to the repository you want to serve. You can run multiple Synapse instances — one per project — each with a different key undermcpServers.
Configuration
CLI flags
Options:
--root <path> Project root directory (default: cwd)
--max-file-size <bytes> Skip files larger than this (default: 524288 = 512 KB)
--max-search-results <n> Cap on search results returned (default: 50)
--max-tree-depth <n> Maximum directory depth for tree view (default: 5)
--max-dependency-depth <n> Import hops for semantic context (default: 2)
--log-level <level> debug | info | warn | error (default: info)Per-project config file
Drop a synapse.config.json at your project root to override defaults for that project:
{
"maxFileSize": 1048576,
"maxDependencyDepth": 3,
"extraIgnorePatterns": ["*.generated.ts", "**/__mocks__/**"],
"cacheEnabled": true
}cacheEnabled (default true) controls the on-disk incremental index cache (.synapse-cache/index.json) used by get_project_index and get_semantic_context to skip re-parsing unchanged files. Set to false to disable it.
All fields are optional. CLI flags take precedence over synapse.config.json.
Performance
Measured on real open-source TypeScript repositories (single run, --depth 1 clone, no warm cache):
| Repository | Files indexed | Time | Heap growth |
|---|---|---|---|
| zod | 55 | 120 ms | 3 MB |
TypeScript compiler src/ | 247 | 257 ms | 24 MB |
The automated benchmark suite enforces upper bounds on a synthetic fixture (3 000 minimal .ts files) to catch regressions under worst-case conditions:
| Operation | CI budget (synthetic fixture) |
|---|---|
get_project_tree — 3 000 files | 5 s |
get_semantic_context — depth 3 | 10 s |
get_changed_files | 2 s |
get_project_index — 60 files | 30 s |
get_project_index — 600 files | 120 s |
The CI budgets are deliberately generous safety margins, not performance estimates — they exist to catch catastrophic regressions (e.g. an accidental O(n²) bug), not to predict real-world timing. The real-repo numbers above are the meaningful reference for expected performance. For large monorepos (1 000+ files), use file_pattern to scope the index to one area at a time.
Security
Synapse is a read-only server. It never writes to the filesystem or modifies the git repository.
- Path traversal protection — every file read goes through
resolveAndValidate(root, path), which throws aPATH_ESCAPEerror if the resolved path escapes the project root. The AI client receives the error code, never the file contents. - Root scoping — only the directory tree under
--rootis accessible. Paths pointing outside (e.g.../../etc/passwd) are rejected at the validation layer. - File size cap — files larger than
maxFileSize(default 512 KB) are rejected before reading. - Binary detection — compiled artifacts and binary files are detected and skipped automatically.
- No outbound network calls — Synapse communicates only over the local stdio pipe to the MCP client. It makes no H
…