Knossos-MCP
The labyrinth mapped once, so nobody has to wander it again.
Knossos (Κνωσός) is the Bronze Age palace at the heart of Minoan Crete, a complex so sprawling that Greek myth remembered it as the Labyrinth, the maze Daedalus built for the Minotaur and that no one could navigate without a thread to follow back out. Ariadne handed Theseus that thread.
- PHP
- Rust
- MCP
- Docker
- Claude Code
GitHub (opens in a new tab)README (opens in a new tab)Changelog (opens in a new tab)
What it does
Ask an agent what depends on a class and it reads the source tree again, every session, and tells you what it inferred. Knossos-MCP scans the repository once instead and answers from a graph where every fact carries a file and a line. What static analysis cannot prove is labelled with its confidence rather than quietly guessed at.
Four languages land in the same graph. A Vue component that calls a PHP endpoint, a Python worker that consumes the same endpoint, a Rust binary beside them: they reconcile into one set of nodes and relationships, so a question about impact crosses a language boundary the way the code does.
Scanning never installs dependencies, imports a module, or boots an application framework: workers run supervised, resource-capped, and their output only counts once it passes a schema and limit check. Thirty-three MCP tools cover orientation, projects and history, finding and reading components, structure and impact analysis, and maintenance; only server_info has no CLI equivalent. The four write tools preview by default and only apply once you pass execute explicitly.
Quick start
Knossos-MCP is not yet published to Packagist or any container registry, so build the image yourself from source. The recommended distribution is Docker: it pins PHP, Node, Python, Composer, SQLite, the PHP parser, and the TypeScript compiler, so the scanned project needs none of them. The Rust worker is compiled in a builder stage and copied in as a binary, so the runtime image carries no Rust toolchain either.
docker build -t knossos-mcp:dev .
docker run --rm knossos-mcp:dev doctor --jsonExamples
Two calls, both run for real against Knossos-MCP's own source, abridged with '…'.
Scanning the repository:
$ knossos scan . --json
{"summary":"Scanned 411 files into 5851 nodes and 33284 relationships.",
"data":{"files":411,"nodes":5851,"edges":33284,"diagnostics":0,"mode":"full",
"scanner_metadata":{"knossos.php":{"files_scanned":377},
"knossos.typescript":{"files_scanned":17,"programs":1},
"knossos.python":{"files_scanned":7,"parser":"python.ast"},
"knossos.rust":{"files_scanned":10,"parser":"rust.syn"}},
"metrics":{"elapsed_ms":6494.8, …}}}All four workers contribute to that one scan, and it reports zero diagnostics.
Orienting yourself in the resulting graph:
$ knossos architecture-summary project_1b4f41… --json
{"summary":"Knossos-MCP contains 5851 nodes and 33284 relationships.",
"data":{"node_kinds":[{"kind":"method","count":3979},{"kind":"class","count":437},
{"kind":"external_method","count":407},{"kind":"external_function","count":310},
{"kind":"function","count":297}, …],
"languages":[{"kind":"php","count":377},{"kind":"javascript","count":17},
{"kind":"rust","count":10},{"kind":"python","count":7}]}}Capabilities
| Category | Tools (selection) | What it answers |
|---|---|---|
| Orientation | server_info, diagnose_runtime | Which roots are readable, whether the runtimes are healthy |
| Projects and history | scan_project, list_snapshots, snapshot_diff, quality_gate | Build or refresh the graph, what changed between two scans, whether a change breaches architecture budgets |
| Finding and reading components | find_component, inspect_component, list_usages, architecture_summary | Ranked candidates from a partial name, a component's roles and relations, every usage with evidence |
| Structure and impact analysis | impact_analysis, explain_flow, dependency_cycles, change_impact, test_impact, review_diff | What depends on a symbol, how A reaches B, circular dependencies, the blast radius of a change, which tests it touches |
| Maintenance | annotate_component, remove_project, cleanup_stale_scans, maintain_database | Recording a durable annotation, cleaning up projects, checking database integrity |
| Language | Extraction | Framework enrichment |
|---|---|---|
| PHP 8.3+ | Declarations, inheritance, calls, construction, types, injection | Laravel, Symfony |
| TypeScript/JavaScript | Compiler symbol resolution, imports, calls, types, project references | Next.js, React, Vue, stores, endpoints |
| Python 3.11+ | Standard-library AST in an isolated interpreter; manifests, packages, calls, routes | FastAPI, Django, Flask, Celery |
| Rust 1.82+ | syn parsing; Cargo manifests, cross-file impl blocks, routes. Never invokes cargo or rustc | axum, actix, Rocket |
Rust is the one language that is optional on a native install: without cargo there is no Rust worker, and the container always has one.
impact_analysis and related tools label every conclusion with a confidence: certain, probable, or possible. A relationship the scanner cannot vouch for is dropped instead, which is a deliberate false negative.
Configuration
Knossos-MCP reads knossos.json (or knossos.jsonc) from the scanned project's root. This is Knossos-MCP's own configuration:
{
"$schema": "./schemas/project-config-v1.schema.json",
"version": 1,
"ignores": ["tests/Fixtures"],
"boundaries": [
{ "name": "core", "path_prefix": "src" },
{ "name": "php-worker", "path_prefix": "workers/php" },
{ "name": "typescript-worker", "path_prefix": "workers/typescript" },
{ "name": "python-worker", "path_prefix": "workers/python" },
{ "name": "tooling", "path_prefix": "tools" },
{ "name": "tests", "path_prefix": "tests" }
],
"policies": [
{
"id": "workers-are-out-of-process",
"from_boundary": "php-worker",
"deny_targets": ["core"]
}
],
"quality_budgets": {
"new_cycles": 0,
"boundary_violations": 0,
"error_diagnostics": 0,
"warning_diagnostics": 0,
"hub_degree_growth": 25,
"unreferenced_candidates": 110
}
}boundaries divides the codebase into named regions, policies forbids specific relationships between those regions, and check_architecture tests every change against those policies. quality_budgets sets hard thresholds on regressions such as new circular dependencies or boundary violations, and quality_gate enforces them.
Session orientation for Claude Code
The server answers structural questions whenever an agent thinks to ask one. A separate plugin is what makes it think to ask.
Installing it adds two things to a Claude Code session. A SessionStart hook renders a short brief: a one-line verdict on whether the graph still matches the tree, plus the project's boundary rules and recorded notes. Entry points and hubs come too, on a fresh verdict and nothing else.
The second half is a skill that tells the session which questions to bring back to the graph and which to leave alone. A config key, an error message, a TODO stay with grep, because structure is what the graph indexes. A file you are about to edit stays with Read, because Edit matches the exact bytes. And while the verdict reads stale, no structural question is worth asking at all.
Nothing invokes that skill by name. The brief's closing line is what arms it, which is why that line falls outside the brief's character budget: a brief that fits its budget by dropping the pointer leaves the skill unarmed for the rest of the session.
knossos install-agent-plugin # previews; add --execute to applyThe plugin ships no binary of its own. The hook runs the first knossos it finds in a deliberately short list, KNOSSOS_BIN, then PATH, then three conventional locations, because a long search is a slow session start. When it finds none it exits silently, like every failure path in that hook: one that breaks a session start costs more than the brief was ever worth. A symlink into ~/.local/bin, one of those three, is usually the one step missing.
There is no public marketplace route, on purpose. The descriptor is generated into a directory that stays out of git and is never committed, so claude plugin marketplace add AraneaDev/Knossos-MCP fails with Marketplace file not found. It has to fail there: the clone it would otherwise resolve to has no vendor/, so its own bin/knossos cannot run, and an install that fails silently every time would produce nothing and say nothing about why.