# Codebase MCP: Symbol Navigation in octofs 0.25.1

> A codebase MCP should answer definitions, references, callers and paths. octofs 0.25.1 answers those queries without a persistent index.

A codebase MCP is useful when it can answer a question like “what calls this function?” without asking you to paste half the repository. On November 15, 2026, octofs 0.25.0 added a `symbol` tool for definitions, references and code relationships, and 0.25.1 followed the same day with a call-graph fix. The Octomind tap registry now uses octofs by default for structural and graph code search. I build Octomind, octofs and octocode, so these are first-party measurements.

**The short answer:** use symbol navigation for exact questions about names and relationships, and semantic search when you need to find code by what it does. In one run across six tasks in the tokio and cargo repositories, octofs returned 7,662 response tokens over 15 calls; octocode returned 15,919 over 22 calls. That sample has a shared miss and unverified type results, so treat it as a cost comparison, not an accuracy verdict. If you need to choose, compare the questions answered, definition tokens, calls and first-call setup for your own repository.

## What should a codebase MCP answer?

A codebase MCP server should let an agent move from a symbol to the code around it: its definition, references, callers, callees, imports and a path to another symbol. These questions are different from searching for a concept such as “where do we retry failed requests?”

A useful first evaluation is to ask the same concrete questions of any server:

| Question                       | Capability to look for | What to inspect                              |
| ------------------------------ | ---------------------- | -------------------------------------------- |
| Where is `compile_ws` defined? | Definition lookup      | Exact match or bounded preview               |
| What uses it?                  | References             | Grouping, omissions and pagination           |
| Who calls it?                  | Call graph             | Whether uncertain edges are marked           |
| How does A reach B?            | Path query             | Depth and truncation notices                 |
| Where is the retry policy?     | Semantic search        | Whether meaning-based retrieval is available |

A code index MCP or a [code graph MCP](/product/octocode) is easier to evaluate on the same questions: whether indexing is a required setup step, whether data persists, what gets refreshed after edits and whether search is exact or semantic. “No index” alone does not mean “no first-query work.”

## What changed in octofs 0.25.1?

