Lodesman
Compiler-grade code intelligence over MCP. Lodesman puts a real language server behind your coding agent's tools, so "who calls this?" is answered by the compiler rather than by a text search.
A lodesman is the pilot who comes aboard and steers a ship through waters the captain doesn't know. That is the job: an agent dropped into an unfamiliar repository, guided by something with local knowledge.
Status: alpha. The tool surface is still growing and not every tool is finished. If you hit something broken, an issue is genuinely useful — see Status.
Why
An agent's dominant cost is reading files into context, and a tool that returns
coordinates makes that worse, not better — Program.cs — L135 forces the
agent to read the file anyway.
Measured on a real C# repository, answering "what uses RagQueryService":
| approach | cost |
|---|---|
| read the three files involved | 1745 lines, ~17.7k tokens |
| the 3 references, with ±6 lines of code each | ~36 lines, ~370 tokens |
~48× cheaper, and it is a better answer. So Lodesman's tools return code, not locations. A location is a promise of future cost; the code is the answer.
The second reason is correctness. An agent cannot tell a true "no results" from a broken query, so a plausible empty answer is the most dangerous thing a navigation tool can produce. Lodesman gates every answer on the language server actually being ready, and distinguishes "none" from "couldn't tell".
Install
Requires Python 3.11+.
uvx lodesman-mcp # run without installing
pipx install lodesman-mcp # or install it
Wire it into Claude Code
claude mcp add lodesman --scope user -- uvx lodesman-mcp
Or, for any MCP client, in the config directly:
{
"mcpServers": {
"lodesman": {
"command": "uvx",
"args": ["lodesman-mcp"]
}
}
}
With no arguments Lodesman binds to the working directory it is launched in, which is what MCP clients give it. One user-scoped entry therefore works across every project — no per-project configuration.
To point it somewhere explicitly:
lodesman-mcp /path/to/repo --language csharp
First run
The language server itself is downloaded on first use into ~/.solidlsp
(override with SOLIDLSP_HOME). For C# this pulls Roslyn from NuGet and can
take several minutes. Later runs reuse it and start in seconds.
The server process starts immediately; the language server behind it starts lazily on the first tool call and is then kept warm for the life of the process. That is the whole design: a cold Roslyn costs minutes, a warm one answers in milliseconds and tracks your edits incrementally.
Verify your install
python scripts/smoke_test.py /path/to/repo --language csharp
This starts a real language server against a real repository and proves it answers the two questions everything else is built on — what symbols are in this file, and who references this symbol — with cross-file results the compiler agrees with.
Tools
| tool | what it answers |
|---|---|
project_info |
which repository this server bound to, and how |
find_symbol |
find a symbol by name anywhere in the project |
find_definition |
where is this defined |
find_references |
what actually uses this, with the surrounding code |
find_implementations |
concrete implementations of an interface or abstract member |
document_symbols |
outline one file: its types, methods and fields |
get_symbol_body |
the full source of one declaration, by name |
explain_symbol |
resolved type, signature and documentation |
blast_radius |
what breaks if this symbol changes |
rename_symbol |
rename everywhere, using the compiler's understanding |
check |
compiler diagnostics for one file, from the warm server |
blast_radius and check are the two that exist specifically because agents
edit code they haven't read: one tells you the cost of a change before you make
it, the other verifies it afterwards without a full build.
rename_symbol is a dry run by default and lists every file it would touch.
Pass apply=true to write; it reports how many files actually changed on disk.
Tools depend on what the language server behind them implements. pyright, for
instance, does not serve textDocument/implementation, so find_implementations
reports that rather than pretending the answer is "none" — a distinction that
matters more to an agent than to a person.
How it binds to a project
One server process serves one repository, chosen at startup: the path you pass, or the working directory if you pass nothing.
The language is detected by counting source files under that root and taking the
majority. Pass --language when that guess is wrong — a repo with a TypeScript
frontend and a C# backend has to be told which one you mean:
lodesman-mcp . --language typescript
Status
Alpha. The tool surface is still growing, and not every tool is finished.
Lodesman inherits SolidLSP's language coverage, and runs wherever its language servers do. Not every language and platform combination has been exercised yet, so if you try one and it breaks, please open an issue — a report with the language, the OS and the stderr output is the most useful thing you can send. Testing help is very welcome.
Known issues
None currently open.
Fixed in 0.3.1:
rename_symbol(apply=true)reported success while writing nothing to disk. It now writes, preserves CRLF line endings, handles UTF-16 column offsets, and reports the number of files whose bytes actually changed.- Language detection descended into dot-directories, so starting a server in a
home directory could bind it to a "project" made of
.cacheand.local. - Pointing the server at a directory with no recognized source files produced an unhandled traceback, which an MCP client renders as "failed to connect".
- Tools taking a
fileargument did not verify the path stayed inside the repository. - The per-project cache key was case-folded on every platform, so on a case-sensitive filesystem two distinct repositories could share one cache.
Development
git clone https://github.com/florpan/lodesman
cd lodesman
python -m unittest discover tests # fast, no language server needed
python scripts/smoke_test.py <repo> --language csharp
Built on SolidLSP
The language-server client layer is SolidLSP,
MIT, vendored unmodified under src/lodesman/_vendor/. It is bundled rather
than depended on because it is not published to PyPI independently of the Serena
application, which is GPL and is not included here.
Everything Lodesman does lives outside that tree — the project anchoring, the readiness gate, the cross-file indexing wait, symbol ranking, and the decision to return code instead of coordinates were all solved by calling SolidLSP differently, never by editing it. That rule is what keeps re-syncing with upstream cheap.
See NOTICE.md for full attribution.
License
MIT — see LICENSE.
Bundled third-party code, its copyright holders and its license texts are listed in NOTICE.md. Everything bundled is MIT-licensed.
Release files for lodesman-mcp 0.3.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 | |
|---|---|---|---|
| lodesman_mcp-0.3.1.tar.gz | 427.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lodesman_mcp-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 971.9 kB
Release files / lodesman_mcp-0.3.1.tar.gz
| Download URL | lodesman_mcp-0.3.1.tar.gz |
|---|---|
| Size | 427.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2de871122b0a7af211d2c37083803c9b63a736a2cfa0200433facf518f3b7669
|
|
BLAKE2b-256 checksum How to use checksums |
e1fe225ba279b43a67d757f670f0820385ce4620ba95eb5922deaa7bd3fcde82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / lodesman_mcp-0.3.1-py3-none-any.whl
| Download URL | lodesman_mcp-0.3.1-py3-none-any.whl |
|---|---|
| Size | 544.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d47483df8c31d48405908fe86dfe22f5ae01ed7ab8844f057ff8336ae90bdbdf
|
|
BLAKE2b-256 checksum How to use checksums |
05df5c499907c41db464af9b91994ec20952020c1a60a298c4ffe0326d1333af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|