ID |
|
|---|---|
Status |
Backlog |
Bucket |
feature |
Theme |
dev-loop |
Graphitron MCP server programme: agent-facing schema, catalog, code, and docs tools in graphitron:dev
This item is a programme, not a single deliverable. It absorbs the earlier single-feature R118 (live catalog discovery + docs RAG) and widens it into the full agent-facing surface of the MCP server embedded in graphitron:dev. The foundational use case is unchanged and still anchors the programme: greenfield onboarding, where a developer points graphitron at a large existing database with an empty (or nearly empty) GraphQL schema and needs to discover what exists before authoring anything. The programme generalises that into a standing capability: any MCP-aware client (Claude Code, Cursor, others) can discover the database catalog, the hand-written Java the schema wires to, the current schema and its classifications, the directive grammar, and the live diagnostics, plus semantic search over the catalog and the bundled documentation, all without a hosted service, an external database, or an API key.
Each section below names a slice that can be filed as its own item and implemented independently. This programme item is the strategic anchor and the home of the cross-cutting principles; it is not itself implemented.
What the skeleton already ships (R341, Done)
R341 delivered the transport-and-lifecycle seam: a graphitron-mcp module hosting the official MCP Java SDK’s Streamable HTTP transport in embedded Jetty, loopback-only on 127.0.0.1:8488, a single /mcp endpoint, wired into DevMojo as a sibling of the LSP DevServer (shared bind/cleanup, fail-fast on a taken port). It serves static content only today: the initialize handshake instructions plus a single argument-less about prompt. The module is the dependency-quarantine seam: the heavy semantic-layer dependencies (in-process embedder, vector store) land here, off `graphitron-maven-plugin’s compile surface.
Architecture spine
Structured vs semantic — two data shapes, two mechanisms
-
Structured (catalog tables/columns/FKs, service/condition/record signatures, current schema and classifications, diagnostics, directive grammar) is already held in memory by the dev JVM and exposed as deterministic tools straight over the live Java model. No store, no embedder; it is the freshest and most accurate answer the server can give, and because it is exact the agent cannot be misled by an approximate match.
-
Semantic (documentation RAG, fuzzy catalog discovery over names + comments) is the only part that needs a vector store and an embedder.
Only two tools in the whole surface are semantic. Everything else ships without the RAG stack.
One model, two views — this is the LSP integration
The MCP server does not speak the LSP wire protocol, and the agent is not wired as an LSP client. Both would be the wrong altitude: LSP is position/document-keyed (caret-centric), agents are concept-keyed. Instead the MCP server reads the same live model the LSP reads, the Workspace already held by DevMojo (its CompletionData catalog, the LspSchemaSnapshot, the SourceWalker.Index, the ValidationReport, the LspVocabulary). One source of truth, two thin views: LSP for editors (positional), MCP for agents (semantic). The catalog tools additionally read the raw jOOQ catalog (JooqCatalog) for unmediated DB truth. The only new wiring is handing GraphitronMcpServer the live Workspace handle, refreshed on the existing dev triggers.
Stability gradient
The corpora differ in how often they change, and that volatility maps onto how each is stored and refreshed:
| Corpus | Stability | Strategy |
|---|---|---|
Graphitron documentation |
Stable; changes only with a graphitron version |
Bundled in the jar as a prebuilt index, pre-embedded at build time, loaded at startup |
Database catalog (jOOQ meta) |
Slow; changes when the DB schema is re-captured |
Indexed at startup from the project’s catalog, persisted by catalog-jar content hash, refreshed on the classpath-change trigger |
Service / condition / record code |
Faster churn |
Structured tools always live; optional semantic method index deferred |
GraphQL schema |
Least stable; it is the work itself |
Never embedded; served live and structured from the |
The gradient is what lets an embedded store work without fighting itself: the most volatile data never enters the store.
Cross-cutting principles (binding on every slice)
-
Bind sync, warm async, never block the dev loop. The transport bind stays synchronous (fail-fast on a taken port). The embedder load and index build run on a background daemon thread;
graphitron:devreaches its watch loop without waiting. Structured tools are ready the instant the transport binds; semantic tools degrade gracefully ("index warming, use the structured tools meanwhile") until ready, and a RAG failure never takes down dev ; the server falls back to structured-only. -
Stable cross-tool node IDs = edges. Every tool emits and accepts stable identifiers (a schema coordinate
Type.field, a table name, a method refClass.method/arity). A result names its neighbours by ID; the agent traverses by following IDs through tool calls. This is the whole "graph" mechanism: no graph database, no query language. -
Store choice is Lucene for V0. The semantic layer sits behind an
EmbeddingStoreseam; Lucene HNSW is the committed V0 backend (pure Java, no native dependency beyond the embedder, BM25 hybrid search in the same index). DuckDB is deferred to the R117 knowledge-base programme.
Tool & resource surface
Tools (structured unless marked semantic):
-
catalog.tables; list tables (optional schema/name filter), raw jOOQ -
catalog.describe; one table: columns, types, nullability, PK, FKs in/out, raw jOOQ -
catalog.search; semantic ; fuzzy discovery over names + comments -
services;@service-referenceable classes + method signatures + source locations -
conditions;@condition-referenceable condition methods (return typeCondition) -
records; consumer record/POJO backings + components/types + source locations -
schema; current types/fields, classifications, backing shapes,@nodemetadata, definition locations -
diagnostics; current validation errors/warnings (closes the authoring loop) -
docs.search; semantic ; retrieval over the bundled documentation -
(optional) method search ; semantic ; per-category fuzzy discovery over external-reference methods
Resources:
-
directives; directive vocabulary cheat-sheet (arguments, applicable locations, descriptions) fromLspVocabulary+ user-declared directives; static-ish standing context, pinned rather than invoked
Slices
-
Shared-model seam (foundational). Hand the live
Workspace+ jOOQ catalog intoGraphitronMcpServer, refreshed on the existing dev triggers; declare thetoolscapability. Every structured tool depends on this. -
Catalog tools.
catalog.tables,catalog.describeover raw jOOQ. SQL names for discovery; comments only if jOOQ codegen captured them (degrade to name-only). -
Code tools.
services/conditions/recordsover theExternalReferencescan, categorised by return type (Condition→ condition, record components → record, else service); source locations via theSourceWalker.Indexjoin. -
Schema tool.
schemaover theLspSchemaSnapshot. -
Diagnostics tool.
diagnosticsoverWorkspace.validationReport(). -
Directives resource. Generated cheat-sheet from
LspVocabulary(+ snapshot user directives), exposed as an MCP resource. -
Cross-reference edges. Forward edges inline + stable IDs (nearly free); then a reverse-edge index (impact analysis: "what schema fields break if I touch this column/method?") and an optional
neighborhoodsubgraph tool as a follow-on, only if round-trip count proves painful. -
RAG foundation.
bge-small-en-v1.5-qvia langchain4j in-process ONNX behind a swappableEmbeddingModel; Lucene HNSW behind anEmbeddingStoreseam (an in-memory store suffices for the small docs corpus). The dependency-quarantine payoff forgraphitron-mcp. -
Docs search.
docs.search: chunk the.adocdocs at build time (heading-aware structural default; an opt-in// rag:splitAsciiDoc-comment delimiter overrides where structure is clumsy; prepend each chunk’s heading path before embedding), pre-embed, bundle the index in the jar, async-load at startup. -
Catalog search.
catalog.search: compose a readable per-table descriptor (name + comment + columns), embed, Lucene HNSW, persist keyed by catalog-jar content hash, async-warm and refresh on the debounced classpath trigger decoupled from the LSP catalog swap. -
(optional) Method search. Per-category semantic corpus over external-reference methods.
Local RAG stack (settled decisions)
-
Embedding: in-process, no API key, no network.
bge-small-en-v1.5-q(384-dim, MIT) bundled via langchain4j, behind langchain4j’sEmbeddingModelso the model stays swappable. bge is asymmetric: apply its query-instruction prefix on the query side. -
The native footprint is the embedder, not the store. ONNX Runtime (JNI + per-platform natives) is the one heavy dependency; this is exactly why
graphitron-mcpexists as a quarantine module. -
Storage: Lucene HNSW (pure Java, hybrid BM25 + KNN in one index). In-memory store for the docs-only first slice; graduate to Lucene for the large catalog corpus. Both behind the
EmbeddingStoreseam. -
Licensing is permissive throughout (Lucene / langchain4j Apache 2.0; ONNX Runtime / bge MIT), safe to redistribute.
Transport (settled; the skeleton implements it)
Streamable HTTP (the current spec transport) on a loopback port in the long-running graphitron:dev JVM. stdio is unusable here because the host process writes freely to stdout; loopback HTTP matches the LSP’s posture. Clients that can only spawn a stdio subprocess are supported through a thin stdio-to-HTTP proxy. A configurable MCP port is deferred (8488 is fixed in the skeleton).
Open questions for the Spec phase (per slice)
-
Store backend beyond V0: Lucene is committed; revisit only if the R117 KB single-store case forces DuckDB.
-
Multilingual embedding. Consumer DBs (notably Sikt’s own) may carry Norwegian comments; bge-small-en is English-only. Swap to
multilingual-e5-smallif real catalog data needs it (may mean bundling the ONNX ourselves rather than a prebuilt langchain4j module). -
Name normalization. Split snake_case / camelCase and compose readable descriptors before embedding; model-agnostic, lifts catalog retrieval regardless of model choice.
-
Comment-capture expectation. Surface to consumer projects that catalog semantic search depends on jOOQ codegen capturing table / column remarks; degrade to name-only otherwise.
-
Result paging. Large catalog queries can exceed MCP response limits; pick a default page size and a cursor.
-
Edge sequencing. Ship forward edges first; materialise reverse edges / neighborhood only for traversals agents actually walk.
Out of scope
The R117 DuckDB self-knowledge KB and its cross-dimension joins (a separate programme that can reuse the same embedding interface); service-code and generated-code embedding beyond the optional method-search slice; a hosted or SaaS deployment model (local, in-process is V0); authentication beyond loopback binding and filesystem permissions; any API-key-dependent embedding or generation.
Related
R117 (knowledge-base programme) is the internal-model counterpart; this MCP programme is its consumer surface and can later expose R117 dimensions (for example a @capability lookup tied to R112 and the capability catalog) through the same tool and embedding seams.