Skip to main content
Glama
robfischer1

Calliope MCP Server

by robfischer1

@forge/calliope — the prose/body-facet constellation star

Calliope stores and serves node bodies behind an MCP server — since the Git for Ideas arc (2026-08-16), as git's factoring: immutable content-deduped blobs in Calliope's own Postgres, tree/commit/history as facts in the chaos graph, one save = one transaction, history = a read at an earlier transaction. It is the peer of clotho (the work/graph facet): clotho owns graph structure (parent, dependsOn, status, …); Calliope owns every body, prose notes and work-node plan prose alike [Rob, 2026-07-04]. The same engine ships twice: the fleet star, and the Grace desktop sidecar running a bundled PostgreSQL + the real chaosstore binary (baby chaos, F13).

The Muse shed its UI (2026-07-04). Through spec 001-muse-sheds-ui, the ProseMirror editor component that used to live here moved to @forge/aglaia. This repo is now service-only: the body-model types, three body-store backends (pg/hades/urania, plus an in-memory fixture for tests), and an MCP server exposed over stdio and streamable-HTTP. If you're looking for the editor UI, it's in aglaia.

The repo is a turbo monorepo (2026-07-10). Adopted onto the frontend-repo-template (chore/adopt-frontend-template, flat → monorepo): the package now lives at apps/calliope/ (workspaces: apps/*, currently just this one app; packages/* is reserved by the template, unused so far). Root package.json scripts (lint/typecheck/test/build) delegate to turbo run <task>, which fans out to each workspace's own script. All src/ paths below are relative to apps/calliope/, not the repo root.

Body model — the blob store and the tree (Git for Ideas, 039–047)

Since 2026-08-16 the store IS git's factoring (specs 039047, the Git for Ideas master-plan (vault), all fourteen features landed in one arc):

  • Blobs (apps/calliope/src/blob-store.ts, table blobs in calliope-db): immutable, content-deduped prose — id bigint identity, text, identity enforced by a unique expression index over an IMMUTABLE sha256 wrapper (blob_content_hash). Mint returns the existing id on a duplicate; identical prose anywhere in the system is ONE row.

  • The tree (facts in the chaos graph, per-tenant): a container node holds tree_member edges to kind-Block slot nodes; each slot holds a fractional tree_position literal and a tree_content edge into the blob store (chaos's third object domain, o_blob). Container+position is identity — an edit repoints ONE slot, a reorder rewrites ONE position.

  • A save is one commit (container-write.ts): the client computes the op batch (aglaia's diff), blobs mint first, and the surviving tree facts ride a single admitted graph transaction. Byte-identical content nets out — a save whose ops all net to nothing writes nothing.

  • History is not a feature (container-read.ts + chaos's history verb): every save carries a transaction id, so any past state is the same tree read with as_of_tx, and the history listing is the graph's own transaction log. No revision tables.

  • Blob GC (blob-census.ts): an inverted census — chaos reports the LOG of blob ids each tenant graph has ever named (held_blobs), calliope reaps only on a complete roster of reports, mark-and-sweep across two complete censuses.

The old model — the sections table with copy-on-write lineage, supersessions, comments_on — was migrated (7,416 containers, full two-sided parity; report at specs/043-migrate-tree/parity-report.json) and then dropped from production (the gated cut, spec 047). A fresh install bootstraps the blob store only; the legacy DDL exists solely behind ensureSchema({ legacy: true }), which the migration suite uses to simulate an old store. src/order-key.ts still mints the fractional position keys (COLLATE "C", compared as raw bytes).

Related MCP server: memory-mcp

Backends

Backend selection (src/mcp/backend.ts) reads the environment, in order:

CALLIOPE_MCP_BACKEND

Condition

Client

Store

pg

DATABASE_URL set (or explicit)

PgBodyClient

sovereign store calliope-dbthe default in production

hades

CALLIOPE_WRITE_VIA_HADES=1 / CHARON_URL set (or explicit)

UraniaBodyClient + HadesCapture

gateway-auth path; writes carry authored_by=human

urania

fallback

UraniaBodyClient + LiveUraniaCapture

direct chaos/urania engine service (CHAOS_URL, legacy URANIA_URL) — migration reads only, post-C2

fixture

explicit only

FixtureBodyClient

in-memory — dev/test

The pg and fixture backends additionally provide a document store (C3, the internal dissolve sink — its verbs retired in F12), a revision store (C4), and the container facet (blobs + the chaos dial — the write path) off the same pool/memory; the substrate-direct backends (urania, hades) do not. Both fleet entries pass the container facet to the server explicitly (an F12 audit finding: it was wired in the backend since F4 but served by neither entry until the cut — the production-shape regression pin in __tests__/mcp-http.test.ts keeps it that way).

The desktop is its own backend (F13/F14, specs 045/046): the Grace sidecar (src/mcp/sidecar.ts) boots a bundled PostgreSQL + the real chaosstore binary (src/mcp/babychaos.ts) and serves everything from ONE LocalEngineStore (src/local-store.ts) — node identity is the markdown path, the container is the graph node labelled by it, the markdown directory is a projected WORKING TREE (external edits ingest like git add), and admits translate in-process without themis (src/local-admit.ts, a port of go-court ToWire held by the court's own pinned constants). Payloads are assembled by scripts/fetch-babychaos-payload.ts (zonky embedded-postgres + a go build of chaosstore, linux and windows).

MCP tools — the post-cut surface (F12)

The fleet serves sixteen verbs, pinned (names AND annotations) by an executable fence in __tests__/mcp-http.test.ts — change the surface only alongside the plan that licenses it:

The container surface (the ONE write path):

  • write_container(container, ops, tenant?) — the tree-native save: one graph transaction, blob-first, identical content nets out

  • read_container(container, as_of_tx?) — ordered blocks (slot, position, blobId, text); dangling blobs surfaced, never fabricated

  • container_history(container) — the container's transactions (history IS the graph)

  • blob_census() — the F7 GC (roster-gated mark-and-sweep)

The note-native verbs (C8/F10): create_note, dissolve_note, export_note, materialize_note. Findability: search, list_tags, list_by_tag, copy_reference. Attention: look, unpin. The frozen git-for-ideas archive (read-only): file_revisions, revision_deltas.

Retired by the F12 cut (2026-08-16) — the body family (read_body, write_body, has_body, read_body_revisions, read_body_at), the section family (apply_section_ops, append_section, edit_section), the block family (create/read/update/delete/split/merge_block, list_blocks, coalesce_block_writes), the document/plan verbs (write_document, read_documents, read_plan), and the comments pair. Charon's /body allowlist moved with the surface; the fleet-wide caller sweep ran first (theia's clients were repointed in the same feature).

The desktop exception: the sidecar's loopback /mcp additionally serves path-addressed body verbs (read_body/write_body/ apply_section_ops/read_body_revisions/read_body_at/has_body) behind the pathBodies server option ONLY it passes — those are the F14 engine-backed surface sharing the old wire spellings, not the old model.

Transports

Two bins, same server (src/mcp/server.ts, four-to-nine tools depending on which facet stores the backend supplies), reused unforked:

  • calliope-mcp (src/mcp/main.ts) — stdio, for local/CLI use.

  • calliope-mcp-http (src/mcp/http.ts) — streamable-HTTP, POST /mcp on $PORT (else $CALLIOPE_MCP_PORT, else 8204). Stateless: a fresh server+transport per request over a long-lived backend. This is the constellation-star form — the Hades MCP gateway fronts it east-west at http://calliope-mcp:8204/mcp.

Deploy (nas01 star)

Deploy is no longer local to this repo. The repo used to ship its own compose.yaml + .forgejo/workflows/deploy.yml; both are retired ("services lane owns deploy now" / "state lives in the services lane") — there is no infra/ and no local deploy.yml here anymore. What remains in this repo:

  • Dockerfile — the image build only (see below), no deploy step.

  • star.toml — the conformance target the shared admission gate reads (image ref, entrypoint apps/calliope/src/mcp/http.ts, the governance policy bundle). Derived by the Hephaestus foundry — do not hand-edit.

  • .forgejo/workflows/build.yml — a caller stub (push to main, non-docs/non-infra paths) delegating to the shared, language-agnostic foundry/foundry-stocks reusable build workflow (docker build ., the Dockerfile does the rest).

  • .forgejo/workflows/ci.yml — a caller stub (on pull_request) delegating to the shared frontend-ci.yml reusable workflow (bun install + bun run gate + audit + opengrep).

The image itself: oven/bun-based multi-stage build on stellar_core:bun-mcp (digest-pinned, not a floating tag); the runtime stage ships only the bun build --target=bun-bundled server.jsno source tree, no node_modules, no bun install in the deployed image (see Dockerfile). Publish/sign/scan/deploy mechanics now live in the shared foundry-stocks workflows and the services-lane deploy pipeline, not in this repo — read star.toml + the two .forgejo/workflows/*.yml caller stubs for what this repo actually controls, not this README, if those diverge.

Project structure

Turbo monorepo root — the package lives under apps/calliope/:

apps/calliope/
  src/
    types.ts              Section / SectionInput / BodyClient contract (capability
                           methods REQUIRED since the F14 interface collapse)
    index.ts              public package exports (@forge/calliope)
    order-key.ts           fractional order-key scheme (COLLATE "C")
    blob-store.ts          BlobStore / FixtureBlobStore / PgBlobGc — F1/F7
    tree.ts                tree vocabulary + slot op builders + readTree — F3
    container-write.ts     writeContainer: ops -> blobs -> ONE admit — F4
    container-read.ts      readContainer (HEAD / as-of) + containerHistory — F5
    blob-census.ts         the inverted-census GC — F7
    chaos-client.ts        ChaosDial (Live/Fixture) — the graph wire
    local-admit.ts         LocalChaosDial — themis-free desktop admit (F13)
    local-store.ts         LocalEngineStore — the desktop backend: engine +
                           working-tree projection/ingestion + tags + FTS (F14)
    search-types.ts        the search seam types (SearchProvider et al.)
    eros-provider.ts       the fleet's search arm (eros-routed)
    fixture-client.ts      FixtureBodyClient — in-memory, dev/test
    urania-client.ts       UraniaBodyClient — substrate-triple mapping (legacy reads)
    pg-client.ts           PgBodyClient — blob-store DDL; the legacy sections DDL
                           only behind ensureSchema({legacy: true}) (migration suite)
    document-store.ts      DocumentStore (C3) — the internal dissolve sink
    revision-store.ts      RevisionStore (C4) — frozen archive, read-only
    plan-blocks.ts         plan block-addressing (C7; its verb retired in F12)
    mcp/
      backend.ts           env -> BackendKind -> BodyClient + facet stores
      server.ts            createServer() — the 16-verb fleet surface;
                           pathBodies option adds the desktop's body dialect
      tools.ts             tool handler functions (pure over a BodyClient)
      main.ts              calliope-mcp bin (stdio)
      http.ts              calliope-mcp-http bin (streamable-HTTP, :8204)
      sidecar.ts           the Grace desktop sidecar — engine-backed (F13/F14)
      babychaos.ts         payload resolve + engine boot/stop (F13)
      drop-old-tables.ts   the F12 gated drop (parity report + frozen-store check)
      migrate-tree.ts      the F6 migration engine (retry armor, crash recovery,
                           carrier fallback) — the old store's replay
      index-push.ts        IndexingBodyClient — similarity-index push decorator
      backfill-index.ts    one-off index backfill CLI
      heartbeat.ts         op-contract heartbeat -> Pontus
      hades-capture.ts / live-capture.ts   legacy substrate transports
      migrate.ts / migrate-documents.ts / migrate-revisions.ts /
      migrate-dissolution-archive.ts       the C2-C5 era migrations (historical)
  scripts/
    fetch-babychaos-payload.ts   assemble the desktop engine payload (F13)
  __tests__/               vitest specs (49 files; engine suites gated on
                           CALLIOPE_BABYCHAOS_DIR / CALLIOPE_CHAOSSTORE_BIN)
docs/body-facet.md         C2 ownership record (historical; superseded by 039-047)
specs/                     spec-kit feature dirs — 039-047 are the Git for Ideas
                           arc; 043 carries the production parity report

Develop

From the repo root (turbo fans out to the one workspace, apps/calliope):

bun install
bun run lint         # turbo run lint       -> eslint .
bun run typecheck    # turbo run typecheck  -> tsc --noEmit
bun run test         # turbo run test       -> vitest run
bun run format       # prettier --write "**/*.{ts,tsx,json,css}"
bun run format:check
bun run gate         # format:check && turbo run lint typecheck test build

Or from apps/calliope/ directly (same scripts, plus dev/run):

bun run test:watch   # vitest
bun run start        # calliope-mcp over stdio
bun run start:http   # calliope-mcp-http, :8204
bun run dev          # bun run --watch src/mcp/http.ts
bun run build        # bun build src/mcp/http.ts --target=bun --outfile dist/server.js

bun runs the TypeScript directly in dev/test — no build step, no dist/, until you explicitly bun run build (or the Dockerfile does, for the deployed image). Requires Node >=22.13 (.nvmrc: 22) and the pinned bun@1.3.14 (packageManager in the root package.json).

Status

Version 0.1.0, Apache-2.0, single-author (Rob Fischer). The Git for Ideas arc is complete (2026-08-16, specs 039047): the blob store (F1), the tree + container write/read/history (F3–F5), blob GC (F7), the ferry + editor + consumer repoints (F8–F11), the full production migration to two-sided parity (F6 — 7,416 containers, report archived in specs/043-migrate-tree/), the desktop engine (F13 baby chaos), the deletion of the parallel fs implementation (F14), and the cut (F12 — the old verb families retired and sections/supersessions/comments_on dropped from production behind the gated tool). The C2–C5/A8/A11/C7 era described in docs/body-facet.md and the older spec dirs is historical context: its storage model and most of its verb surface no longer exist.

Available Tools

4 tools
append_sectionAppend a sectionA

Append one new section to the end of a plan node's body. Returns the appended { section } and the new body { count }.

ParametersJSON Schema
NameRequiredDescriptionDefault
node_idYesThe node to append to.
textYesThe new section's prose.

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description carries full burden. It discloses the append action and return values (section and count) but lacks details on idempotency, permissions, or edge cases. Adequate but not rich.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences: first states the action, second states the return. No fluff, well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with 2 params and no output schema, the description covers core behavior and returns, but misses potential error conditions, prerequisites, or clarification of 'section' and 'count' which could affect agent understanding.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with clear descriptions. The tool description adds context that 'text' is prose for a new section appended to the end and specifies return fields, adding value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Append' and the resource 'one new section to the end of a plan node's body,' distinguishing it from sibling tools like 'edit_section' (modify) and 'write_body' (overwrite).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies appending is the intended use but does not explicitly contrast with siblings or state when not to use it, leaving the agent to infer from tool names.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

edit_sectionEdit one sectionA

Replace the prose of a single section (copy-on-write), keeping its position and every other section untouched. Returns the edited { section }.

ParametersJSON Schema
NameRequiredDescriptionDefault
node_idYesThe node owning the section.
section_idYesThe section to edit.
textYesThe section's new prose.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses key behavioral traits: it performs a copy-on-write, preserves position and other sections, and returns the edited section. Since no annotations are provided, the description carries the full burden and does so adequately, though it could mention side effects like required permissions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences, front-loading the action and purpose without extraneous details. Every sentence adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and no annotations, the description covers the core behavior and return value. It includes details like copy-on-write and positional preservation, but could be more complete with error handling or prerequisites.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the description adds no additional meaning beyond the schema. The baseline of 3 is appropriate as the schema already documents the parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Replace the prose of a single section' with a specific verb and resource, and distinguishes from siblings like 'append_section' and 'write_body' by specifying it edits one section while keeping others untouched.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies use when editing a single section rather than appending or rewriting the whole body, but does not explicitly state when not to use or provide alternatives. The sibling tool names provide additional context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_bodyRead node bodyA

Resolve a plan node's body — its prose sections, sorted by order key. Returns { sections: [{ id, text, orderKey }] }; a node with no body returns an empty list.

ParametersJSON Schema
NameRequiredDescriptionDefault
node_idYesThe node whose body to read.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Describes return format and empty body behavior; no annotations, but read-only nature is clear.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences front-loading action and output details; no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers purpose, output, and edge case; no mention of size limits but adequate for simple tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter fully described in schema; description adds no extra meaning beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it reads a plan node's body, returns sorted prose sections, and distinguishes from siblings like write_body.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage for retrieving node body, but no explicit when-to-use or when-not-to-use compared to sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_bodyWrite node body (coarse save)A

Replace a plan node's whole body with the given sections, in display order. The substrate mints fresh order keys and copy-on-writes changed prose. Returns { ok, count }.

ParametersJSON Schema
NameRequiredDescriptionDefault
node_idYesThe node whose body to replace.
sectionsYesThe new sections, in display order.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses internal behaviors: 'mints fresh order keys and copy-on-writes changed prose', and specifies the return format. It could mention side effects like overwriting existing sections, but that is implied by 'replace whole body'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: first states purpose, second adds behavioral detail and return. Every word is earned. No redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple tool with full schema coverage and no output schema, the description covers purpose, behavior, and return. It lacks guidance on when to use versus siblings and prerequisites, but overall it is sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, but the description adds value by clarifying that sections are 'in display order', which is not in the parameter schema. It also reinforces that the replacement is whole-body.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'replace' and the resource 'plan node's whole body', specifying sections and display order. It effectively distinguishes from siblings by implying full replacement versus append/edit/read.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit when-to-use or when-not-to-use guidance is given. The purpose implies replacement for full body changes, but alternatives like append_section or edit_section are not mentioned, leaving usage somewhat implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 4 tool updatesv0.1.0
    • First observedappend_section
    • First observededit_section
    • First observedread_body
    • First observedwrite_body

TDQS

A4.2/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: appending a new section, editing a single section's prose, reading all sections, and replacing the entire body. No overlap or confusion.

Naming Consistency5/5

All tool names follow the consistent verb_noun pattern: append_section, edit_section, read_body, write_body. No mixing of styles.

Tool Count5/5

With 4 tools, the server is well-scoped for managing sections of a plan node. Each tool serves a fundamental operation without unnecessary bloat.

Completeness4/5

The set covers read, create (append), update (edit), and full replacement (write_body), but lacks a dedicated delete_section tool. However, deletion can be achieved via write_body by omitting a section, so the gap is minor.

Maintenance

ActivityActive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Connectors

Related MCP Servers

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/robfischer1/calliope'

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