Split
MCP server: fn-level code index with bidirectional sync
Ask AI about Split
Powered by Claude Β· Grounded in docs
I know everything about Split. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
split |
MCP server that indexes source files at the function level.
Instead of loading entire files into context, you load one function at a time. Instead of grepping files, you search across 3000+ indexed functions in a single call.
π‘ Why
Every time an AI reads a source file, it loads the entire thing β imports, structs, every function β even if you only need one. This wastes context window on code that isn't relevant to the task.
split fixes this by pre-indexing each source file into per-function body files under .split/. The AI loads a function map (cheap), picks what it needs, reads only that (cheap), then edits the original source file with normal tools. The watcher re-splits whenever the source changes.
Source = truth. .split/ = derived cache. One-way sync. Blow it away anytime; it rebuilds from source.
β‘ Token savings
| Operation | Without split | With split |
|---|---|---|
| Explore a large file | ~2700 tokens | ~140 tokens |
| Cross-codebase symbol search | ~5000 tokens | ~50 tokens |
βοΈ How it works
src/config/parser.rs β .split/src/config/parser.skel.rs (structure)
.split/src/config/parser/parse.fs
.split/src/config/parser/validate.fs
.split/src/config/parser/load_file.fs
data/schema.json β .split/data/schema.skel.json (structure)
.split/data/schema/_body.fs
- Skeleton = imports, struct definitions, fn signatures with
// Β§refplaceholders - Body files = one
.fsfile per function. First line carries the source path + line range, e.g.// Β§head src/config/parser.rs:42-89 parseβ jump straight from body to source line. - Watcher = one-way: source change β re-split.
.fsfiles are read-only for agents; edit the source instead.
π οΈ Tools
| Tool | What it does |
|---|---|
index_dir | π Bootstrap: split all files in a directory tree |
open_source | π Open a file: auto-splits on first access, returns fn list sorted by size |
read_body | π Load one function body |
search_bodies | π Grep across all indexed functions |
list_bodies | π List functions in a directory, sorted by size |
find_large | β οΈ Find functions exceeding SPLIT_MAX_LOC lines |
list_languages | π List installed languages (extensions with fn-level support) |
πΏ Install
Terminal
claude marketplace add yesitsfebreeze/split
claude plugin install split@yesitsfebreeze
Inside Claude
/plugin marketplace add yesitsfebreeze/split
/plugin install split@yesitsfebreeze
Done. MCP server + skill installed automatically.
ποΈ Building
Requires Rust and the WASM target:
rustup target add wasm32-wasip1
cargo install --git https://github.com/yesitsfebreeze/split
Then wire it up manually. Add to .mcp.json:
{
"mcpServers": {
"split": {
"command": "split",
"env": {
"SPLIT_EXT": "rs",
"SPLIT_SRC_DIR": "src",
"SPLIT_INDEX_DIR": ".split",
"SPLIT_MAX_LOC": "256"
}
}
}
}
Bootstrap the index once:
index_dir(src_dir="src", index_dir=".split")
Add to .gitignore:
.split/
Optional: drop a split.ini in the project root instead of env vars β safe to commit.
π§ Configuration
Place a split.ini in your project root. Safe to commit β no secrets.
SPLIT_EXT = rs
SPLIT_SRC_DIR = src
SPLIT_INDEX_DIR = .split
SPLIT_DEBOUNCE_MS = 500
SPLIT_MAX_LOC = 256
Priority: env vars > split.ini > hardcoded defaults.
π Languages
split has a WASM language system. Each language is a .wasm module that teaches the parser how to decompose a given file extension.
Language modules live in:
.split/languages/{ext}.wasmβ project-level~/.config/split/languages/{ext}.wasmβ user-level- embedded β built-in (
rs,py)
Resolution: project > user > builtin.
Use the list_languages MCP tool to see what is installed in the current environment.
Any language that compiles to wasm32-wasip1 can be a language module. Export:
wasm_alloc(size: i32) -> i32
language_split(ptr: i32, len: i32) -> i32
language_result_ptr() -> i32
language_meta_ptr() -> i32
language_meta_len() -> i32
π§± Built-in languages
Each language declares its own comment marker and produces a .skel.<ext> skeleton matching the source extension.
| Language | Ext | Comment | Extracts |
|---|---|---|---|
rs | .rs | // | fn items (free + impl methods) |
py | .py | # | def / async def + class methods (qualified Class.method) |
Any other extension β whole file stored as one body. Index + search + watch still work; just no fn-level decomposition. Drop a .wasm module into .split/languages/{ext}.wasm to add fn-level support for any language.
