Astrolabe / ajxpublic /astrolabe
Repository

WebMCP Integration

reference scope internal/wiki/webmcp Verification failed
  • internal/wiki/webmcp/webmcp.js
  • internal/wiki/webmcp/astrolabe-mcp.js
Relevant source files · 2

The internal/wiki/webmcp directory ships the JavaScript that turns a generated wiki site into something an AI agent can use, not just read. Two files cooperate: webmcp.js is a vendored copy of the webmcp.dev widget — a small floating button that opens a WebSocket bridge so a local MCP client (Claude Desktop, Cursor, …) can discover and call tools on the page Label. astrolabe-mcp.js is Astrolabe's own script: it defines a set of read-only tools over the wiki bundle and exposes them two ways — through the W3C WebMCP document.modelContext API for browser-native agents, and through the widget when it is present Label. The result is that a reader's own agent can answer questions about the codebase using exactly the same bundle the human sees.

How it works

Everything starts from the static bundle. All tool data comes from plain files — index.json, graph.json, version.json, pages/<slug>.md and the src/ snapshot — fetched once and memoized in a small cache keyed by path and format, so repeated tool calls don't re-download the bundle Label. Because fetching requires http(s), a wiki opened from file:// can serve prose but not tools.

The tools

The script builds a tools array of seven read-only functions over that data Label:

Tool What it does
astrolabe_overview Lists the repo, commit/branch/tag and every page with type, scope, symbols and verification status Label
astrolabe_read_page Returns one page as Markdown (flagged untrusted — it's remote page content) Label
astrolabe_search_wiki Paragraph-level full-text search with term-frequency scoring, page slug and nearest heading in the results Label
astrolabe_search_symbols Substring search over graph.json nodes, ranked with exact matches first Label
astrolabe_symbol_details One symbol: location, commit-pinned source link, documenting page, and all in/out graph edges Label
astrolabe_read_source Numbered source lines from the src/ snapshot; rejects .. traversal and falls back to a forge URL when the bundle links out instead of shipping source Label

Source links are resolved by sourceLink, which either fills the {path}/{line}/{endline} template recorded in index.json (a commit-pinned code-host URL) or points into the bundle's own src/ snapshot with an #L fragment Label. This mirrors the citation model of the Wiki Bundle & Pages generator: whatever the wiki cites, the agent can read.

Two registration surfaces

At load time init() tries both surfaces and records the outcome on window.AstrolabeMCP Label:

  • W3C WebMCP. registerSpec registers each tool on document.modelContext, falling back to the legacy navigator.modelContext (the MCP-B polyfill surface), and annotates each tool with readOnlyHint: true and untrustedContentHint for tools returning wiki content Label.
  • webmcp.dev widget. If webmcp.js was loaded first, registerWidget instantiates WebMCP tinted with the theme's --accent color and registers the same tools with a registerTool(name, description, schema, fn) signature Label.

In both cases the execute wrapper normalizes results to MCP text content blocks.

The widget bridge

webmcp.js is a self-contained class. On construction it injects a small trigger button plus a connection panel into the page (guarding against double initialization) Label, and immediately checks sessionStorage for a token from a previous page visit so navigation doesn't drop the connection Label.

Connecting is a two-step handshake. The reader pastes a base64 token from npx @jason.today/webmcp; _processConnectionToken decodes it into {server, token} and derives the channel name from the page's hostname Label. The script then registers with a relay over a /register WebSocket, sending the token plus the formatted host and receiving a session token back Label, before opening the real channel socket at server/channel?token=… Label. Registration is skipped entirely when the stored connection info matches the current server and host Label.

Once connected, the widget becomes a thin MCP relay. Server-initiated messages are dispatched to _handleToolCall, which looks the tool up in the local registry, executes it (resolving Promises asynchronously), and replies with a toolResponse — or an error payload if the tool is missing or throws Label. Prompt and resource requests follow the same pattern. Tools reach that registry via the public registerTool, which stores name/description/schema/execute locally, announces the tool to the server if already connected, and persists it to sessionStorage so reconnection restores it Label. On reconnect, _registerItemsWithServer replays every registered tool, prompt and resource Label. A safety valve disconnects after five minutes of inactivity (configurable via inactivityTimeout) Label. Disconnection clears the socket, the stored token and the saved registrations Label.

sequenceDiagram
    participant Agent as MCP client / browser agent
    participant Page as wiki page
    participant MCP as astrolabe-mcp.js
    participant Widget as WebMCP widget
    participant Relay as webmcp relay

    Page->>MCP: load with data-root
    MCP->>MCP: fetch + cache index.json, graph.json, pages/
    MCP->>Page: document.modelContext.registerTool ×7
    MCP->>Widget: registerTool ×7 (if webmcp.js loaded)
    Agent->>Relay: token handshake (/register)
    Relay-->>Widget: session token
    Widget->>Relay: open channel WebSocket
    Agent->>Relay: tool call
    Relay->>Widget: _handleToolCall
    Widget->>MCP: execute cached tool
    Widget->>Relay: toolResponse

Trust and safety notes

Two properties are deliberate. First, all tools are read-only: the annotations sent to the W3C surface declare readOnlyHint for every tool Label, and none of the runners mutate anything. Second, tools that return wiki-authored prose (astrolabe_read_page, astrolabe_search_wiki, astrolabe_read_source) are marked untrusted so consuming agents treat the content as data, not instructions Label. Input handling also defends the bundle itself: page slugs are validated against a strict pattern Label and source paths are stripped of leading slashes and rejected if they contain .. Label.

Reference

Symbol Kind What it does Location
WebMCP (class) class Widget: token handshake, WebSocket relay to MCP clients, tool/prompt/resource registry, session persistence internal/wiki/webmcp/webmcp.js#L8
WebMCP#connect method Decodes token, registers with relay, opens channel WebSocket internal/wiki/webmcp/webmcp.js#L895
WebMCP#_registerWithServer method /register handshake exchanging the pasted token for a session token internal/wiki/webmcp/webmcp.js#L1097
WebMCP#_handleToolCall method Dispatches server tool calls to the local registry and replies toolResponse internal/wiki/webmcp/webmcp.js#L1268
WebMCP#registerTool method Public tool registration; persists to sessionStorage and announces to the server internal/wiki/webmcp/webmcp.js#L1632
tools array The seven read-only Astrolabe tools over the wiki bundle internal/wiki/webmcp/astrolabe-mcp.js#L87
sourceLink function Builds commit-pinned source URLs from index.json template or the src/ snapshot internal/wiki/webmcp/astrolabe-mcp.js#L70
registerSpec function Registers tools on document.modelContext (or legacy navigator.modelContext) internal/wiki/webmcp/astrolabe-mcp.js#L219
registerWidget function Registers the same tools on the webmcp.dev widget when present internal/wiki/webmcp/astrolabe-mcp.js#L239
init function Entry point; wires both surfaces and exposes window.AstrolabeMCP internal/wiki/webmcp/astrolabe-mcp.js#L253

Generated by astrolabe from commit ecc180b3 (tag 0.4.0).