Skip to main content
Glama

arcscope

A fully-local MCP server that gives an AI coding agent precise views of an unfamiliar codebase — fast symbol navigation, a compiler-exact call graph and flow surface, and a repo-declared architecture vocabulary answered live against current code — so it stops re-deriving structure with grep, and stops missing the this.service.foo() calls grep can't see.

Status: 0.1.0. Three tiers — tree-sitter breadth, an agent-authored knowledge layer, and a compiler-exact TypeScript precise tier — work end-to-end. TS / JS / TSX.

npm i -D arcscope
npx arcscope init        # index once, write MCP config, update .gitignore
# reload Cursor (Settings → MCP) or restart Claude Code

init writes the same offline node … serve entry to .cursor/mcp.json (Cursor) and .mcp.json (Claude Code). When arcscope is installed under node_modules, the path is project-relative so you can commit .cursor/mcp.json for the team.

Everything runs on your machine: no network at query time or at server spawn, no telemetry, no embeddings. Breadth comes from tree-sitter (WASM grammars bundled offline); precision comes from the TypeScript compiler running locally. Every result carries a precision tier so the agent never mistakes a heuristic for a compiler-accurate answer.

How it's being used

npx arcscope stats

One local command — no network, no telemetry — that shows both halves:

  • How much — reads .arcscope/usage.jsonl (one line per tool call, written as the server runs): totals, a breakdown by tool, and the most-queried symbols/concepts/entry points, plus your committed concepts and their drift baselines.

  • Is it useful (vs grep) — the server only sees its own calls, so stats also reads the newest Claude Code session transcript for this repo, replays every search/navigation call in order (arcscope ✅ vs grep 🔎 vs ToolSearch 🔍), and reports arcscope's share of arcscope + grep. No transcript yet → it says so and shows the usage half only.

    Reads Claude Code transcripts only (~/.claude/projects); Cursor sessions aren't included. The share is a whole-session volume ratio — a quick "is the agent reaching for it?" gut check, not a formal adoption gate.

Related MCP server: agentmako

Tools

tool

answers

find_def

where a symbol is defined, with its signature

find_refs

who references it — compiler-exact for methods when a tsconfig governs the file (member access obj.method() resolved); import-resolved otherwise

dep_graph

the file/module dependency graph: hubs, a file's neighborhood, or circular dependencies

call_graph

the method-resolved outgoing call graph from a function — follows this.x.foo() through the type checker

flow

the complete surface of a flow before you change it: the call closure + a structural edge-case checklist

arch_list

the repo's named architecture concepts (committed + agent-asserted)

arch_query

resolve one concept to its live code locations, with drift + conformance

arch_assert

record a concept — or a reviewed flow — so a later session inherits it, re-verified live

arch_candidates

find a concept's likely missing members by structural (AST-shape) similarity

The precise tier — compiler-exact, still local

tree-sitter can't tell you who calls this.documentService.clone() — resolving a method call needs the receiver's type. arcscope's precise tier runs the TypeScript compiler + language service locally (no network) to answer that exactly:

  • find_refs on a method finds its member-access call sites (obj.method()), resolved through the type checker — the call sites grep and import-resolution miss.

  • call_graph traces the outgoing closure from an entry point with method dispatch resolved to the concrete implementation (DI-injected services, inheritance).

  • flow maps the complete surface of a flow before you touch it: every function it transitively calls, annotated with each function's edge cases (branches, error handling, async). So you catch every case a change must handle.

flow cloneUser
# Flow surface from `cloneUser` (apps/.../clone-user.service.ts:44) — 38 functions, precision tier: typescript:
# cloneUser  apps/.../clone-user.service.ts:44  (+5 lib)  {2 branch}
# ├─ loadRecord  apps/.../record.repository.ts:183  (+2 lib)  {2 branch, 3 await}
# │  └─ …
# └─ performClone  apps/.../clone-user.service.ts:62  (+3 lib)  {1 err, 1 await}
#    └─ cloneRecord  libs/.../record-clone.ts:32  (+1 lib)
#       └─ cloneItem  libs/.../record-clone.ts:104
#          └─ reindexAfterClone  libs/.../reindex.ts:41
# … (38 functions; tree abbreviated)
# Edge-case surface: 6 decision points (if/switch/ternary) · 1 error-handling site (try/throw) · 7 async boundaries (await).
# Each {…} tag marks where behaviour forks, fails, or awaits — verify your change handles each before you write it.

