🌐 Language: English | Русский
Local stdio MCP that gives Claude Code semantic search over one or more C# codebases. Spawns
CodeIndex.Server.dll under your .NET 10 runtime; embeddings are computed by your local
Ollama instance (qwen3-embedding:4b) — no maintainer-owned server in the path, no code ever
leaves your machine except to localhost:11434.
Four tools: code_search, code_get_chunk, code_index_status, code_reindex. Full parameter
documentation and usage guidance lives in the bundled skill, code-search — read
skills/code-search/SKILL.md or just ask Claude to search your
code once the plugin is installed.
Unlike a plugin that talks to a public server, this one has real local prerequisites — the launcher checks all of them before starting the server and tells you exactly what's missing (see Troubleshooting below):
- .NET 10 runtime on PATH (
dotnet --list-runtimesshows aMicrosoft.NETCore.App 10.xline). Install: https://dotnet.microsoft.com/download/dotnet/10.0. - Ollama, running locally (
ollama serve). - The
qwen3-embedding:4bmodel pulled (ollama pull qwen3-embedding:4b, ~2.5 GB one-time download, ~10 GB of VRAM resident while it runs). If that doesn't fit your GPU,Embeddingis configurable (see Configuration below) — the repository README's model comparison measures four lighter alternatives on the same benchmark, including one (all-minilm) that costs under 30 MB of VRAM, so you can pick with numbers instead of guessing. - At least one project configured — see Configuration below. There is no usable default here: project paths are only known to you.
/plugin marketplace add StaticBit-io/code-index-mcp
/plugin install code-index@code-index-mcp
(Or, for a local checkout: /plugin marketplace add /path/to/code-index-mcp.)
Create ~/.code-index-mcp/config.json (Windows: %USERPROFILE%\.code-index-mcp\config.json)
with the project(s) you want indexed:
{
"CodeIndex": {
"Projects": [
{ "Id": "myproject", "Root": "/path/to/MyProject" }
]
}
}This is the same shape as the server's own CodeIndex/Embedding configuration (see the
repository README) — Id is the cache key, Root is the absolute path
to the repository, and an optional Extensions list narrows or widens which files get indexed
per project. Add more entries to index several repositories from one server:
{
"CodeIndex": {
"Projects": [
{ "Id": "myproject", "Root": "/path/to/MyProject" },
{ "Id": "otherproject", "Root": "/path/to/OtherProject", "Extensions": [".cs"] }
]
},
"Embedding": {
"Endpoint": "http://localhost:11434",
"Model": "qwen3-embedding:4b"
}
}Embedding is optional — omit it to use the defaults above.
Expressing several projects purely through environment variables means one clunky, indexed variable per field:
CODEINDEX_CodeIndex__Projects__0__Id=myproject
CODEINDEX_CodeIndex__Projects__0__Root=/path/to/MyProject— and Claude Code does not forward arbitrary host environment variables into a plugin's
subprocess; only the variables a plugin's .mcp.json explicitly declares are passed through (see
env in .mcp.json). A dynamic, unbounded list like "one project per index" can't
be declared that way. A config file the launcher reads directly has no such limit and is the only
practical way to configure more than one project. It also means your local repository paths never
need to touch .mcp.json, an environment variable, or anything else Claude Code stores.
Three settings are declared in .mcp.json and can be overridden per the normal environment
rules of your OS/shell — CODEINDEX_CONFIG_FILE (point at a different config file location),
CODEINDEX_Embedding__Endpoint, and CODEINDEX_Embedding__Model. For every setting, an
environment variable already present when Claude Code launches the server wins over the same key
in the config file; the config file fills in anything not already set that way. In practice: use
the file for Projects (the part env vars are clumsy for), and env vars only if you specifically
need to override the Ollama endpoint or model without editing the file.
Restart Claude Code (or just retry your search) after creating or editing the config file.
The very first time code_search (or code_reindex) runs against a project, there is no index
yet — every file has to be chunked and embedded from scratch. For a project of a few hundred
files this is several minutes, not a hang. code_index_status reports progress-relevant
numbers (file/chunk counts, last build time) once it completes; subsequent searches refresh
incrementally and are fast (sub-second to a few seconds). If Claude appears to sit quietly after
your first search on a freshly configured project, that is the index being built — let it finish
rather than assuming something is stuck.
/mcp
Should show code-index: connected, 4 tools. Then try:
Search this codebase for where trustline deletion is validated.
The agent will pick mcp__plugin_code-index_code-index__code_search.
The launcher (bin/server.js) checks the following before the server ever starts, and prints one
of these to stderr instead of a stack trace or a silent hang:
No project configured:
[code-index] No project is configured — there is nothing to search yet.
[code-index] Create <path>\.code-index-mcp\config.json with at least one project:
{
"CodeIndex": {
"Projects": [
{ "Id": "myproject", "Root": "C:\\path\\to\\MyProject" }
]
}
}
[code-index] Then restart Claude Code so the server picks up the new configuration.
Ollama not running:
[code-index] Cannot reach Ollama at http://localhost:11434.
[code-index] code-index-mcp needs Ollama running locally to compute embeddings.
[code-index] Start it with:
ollama serve
[code-index] Then ask your question again.
Model not pulled:
[code-index] Ollama is running, but model 'qwen3-embedding:4b' is not pulled yet.
[code-index] Pull it (about 2.5 GB, one-time download):
ollama pull qwen3-embedding:4b
[code-index] Then ask your question again.
.NET 10 runtime missing produces a similar message naming dotnet --list-runtimes and the
download link.
If the server actually starts but a later embedding call fails (e.g. Ollama was stopped mid
session), code_search degrades instead of erroring outright — see "The warning field" in the
skill for what a stale-index warning means and why the hits are still usable.
The plugin repository does not carry the published server build — it's a ~14 MB, mostly
binary artifact that doesn't delta-compress in git, so committing it on every release would grow
the repository forever. Instead bin/server.js fetches it from a
GitHub Release on first use and caches
it locally:
- The launcher reads
serverVersionfrom the plugin's own manifest (.claude-plugin/plugin.json— a field separate from the plugin's ownversion, since a docs/skill-only plugin release shouldn't force a redundant server re-download). - If
~/.code-index-mcp/server/<version>/already contains a verified install, it runs immediately — no network access at all. - Otherwise it downloads
code-index-server-<version>.tar.gzfrom the matchingserver-v<version>release, checks its SHA-256 againstbin/server.sha256(committed in this repository — the repo is the trust anchor, so verification never depends on anything fetched over the network), extracts it, and only then runs it. A checksum mismatch is refused outright, never run.
You'll see progress on stderr the first time a version downloads:
[code-index] Server v0.2.2 not found in local cache — downloading from GitHub Releases (~14 MB, one-time)...
[code-index] Downloaded 14.1 MB / 14.1 MB (100%)
[code-index] Verifying checksum...
[code-index] Checksum OK — extracting...
[code-index] Server v0.2.2 installed at C:\Users\you\.code-index-mcp\server\0.2.2\
After that, every subsequent launch (any project, any session) reuses the cached install with no
network involved, until serverVersion changes.
Building on a different server version locally? Set CODEINDEX_SERVER_DIR to a published
CodeIndex.Server build directory (e.g. the output of
dotnet publish src/CodeIndex.Server -c Release -o some/dir from a checkout of the
repository) and the launcher will run that directly — no download, no checksum check.
This is a development escape hatch, not something to set for normal use.
No network reachable, nothing cached yet:
[code-index] Server v0.2.2 is not installed yet, and GitHub could not be reached to download it.
[code-index] Network error: <underlying error>
[code-index] Check your internet connection and try again. If you are offline, download the release
[code-index] manually and extract it into the folder below:
https://github.com/StaticBit-io/code-index-mcp/releases/download/server-v0.2.2/code-index-server-0.2.2.tar.gz
C:\Users\you\.code-index-mcp\server\0.2.2\
[code-index] Then ask your question again — the launcher will find it there and skip the download.
Checksum mismatch (corrupted download or compromised asset) — never run:
[code-index] Downloaded server v0.2.2 but its checksum does not match — refusing to run it.
[code-index] expected: <64-char sha256>
[code-index] actual: <64-char sha256>
[code-index] This usually means a corrupted download or a compromised release asset. The file was
[code-index] not installed. Try again; if this keeps happening, please report it:
https://github.com/StaticBit-io/code-index-mcp/issues
Release asset not published for this plugin version:
[code-index] No GitHub release found for server v0.2.2 (tag server-v0.2.2).
[code-index] This plugin build expects a matching server release that is not published — check
[code-index] https://github.com/StaticBit-io/code-index-mcp/releases
[code-index] for available versions, or download it manually once published:
https://github.com/StaticBit-io/code-index-mcp/releases/download/server-v0.2.2/code-index-server-0.2.2.tar.gz
Private repository, no credentials available (this repository is private today; the same code path works unchanged, with no token needed, if it ever becomes public):
[code-index] GitHub returned 401 while requesting the server v0.2.2 release.
[code-index] This repository is private and needs authentication to download release assets.
[code-index] Provide a token with 'repo' scope one of these ways:
[code-index] - set CODEINDEX_GITHUB_TOKEN (or GH_TOKEN / GITHUB_TOKEN) in your environment, or
[code-index] - authenticate the GitHub CLI (`gh auth login`) — the launcher borrows its token automatically
[code-index] Or download the asset manually with your browser and extract it into:
C:\Users\you\.code-index-mcp\server\0.2.2\
https://github.com/StaticBit-io/code-index-mcp/releases/download/server-v0.2.2/code-index-server-0.2.2.tar.gz
Two Claude Code windows starting at once each download and extract into their own uniquely-named
temp directory under ~/.code-index-mcp/server/, then atomically rename it onto the final,
version-named path. Whichever finishes first wins; the other detects the now-valid install and
just uses it instead of failing or double-writing. A launcher killed mid-download only ever leaves
debris in its own temp directory — never at the path other launchers check — so a partial file is
never mistaken for a good one.
The published build is a portable, framework-dependent publish of CodeIndex.Server — no
native/AOT dependencies anywhere in its dependency graph (pure managed code: Roslyn,
System.Numerics.Tensors, no SQLite or other native interop), so the same build runs under
dotnet CodeIndex.Server.dll on any OS with a matching .NET 10 runtime. It's built by CI
(.github/workflows/release-server.yml) on ubuntu-latest with
-p:SatelliteResourceLanguages=en, so it doesn't carry the build machine's fingerprint the way a
build done on a developer's own Windows machine would (locale-specific Roslyn satellite
assemblies, in particular).
- Nothing leaves your machine except outbound HTTP to your own Ollama instance (
localhost:11434by default), disk I/O under the project roots you configured and the on-disk index cache (%LocalAppData%/code-index-mcp/<Id>by default), and — only the first time a given plugin version runs, and only until its server build is cached — outbound HTTPS toapi.github.com(release metadata and, for small assets, the download itself) andobjects.githubusercontent.com(the pre-signed storage URLapi.github.comredirects to for the actual asset download; seedownloadAssetBufferinbin/server.js) to fetch that build. No project code or search query is ever part of that request; see How the server binary is fetched. - The server process lives only as long as Claude Code keeps the stdio pipe open — terminates with the client.