codenav-mcp
An MCP server that gives AI agents type-resolved Python navigation, backed by ty's language server. Definitions, references and call sites go through real type inference (imports, dependency-injected parameters, dataclass fields), not text grep.
The same resolution powers its edits: rename a symbol, change a signature, or move a function or module, and every usage follows, including overriding methods and injected dependencies. Edits are type-checked and previewable before they are written, and can be undone.
Quick start
ty is installed with the package, so all you need is
uv (or pipx):
uvx codenav-mcp
Register it with your MCP host. For Claude Code, from the project root:
claude mcp add codenav -- uvx codenav-mcp
Or add it to a project .mcp.json (Claude Code) or .cursor/mcp.json (Cursor):
{
"mcpServers": {
"codenav": {
"command": "uvx",
"args": ["codenav-mcp"],
"env": {
"CODENAV_MCP_SOURCE_ROOT": "src"
}
}
}
}
In Cursor, also set "CODENAV_MCP_WORKSPACE": "${workspaceFolder}", because
Cursor may start MCP servers with your home directory as the working directory.
Tools
Start with the name-based tools:
| Tool | Answers |
|---|---|
symbol_info |
What is this? Header, hover, definition and references in one call |
outline |
What's in this file? (classes, methods, functions) |
callers |
Who actually calls this function? (call hierarchy, not imports) |
implementations |
Which classes structurally implement this Protocol? (type-checked) |
search_symbol |
Workspace symbol search by name (ranked, capped; optional kind= / path= filters; production code before tests; fuzzy-only hits summarised unless fuzzy=true) |
workspace |
Which directory is being navigated, and why |
Then use the position tools once you have a path:line:col:
| Tool | Answers |
|---|---|
hover |
Type and docs at a position |
definition |
Go to definition (resolves through injected parameters) |
references |
All usages across the workspace |
diagnostics |
ty type-check diagnostics for one file |
name and query are accepted as aliases on the name-based tools
(port_name / name / query on implementations). A missing or wrong
parameter gets a short hint back instead of a validation error. Dotted names
may nest (Outer.Inner.method). implementations also takes file_path to
pick one port when the name exists in several files, and counts inherited
members and dataclass/self.x fields toward a port's required names.
Write tools: change code with a type check before every write
The navigation tools above are read-only. These change code, and share one rule: the edit is applied to in-memory copies first, ty re-checks the edited files and the files importing them, and the response says which diagnostics the edit would add or fix. Nothing is written until that is on the table.
| Tool | Does |
|---|---|
edit |
Type-checked text edit of a Python file: old_string/new_string or a whole new_text. For anything that is not a whole definition |
edit_symbol |
action="replace" / "insert" / "delete" a function, method or class by name: re-indented to the file's style, PEP 8 spacing, imports=[...] added, syntax-checked. Delete refuses while anything uses the symbol and prunes now-dead imports |
rename_symbol |
Rename across the workspace (imports, aliases, keyword arguments, parameter= for a function's parameter). Also renames what ty's rename misses: overriding methods, super().name() calls, and Protocol members together with the classes that satisfy them (linked=false to opt out). Lists remaining mentions of the old name (untyped accesses, strings, comments, docs; other worktrees are skipped) |
change_signature |
Add / remove / reorder parameters and rewrite every call site (found through ty's references, so injected dependencies and typed attributes work). Overrides follow. *args calls and uses as a value are listed as manual work |
move |
With name: move a module-level function or class to another file with the imports it needs; without it, move or rename the module file_path. Rewrites imports everywhere, drops imports only the moved code used, warns about import cycles |
quick_fix |
Apply ty's own fixes (missing imports) with correct placement; ambiguous fixes are listed instead of guessed |
verify_changes |
After editing with any tool: which type errors the working tree gained or lost since a git revision (default HEAD) |
apply_edit / undo_edit |
Write a previewed edit by id; revert an applied one |
One rule for every write tool: it writes when the edit adds no more than max_new_errors
(default 0) type errors in the edited files and their importers. Otherwise nothing is
written and you get the diagnostics plus an id for apply_edit. apply=false always
previews. Hint-level diagnostics (unused, deprecated) are not counted.
Safety rules, enforced in code:
- Only
.py/.pyifiles inside the workspace are written; virtualenvs,site-packages, typeshed and symlinks that leave the workspace are refused. - A preview remembers the exact bytes of every file;
apply_editrefuses if any file changed since. Files are replaced atomically, and a failure part-way restores the ones already written. - Every applied edit is undoable (
undo_edit) unless the files were changed after it. - Output is never written if it is not valid Python.
- Edits touching more than 40 files need
allow_large=true. CODENAV_MCP_READ_ONLY=1turns every write into a refusal (previews still work).
New files an edit would create are written to disk for the few moments of the type check (ty finds modules through the file system) and removed again, even on errors.
Positions are 1-indexed. column is a UTF-16 character offset (a leading
tab counts as one character).
Python only (.py / .pyi).
Which ty runs
- The project's own
.venv/bin/ty(.venv\Scripts\ty.exeon Windows), so the ty version matches the project's pin and config. - The
tyinstalled alongside codenav-mcp. tyonPATH.uvx ty serveras a last resort.
Environment
| Variable | Default | Purpose |
|---|---|---|
CODENAV_MCP_WORKSPACE |
unset: follows the client's MCP roots when they name a worktree of the same git repository, else CLAUDE_PROJECT_DIR, else the working directory |
Pins the project root (never overridden). See the workspace tool |
CODENAV_MCP_SOURCE_ROOT |
whole workspace | Directory scanned for implementations candidates and used to derive dotted import paths (e.g. src) |
CODENAV_MCP_READ_ONLY |
unset | 1/true: write tools refuse to write (previews and checks still work) |
CODENAV_MCP_EXTRA_SOURCE_ROOTS |
none | Comma-separated directories (e.g. tests) that implementations also scans; matches (test doubles) are listed under a separate heading |
Requirements
- Python ≥ 3.11
- Installed automatically:
mcp,ty,ruff(sorts imports in files a move touched, only where they were already sorted),mcp-nav-shared
Related
webnav-mcp: the same kind of navigation for JS/TS/HTML/CSS.- Design notes (Protocol conformance probe, positioning, output formats): docs/agent-tooling.md.
Development
Source: github.com/illescasDaniel/codenav-mcp. From a
checkout: uv sync --group dev, then uv run codenav-mcp.
License
MIT. See LICENSE.
Metadata
Release files for codenav-mcp 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| codenav_mcp-0.2.1.tar.gz | 65.1 kB | Without provenance | Details for codenav_mcp-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| codenav_mcp-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for codenav_mcp-0.2.1-py3-none-any.whl |
Total release size: 141.7 kB
Security for codenav-mcp 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.