The architecture vocabulary — the differentiator

Where other tools keep project knowledge as static prose that silently rots, arcscope binds each named concept to an executable locator recomputed on every query. The knowledge is agent-authored, not hand-edited: as the agent works out a concept, it records it with arch_assert into a committed .arcscope/assertions.yaml — a binding of locators, never a frozen list — so a later session inherits it. One concept looks like:

concepts:
  repository-tokens:
    title: Repository-token pattern (I{Name}Repository)
    locators:
      - { kind: symbol, query: "interface I*Repository", in: "libs/data-access/**" }
      - { kind: symbol, query: "const *_REPOSITORY = InjectionToken", in: "libs/**/tokens/**" }
      - { kind: path,   glob: "apps/**/firestore-*.repository.ts" }

arch_query repository-tokens resolves this against the current tree and flags drift when the resolved set diverges from its accepted baseline. Locators come in three kinds — symbol (a tree-sitter query), path (a glob), and import (every file importing a module specifier) — and resolve through arcscope's own engine; a committed assertion can never run a shell command.

Three things keep an agent-written assertion honest:

  • a must invariant — a rule every member must satisfy, re-checked live (conformance); a violation surfaces on every query, not when it ships.

  • arch_candidates — finds the members a binding missed, by AST-shape similarity (name-independent, so it catches a hand-copied re-implementation that shares no name or import). The "fixed it twice" antidote.

  • a flow conceptarch_assert a reviewed flow by its entry point; arch_query recomputes the whole flow live (precise tier) and drifts when a function enters or leaves it.

Nothing is stored as a bare fact: every assertion is re-verified against live code on read, so it can't silently rot.

Drift in practice

The first arch_query records a baseline; later queries compare against it:

arch_query repository-tokens
# Concept `repository-tokens` — Repository-token pattern (7 locations, fresh (baseline captured)):
#  … later, someone adds apps/audit/firestore-audit.repository.ts …
arch_query repository-tokens
# Concept `repository-tokens` — Repository-token pattern (8 locations, DRIFTED):
#   ⚠ DRIFT vs baseline: 1 added, 0 removed, 0 changed.
#     + apps/audit/firestore-audit.repository.ts
arch_query repository-tokens reaccept:true     # accept the new shape → fresh again

How it works

One local Node process speaking MCP over stdio, in tiers:

  • Engine (tree-sitter) — web-tree-sitter parses each file (lazy WASM grammars) into symbols + import edges. The always-on breadth substrate.

  • Graph — a derived view over those import edges (dependency graph, cycles), grouped by directory + import-clustering — never a build tool's project model (nx.json, BUILD files).

  • Knowledge — the live, agent-authored architecture vocabulary above.

  • Precise tier (TypeScript) — a local ts.Program + language service, built lazily per tsconfig and cached, powering the call graph, flow surface, and compiler-exact method references.

Precision tiers & limits

Two tiers, labeled on every result:

  • tree-sitter — fast, broad (multi-language breadth), structural. The always-on substrate; complete for imported-symbol references.

  • typescript — compiler-exact, via the local TypeScript compiler + language service. Resolves method dispatch, DI, inheritance, overloads.

arcscope never presents a tree-sitter heuristic as compiler-exact. Honest residual limits (the precise tier counts these at the boundary, never hides them):

  • any-typed / higher-order callbacks and runtime-wired providers (InjectionToken, useFactory) may resolve to the declared member rather than the concrete impl.

  • the precise tier is per-tsconfig — a single flow rarely spans module systems, but cross-project closures aren't unioned. It builds a TS program on first use (seconds), cached after.

  • TS / JS / TSX only; module grouping is general-first (directory + import clustering), never a build tool's project model.

A
license - permissive license
-
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
Release cycle
1Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

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/iliedanila/arcscope'

If you have feedback or need assistance with the MCP directory API, please join our Discord server