[MCP host] Muse adapter does not forward MCP tool outputs (no viewers/archives) · Issue #59 · superWorldSavior/casys-digital-thread · GitHub
Skip to content

[MCP host] Muse adapter does not forward MCP tool outputs (no viewers/archives) #59

Open

Description

@superWorldSavior

Parent: #53 (Phase B export step blocked). Follow-up of #58.

Observed

With bex-co/muse-code-acp 0.7.0, a completed MCP tool call reaches the coordinator as a tool_call event with:

  • title namespaced as mcp____,
  • rawInput = bare arguments (no {server, tool} envelope),
  • NO rawOutput field,
  • content = prose summary only (no artifact URIs).

The acpx session record keeps the same gap (tool_results content is empty Text). The agent itself sees the full result, so the export executes, but the host cannot capture tool results, archive export bytes, or build viewers. Viewers stay at 0 after a successful build123d_export turn.

Evidence: instrumented packaged-host run 2026-09-28 (CASYS_DEBUG_EVENTS, since removed).

Also noticed

bex emits reminderChild inProgress/completed pseudo tool calls that land as user-visible tool messages (noise, minor).

Acceptance

Activity

  1. superWorldSavior commented on Sep 28, 2026

    @superWorldSavior
    OwnerAuthor

    Qualification result (2026-09-28):

    • bex-co/muse-code-acp 0.7.0 is the latest published (2026-09-26). No upgrade path.
    • Verified in bex dist source: presentResult attaches rawOutput only for bash/read_file; MCP tools fall in the default branch (content text only, no rawInput envelope, no rawOutput). The full MCP output never reaches the ACP wire, so no host-side parsing can recover viewers/archives. A relay-side snoop cannot attribute bytes to a conversation (shared relay), and re-execution is forbidden.
    • @brokkai/muse-acp 0.7.0 evaluated and DISQUALIFIED: its README states it ignores ACP client-attached MCP servers (ignoring client-provided MCP servers), which our per-runtime relay model requires.

    Shipped meanwhile (fc2130c): the reminderChild noise filter (second acceptance item) — exact-prefix drop before transcript/capture, unit-tested, live-verified (0 reminderChild, real MCP tools intact).

    #59 stays open, blocked on vendor (bex MCP tool-result forwarding). #53 export step stays blocked behind it.

  2. superWorldSavior commented on Sep 28, 2026

    @superWorldSavior
    OwnerAuthor

    Cursor-agent qualification (2026-09-28, cursor-agent 2026.09.26, custom command profile, no code change): INCOMPATIBLE, worse than bex.

    • cursor-agent in ACP mode silently ignores client-attached MCP servers (confirmed live + by 3 independent community docs). The agent saw zero MCP tools and went spelunking (shell find/grep) instead — including curling the provider port directly, bypassing the relay.
    • Workaround attempt (write .cursor/mcp.json with the relay URL into the agent workspace + --approve-mcps): also ineffective — agent still reports build123d_export absent from its tools.
    • Output forwarding therefore untestable on cursor; plus the injection path would leak ambient ~/.cursor/mcp.json servers into the agent.

    Conclusion: no agent swap fixes #59. bex stays (tools work, outputs missing). The relay tap + coordinator matcher remains the only host-side fix, and it is agent-agnostic.

  3. superWorldSavior commented on Sep 28, 2026

    @superWorldSavior
    OwnerAuthor

    DEV bridge shipped (8684dfc), per direction: implement the tap, keep it dev-only, document the production limitation.

    • CASYS_DEV_RELAY_TAP=1 enables per-relay correlation taps + coordinator attribution (unique match on tool + canonical args + turn recency, consume-on-match, fail-closed on zero/ambiguity). Title is lookup key only; bytes always from the relay record.
    • Proof on packaged host: export turn with tap -> viewers=1, revision 1, .step saved (15 KB); without tap -> viewers=0, production behavior unchanged. 183 tests green.
    • Quickstart documents the dev tap and keeps the packaged-app limitation explicit.

    #59 proper fix still blocked on vendor (bex MCP output forwarding). #53 export step still pending behind it.

  4. superWorldSavior commented on Sep 29, 2026

    @superWorldSavior
    OwnerAuthor

    Spike: can bex be adapted cleanly (no hacks) for modern MCP Apps? VERDICT: NO — impossible, the bytes don't exist on any muse surface.

    Evidence (muse 1.4.0, bex 0.7.0 source + live runs):

    1. muse emits MCP tool results as rendered prose ONLY, on every surface checked: live MSP stream (item/completed has visibleOutput, no outputRef), view/page items via @muse-code/sdk (same keys, outputRef null — verified with a direct MSP script), retained session.jsonl, .msp-view-v1 snapshots, local traces. Zero casys:// URIs anywhere.
    2. bex's clean path (muse/output extension + item/readOutput) is therefore dead input-side. It is additionally triple-gated: bex supportsStoredOutput requires serverInfo 1.2.1 (muse reports 1.4.0); acpx 0.13.1 never declares _meta extension caps (resolveClientCapabilities builds fs/terminal/elicitation only); acpx exposes no extension-call API to hosts (extMethod is internal-only).
    3. A bex fork that only translates better recovers nothing: there is nothing to forward. A fork that MITMs MCP traffic (proxy) is bricolage with more moving parts than our relay tap, which observes the same bytes at our own proxy with exact attribution.

    What would unblock cleanly, in order: (1) Meta emits structured outputs/outputRefs again; (2) bex follows (version gate + forward); (3) acpx declares ext caps + exposes ext calls; (4) we call readOutput. Until then, the DEV relay tap stays the only working observation point, and the production limitation stands.

  5. superWorldSavior commented on Sep 29, 2026

    @superWorldSavior
    OwnerAuthor

    Verdict spike Claude (CLI 2.1.284 + claude-agent-acp 0.84.0)

    Claude expose et appelle nos outils, avec une exception bloquante cote provider.

    Preuve bout-en-bout

    • Serveur MCP HTTP dynamique (via SDK mcpServers) : connected, tools/list 200.
    • build123d_execute appele reellement : Box 10x10x10 -> 999.9999999999998
      (probes /tmp/claude-spike/, provider :3014 via proxy :3999).

    Cause racine de l'invisibilite initiale

    • build123d_project_2d a un inputSchema avec oneOf au top-level (pas type: object).
    • Le CLI Claude rejette cet outil ET droppe tout le serveur (0/4 outils exposes,
      ToolSearch zero resultat, ni charges ni differes).
    • Bissection prouvee : execute seul OK (1/1), +export OK (2/2), +observe OK (3/3),
      project_2d seul KO (0/1).
    • Ni outputSchema ni _meta.ui (strippes via proxy, sans effet) ne sont en cause.

    Consequence pour #59

    • Ce n'est pas un probleme d'adaptateur : le path ACP/SDK transporte et expose
      correctement les outils valides.
    • Le fix propre appartient au provider build123d (image publiee, hors repo) :
      normaliser le schema de project_2d en type: object au top-level.
    • En attendant : limitation documentee (serveur complet invisible sous Claude tant
      que project_2d est servi tel quel). Le relay ne reecrit pas les contrats
      provider, pas de filtrage contournement prevu.
    • Auth : login ambient preserve pendant tout le spike (cwd isoles, pas de login).

    Restes ouverts (pas testes ici)

    • Viewers MCP Apps + export archives sous Claude (turn export via profil custom).
    • Comportement via l'adaptateur ACP 0.84.0 lui-meme (spike mene via SDK direct) ;
      a confirmer dans l'app.
  6. superWorldSavior commented on Sep 29, 2026

    @superWorldSavior
    OwnerAuthor

    Spike turn export / viewers via Claude (adaptateur ACP 0.84.0)

    L'adaptateur Claude transmet les outputs complets (contraire de bex)

    • Appel reel via ACP direct : mcp__build123d__build123d_export (Box 10x10x10,
      formats step) -> tool_call_update status=completed avec rawOutput
      contenant le JSON export complet : metrics (volume 999.9999999999998),
      artefact STEP casys://build123d/artifacts/26fa6bde....step (15379 octets).
    • Preuve : /tmp/claude-spike/acp-direct3.mjs contre proxy 3-outils :3999
      (sans project_2d, formes provider reelles, ni strip ni rewrite).

    Mais le path normal du coordinator ne peut pas le consommer

    • acpx transmet rawInput/rawOutput verbatim (runtime.js
      assignForwardedToolPayload).
    • Le coordinator attend rawInput={server,tool,...} et
      rawOutput={result,error} (parseMcpRawInput/parseMcpRawOutput).
    • Claude envoie les formes ACP brutes : rawInput = objet args,
      rawOutput = string JSON du resultat. Donc : normal path ignore,
      fallback tap en DEV, rien en prod. Meme sort que bex, pour une raison
      differente (forme, pas absence).

    En DEV, le tap attribue mecaniquement sous Claude

    • Titre mcp__build123d__build123d_export matche MCP_NAMESPACED_TITLE,
      rawInput objet -> canonicalJson matche l'enregistrement relay
      (meme mecanique que bex, prouvee en 8684dfc). Viewers + turn export OK.
    • E2E in-app reste bloque par le poison project_2d (commentaire precedent) :
      le relay sert les 4 outils, Claude droppe le serveur.

    Fix prod propre, borne, in-repo (proposition)

  7. superWorldSavior commented on Sep 29, 2026

    @superWorldSavior
    OwnerAuthor

    Fix provider applique : project_2d re-expose sous Claude (4/4)

    Changement (repo mcp-build123d, non commite)

    • src/tools/projection-2d.ts : PROJECTION_2D_INPUT_SCHEMA passe de
      oneOf top-level a type: object avec les variantes step /
      stepResource en proprietes optionnelles + includeSection, et un
      oneOf: [{required:[step]}, {required:[stepResource]}] imbrique.
    • Payloads acceptes inchanges : {step} xor {stepResource}, chacun avec
      includeSection optionnel. La garde serveur pre-existante
      (projection-2d-bridge.ts, "exactly one of step or stepResource") reste
      l'enforcement.
    • tests/projection-2d_test.ts : assertions top-level object + proprietes,
      cas supplementaires (variantes avec/sans includeSection, rejet de
      {includeSection} seul, rejet des deux variantes), nouveau test
      "enforces exactly one STEP variant server-side".

    Verifications observees

    • deno test tests/projection-2d_test.ts : 7 passed, 0 failed.
    • deno fmt --check + deno lint sur les 2 fichiers : verts.
    • Preuve Claude : les 4 outils serves avec le schema project_2d importe
      du code modifie -> init expose
      mcp__build123d__{execute,export,observe_assembly_integrity,project_2d}
      (4/4, contre 0/4 avant). Le oneOf imbrique sur required passe le CLI.

    Reste a faire cote provider

    • Commit + release + republication de l'image mcp-build123d.
    • Apres redeploiement : e2e in-app (relay 4 outils -> Claude -> viewers)
      et parseur coordinator facon-Claude (proposition du commentaire precedent).
  8. superWorldSavior commented on Sep 29, 2026

    @superWorldSavior
    OwnerAuthor

    0.7.1 publie : project_2d corrige en production

    • PR chore: release mcp-build123d 0.7.1 mcp-build123d#17 mergee, tag v0.7.1, CI Publish verte (check + image-smoke + publish-jsr + publish-ghcr).
    • Verifie : JSR @casys/mcp-build123d@0.7.1 liste, image ghcr.io/casys-ai/mcp-build123d:0.7.1 (multi-arch) pullable.
    • Contenu : schema project_2d en type object top-level (CHANGELOG 0.7.1), payloads acceptes inchanges, garde serveur inchangee.
    • Prochaine etape : redeployer le provider local sur 0.7.1, puis e2e in-app (relay 4 outils -> Claude -> viewers) et parseur coordinator facon-Claude.
  9. superWorldSavior commented on Sep 29, 2026

    @superWorldSavior
    OwnerAuthor

    Redeploiement 0.7.1 + parseur Claude : fait. E2E in-app : en attente quota

    Redeploiement local 0.7.1 (fait)

    • Conteneur local recree sur le digest 0.7.1 : health 0.7.1, 4 outils.
    • Repin atelier commite (f1b6262) : fleet + sandbox, catalogue, compose,
      launch groups (MCP_BUILD123D_071), observer pins, probe (identite +
      fingerprint 28e6c8c9...), doc provider. Probe : current-surface.
    • Tests : 14 + 19 + 92 verts sur les suites touchees.

    Parseur coordinator facon-Claude (fait, d5b8a87)

    • #captureToolResult capte desormais les events bruts : titre
      mcp__serveur__outil + rawInput args + rawOutput string JSON (observe)
      ou bloc texte unique (forme SDK). Formes inconnues : tap DEV ou rien.
    • 3 tests : string sans tap, bloc texte, rejet etranger/non-JSON/scalaire.
      Suite coordinator : 85 verts. Prod : plus besoin de tap sous Claude.

    E2E in-app (bloquee : quota Claude epulse)

    • Script pret (/tmp/e2e-claude-071.ts) : host package + tap DEV + profil
      custom + mcp.ensure/enable + turn export.
    • Constate : MCP connecte (4 outils), adaptateur dialogue avec le relay
      (discover/tools/list vus), puis "session limit, resets 6:30pm Taipei".
    • Correctifs e2e au passage : mcpEnsure avant mcp.enable (sinon mcpId None).
    • A relancer apres le reset quota ; le parseur ci-dessus rend le tap
      inutile pour ce parcours.
  10. superWorldSavior commented on Sep 30, 2026

    @superWorldSavior
    OwnerAuthor

    Revue indépendante du chemin MCP Apps/archives, le 30 septembre 2026, sur 0be84e7edba3c2f71f87d01867104039c048b3be, et vérification des sources amont actuelles. L'issue doit rester ouverte pour Muse. Deux problèmes distincts doivent garder des critères distincts.

    Côté fournisseur Build123d / Claude : le oneOf au niveau racine de build123d_project_2d faisait refuser le serveur à Claude. Le pin local a été mis à jour vers Build123d 0.7.1 dans f1b62624, avec le schéma corrigé. Le coordinateur ajoute dans d5b8a87b la capture des événements Claude (mcp__server__tool, arguments directs, rawOutput JSON/texte). Les 104 tests ciblés coordinateur/relay/tap passent. C'est un progrès de compatibilité concret ; le dernier essai réel dans l'application est néanmoins arrêté par la quota Claude, donc aucune preuve finale de viewer/archive dans l'app ne peut encore être déduite de ces fixtures.

    Côté Muse / adaptateur ACP : le pin empaqueté est toujours @bex-co/muse-code-acp 0.7.0. Vérification du registre npm : latest 0.7.0, publié le 26 septembre 2026 à 05:23:24 UTC, commit e0cce00b, intégrité conforme au pin local. Les événements de cette version transmettent du texte borné et éventuellement les arguments, sans le rawOutput MCP complet attendu ici. ACP rend rawOutput optionnel : la seule présence d'un adaptateur ACP ne garantit pas la fidélité des résultats.

    Le README annonçant la lecture de sorties complètes ne démontre pas une correction plus récente : la documentation exacte de 0.7.0 qualifie une extension _muse/readOutput sur Muse 1.2.1, avec une référence native disponible. La preuve publiée concerne des sorties shell. Elle précise que le mécanisme ne reconstitue pas les images/audio/ressources MCP aplatis ou omis ; le code vérifie précisément la version 1.2.1. Cela ne prouve pas les viewers/archives MCP sur le Muse 1.4.0 testé par Casys.

    Le tap de corrélation est toujours explicitement développement seulement, activé par CASYS_DEV_RELAY_TAP=1 ; le parcours normal empaqueté ne le configure pas. Un succès obtenu avec ce tap doit rester identifié comme tel et ne clôt pas le comportement distribué.

    Suite attendue : obtenir et qualifier un chemin de production conservant le résultat MCP exact, les métadonnées App et les artefacts sous Muse, puis compléter #53. Si un mécanisme natif/extension est retenu, prouver ses références, son association à la bonne conversation/appel et le comportement d'absence de sortie. Ne pas remplacer implicitement l'acceptance Muse par Claude. #58 reste également ouvert sur le lancement et le changement d'agent ; #51 sur la conservation des identités des résultats.

    Limites de cette revue : sources et tests déterministes, plus lecture des preuves existantes ; aucun nouveau tour LLM, appel fournisseur, changement de credentials ou modification du dépôt. PR #60 ouverte, non fusionnée ; main distant reste 94aaa037.

  11. superWorldSavior commented on Sep 30, 2026

    @superWorldSavior
    OwnerAuthor

    Implémentation reprise et validée le 2026-09-30. Changements dans le commit local, non poussé 070f66c8 sur codex/desktop-mcp-host-reliability ; ces preuves ne sont pas une livraison sur main.

    Le chemin de production observe maintenant la paire JSON-RPC exacte à travers une URL privée/revocable propre à chaque tour, sur le relais existant partagé. Cette URL est renouvelée à la reprise de la session ACP ; un résultat tardif d'un ancien tour ne peut plus être attribué au nouveau. Les cartes ACP restent textuelles et ne doublonnent pas les archives. Aucun flag DEV ni corrélation heuristique outil+arguments+temps n'est requis.

    Tests : sessions concurrentes/appels identiques, annulation, retarget, reprise après échec préprompt, queue bornée et isolation passent. Une réponse >8 MiB est transmise intégralement sans capture ni fausse 502 ; le provider n'est exécuté qu'une fois. Le test du host empaqueté avec agent ACP sans rawOutput conserve deux révisions et leurs octets après restart.

    Preuve réelle supplémentaire : paquet final Codex/ACPX + image Build123d 0.7.1, trois résultats, trois fichiers exportés sauvegardés et relus hors ligne. Les tours Muse réels restent distinctement non qualifiés.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions