Skip to content

Feat/mcp apps route planner load once fr - #292

Merged
damienesp merged 2 commits into
mainfrom
feat/mcp-apps-route-planner-load-once-fr
Oct 9, 2026
Merged

damienesp merged 2 commits into
mainfrom
feat/mcp-apps-route-planner-load-once-fr

Conversation

@damienesp

@damienesp damienesp commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Four changes to the MCP Apps boards, on top of #290 / #291:

  1. The Route Planner is the second MCP Apps view, for leadbay_followups_map, on /chatgpt/mcp and /apps/mcp.
  2. Boards load once: they render the tool call that opened them instead of calling it again.
  3. Boards in French: both boards and the kit's status picker follow the host's or the browser's language.
  4. Trip plans open the planner in ChatGPT: tour_plan's "Route planner" step now works on MCP Apps hosts.

Claude is unchanged: /mcp and /fr/mcp carry no board pointer, the followups_map description there is byte-for-byte the same, and tour_plan's steps on Claude are identical.

Changes

Route Planner as an MCP App

  • apps.ts: ui://leadbay/route-planner for leadbay_followups_map. It declares https://cdnjs.cloudflare.com (Leaflet) as its only resourceDomains; the triage board still declares no CSP.
  • The planner hard-wired window.claude.use("mcp"), so it was dead in cowork and in MCP Apps hosts. It now uses claude.ai's bridge only on claude.ai, and the kit's transport everywhere else.
  • Sizing: its 100% / vh layout collapses in a frame sized from the page's own height. Under data-lb-surface="mcp-app", set by the bridge after the handshake, it gets:
    • 680px, or the host's containerDimensions (--lb-frame-height / --lb-frame-max-height);
    • a 360px map on a phone.
  • It opens on the agent's city / city_id.
  • followups-map.md.tmpl: an {{apps}} sentence says the board is the rendering, so ChatGPT doesn't also draw place cards. That description is 16,725 chars on the apps surfaces.

Load once

  • The bridge keeps the first ui/notifications/tool-input and tool-result.
  • lb.openingResult() hands that result to the board. It's null on cowork and claude.ai, and on an error result.
  • Both boards render it, then continue with the agent's count and lensId (the triage board pins result.lens.id). That means one call and one LEAD_SEEN receipt instead of two.

French

  • lb.locale() returns "fr" | "en": the MCP Apps host's locale once it's reported, otherwise navigator.languages[0].
  • lb.i18n({ en, fr }) returns t(key, vars), falling back to English per key.
  • Both boards render every label through it, and the fixed markup carries data-i18n / data-i18n-aria / data-i18n-placeholder.
  • lb.leadStatus options are localized.
  • Wording follows the team's choices: "Wanted" → En cours, "Still chasing" → Toujours en cours, "Meeting planned" → Rendez-vous planifié, "Monitor" → My leads / Mes leads.

Trip plans on MCP Apps hosts

  • tour_plan's "Route planner" step told the agent to publish the route_planner artifact, which these hosts can't do.
  • client.apps is now set by buildServer from includeApps, following the same pattern as client.commerce.
  • On apps hosts the step calls leadbay_followups_map with the tour's city (kind: "open_board"), and the artifact-only lead-desk step is dropped.

