code-index
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@code-indexwho calls train in model.py?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
code-index
Structural, queryable understanding of a Python codebase for a coding agent — built as an AST-derived RDF graph, stored in an embedded triple store, and exposed as MCP tools.
Instead of an agent re-discovering "who calls this function" or "what does
this class inherit from" via repeated grep/read cycles, code-index parses
the codebase once into a graph of facts and answers those questions as
direct lookups, in milliseconds.
Why
Grep and file reads are the default way an LLM coding agent explores a repository, but they're the wrong tool for structural questions:
"What calls this function, anywhere in the repo, directly or transitively?" — grep finds text matches, not resolved call edges.
"What does this class inherit from, or what inherits from it?" — requires actually resolving imports across files.
"Give me a cheap overview of this folder before I decide what to read in full." — grep/read either gives you everything or nothing.
code-index answers these by parsing structure once and storing it as
facts, so the agent can query instead of re-deriving.
Related MCP server: CodeGB
Concept
Parse — Python's stdlib
astwalks each file and extracts structural facts: modules, classes, functions, signatures, line ranges, docstrings, decorators, variable reads/writes, and unresolved call/import/inherit targets (by name only, not yet a link to the actual defining symbol).Resolve — a real Pyright language server runs as a managed subprocess for the duration of a build. It supplies return-type inference (
hover) and cross-file symbol resolution (definition), which get attached onto the AST-built nodes —astowns identity and structure, Pyright only annotates it.Store — every fact becomes an RDF triple (subject-predicate-object) in an embedded pyoxigraph store, one named graph per source file. This makes incremental re-indexing a drop-and-replace of a single file's graph, and gives the whole thing a real SPARQL 1.1 query engine for free.
Materialize closures —
calls,imports, andinheritsare transitive relationships. Rather than walking property paths at query time, the full transitive closure of each is precomputed at index time and written into a dedicatedurn:code:graph:inferredgraph. "Every caller of X, however deep" becomes a direct lookup, not a graph traversal.Serve — an MCP server exposes six tools over the store: a token-cheap structural browser (
get_context), a full-detail single-node lookup (get_details), three curated graph queries (get_callers,get_dependencies,get_class_hierarchy), and a raw SPARQL escape hatch (query_sparql) for anything the curated tools don't cover.
Everything downstream of parsing is just facts and queries over those facts — no LLM involved in indexing itself, so results are exact, not guessed.
Example: what actually gets stored
For a class like this:
class FeatureScaler:
"""Scales numeric features into [0, 1]."""
def transform(self, values: list[float]) -> list[float]:
"""Scale values into [0, 1]."""
return [self._normalize(v) for v in values]parsing produces triples roughly equivalent to:
urn:code:src/scaler.py::FeatureScaler a code:Class
urn:code:src/scaler.py::FeatureScaler code:defines urn:code:src/scaler.py::FeatureScaler.transform
urn:code:src/scaler.py::FeatureScaler.transform a code:Function
urn:code:src/scaler.py::FeatureScaler.transform code:signature "transform(self, values: list[float]) -> list[float]"
urn:code:src/scaler.py::FeatureScaler.transform code:description "Scale values into [0, 1]."
urn:code:src/scaler.py::FeatureScaler.transform code:calls urn:code:src/scaler.py::FeatureScaler._normalize
urn:code:src/scaler.py::FeatureScaler.transform code:startLine "5"get_context("src/scaler.py") returns the cheap structural summary (names,
signatures, line ranges — no docstrings). get_details(node_id) returns
everything for one specific node, including its docstring. get_callers
and get_class_hierarchy are direct lookups against the precomputed
transitive closure, not live traversals.
Install
Requires Python 3.13+, uv, and Node.js (used
only to vendor pyright-langserver as an internal subprocess — never a
user-facing server).
git clone https://github.com/RaviIITk/code-index.git
cd code-index
uv sync
npm install # vendors pyright-langserver into node_modules/Usage
CLI
# Build (or incrementally rebuild) the index for a repo
uv run code-index build /path/to/repo
# Check what's currently indexed
uv run code-index status /path/to/repo
# Run a raw SPARQL query against the index
uv run code-index query "SELECT ?fn WHERE { ?fn a <http://example.org/code-ontology#Function> }" /path/to/repoThe index itself is stored outside the repo, in
~/.cache/code-index/<repo-slug>-<hash>/, keyed by the repo's canonical
path — nothing is written into the working tree.
As a Python library
Everything the CLI and MCP server do is just calls into the library — useful for scripting or embedding in something else:
from pathlib import Path
from code_index.cache.location import store_path
from code_index.incremental.build import run_incremental_build
from code_index.mcp_server import tools
from code_index.store.triple_store import TripleStore
repo = Path("/path/to/repo")
store = TripleStore(store_path(repo))
# Build (or incrementally refresh) the index
report = run_incremental_build(store, repo, pyright_bin="pyright-langserver")
print(report.added, report.changed, report.deleted, report.parse_failures)
# Query it with the same functions the MCP tools delegate to
print(tools.get_context(store, "src/scaler.py", depth=1))
fn_id = "urn:code:src/scaler.py::FeatureScaler.transform"
print(tools.get_details(store, fn_id))
print(tools.get_callers(store, fn_id))
print(tools.get_dependencies(store, "src/scaler.py"))
print(tools.get_class_hierarchy(store, "urn:code:src/scaler.py::FeatureScaler"))
# Or drop to raw SPARQL 1.1
print(tools.query_sparql(store, "SELECT ?fn WHERE { ?fn a <http://example.org/code-ontology#Function> }"))node ids are the same urn:code:<file_path>::<qualified.name> IRI strings
returned in every get_context/get_details result's "id" field, so you
can chain a broad query into a specific one without hand-building IRIs.
As an MCP server
Register it with an MCP-speaking agent host by adding to that host's MCP
config (e.g. .mcp.json):
{
"mcpServers": {
"code-index": {
"command": "uv",
"args": ["run", "--directory", "/path/to/code-index", "code-index-mcp", "/path/to/repo"]
}
}
}This starts a resident server (one per repo, guarded by an exclusive lock) exposing six tools:
Tool | Signature | Purpose |
|
| Token-cheap structural summary rooted at a file or folder; increase |
|
| Full structural facts for one node, plus its docstring if the source has one. |
|
| Every function that calls |
|
| Every file that |
|
| Transitive ancestors and descendants of a class. |
|
| Raw SPARQL 1.1 escape hatch; the tool description embeds an ontology cheat-sheet so the agent has schema context without an extra call. |
A typical agent workflow: call get_context on the repo root to see the
folder tree, drill into a file of interest, grab a function/class id from
that summary, then call get_details or get_callers with that id for the
full picture.
Note: the MCP server only ever serves whatever is already in the store when
it starts — run code-index build (or wire a session-start hook to do so)
before pointing an agent at a repo whose index may be stale.
Development
uv run pytest # 44 tests
uv run ruff check .
uv run ruff format .Scope
v1 targets small-to-medium Python repos (hundreds of files). Deliberately out of scope for now: other languages, LLM-generated summaries/purpose fields, graph-centrality ranking, and transparent multi-session server sharing (each repo currently gets one resident server; a second concurrent session refuses to start rather than silently sharing state).
License
Dual-licensed under either of
at your option.
Available Tools
6 toolsget_callersA
Every function that calls fn (a node id from get_context/get_details),
directly or transitively.
| Name | Required | Description | Default |
|---|---|---|---|
| fn | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears full burden. It discloses the key behavior (direct/transitive callers) but omits details like recursion depth limits, performance implications, or how transitively is defined. Adequate for simple use.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Single sentence, no redundant words, front-loaded with the key action. Every part is essential and informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given low complexity (1 param, output schema present), the description covers the core functionality. It explains parameter origin and result scope. Could mention if output is function IDs or names, but output schema likely handles that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description adds meaning by specifying that `fn` is a node ID from get_context/get_details, giving context for parameter usage. No examples or validation constraints provided, but valuable addition beyond schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the tool returns functions that call a given function `fn`, with direct or transitive calls. Differentiates from sibling tools by focusing on callers rather than dependencies or hierarchy. Could be slightly more explicit but is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides context that `fn` comes from get_context/get_details, which guides where to obtain the input. However, it does not explicitly state when to use this tool over alternatives like get_dependencies, leaving agents to infer from purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_class_hierarchyA
Transitive ancestors and descendants of a class (a node id from get_context/get_details).
| Name | Required | Description | Default |
|---|---|---|---|
| cls | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It describes the core behavior (transitive ancestors/descendants) but lacks details on permissions, rate limits, or side effects, which are acceptable for a read-only query.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no redundant words. It could be slightly improved by clarifying the output structure, but it is appropriately concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity, the description covers the input and output goal but does not specify whether the output is a flat list or hierarchical, nor its exact structure, leaving some ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, but the description adds crucial context: the 'cls' parameter is a node id from get_context/get_details, which compensates for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns 'transitive ancestors and descendants' of a class, which distinguishes it from sibling tools like get_callers or query_sparql.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It specifies the prerequisite (node id from get_context/get_details) and implies use for class hierarchy queries, but does not explicitly exclude alternatives or state when not to use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_contextA
Token-cheap structural summary rooted at a file or folder path (workspace-relative). Structural facts only (names, signatures, line ranges) — no docstrings, use get_details for those. Increase depth to drill from folder -> file -> function/class detail.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| depth | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It mentions 'token-cheap' (cost awareness) and the structural nature, but does not explicitly state read-only or side-effect-free behavior. Adequate but not fully transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core purpose, then specific details and related tool. No extraneous words. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple tool with 2 params and no output schema, the description covers what it returns, how to use the parameters, and how it relates to a sibling tool. It is complete for the context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so description must add meaning. It explains 'path' as workspace-relative and 'depth' as drilling from folder to detail levels. This adds significant value beyond the schema's names and default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns a 'structural summary' with 'names, signatures, line ranges' for a file or folder path. It distinguishes from get_details by excluding docstrings. This is specific and differentiates from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly advises using get_details for docstrings, implying that get_context is for structural info only. It does not explicitly state when not to use it, but the guidance is clear and helpful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dependenciesA
Every file (workspace-relative path) that file transitively
depends on via its import edges.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the core behavior: transitive dependency resolution via import edges. However, it omits details like cycle handling or response shape, though the output schema exists to cover return values.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, clear sentence with no wasted words. It is front-loaded with the key action and resource.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one parameter, no annotations, and an existing output schema, the description adequately explains the tool's function. It could mention what the returned list contains (file paths), but the output schema likely covers that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter 'file' has no schema description (0% coverage), so the description compensates by specifying it expects a 'workspace-relative path', which adds meaningful context beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns every file a given file transitively depends on via imports. It distinguishes itself from siblings like get_callers and get_class_hierarchy by focusing on import dependencies, not callers or class hierarchy.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies use for dependency analysis but lacks explicit guidance on when to use this tool versus its siblings (e.g., get_callers, get_context). No mention of when not to use or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_detailsB
Full structural facts for one node (a node id from get_context), plus its full stored docstring if the source actually has one.
| Name | Required | Description | Default |
|---|---|---|---|
| node | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description bears full burden. It discloses that it returns structural facts and optionally a docstring, but does not detail permissions, errors, or side effects. Adequate but minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Extremely concise: two sentences with no wasted words. Core purpose is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Tool is simple with one parameter and no output schema. Description covers core behavior but lacks details on output structure, errors, or edge cases. Adequate but could be more comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
While the input schema only specifies type 'string' for 'node', the description adds useful context that the node id originates from get_context. This compensates for the 0% schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states that the tool returns 'Full structural facts for one node' and optionally includes its docstring. It ties the input to get_context, which helps differentiate from siblings like get_context and get_dependencies, but lacks explicit differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool versus alternatives. Only implies that the node id should come from get_context. No mention of when not to use or other considerations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_sparqlA
Prefix: code: http://example.org/code-ontology# Node IRIs: urn:code:<repo/relative/path.py> (module), urn:code:<path.py>::<Qualified.Name> (class/function).
Classes: code:Module, code:Class, code:Function Datatype properties: code:name, code:startLine, code:endLine, code:signature, code:returnType, code:description, code:contentHash Object properties: code:defines (parent->child), code:belongsTo (child->parent, inverse of defines), code:reads, code:writes, code:raises, code:decoratedBy, code:imports, code:calls, code:inherits (imports/calls/inherits objects may be a string Literal if unresolved, or a NamedNode if Pyright resolved the target — both may be present)
Named graphs: urn:code:graph:<path.py> holds one file's direct/structural triples; urn:code:graph:inferred holds the fully materialized transitive closure (R+, includes direct edges) of calls/imports/inherits across the whole repo.
Every query runs with use_default_graph_as_union=True, so a plain WHERE clause with no GRAPH block already searches across every named graph — add an explicit GRAPH urn:code:graph:inferred { ... } block only when you specifically want the transitive/materialized edges rather than a single file's direct ones.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the default behavior (use_default_graph_as_union=True) and explains graph partitioning. However, it does not state whether queries are read-only or any side effects, which is a minor gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is relatively long but well-organized, starting with prefix/IRI definitions, then classes/properties, then named graphs, and usage guidance. It could be trimmed slightly but is effectively structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema (context shows true), return values are likely covered elsewhere. The description thoroughly explains ontology and graph context needed for queries, but omits possible SPARQL construct restrictions or output structure, which is a minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema coverage, the description must compensate but only provides ontology context for writing queries, not syntax or constraints for the query parameter itself. The ontology info is valuable, but the parameter semantics remain vague.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool executes SPARQL queries against a code ontology, with specific details on prefixes, node IRIs, classes, and properties. It distinguishes itself from sibling tools like get_callers or get_class_hierarchy by being a generic query tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on graph selection: plain WHERE searches all graphs, while an explicit GRAPH block targets inferred edges. It does not mention when to avoid this tool or directly compare to siblings, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
6 tool updates
v0.1.0- First observed
get_callers - First observed
get_class_hierarchy - First observed
get_context - First observed
get_dependencies - First observed
get_details - First observed
query_sparql
TDQS
Each tool has a distinct purpose: callers, class hierarchy, structural context, dependencies, detailed node info, and SPARQL queries. There is no overlap or ambiguity between them.
Most tools follow the 'get_' prefix pattern (get_callers, get_class_hierarchy, etc.), but query_sparql deviates slightly by using 'query' instead. The naming is still clear and predictable overall.
With 6 tools, the set is well-scoped for a code indexing server. Each tool provides essential functionality without redundancy or excess.
The tools cover structural analysis (context, details) and relational queries (callers, hierarchy, dependencies). The SPARQL endpoint allows arbitrary queries, filling most gaps. Minor missing direct tool for listing all modules, but query_sparql can handle that.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Ask a codebase what calls what: search, blast radius, paths between symbols, and diffs.
Hosted code graph over MCP: exact callers, dependencies, and cross-repo blast radius for AI agents.
251Ground-truth code graph for your codebase: exact callers, callees, symbols & dependencies.
Deterministic context layer for your codebase: change impact, blast radius, answers with receipts.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceIndexes Python codebases using AST and BM25, providing 8 MCP tools for code exploration and search.-
- FlicenseNot gradedqualityFmaintenanceProvides a local code knowledge graph for Java projects, enabling querying of classes, methods, fields, calls, inheritance, and imports via MCP tools like query, context, impact, and cypher.1-
- AlicenseAqualityBmaintenanceIndexes a mono-repo into a knowledge graph and provides MCP tools to query code structure—packages, components, routes, HTTP calls—without file reads or grep round-trips.722MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that indexes a local Python codebase into a SQLite graph for hybrid code search, file context, lazy explanations, dependency traces, and version-aware symbol history.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/RaviIITk/code-index'
If you have feedback or need assistance with the MCP directory API, please join our Discord server