MCP
Connect AI agents like Claude Code, Codex, and Cursor to your GalaxyBrain workspace. Read, write, search, and monitor your pages, templates, and layout in real time.
Contents
Setup
Prerequisites
- Bun runtime installed
- GalaxyBrain open in a Chromium-based browser (Chrome, Edge, Brave)
Install
Ask your AI assistant to install the GalaxyBrain MCP server (package: galaxybrain-mcp). Most AI tools can configure MCP servers automatically.
Or install manually. Add to your tool's MCP settings:
{
"mcpServers": {
"galaxybrain": {
"command": "npx",
"args": ["-y", "galaxybrain-mcp"]
}
}
}
The MCP server starts a local API server automatically if one isn't already running. It communicates with GalaxyBrain browser tabs over a local WebSocket connection (default port 1924).
Port override
{
"mcpServers": {
"galaxybrain": {
"command": "npx",
"args": ["-y", "galaxybrain-mcp"],
"env": { "GB_API_PORT": "3000" }
}
}
}
If you override the port, also pass ?gb_port=3000 in the GalaxyBrain browser URL.
How It Works
The MCP server is a thin translation layer. It receives tool calls from your AI assistant, converts them to WebSocket commands, sends them to the API server, and formats the responses.
Multiple MCP server processes can connect simultaneously. The API server is started automatically if not already running. When the MCP session that spawned the API server exits, it terminates the API server. Other connected MCP sessions will automatically re-spawn it on their next command.
Version Checking
The MCP server performs two version checks:
- Protocol compatibility — Before connecting to an API server, the MCP server checks the API server's protocol version (from the HTTP health check response
"GalaxyBrain API Server/{version}"). If the versions don't match, it returns an error with instructions to stop the old server. This also applies after spawning a new API server, as a belt-and-suspenders check for npm dependency mismatches. - npm update check — On startup, the MCP server checks the npm registry for newer versions of
galaxybrain-mcp. If an update is available, it logs a warning to stderr and prepends the update notice togalaxybrain_status,galaxybrain_orient, andgalaxybrain_helpresponses. The rawgalaxybrain_statusoutput also exposes a structuredmcp.updateStatefield so agents can detect the update programmatically and callgalaxybrain_updateto warm the npx cache.
Tools Overview
The MCP server provides 13 tools. Use galaxybrain_help to look up detailed schemas for complex nested payloads.
galaxybrain_status
Check whether the API server is running and list connected browser tabs. Shows each tab's state, project, and connection details. Use this first to confirm connectivity.
The raw output of galaxybrain_status is MCP-enriched (not a pure pass-through of the API response). Two top-level blocks are injected:
mcp—{ version, updateState }.updateStateis one of"checking","up-to-date","available", or"failed". When the state is"available", the block also includeslatestKnownandupdateAvailable: true.api—{ protocolVersion, port }. The MCP ↔ API protocol version in use and the bound port.
Agents can gate offers of galaxybrain_update on mcp.updateAvailable === true.
galaxybrain_project
Manage the project lifecycle: list available folders and demos, open_folder by ID, open_demo by name, close the current project, or remove_folder from recents.
galaxybrain_orient
Get a structural overview of the open project — page and template counts, hub structure (link hierarchy), and currently open tabs. Call this after opening a project.
galaxybrain_read_pages
Read full serialized content of pages or templates. Select by ID or read all open tabs. Control returned fields with icon, title, subtitle, blocks flags. Use blockIds to read specific blocks. Supports scope: "templates".
galaxybrain_query
Search and filter pages with text search, error search, references search, graph filters, count filters, field projection, sorting, and pagination. Returns lightweight results by default — use fields to include additional data. Call galaxybrain_help("query") for full filter docs.
References search — search: { references: <target>, sections?: ["subtitle","blocks"] } finds structural references to a single target across subtitles, block items, var formulas, and block linkOrder keys. Targets:
{ imageId: "<64hex>" }or{ imageId: "<64hex>.<ext>" }— image items only{ varName: "...", prefix?: true }— var defs + V refs + PLCV refs + linkOrder keys (V refs use live name lookup;prefix: trueenables trailing-* match){ metaRef: { head, pageId?, blockId?, varId?, type?, derivation?, varName?, format? } }—headmust be"CT","CA","UA","V","PLCV", or"M"{ pageLink: { pageId } }— both standalone page link items and inline pageLink units{ webLinkUrl: "..." }— exact URL match on webLink units
galaxybrain_traverse
Build a recursive page-link tree starting from a root page:
- down (MAP) — walks outbound links.
limitsis optional: passnullfor auto mode (~200 page budget) or[]for leaf only. - up (ANCESTORS) — walks inbound links.
limitsis required (e.g.[10, 5, 3]for per-layer budgets) — there is no auto mode.
Optionally include subtitle text and block text previews.
galaxybrain_write_pages
Create, update, or delete pages or templates. Supports full replacement, surgical block-level edits, and image uploads via base64.
galaxybrain_create_from_template
Create a page from a template with automatic value resolution: nextNumber, nextDay, dateToday. A page link is inserted into the specified source block.
galaxybrain_items
Push (insert) or pop (remove) items from specific blocks. More precise than full page updates — useful for appending tasks, inserting links, or removing items.
galaxybrain_workspace
Read or write the workspace tab layout — which tabs are open, their widths, scroll positions, and navigation paths. Supports optimistic concurrency via readVersion.
galaxybrain_watch
Start watching for real-time events. Returns a shell command to run with your AI tool's process monitor. Supports event-type filters, content-derived filters, and hooks. See Event Watching.
galaxybrain_update
Warm the npx cache for galaxybrain-mcp@latest so the next MCP host restart picks up the new version. Input schema is empty. Check galaxybrain_status.mcp.updateAvailable first; offer this tool when it is true. On success, returns a message instructing the user to restart their MCP host. No-op for non-npx installs. Process timeout is 120 seconds.
galaxybrain_help
Look up detailed documentation on a specific topic during a session. Available topics:
| Topic | Description |
|---|---|
commands | Overview of all tools and workflow guidance |
query | Search filters, fields, sorting, pagination |
meta_refs | Meta reference format strings |
styles | Text item style values |
link_order | Link order format and sort keys |
units | Unit types, fields, and context restrictions |
images | Image ID format and images map |
versions | Version semantics and conflict detection |
instances | Instance states and routing |
templates | Template pages and value types |
workspace | Workspace layout and validation rules |
anchor_offset | Push/pop anchor and offset semantics |
page_body | Full page body schema |
surgical_update | Surgical update fields and behavior |
read_shapes | Serialized schemas from read commands |
watch | Watch system: events, content filters, hooks |
errors | Common error codes |
troubleshooting | Version mismatches, updating, common errors |
docs | Links to full online documentation |
Typical Workflow
If no project is open, use galaxybrain_project to list and open one first. Most of the time, a project is already open in the browser.
Data Model
GalaxyBrain organizes content in a hierarchy: Pages → Blocks → Items → Units.
Pages
| Field | Description |
|---|---|
pageId | 20-character alphanumeric ID (e.g. AbcDef1234567890GhIj) |
icon | Single emoji |
title | Array of title units (text and template values only) |
subtitle | Array of units (all types) |
blocks | Array of blocks |
Read-only fields: blockOrder, createdAt, updatedAt, templateValues, counts.
Blocks
| Field | Description |
|---|---|
blockId | Non-negative integer, unique within the page |
items | Non-empty array of items |
linkOrder | Optional sort rule for page-link items (e.g. A.M.tt for title A-Z) |
Items
| Type | Description |
|---|---|
text | Styled text content with a style and content units |
var | Named variable with a formula that evaluates to a value |
image | Image, referenced by content-addressed ID |
pageLink | Standalone link to another page |
Text item styles
| Style | Meaning |
|---|---|
"" | Body text |
"#" | Heading 1 |
"##" | Heading 2 |
"###" | Heading 3 |
"*" | Bullet list |
"[ ]" | Unchecked checkbox |
"[X]" | Checked checkbox |
"ol" | Ordered list |
Text items also support indentLevel (0-8) for nesting.
Units
| Type | Description |
|---|---|
text | Plain or styled text (unitStyle: bold, italic, boldItalic) |
webLink | Hyperlink with display text and URL |
pageLink | Inline reference to another page |
metaRef | Live computed value (timestamps, counts, variables) |
templateValue | Placeholder resolved when creating from a template |
Templates
Templates are special pages that serve as blueprints. They use the same structure as regular pages but can contain templateValue units resolved at creation time. Access templates by passing scope: "templates" to read, write, and items tools.
Writing Content
Creating a Page
Pass a full page body to galaxybrain_write_pages with action: "create":
{
"action": "create",
"pages": [{
"icon": "📝",
"title": [{ "type": "text", "text": "My Page" }],
"subtitle": [],
"blocks": [{
"blockId": 0,
"items": [{
"type": "text",
"style": "",
"content": [{ "type": "text", "text": "Hello world" }]
}]
}]
}]
}
Pass null in the pages array to create a default blank page.
Updating a Page
For a full replacement, pass the complete page body with a pageId:
{
"action": "update",
"pages": [{
"pageId": "AbcDef1234567890GhIj",
"icon": "🔥",
"title": [{ "type": "text", "text": "Updated Title" }],
"subtitle": [],
"blocks": [{ "blockId": 0, "items": [...] }]
}]
}
Surgical Updates
Modify specific blocks without replacing the entire page:
{
"action": "update",
"pages": [{
"pageId": "AbcDef1234567890GhIj",
"title": [{ "type": "text", "text": "New Title" }],
"updateBlocks": [{ "blockId": 0, "items": [...] }],
"insertBlocks": [{ "blockId": 5, "items": [...] }],
"deleteBlockIds": [2, 3]
}]
}
blocks (full replacement) and surgical fields are mutually exclusive.
Push and Pop
Use galaxybrain_items for targeted insertions and removals:
Push (insert items)
{
"action": "push",
"operations": [{
"pageId": "AbcDef1234567890GhIj",
"blockId": 0,
"anchor": "bottom", "offset": 0,
"items": [{
"type": "text", "style": "[ ]",
"content": [{ "type": "text", "text": "New task" }]
}]
}]
}
Pop (remove items)
{
"action": "pop",
"operations": [{
"pageId": "AbcDef1234567890GhIj",
"blockId": 0,
"anchor": "bottom", "offset": 0,
"count": 1
}]
}
Position reference
| Position | Meaning |
|---|---|
top + 0 | Beginning of the block |
bottom + 0 | End of the block |
top + 2 | After the second item |
bottom + 1 | Before the last item |
Batch Semantics
Create, update, delete, push, and pop all accept arrays. Each entry succeeds or fails independently. Responses include a results array aligned to input order.
Normalization
Written content is normalized automatically: adjacent compatible units are merged, lone pageLink units in unstyled text items are promoted to standalone items. Content may look different on read.
Output Modes
| Mode | Description |
|---|---|
summary | Human-readable formatted text |
raw | Full JSON response from the API |
full | Summary text with raw JSON appended |
Defaults by tool
| Default | Tools |
|---|---|
summary | galaxybrain_status, galaxybrain_orient, galaxybrain_query, galaxybrain_traverse |
full | galaxybrain_read_pages, galaxybrain_write_pages, galaxybrain_create_from_template, galaxybrain_items, galaxybrain_workspace, galaxybrain_project |
galaxybrain_help, galaxybrain_watch, and galaxybrain_update do not use output modes.
Instances
A GalaxyBrain instance is a browser tab connected to the API server.
| State | Description |
|---|---|
picker | No project is open |
folder | A folder-backed project is open |
demo | A demo project is open |
Routing rules
- One instance connected —
instanceis optional; auto-routed. - Multiple instances —
instanceis required. Usegalaxybrain_statusto list them. - No instances — commands fail with
NO_INSTANCES. Open GalaxyBrain in a browser.
Versions & Conflict Detection
Each page has an independent integer version that increments on every mutation. Pass readVersion with mutations for optimistic concurrency:
- Match — mutation proceeds.
- Mismatch —
CONFLICTerror. Re-read and retry. - Omitted — conflict check is skipped.
Where readVersion goes
| Command | Location |
|---|---|
| Page updates | Inside each page object in the pages array |
| Push/pop operations | Inside each operation object |
| Workspace writes | Top-level readVersion parameter |
| Create and delete | Not used |
Event Watching
The galaxybrain_watch tool sets up real-time event monitoring. It returns a shell command to run with your AI tool's process monitor. Each matching event prints a line to stdout.
galaxybrain_watch.
Event Types
Page events
| Event | Description | Filters |
|---|---|---|
pages_created | Pages were created | templateId, titlePattern |
pages_deleted | Pages were deleted | — |
pages_updated | Page content changed | pageIds, scope, role, source |
Workspace events
| Event | Description | Filters |
|---|---|---|
workspace_tab_opened | Tab opened | pageId |
workspace_tab_closed | Tab closed | pageId |
workspace_tab_navigated | Tab changed pages | newPageId |
workspace_tab_resized | Tab resized | — |
workspace_scrolled | Workspace scrolled | pageId |
workspace_changed | Layout changed | — |
Project events
project_opened, project_closed, concurrent_access_detected
File events
files_changed โ fires for each filesystem change produced by an active FILES_WATCH subscription (see File Watching below).
File Watching
File watching lets you drive agents off filesystem activity inside your GalaxyBrain project folder, not just app-internal mutations. It's a thin wrapper around Chromium's FileSystemObserver, exposed through the same monitor script as everything else in galaxybrain_watch.
Typical uses:
- Inbox processing. Drop a PDF into
inbox/, have the agent OCR it, write a page, move the file toinbox/processed/. - External edit sync. Watch a subfolder you also edit outside GalaxyBrain and reconcile changes back into pages.
- Attachment pipelines. React when images, audio, or exports land in a known drop folder โ e.g. transcribe voice memos, tag screenshots, thumbnail photos.
- Cleanup / audit. Alert on unexpected deletions or moves inside critical folders.
Pass files_subscriptions to galaxybrain_watch to start one or more folder watches when the monitor connects. Each entry fires a FILES_WATCH against the open instance before the monitor subscribes to the event stream:
{
"files_subscriptions": [
{ "subpath": "inbox", "recursive": true }
]
}
subpath is forward-slash-delimited and must resolve to an existing directory under the project root. Leading /, backslashes, Windows-absolute paths, .., ., and empty segments are rejected. recursive defaults to false โ without it you only see direct children of the folder.
Each change produces one files_changed stdout line carrying subscriptionId, subpath, recursive, changeType, path (array, relative to subpath), and movedFrom (array on moved, null otherwise). Change types mirror the platform API:
| changeType | Meaning |
|---|---|
appeared | A file or directory was created or moved into the watched subtree. |
disappeared | A file or directory was removed from the watched subtree. |
modified | A file's contents or metadata changed. |
moved | A file or directory was renamed within the same directory. movedFrom carries the previous path. |
unknown | The OS dropped events โ state may have diverged; rescan if correctness matters. |
errored | The observation is dead. GalaxyBrain removes the subscription automatically; issue files_subscriptions again on the next monitor run. |
Use files_change_types to narrow the stream to the records you care about:
{
"files_subscriptions": [{ "subpath": "inbox", "recursive": true }],
"files_change_types": ["appeared", "moved"]
}
File watches fail with specific wire errors you may need to handle:
FOLDER_UNAVAILABLEโ the open project is a demo / in-memory, so there's no real folder to observe.UNSUPPORTED_BROWSERโ the browser doesn't exposeFileSystemObserver(currently Chromium-only).FOLDER_NOT_FOUNDโ thesubpathdoesn't resolve to an existing directory under the project root.NO_PROJECTโ no project is open.
FILES_UNWATCH on graceful exit and on reconnect (so duplicates don't accumulate). A hard kill leaves watches running on the instance until the project is closed, the folder is switched, the app is reloaded, or Chrome emits an errored record.
Built-in filter: files_changed events whose last path segment is .DS_Store are dropped before emission โ macOS metadata noise is never forwarded to the agent.
Other sharp edges: Windows reports cross-directory moves as a disappeared+appeared pair rather than a single moved record. File events are not file-readiness events โ a large file copy produces appeared (and possibly modified) before the writer has finished, so use temp-then-rename or wait for size/mtime stability if completion matters. Per-origin observation limits are OS-dependent and surface as errored.
Content Filters
Content filters detect specific changes within pages_updated events by comparing before/after state. Each filter has a required type field and optional scoping.
Block-level filters
Support pageIds and blockId scoping:
| Filter | Detects | Extra fields |
|---|---|---|
block_changed | Any modification to a block | — |
checkbox_count_changed | Total checkbox count changed | — |
checked_count_changed | Checked checkbox count changed | — |
image_count_changed | Image item count changed | — |
page_link_item_count_changed | Page link count changed | targetPageId (optional) |
item_style_changed | Text item style changed | — |
web_link_unit_added / removed | Web link units added/removed | — |
meta_ref_unit_added / removed | Meta ref units added/removed | — |
Page-level filters
Support pageIds scoping:
| Filter | Detects | Extra fields |
|---|---|---|
page_link_unit_added / removed | Inline page link units | targetPageId (optional) |
var_value_changed | Variable value changed | pageId (required), varId (optional) |
var_added / var_removed | Variable items added/removed | — |
title_changed | Page title changed | — |
subtitle_changed | Page subtitle changed | — |
icon_changed | Page icon changed | — |
block_created / block_deleted | Blocks created/deleted | — |
include_diffs: false to reduce token usage and only receive change metadata.
Hooks
Hooks are optional JavaScript/TypeScript modules that run on each matched event before it reaches the agent. They can perform side effects, suppress events (return false), or replace the output (return a string).
// update-subtitle-hook.ts
export default async function(match, context) {
if (match.output.filter === "checked_count_changed"
&& match.output.afterChecked > match.output.beforeChecked) {
await context.sendCommand("UPDATE_PAGES", {
pages: [{ pageId: match.output.pageId,
subtitle: [{ type: "text", text: "Processing..." }] }]
});
}
}
Return values
undefined— event passes through normallyfalse— event is suppressed (agent is not woken)string— replaces the default output (agent sees your string)
Use hook_debug: true for verbose tracing of all hook calls.
source: ["user"] in your filter spec to prevent infinite loops. Commands from context.sendCommand have source "api".
Error Reference
Routing errors
| Code | Meaning |
|---|---|
NO_INSTANCES | No GalaxyBrain browser tabs connected |
INSTANCE_REQUIRED | Multiple tabs connected; specify instance |
UNKNOWN_INSTANCE | Specified instance ID not found |
Command errors
| Code | Meaning |
|---|---|
NO_PROJECT | Command requires an open project |
CONFLICT | readVersion mismatch — re-read and retry |
PARSE_ERROR | Invalid payload shape or field types |
PAGE_NOT_FOUND | Page or template does not exist |
TEMPLATE_PAGE | Regular-page command sent to a template |
NOT_TEMPLATE_PAGE | Template command sent to a regular page |
LAST_PAGE | Cannot delete the last remaining page |
NO_REMAINING_ITEMS | Pop would remove every item from a block |
SELF_LINK | Page link points to itself |
PERMISSION_REQUIRED | Browser requires user gesture for folder access |
BLOCK_NOT_FOUND | Block ID doesn't exist |
BLOCK_ALREADY_EXISTS | Inserted block ID already exists |
NO_UPDATES | Surgical update contained no changes |
DUPLICATE_BLOCK_OP | Same block in multiple surgical operations |
BLOCK_ORDER_MISMATCH | blockOrder doesn't match final block set |
UNEXPECTED_ITEM_TYPE | Pop expectedItemType mismatch |
INVALID_TEMPLATE_ID | Template ID doesn't exist |
NO_ITEMS | Empty items array |
DUPLICATE_VAR_ID | Duplicate variable ID within a page |
Troubleshooting
Prerequisites
GalaxyBrain MCP requires Bun. Install:
- macOS/Linux:
curl -fsSL https://bun.sh/install | bash - Windows:
powershell -c "irm bun.sh/install.ps1 | iex"
After installing, fully quit your MCP host and relaunch it from a fresh terminal where bun --version works — the host inherits PATH from the terminal that launched it, not from ~/.zshrc or ~/.bashrc.
If Bun is installed at an unusual path, set GB_BUN_PATH to its absolute path in the host's environment.
Recommended Setup
Configure your MCP client with:
{ "command": "npx", "args": ["-y", "galaxybrain-mcp"] }
The -y flag auto-confirms the install prompt. Without it, npx may hang waiting for confirmation since MCP servers have no interactive terminal.
Updating
The MCP server checks for updates on startup and re-checks lazily during long sessions. When an update is available, the notice is prepended to galaxybrain_status, galaxybrain_orient, and galaxybrain_help output; agents can also detect it programmatically via galaxybrain_status raw output (mcp.updateAvailable === true).
Agents should prefer calling galaxybrain_update — it warms the npx cache without requiring the user to drop to a shell. After it reports success, the user must restart their MCP host for the new version to take effect. The shell equivalent is:
npx -y galaxybrain-mcp@latest
To update the API server:
npx -y galaxybrain-api@latest
If an old API server is still running, stop it first:
lsof -ti :1924 | xargs kill
npx Caching
npx caches packages locally. Running npx -y galaxybrain-mcp uses the cached version without checking for updates — this keeps startup fast. To force an update, run npx -y galaxybrain-mcp@latest once. Subsequent runs use the updated cache.
Do not use @latest in your MCP client configuration — it causes a network request to the npm registry on every startup, adding latency.
Version Mismatches
The browser app, API server, and MCP server share a protocol version. When versions don't match:
- MCP ↔ API server — The MCP server checks protocol compatibility before connecting. Incompatible versions produce a clear error with update instructions.
- Browser app ↔ API server — The app checks on WebSocket connect. Incompatible versions show a warning toast with update instructions.
Common Errors
| Error | Cause | Fix |
|---|---|---|
GalaxyBrain MCP requires Bun | Bun not installed or not findable from the MCP host's PATH | Install Bun (see Prerequisites above); if already installed, relaunch the host from a terminal where bun --version works |
env: bun: No such file or directory | Host launched from a shell without Bun on PATH | Quit the host, open a fresh terminal where bun --version works, relaunch the host from there |
| "incompatible version" | MCP/API protocol versions don't match | Update both: npx -y galaxybrain-api@latest and npx -y galaxybrain-mcp@latest |
| "Port in use by another process" | Non-GalaxyBrain process on port 1924 | Stop it: lsof -ti :1924 | xargs kill |
| "No GalaxyBrain browser tabs connected" | No browser tab connected to the API server | Open GalaxyBrain in Chrome, or check for version mismatch |
| "No project is open" | Browser tab is on the folder picker | Open a folder or demo via galaxybrain_project |
Further Reading
- GalaxyBrain API Reference — full WebSocket API with transport details, data model schemas, and all command specifications.
galaxybrain_helptool — call it from your AI tool for detailed, contextual documentation during a session.