Docs and release

  • Kit guide: a new "One page, three surfaces" section (never hard-wire a host runtime, load once, size for the frame, label in the viewer's language), the three surface helpers, and both recipes updated.
  • CLAUDE.md lists both views.
  • Version 0.45.0: CHANGELOG, package.json, server.json, plugin.json.

Tests

New files:

  • components/test/mcp-app-opening.test.ts (12): opening result, first result kept, cancel/timeout, frame variables, locale, i18n, French status picker.
  • components/test/boards-as-mcp-app.test.ts (9): both real boards booted in jsdom, as a fake MCP Apps host and as Claude artifacts.
    • Triage board: no second pull_leads, and next page continues with the agent's count and lensId.
    • French via the host locale and via the browser.
    • Route Planner: opens on the agent's city with no second call; loads on cowork; keeps its claude.ai bridge.
  • components/test/guide-one-page-three-surfaces.test.ts (3).
  • mcp/test/unit/mcp-apps-route-planner.test.ts (6): Claude side clean, pointer and sentence on both apps surfaces, CSP exactly cdnjs.
  • core/test/unit/composite/tour-plan-board-on-apps-hosts.test.ts (6) and mcp/test/unit/mcp-apps-client-flag.test.ts (2).

Existing tests touched: five lines in mcp-apps-gate, mcp-apps-path and mcp-apps-description (from #290). They pinned a single board (toEqual(["leadbay_pull_leads"]), toEqual([TRIAGE_URI]), skipping only pull_leads) and are widened to admit the second one. No Claude-side assertion is loosened.

Results:

  • Components: 632/632. Core: 1942/1942.
  • MCP: all green except the 8 known Windows-only failures (release scripts, file mode, symlink). The promptforge snippet-path test is also Windows-only. All of these fail identically on main.
  • Generated files are up to date.

How to verify

  1. Deploy, then in ChatGPT developer mode on /chatgpt/mcp:
    • "Show me my follow-ups in Lyon on a map": the planner opens in the chat on Lyon, fills its frame (no collapsed map), and doesn't load the leads twice.
    • "I'm in Lyon Thursday, who should I meet?": then pick "Route planner"; the planner opens on Lyon.
    • "Show me today's leads": the triage board opens; "Next" continues the same batch.
    • With ChatGPT or the browser in French: labels are in French.
  2. In Claude: the trip-plan "Route planner" step still publishes the artifact, which loads as before (now also in cowork) and is labeled in French for a French browser.

🤖 Generated with Claude Code

damienesp and others added 2 commits October 8, 2026 18:00
… in French

The route planner is the second MCP Apps view, for leadbay_followups_map, on
/chatgpt/mcp and /apps/mcp. Claude is unchanged: no pointer on /mcp, and the
followups_map description there is byte-for-byte what it was.

- route planner: reaches Leadbay through claude.ai's runtime only on claude.ai
  and through the kit's transport everywhere else (it was dead in cowork and
  in MCP Apps hosts); sizes itself under data-lb-surface="mcp-app" (680px or
  the host's frame limits, a 360px map on a phone) so its 100%/vh layout does
  not collapse in a frame sized from the page; opens on the agent's city
- apps.ts: ui://leadbay/route-planner, declaring cdnjs (Leaflet) as its only
  resourceDomain; {{apps}} sentence in followups_map says the board is the
  answer (16,725 chars on the apps surfaces)
- load once: the MCP Apps bridge keeps the first tool-input/tool-result;
  lb.openingResult() hands it to the board, which renders it instead of
  calling the tool again and continues with the agent's count / lensId / city
- French: lb.locale() (host locale, else browser) and lb.i18n({en, fr}); both
  boards label through it (data-i18n on fixed markup), the kit's status
  picker is localized; "Monitor" now reads "My leads" / "Mes leads"
- guide: "One page, three surfaces" rules for any board; CLAUDE.md lists both
  views
- tests: 28 new in four new files; five lines widened in three existing apps
  tests that pinned a single board
- 0.45.0

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…s hosts

On ChatGPT and other MCP Apps hosts the step told the agent to publish the
route_planner artifact, which those hosts cannot do, so the map never
opened. There it now calls leadbay_followups_map with the tour's city (or
city_id) — the call the host shows the route planner for — and the
artifact-only lead-desk step is dropped. Claude's steps are unchanged.

- client.apps, set by buildServer from includeApps (the commerce pattern)
- NextStepOption kind "open_board"
- tests: tour-plan-board-on-apps-hosts, mcp-apps-client-flag (new files)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@damienesp damienesp self-assigned this Oct 8, 2026
@damienesp
damienesp merged commit 19af189 into main Oct 9, 2026
8 checks passed
@damienesp
damienesp deleted the feat/mcp-apps-route-planner-load-once-fr branch October 9, 2026 07:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant