mcp

An MCP server that gives Claude, Codex and other MCP clients the kosha index as a set of tools.

The tools call the same Kosha methods as the command line and the daemon. The mcp package is a dependency of kosha, and nothing extra needs installing. kosha indexes the repository it starts in and that repository’s environment. Start the server at the project root, inside the project’s environment. uv run does both:

uv add --dev koshas
uv run kosha-mcp            # serves over standard input and output; add --http for Streamable HTTP

The server creates one Kosha on the first tool call and keeps it. The embedding model loads once per server and not once per call. The server converts results to plain JSON types before it returns them.

Index management

status reports whether the index is current. An agent should call it first. A stale index looks like missing code. sync updates the index with the same switches as Kosha.sync and returns the new status.

from fastcore.test import test_eq

sync

def sync(
    dir:str | None=None, pkgs:list | None=None, embed:bool=True, force:bool=False, repo:bool=True, env:bool=True,
    graph:bool=True, graph_mode:str='fast', graph_metrics:bool=True
)->dict:

Update the repo index, the package index and the call graph, then return the status; graph=False skips the graph.


status

def status()->dict:

How fresh the index is: {files, packages, graph_nodes, stale_files, stale_pkgs, new_files}; call it first and sync if anything is stale.

# `sync` passes `graph_mode` and `graph_metrics` to `Kosha.sync` unchanged.
_mcp_calls = []
class _McpKosha:
    def sync(self, **kwargs): _mcp_calls.append(kwargs)
    def status(self): return {'graph_nodes': 1}
_mcp_k, _k = _k, _McpKosha()
try: _mcp_status = sync(graph_mode='full', graph_metrics=False)
finally: _k = _mcp_k
test_eq((_mcp_calls[0]['graph_mode'], _mcp_calls[0]['graph_metrics']), ('full', False))
test_eq(_mcp_status['graph_nodes'], 1)

Call graph

These tools take full dotted node names, such as fastcore.basics.merge, as found in a search hit’s mod_name. node_info returns a node’s callers, callees, co-dispatched peers and PageRank. A high PageRank means much of the code depends on the node. pkg_url returns the web address of an installed package, for looking up its documentation.


pkg_url

def pkg_url(
    pkg:str
)->str:

The repository or home page address of an installed package, for looking up its docs or changelog.


dep_stack

def dep_stack(
    seeds:list | None=None, depth:int=1
)->list:

Layers of packages imported by the seed packages (default: the pyproject dependencies), breadth first.


api_paths

def api_paths(
    from_pkg:str, to_pkg:str, k:int=15
)->dict:

Shortest call paths from the top public functions of from_pkg to those of to_pkg.


top_nodes

def top_nodes(
    pkg:str, k:int=5
)->list:

The k public names of a package with the highest PageRank.


public_api

def public_api(
    pkg:str, limit:int=200
)->list:

Public names and docstrings of a package or module, including functions that @patch adds to its classes.


short_path

def short_path(
    src:str, tgt:str
)->list:

The shortest chain of calls from node src to node tgt.


neighbors

def neighbors(
    node:str, depth:int=1
)->list:

Every node within depth edges of node, callers and callees alike.


node_info

def node_info(
    mod_name:str
)->dict:

Callers, callees, co-dispatched peers and PageRank of a node such as fastcore.basics.merge; high PageRank means much code depends on it.


main

def main():

Run the server for the kosha-mcp command, over stdio, or Streamable HTTP with –http.

Connect a client

The server must start at the project root inside the project’s environment. Use uv run kosha-mcp. uvx kosha-mcp runs the server in a separate environment that does not have your project’s packages.

For Claude Code, run this inside the project:

claude mcp add kosha -- uv run kosha-mcp

For Codex, add this to ~/.codex/config.toml. Codex starts servers in your session’s working directory. Start Codex at the project root.

[mcp_servers.kosha]
command = "uv"
args = ["run", "kosha-mcp"]

Claude Desktop does not start in your project. Name the project in claude_desktop_config.json:

{"mcpServers": {"kosha": {"command": "uv", "args": ["run", "--project", "/path/to/your/repo", "kosha-mcp"]}}}