Skip to content

Add MCP server + Celaut .service (full reads + wired reputation writes) - #1

Open
agenticaihome wants to merge 164 commits into
mainfrom
feat/celaut-mcp-service
Open

Add MCP server + Celaut .service (full reads + wired reputation writes)#1
agenticaihome wants to merge 164 commits into
mainfrom
feat/celaut-mcp-service

Conversation

@agenticaihome

Copy link
Copy Markdown
Owner

What

Adds an agent-drivable surface to Game of Prompts — a local MCP server (stdio) and a sealed Celaut microVM .service (HTTP MCP + REST) — following the proven ergo-basics-template/MCP.md recipe and mirroring source-application / forum-application.

Additive only. No theme/style/UI/existing src files were modified — only two new folders (mcp/, .service/). The existing theme toggle, mode-watcher, wallet component, and template shell are untouched.

Files added

mcp/ (stdio MCP):

  • core.mjs — Svelte-free port of the read surface (src/lib/ergo/** + src/lib/common/**). Compiles every contracts/*.es with the same dependency-injection order as src/lib/ergo/contract.ts, and imports reputation_proof + digital_public_good pre-compiled from reputation-system/node (derived hashes verified identical to the app's).
  • lib.mjsmakeSigner() (GOP_SIGNER_MODE=seed|unsigned, default unsigned), fetchMainBox(), describeResult().
  • writes.mjs — wired reputation-opinion writes + documented BROWSER_ONLY_ACTIONS.
  • tools.mjs (shared TOOLS+HANDLERS), server.mjs (stdio), package.json, README.md, contracts/*.es.

.service/ (Celaut microVM): server-http.mjs (0.0.0.0:8080: /health, /mcp Streamable HTTP, full REST /api/*), copies of core/lib/writes/tools + contracts/, Dockerfile, service.json (port 8080, sealed to api.ergoplatform.com), start.sh, pack_config.json, package.json, README.md.

Tools / endpoints (26 MCP tools, REST mirror)

Info: get_gop_config, get_contracts_info, list_browser_only_actions
Game reads: fetch_active_games, fetch_resolution_games, fetch_cancellation_games, fetch_all_games, fetch_game, load_game_by_id, fetch_game_history, get_game_phase
Participation reads: fetch_participations, fetch_participation_batches, fetch_solver_id_box
Reputation / token / chain reads: fetch_opinions_about, fetch_token_details, token_creation_height, get_current_height
Pure helpers: derive_game_phase_snapshot, compute_commitment, find_matching_score_for_commitment
Writes: create_reputation_profile, create_opinion, submit_creator_opinion, judge_invalidate_vote, judge_invalidate_unavailable_vote

REST: GET /api/{config,contracts,browser-only-actions,height,games,games/active,games/resolution,games/cancellation,games/:id,games/:id/history,games/:id/phase,games/:id/participations,games/:id/batches,solver/:id,opinions,tokens/:id,tokens/:id/creation-height} and POST /api/{profile,opinions,opinions/creator,opinions/invalidate,opinions/invalidate-unavailable}.

Wired vs browser-only writes (honest scope)

Wired (through create_opinion_with_signer / create_profile_with_signer in reputation-system/node; serve seed AND unsigned modes):

  • create_reputation_profile (mint a JUDGE/profile rep box)
  • create_opinion (generic building block)
  • submit_creator_opinionplatform.ts:submitCreatorOpinion
  • judge_invalidate_vote — opinion half of platform.ts:judgesInvalidateVote
  • judge_invalidate_unavailable_vote — opinion half of judgesInvalidateUnavailableVote

Browser-only (NOT wired — enumerated by list_browser_only_actions): the core game-lifecycle txs in src/lib/ergo/actions/* (create_game, resolve_game, submit_score, batch_participations, include_omitted_participation, cancel_game, end_game, distribute_judges_payout, claim_after_cancellation, reclaim_after_grace, drain_cancelled_game_stake, contribute_to_ceremony, judges_invalidate execute) are multi-box / chained ergo-connector builders. Plus accept_judge_nomination (custom R9 = Coll[Coll[Byte]] that create_opinion_with_signer's flat R9 = Coll[Byte] can't express) and publish_solver_id (a plain FALSE-contract box, not an opinion).

Verification (real output)

  • npm install ✅ in both folders; node --check ✅ on all .mjs.
  • Contract compile ✅ — all 11 contracts compile; reputation_proof template hash e84b95d8… matches the reputation-system/node export, confirming the injection chain.
  • stdio MCP tools/list ✅ → 26 tools.
  • .service: curl /health{"status":"ok",…}; /api/height ✅ live 1816829; /api/contracts ✅ all 11 contracts with addresses+hashes; /mcp tools/list ✅ 26 tools; /mcp tools/call ✅.
  • WRITE in unsigned mode (no GOP_MNEMONIC) ✅ — both create_opinion (MCP) and POST /api/opinions (REST) returned submitted:false + a real unsigned EIP-12 tx (2 inputs / 4 outputs / 1 dataInput) against a live reputation main box.
  • No seed-mode write run, no tx submitted, no wallets/secrets/mnemonics touched.

Confirmation

No theme/style/UI/existing files were modified — the change is two new folders (mcp/, .service/) only. reputation-system pinned to canonical upstream github:reputation-systems/reputation-system (has ./node + committed dist/ + @scure derivation), never a fork feature branch.

🤖 Generated with Claude Code

agenticaihome and others added 30 commits March 7, 2026 17:38
feat: apply landing page design system — dark cyberpunk theme
fix: 3 targeted UI fixes (spinner, share button, judge accent color)
0xf965 and others added 29 commits May 13, 2026 23:09
- Game Progress: details hidden by default, toggle via "Detalles" button
  (essentials shown first, deeper technical view opt-in)
- Trust & Security → "Trust Snapshot" when collapsed
- New .paper-prose class: dedicated typography for Paper section markdown
  (larger headings, leading-8 paragraphs, bordered tables, styled code/blockquote)
- .guide-prose: zebra-striped tables, proper list-style-position for nested
  ordered/unordered lists

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…kdown-compact-progress

fix: compact Game Progress panel + richer paper/guide markdown styles
Replace the 3-option Light/Dark/System dropdown in Theme.svelte with a
single-click circular toggle, following StabilityNexus/BenefactionPlatform-Ergo
PR #172. Uses mode-watcher's toggleMode() to flip light<->dark in one step;
the wrapper rotates 180deg per click so the sun/moon swap reads as a spin.
System default is still respected until the user makes a first explicit
choice. Accessibility preserved via a real <button> and sr-only label.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Once a game is finalized the NFT moves to a non-contract (winner/resolver
wallet) box that no longer holds the participation tokens, so reading the
live box reported a 0 prize pool. Derive the final prize pool from the last
resolution/end-game contract box (the box spent by the finalize tx), which
still carries the participation-token balance consumed by getPrizePool().

- fetchGame: include endGameTemplate in the historical box search (the
  end-game box was previously skipped) and use the contract box's
  participation-token amount instead of the wallet box's nanoERG value.
- fetchFinalizedGames: derive value from the last resolution/end-game box.
- Add devCommission to GameFinalized so the dev commission is deducted from
  the finalized prize pool; populate it from history (and in the dev
  competitions fixture).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oggle-and-finalized-prizepool

Single-click theme toggle + GameFinalized prize pool from history
GameDetails.svelte gated commission breakdown computation behind
`status === "Active" || "Resolution"`, leaving resolverPct, developersPct,
judgesTotalPct, and totalPct at 0 for Finalized games. GameFinalized carries
all three commission fields (resolverCommission, devCommission, perJudgeCommission)
populated by the preceding fetch fix, so the status check is widened to include
"Finalized". creatorSlashRatio is cast via (game as any) since it is absent on
GameFinalized but the fallback ?? 0 keeps it safe.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
finalPrizeValue used `lastResolutionBox?.value ?? lastBox.value`, which fell
back to a near-zero post-finalization box (winner/resolver wallet) whenever no
Resolution box existed in history — e.g. games finalized straight from an
end-game/timeout box. That made getPrizePool() compute a 0 prize pool (and, via
the minimal path, 0 commissions) in the UI.

Select the historical contract box with the largest value as the pot-bearing
box: it still carries participation balance + stake right before the finalize
tx. Resolution box stays the preferred source when present; max-value is the
robust fallback before the near-zero lastBox.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ol-display

fix: show prize pool & commissions for Finalized games
…utation writes)

Additive only — adds an agent-drivable surface to Game of Prompts following the
ergo-basics-template MCP.md recipe and mirroring source-application /
forum-application. No theme/style/UI/existing src files were modified.

mcp/ (stdio MCP, 26 tools):
- core.mjs: Svelte-free port of the read surface (src/lib/ergo/** +
  src/lib/common/**). Compiles every contracts/*.es with the same
  dependency-injection order as src/lib/ergo/contract.ts (game_active/
  resolution/cancellation/end_game/judges_paid/participation[_batch]/mint_idt/
  false) and imports reputation_proof + digital_public_good pre-compiled from
  reputation-system/node (derived hashes verified identical). Exposes
  game/participation/reputation/token reads, contract info (address + template
  hash + script hash), game-phase snapshots, and commitment helpers.
- lib.mjs: makeSigner() (GOP_SIGNER_MODE=seed|unsigned, default unsigned) +
  fetchMainBox() + describeResult().
- writes.mjs: wired reputation-opinion writes via create_opinion_with_signer /
  create_profile_with_signer; BROWSER_ONLY_ACTIONS documents the lifecycle txs
  that stay on the ergo connector.
- tools.mjs (shared TOOLS+HANDLERS), server.mjs (stdio), package.json, README.md.

.service/ (Celaut microVM): server-http.mjs on 0.0.0.0:8080 with /health, /mcp
(Streamable HTTP) and a full REST /api mirror; copies of core/lib/writes/tools +
contracts, Dockerfile, service.json (sealed to api.ergoplatform.com), start.sh,
pack_config.json, package.json, README.md.

reputation-system pinned to canonical upstream
github:reputation-systems/reputation-system (has ./node + @Scure derivation).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lt bundle

Replace the ~1k-line hand-ported mcp/core.mjs with a thin adapter over a
committed esbuild bundle of the library's OWN src logic, matching the
just-shipped source-application / forum-application MCPs.

- mcp/build.mjs (esbuild devDep + `npm run build:mcp`) bundles _entry.mjs —
  which re-exports the real src/lib/{ergo,common}/* reads, contract.ts
  compilation, game-phase + commitment helpers — into
  mcp/_generated/lib.bundle.mjs (committed). The contracts/*.es sources inline
  via a text loader, so no contracts/ copy is needed in mcp/ or .service/.
- reputation-system/node and @fleet-sdk/* stay EXTERNAL (same installed
  packages the writes use at runtime — no drift, no multi-MB compiler inlined);
  browser-only edges aliased to inert _stubs/* ($lib/ergo/platform,
  $lib/dev/dev-competitions, the reputation-system Svelte entry, $app/paths,
  sibling source/forum packages).
- core.mjs is now a thin adapter: points the src explorer_uri store at
  GOP_EXPLORER_API, re-exports pure helpers/constants, and JSON-shapes the rich
  src results (Map→array, BigInt→string, inert platform stub stripped).
- writes.mjs / lib.mjs unchanged (wired reputation-opinion writes + signer);
  the 26-tool surface is unchanged.
- Dedup .service: server-http.mjs imports the shared ../mcp/*; deleted the
  duplicated .service/{core,lib,writes,tools}.mjs + .service/contracts/ + the
  mcp/contracts/ copy; Dockerfile copies the single mcp/ + prebuilt bundle.

Verified: all 11 contracts (9 game + reputation_proof + dpg) compile to
byte-identical addresses/hashes vs the prior hand-port; stdio + .service HTTP
tools/list both return the same 26 tools; GET /api/contracts returns every
address+hash; live reads return clean data/empty; an unsigned write returns an
unsigned EIP-12 tx over both transports. Net ~5.3k hand-written lines removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@agenticaihome

Copy link
Copy Markdown
Owner Author

DRY refactor — MCP now reuses src/, mirroring the source/forum MCPs

Replaced the ~1k-line hand-ported mcp/core.mjs with a thin adapter over a built bundle of the library's own src/ logic — the same pattern the just-shipped source-application/mcp and forum-application/mcp use. The read + contract-compilation business logic now lives once, in src/lib/{ergo,common}/*.

Mechanism

  • mcp/build.mjs (esbuild devDep, npm run build:mcp) bundles mcp/_entry.mjs — which re-exports the real src symbols (fetch.ts reads, contract.ts compilation, game-phase.ts, commitment.ts, reputation/fetch.ts, constants/types) — into the committed mcp/_generated/lib.bundle.mjs.
  • The contracts/*.es sources inline into the bundle via a text loader (esbuild plugin strips Vite's ?raw), so no contracts/ copy is needed in mcp/ or .service/ anymore.
  • reputation-system/node and @fleet-sdk/* stay external → reads resolve the SAME installed packages the writes use at runtime (no drift; no multi-MB ErgoScript compiler inlined → bundle is 204 KB, not 27 MB).
  • Browser-only edges aliased to inert _stubs/*: $lib/ergo/platform (the ErgoPlatform write graph), $lib/dev/dev-competitions, the reputation-system Svelte entry (re-exports node + the two .es.js contract sources + calculate_reputation), $app/paths, and the sibling source/forum-application packages.
  • core.mjs is now a thin adapter: points the explorer_uri store at GOP_EXPLORER_API, re-exports pure helpers/constants, and JSON-shapes the rich src results (Map → array, BigInt → string, the inert platform field stripped). writes.mjs / lib.mjs unchanged (wired reputation-opinion writes + signer); the 26-tool surface is unchanged.

Dedup mcp/.service/

.service/server-http.mjs now imports the shared ../mcp/* (+ committed bundle). Deleted the duplicated .service/{core,lib,writes,tools}.mjs, .service/contracts/, and the mcp/contracts/ copy. Dockerfile copies the single mcp/ (core/lib/writes/tools/_generated) under a sibling /app/{service,mcp} layout — no build toolchain in the VM.

Verification

  • All 11 contracts (9 game + reputation_proof + digital_public_good) compile to byte-identical addresses / template-hashes / script-hashes vs the prior hand-port.
  • ✅ stdio tools/list and .service HTTP tools/list both return the same 26 tools.
  • GET /health ok; GET /api/contracts returns every contract's address + hashes (proves the reused contract.ts compiles via the bundle).
  • ✅ Live reads return clean data/empty (fetch_game → Finalized snapshot, fetch_active_games/fetch_all_games parity with the old port = 0 for the current contract gen, fetch_token_details, fetch_opinions_about, …).
  • ✅ An unsigned write (no GOP_MNEMONIC) returns an unsigned EIP-12 tx over both the MCP handler and POST /api/profile.
  • node --check passes on every hand-written .mjs; import('./mcp/core.mjs') loads with no svelte / $app / dompurify / marked errors.

Lines

~5.3k hand-written lines removed net: old core.mjs (1064) + duplicated .service/{core,lib,writes,tools}.mjs (1569) + the two contracts/*.es copies (1577 + 1577) removed, vs ~509 added (new core.mjs 161 + _entry.mjs 122 + build.mjs 143 + stubs 83). The committed bundle is a 3,381-line generated artifact (like source/forum commit theirs).

Honest limits

  • The src reads console.warn on validity mismatches (e.g. parseGameActiveBox: invalid constants, fetch_conditions: …). On stdio these are routed to stderr by server.mjs, so the JSON-RPC channel stays clean; on the HTTP service they're harmless stdout logs.
  • @fleet-sdk/serializer is now an explicit runtime dep in both package.jsons (the bundle's calculate_reputation import needs it; it was already transitively present).
  • No on-chain submit performed; no secrets touched. Branch was already current with origin/main (0 behind), so no merge was needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants