The Problem: Agents Reading Blindly
Claude Code spends a significant slice of every session orienting itself in an unfamiliar codebase. The naïve options (reading every file, or running blind grep) burn context fast and return text matches with no structural meaning. There was no cheap, structured way for the agent to ask 'what kind of project is this, and how are its modules related?'
The Architecture: Five Tools Over Stdio
Karta is an MCP server that runs as a subprocess of Claude Code. It exposes five focused tools over the stdio transport: read_project_structure, get_tech_stack, find_relevant_files, get_module_summary, and get_architecture_graph. JSON-RPC 2.0 in, structured JSON out, no port to allocate, no auth to configure. Every response stays under a tight token budget by returning summaries and snippets rather than file bodies.
Stack-Aware Strategy Dispatch
A generic dependency graph is rarely the most useful view. Karta detects the stack from package.json and dispatches to a strategy module: a NestJS @Module decorator graph (with three-color DFS cycle detection), a Next.js route map (App or Pages Router, with 'use client' detection and route-group stripping), or a generic file-import graph with hub flagging. All AST work goes through ts-morph. No regex parsing of source code, ever.
Two Surfaces, One Engine
The graph builders are pure functions. The stdio MCP server (for the agent) and a separate browser-based 3D viewer (karta-viewer) both call them. The viewer ships as its own binary so the MCP server never opens a port, and loads 3d-force-graph from a CDN rather than bundling WebGL into the npm package. Test coverage: 31 tests across 4 fixture projects (a tiny NestJS app, App-Router and Pages-Router Next.js fixtures, and a plain TS project).
Technical Deep Dive
Karta, Visualizing Itself
The graph below is the actual import structure of Karta's own source, rendered by the same kind of analysis Karta runs against any TypeScript codebase. Drag to rotate, scroll to zoom, click any node to read what it does.
Legend
- EntryServer bootstrap; registers all 5 tools over stdio.
- MCP ToolOne of the 5 functions Claude Code can call.
- Graph StrategyStack-specific analyzer (NestJS / Next.js / generic).
- UtilityShared helpers: file walking, AST parsing, path normalization.
- 3D ViewerSeparate HTTP binary that renders this very kind of graph in a browser.
Click any node to see what it does.
Why an MCP Server (and not a CLI)
Claude Code spends a non-trivial slice of every session orienting itself in an unfamiliar codebase. The naïve options (reading every file, or grepping blindly) are expensive in context. MCP lets Karta expose five focused tools that the agent decides when to call: what stack is this, what's the folder shape, where does X live, what does this folder expose, how are modules related?
Stdio transport keeps the integration zero-config: Claude Code spawns the binary as a subprocess and exchanges JSON-RPC over its stdin/stdout. No port, no auth, no firewall. The trade-off is that stdout is reserved for the protocol; every diagnostic line goes to stderr, or it corrupts the stream.
Stack-Aware Strategy Dispatch
A generic file-import graph is rarely the most useful view. A NestJS developer wants to see which module depends on which; a Next.js developer wants to see the route tree; a plain TS project wants the file graph with hub detection. Karta'sget_architecture_graphdetects the stack from package.jsonand dispatches to one of three strategy modules, each returning a payload with a strategydiscriminator so the caller can switch on shape. Adding a new stack (Remix, SvelteKit) is one new file plus a one-line dispatch addition.
Parsing @Module Decorators With ts-morph (No Regex)
NestJS describes its dependency graph through@Moduledecorators whose first argument is an object literal:{ imports, providers, exports }. Parsing this with regex breaks on the first nested brace, JSX tag, or multi-line argument. Karta uses ts-morph, a wrapper around the TypeScript compiler API, to walk the real AST: find classes with the decorator, narrow each array element via typed node guards (Node.isIdentifier,isCallExpression,isObjectLiteralExpression), and extract the meaningful name. Circular-import risks are surfaced via three-color DFS over the imports graph.
Try It
Karta is published on npm as karta-mcp. One command registers it with Claude Code. No global install required.
Two Surfaces, One Engine
The graph builders are pure functions. The stdio MCP server (for the agent) and the local HTTP viewer (for the human) both call them. Fix a bug in cycle detection and both surfaces benefit. The viewer ships as a separate binary (karta-viewer) so the MCP server never opens a port. It loads3d-force-graphfrom a CDN rather than bundling WebGL into the npm package.