The `symbol` tool arrived in 0.25.0 and answers nine relation types: `definition`, `references`, `callers`, `callees`, `supertypes`, `subtypes`, `imports`, `imported_by` and `path`. It returns exact definitions up to 32 lines in full, groups references by enclosing symbol, and lists graph results one hop per line. 0.25.1 changes one thing: call graphs now resolve calls written with a qualified path, which 0.25.0 missed. See the [octofs code exploration guide](https://github.com/muvon/octofs/blob/master/doc/code-exploration.md) for the full parameter list and answer shapes.

The tap registry now routes structural search and call-graph requests to octofs by default. An existing Octomind install gets the new default when its copy of the tap updates. Semantic search continues to use octocode, and octocode 0.29.2 remains selectable. Octomind’s tap can also select octocode for either capability:

```toml
[capabilities]
codesearch-structural = "octocode"
codesearch-graph = "octocode"
```

My view: simple tools win with today’s models. They have learned to explore code with exact search, and they do it well. Semantic search adds less for an agent than I expected; the step agents lacked was symbol navigation that needs no setup. Cursor ended up in the same place: in July 2026 its staff [wrote](https://forum.cursor.com/t/what-do-you-think-about-cursor-removing-the-codebase-indexing-settings/165899/10) that “Semantic/embeddings indexing is being turned down in favor of grep-based retrieval.” An embedding index has to be built before the first semantic query (`octocode index`), so it stays off until someone sets it up, and I find it helps a person exploring an unfamiliar codebase more than it helps an agent. octocode stays the semantic search provider and a good tool for people who use its CLI. This is my opinion from building and using both; I have not run an experiment comparing agent outcomes. If you want the setup context, see [why we built octofs](/blog/why-we-built-octofs) and the [octofs product page](/product/octofs).

## How many tokens and calls did the same questions take?

The table is one run, six tasks, on November 15, 2026, across tokio commit `ab0814f` and cargo commit `382ecb8`, using an octofs build of the 0.25.0 source made before the version bump (it prints 0.24.0), octocode 0.29.0 and `o200k_base` from tiktoken 0.14.0. The octofs answers were captured on a 12-core Linux box and rerun on an Apple M5 laptop with 10 cores, where every answer came back byte-identical; octocode ran on that laptop against copies without `.git`, using `--no-git`.

The totals combine outline, definition, references, callers, type relations and path queries. They leave out the one extra `graphrag` call that builds octocode’s graph (107 response tokens on tokio, 109 on cargo).

| Repository | Tool         |  Calls | Response tokens |
| ---------- | ------------ | -----: | --------------: |
| tokio      | octofs       |      8 |           6,561 |
| tokio      | octocode     |     12 |          11,093 |
| cargo      | octofs       |      7 |           1,101 |
| cargo      | octocode     |     10 |           4,826 |
| **Both**   | **octofs**   | **15** |       **7,662** |
| **Both**   | **octocode** | **22** |      **15,919** |

These are response tokens summed across tool calls, not model input or full session cost. Query selection and output settings affect the totals.

The octofs tokio caller query needed a second, path-narrowed call after it found 12 definitions; octocode references needed two pagination calls. Neither tool found the real callers of tokio’s free `spawn_blocking` function through a path-qualified call over a re-export; octofs 0.25.1 fixes that miss (see the limits below). The `Spawner` and `Workspace` type-relation results were not verified by hand.

octofs answered “how does `spawn_blocking_inner` reach `spawn_thread`?” in one call and 96 tokens. With octocode the same question took three calls and 578 tokens: two `graphrag` searches to resolve node ids, each returning up to 20 candidate nodes, then `find-path`. Both returned the same chain.

Tool definitions also vary with what an agent is granted. Measured definitions summed to 5,468 tokens for the configuration with octofs structural and graph tools plus octocode semantic search, and 6,455 for the prior provider combination. That’s arithmetic over individual tool definitions of the two measured builds, not a measurement inside a running Octomind session; the sets contain different tools, and the octofs `view` definition from before the change was not measured. For a general token-cost discussion, see [how to cut AI coding costs](/blog/cut-ai-coding-costs-octomind).

## Does “no index” mean no wait?

octofs writes no persistent index or database, but its first symbol query builds an in-memory table. The table refreshes against file metadata on each call, and it parses only files the query may need. The [octofs guide](https://github.com/muvon/octofs/blob/master/doc/code-exploration.md) documents a per-query cap of 600 files and 800 ms, plus a repeat notice when an answer is partial.

In the same-laptop timing run, each fresh octofs process answered its measured calls within 0.105 seconds; the first symbol call includes the in-memory build. I optimized the port for that one job: a bounded answer per query. octocode works differently: the first `graphrag` call in a process builds a full graph. I ran it only on copies without `.git`, using `--no-git`, and did not compare that with a normal checkout, so I give no timing for it here. These numbers describe six tasks and my method; they do not rank the two tools.

octocode’s structural search and signature view do not wait for that graph build. Only its semantic search requires an index on disk; its structural and graph tools do not. For background on the separate semantic-search setup, see [octocode indexing troubleshooting](/blog/octocode-mcp-troubleshooting-indexing).

## When is octocode still the right code search MCP?

If you need to search for code by intent, use semantic search; if you need a person-facing CLI, structural rewrite, language-server tools or one endpoint across repositories, octocode has those options. Its CLI includes `search`, `grep`, `review` and `graphrag overview`; octocode also has `rewrite` and `update_all` operations. Those are documented product differences, not measured advantages in this run.

| Need                                       | Start with               | Why                                                                                 |
| ------------------------------------------ | ------------------------ | ----------------------------------------------------------------------------------- |
| “What does this code do?”                  | octocode semantic search | Search by meaning; its index is required                                            |
| “Who calls `compile_ws`?”                  | octofs `symbol`          | Direct name and relation query                                                      |
| Human CLI workflows or structural rewrites | octocode CLI/tools       | These interfaces remain available                                                   |
| Semantic search plus symbol navigation     | Both providers           | The tap keeps semantic on octocode and routes structural/graph to octofs by default |

Octocode 0.29.2 is unchanged for this announcement and stays selectable. For people orienting themselves in a large repository, the [large-codebase guide](/blog/understand-large-codebase-octocode) covers a broader workflow. This post does not compare agent task success or semantic-search quality.

## What can the symbol tool get wrong?

Treat graph output as a map of names and imports, not a type checker. A `(guess)` row is a lead to confirm with `view`; same-name symbols can be confused, and dynamic calls can be missed. Relations are resolved from names and imports, not types.

A few limits affect whether a result is complete:

- Graph relations work on the local session workdir; they do not run over `ssh://` paths.
- Files over 1 MB are skipped for graph relations, and manifest dependencies and `tsconfig` path aliases are not resolved.
- Traversals can stop at their depth or work cap. A partial response says how many candidate files were examined and asks you to repeat the query.
- A call through an unrecognized receiver can appear as `(guess)`; inspect the file before relying on it.

In this run a clean-looking tokio `spawn_blocking` caller result did not include two real path-qualified callers. octofs 0.25.0 had this miss, and I fixed it in 0.25.1: the same narrowed query now lists 10 callers of that function, those two among them. The token table above is from the 0.25.0 code and was not re-run. Confirm important edges in source. For more on choosing between code search options, see [semantic code search setup](/blog/octocode-mcp-setup-claude-cursor).

## How do I update and try it?

The verified installation route for octofs 0.25.1 is Cargo. The project also documents Homebrew and `npx` routes, but their publication was not checked for this release. The Cargo release and GitHub release were verified on November 15, 2026.

```sh
cargo install octofs
```

Then register the server with your MCP client. These two lines are from the octofs README; I didn’t run them for this post:

```sh
claude mcp add octofs -- octofs mcp --path /path/to/your/project
codex mcp add octofs -- octofs mcp --path /path/to/your/project
```

Ask for a path between two names. This `symbol` request is copied from the measured run on tokio:

```json
{ "name": "spawn_blocking_inner", "relation": "path", "to": "spawn_thread" }
```

The answer it returned, in full:

```text
tokio/src/runtime/blocking/pool.rs:429 Spawner::spawn_blocking_inner -calls-> tokio/src/runtime/blocking/pool.rs:470 Spawner::spawn_task -calls-> tokio/src/runtime/blocking/pool.rs:516 Spawner::spawn_thread
[2 more file(s) spell `spawn_blocking_inner` without looking like declarations and were not searched for further definitions; give `path` (a file or directory) to search them]
```

The tool follows calls, extends and implements relationships, not imports. If the answer is partial, narrow it with `path` or `Owner::name`, then repeat the query. Start with a path question in a repository you know and check the returned lines against the source.

— DK
