Skip to main content
Glama
README.md
# kalpana-context

**Local code search for AI coding agents, as an MCP server.** Your agent asks a question in plain words or identifiers
and gets back only the 1–3 code chunks that matter. It doesn't have to grep and read whole files.

- **Fewer tokens, more tasks solved.** See the benchmark below.
- **Private.** Indexing, embeddings and search all run on your machine, so your code never leaves it.
- **No API keys.** It uses the open-source MiniLM embedder, downloaded once.
- **Zero setup per project.** It detects the folder you have open and indexes it on first use.

Built on [Miru](https://github.com/takara-ai/miru-code), Takara's open-source hybrid code search (MIT), plus the
**Kalpana Discrete RIF** structural reranker and an adaptive context cutoff.

## Requirements

- **Node.js 18+** (check with `node -v`; get it from https://nodejs.org). Bun is installed automatically.
- macOS, Linux or Windows. Development and testing so far have been on macOS.
- About 200 MB of disk for dependencies and the embedding model, plus the index for each project.
- An MCP-capable agent: Antigravity, Claude Code, Claude Desktop, Cursor, VS Code Copilot, Gemini CLI, and others.

## Quick start (2 minutes)

1. Add the server to your agent's MCP config (see the table below).
2. Restart or refresh your agent's MCP servers. `kalpana-context` should appear with 3 tools.
3. Open a project folder in your editor.
4. Ask your agent: *"Use code_search to find where <something> is implemented."*
5. The first search starts indexing the project in the background. The agent is told to use grep for now. After a
   few minutes searches return in about 1 second.

## Install

Add this to your agent's MCP config:

```json
{
  "mcpServers": {
    "kalpana-context": { "command": "npx", "args": ["-y", "kalpana-context"] }
  }
}
```

| Agent | Where |
|---|---|
| Antigravity | Agent panel → ⋯ → MCP Servers → Manage → View raw config |
| Claude Code | `claude mcp add kalpana-context -- npx -y kalpana-context` |
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Cursor | `~/.cursor/mcp.json` |
| VS Code (Copilot) | `.vscode/mcp.json` (use the key `"servers"`) |
| Gemini CLI | `~/.gemini/settings.json` |

You need Node 18 or newer. Bun is installed automatically as a dependency.

### Check that it works

From a terminal you can talk to the server directly:

```bash
npx -y kalpana-context --project /path/to/your/repo
```

It prints `[kalpana-context] ready ...` on stderr and then waits for MCP messages on stdin. Press Ctrl+C to stop.
In your agent, call `index_status` to see the indexing state and the chunk count.

## Architecture

```mermaid
flowchart LR
  subgraph Agent["Your AI agent (Antigravity, Claude, Cursor, ...)"]
    LLM["LLM (cloud)"]
    Host["Agent app"]
  end
  subgraph Local["Your machine: kalpana-context (one Bun process)"]
    MCP["MCP server (stdio)"]
    Proj["Project detection: tool arg > --project > MCP roots > cwd"]
    Emb["Local MiniLM embedder (ONNX)"]
    Miru["Miru hybrid search: BM25 + vectors"]
    RIF["Kalpana RIF: tree-sitter roles -> HRR tensors"]
    Cut["Adaptive cutoff: 1-3 chunks"]
    Worker["Index worker (child process)"]
    Store[("~/.kalpana-context/indexes")]
  end
  Repo[("Your repository")]

  LLM <--> Host
  Host <-->|"JSON-RPC over stdin/stdout"| MCP
  MCP --> Proj --> Miru
  Miru --> RIF --> Cut --> MCP
  Miru <--> Emb
  RIF <--> Emb
  Worker -->|"first use / reindex"| Store
  Repo --> Worker
  Store --> Miru
  Worker <--> Emb
```

Only the 1–3 returned chunks ever reach the agent, and through it the cloud LLM. The repository, the index and
the embeddings stay on your machine.

### What happens on one search

```mermaid
sequenceDiagram
  participant A as Agent
  participant S as kalpana-context
  participant M as Miru index
  participant K as Kalpana RIF
  A->>S: code_search("where are changesets cast?")
  S->>S: resolve project, re-index changed files if needed
  S->>M: hybrid search (BM25 + MiniLM), top-5
  M-->>S: 5 candidate chunks + scores
  S->>K: tree-sitter (role, identifier) pairs -> tensors -> structural scores
  K-->>S: fused = 0.3 x Miru + 0.7 x Kalpana (min-max normalised)
  S->>S: keep chunk i while fused[i] >= 0.6 x fused[0] (1..3)
  S-->>A: 1-3 chunks with path:start-end and code
```

## How it works

```
agent ──code_search("where are changesets cast?")──▶ kalpana-context
   1. Miru hybrid search (BM25 + MiniLM vectors) → top-5 candidates
   2. Kalpana RIF: tree-sitter (role, identifier) pairs → HRR tensors → structural score, fused with Miru's
   3. Adaptive cutoff: send 1 chunk when the winner is clear, up to 3 when it isn't
agent ◀── 1–3 chunks with file path + line range
```

### Choosing the project

The server picks the project in this order:

1. the `project` argument on a tool call
2. `--project <dir>` or `KALPANA_PROJECT`
3. the workspace folder the agent reports (MCP roots)
4. the current directory

The first search in a new project starts indexing in the background. That takes a few minutes for a medium repo.
After that, changed files are re-indexed incrementally. Indexes are stored in `~/.kalpana-context/`, or wherever
`KALPANA_HOME` points.

### Tools

| Tool | Purpose |
|---|---|
| `code_search(query, project?)` | the 1–3 most relevant chunks |
| `index_status(project?)` | index state, chunk count, progress |
| `reindex(project?)` | rebuild the index from scratch |

### Options

`--mode rifad|rif|miruad|miru` (default `rifad`), `--tau 0.6`, `--alpha 0.7`, `--max 3`

## Evidence (honest version)

**Agent benchmark.** 40 code-localization tasks on Ecto (Elixir, doc comments stripped), agent model
`gemini-3.5-flash-lite`, 12-step cap. Every arm had the same tools except `code_search`.

| Setup | Solved | Tokens / solved task |
|---|---:|---:|
| grep + read only | 42% | 72.7k |
| Miru top-3 | 62% | 56.9k |
| Miru + adaptive cutoff | 65% | 45.1k |
| **Miru + Kalpana RIF + adaptive cutoff (default)** | **70%** | **40.1k** |

- Against grep-only, the default solved 14 tasks the baseline missed and failed 3 the baseline solved (p = 0.013, sign test).
- Most of the token saving comes from search plus the adaptive cutoff. RIF's extra over Miru + cutoff was small
  (6 tasks won, 4 lost) and is not statistically significant on 40 tasks.
- **Retrieval benchmarks** (from the Miru_Discrete_RIF research repo): RIF raised Chunk@3 from 54.8% to 59.8% on
  kubernetes/client-go (500 queries, p = 0.0001).
- **Limits:** one repo, one model, localization tasks only. Tau was tuned on the same corpus.

**Parity.** The TypeScript RIF in this package reproduces the original Python implementation exactly: identical
rankings and adaptive cutoffs on 228 of 228 benchmark queries.

## Troubleshooting

| Symptom | Fix |
|---|---|
| Server not listed or shows as failed in the agent | Check `node -v` is 18+. Run `npx -y kalpana-context` in a terminal to see errors. Restart the agent. |
| "No project folder known" | Your agent doesn't send workspace roots. Pass `project` in the question, or add `"args": ["-y", "kalpana-context", "--project", "/abs/path"]`. |
| "Indexing ... for the first time" | Normal on first use. Big repos can take 10–20 minutes. Check with `index_status`. |
| "refusing to index /Users/you" | The server started in your home folder. Open a specific project or pass `--project`. |
| A new file isn't found | Edits are picked up automatically, but new files are not yet. Call `reindex`. |
| First search slow on a fresh install | The embedding model downloads once, about 90 MB. |
| `could not start Bun` | Install Bun (https://bun.sh), or reinstall so the `bun` dependency downloads. |

## Run from source

```bash
git clone https://github.com/maduperera/Kalpana_MCP && cd Kalpana_MCP
npm install
node bin/kalpana-context.mjs --project /path/to/repo           # run the server
node test/smoke.mjs /path/to/repo "what you are looking for"   # end-to-end test as an MCP client
```

In an agent config, point `command` at `node` and `args` at the absolute path of `bin/kalpana-context.mjs`.

## Uninstall

Remove the `kalpana-context` entry from your agent's MCP config and delete `~/.kalpana-context/` (the indexes).

## Credits and licence

MIT © Madusha Perera. Miru is © Takara (MIT) and is used unmodified as a dependency; see [NOTICE.md](NOTICE.md).
This project is not affiliated with Takara and does not use Takara's DS1 model or API.