Engineering

One Question, Four Languages: Cross-Stack Code Intelligence with Fantom MCP Server

A dropdown in a Vue component, a Fantom weblet, a SOX command over UDP, and a Sedona controller. They are one feature and four languages — and until now, four separate searches.

Alper Üzmezler· Sep 16, 2026 · 12 min read

Here is a question a controls engineer actually asks:

"When I drag a component onto the canvas in the Web Editor and hit save, what ends up going out on the wire to the controller?"

It is a completely reasonable question. It is also, in most codebases, a two-hour archaeology session — because answering it means crossing four languages, three runtimes and a network protocol, and no single search tool sees all of them.

Fantom MCP Server was built for that question.

The stack the question crosses

Sandstar Web Editor is a visual programming environment for the Sedona Framework. You drag components onto a canvas, wire them together, and deploy to live controllers. Underneath, one user gesture travels through a genuinely heterogeneous stack:

Sandstar Web Editor canvas Rete.js node graph · PrimeVue widgets .vue .ts Fantom pod (sweExt) serves the app · SkySpark view + weblet .fan Sandstar Web Socket · port 7070 JSON in · 17 SOX command types out router SOX over DASP / UDP reads · writes · subscriptions · file transfer Sedona controller live hardware one question

Four languages, one feature. grep can find the string sox in all of them. What it cannot tell you is that the writeComp handler in the Fantom weblet is the thing the Vue store calls, or that changing its signature breaks a subscription path three layers away.

Twenty-three languages in one index

Fantom MCP Server's language registry covers 23 languages:

axon · c · cpp · csharp · css · dart · fantom · go · html · java · javascript · json · kotlin · php · polymer · python · ruby · rust · scala · swift · typescript · vue · xeto

axon fantom xeto vue typescript javascript html css java kotlin scala csharp python ruby php go rust swift dart c cpp polymer json vue typescript fantom xeto One index. The Web Editor question touches four of these at once. Fantom, Axon and Xeto get purpose-built tree-sitter grammars.

Three of those grammars — Fantom, Axon and Xeto — were written for this project, because none existed. That matters for the same reason it mattered in Axon MCP Server: a chunk that ends mid-block is a chunk that means nothing.

Three indexes, not one

Semantic search alone is not enough to answer a structural question. Fantom MCP Server maintains three stores and uses them together:

  • LanceDB holds the vectors, behind an ANN index. Earlier releases did a full table scan on every query; building the approximate index is what took retrieval from "noticeable" to "immediate."
  • LadybugDB (Kuzu) holds the actual call graph — nodes and edges, persisted. getCallers, getCallees, getCodeImpact and getCodeNeighbors are graph queries, not grep passes re-run per request.
  • FlexSearch holds a keyword index, because sometimes you genuinely do know the identifier.

Results from the vector and keyword sides are fused with reciprocal rank fusion, then optionally re-ranked by a cross-encoder or an OpenRouter reranker. Which of those runs, and where, is a routing decision — covered in its own post.

What this looks like in practice

askCodebase runs a retrieval loop over the index and synthesises a cited answer — the citation being the point. For a cross-language question, the useful shape of an answer is less "here is a paragraph" and more "here are the four functions, in four languages, in call order."

Illustrative — the following is the shape of a cross-stack answer, not a transcript of a specific run:

  • a Vue store action in .ts, which posts a JSON message
  • the weblet handler in .fan that receives it
  • the router entry mapping that message to one of the 17 SOX command types
  • the component-write path that ends up on the wire over DASP/UDP

You can then ask getCodeImpact on any one of them and find out what else moves if you change it. That is the query that is genuinely hard without a persisted graph, and it is the one that saves the afternoon.

Asking how the code got this way

Structure answers "what calls what." A second family of tools answers "and why is it like that":

  • whatChangedRecently — what moved in this project lately
  • getSymbolHistory — how one function evolved
  • explainSymbolChange — what a particular change did
  • diffIndexRuns — what the index itself saw differently between two runs

For a codebase maintained across years and handed between integrators, this is often more valuable than the semantic search. The code is readable. The reasoning is what left with the last engineer.

And it still does the migration

SkySpark 4.0 changed the extension format. migrateSkySpark4x rewrites using statements, converts Axon strings, generates the Xeto files (lib.trio, funcs.xeto, lib.xeto), validates with the Fantom compiler, and tags a Git backup on the way in. commitMigration finishes it; rollbackMigration undoes it with a single call.

41 MCP tools in total, across documentation search, semantic code search, call-graph analysis, history, generation and migration.

The honest summary

Fantom MCP Server does not make your codebase simpler. The Web Editor will still be Vue talking to Fantom talking to SOX over UDP, and that is the correct architecture for what it does.

What changes is that the boundaries between those layers stop being walls for a search tool. One question, asked once, crosses all four — and comes back with the functions, in order, in whatever language they happen to be written in.


Fantom MCP Server is source-available at github.com/Project-SandStar/FantomMcpServer. See also the project page and Sandstar Web Editor.