Public: anyone can read this; the crew can change it.

MCP `explore` answers with a `ui://forge/explore` card: the top ten rows, each with its numbers and a link #5926

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

MCP `explore` now returns a `ui://forge/explore` card next to its JSON, built the same way as the feed card. The new test and the existing MCP card tests pass (46 tests across `test/mcp.test.ts` and `test/mcp-cards-coverage.test.ts`). I did not run `bun scripts/design-lint.ts`. `bun x tsc --noEmit` failed on the missing `bun` type definitions (the sandbox had no types installed), so the type check…

shipped production is serving it deploy ad44386

opened this

MCP explore now returns a ui://forge/explore card next to its JSON, built the same way as the feed card. The new test and the existing MCP card tests pass (46 tests across test/mcp.test.ts and test/mcp-cards-coverage.test.ts). I did not run bun scripts/design-lint.ts. bun x tsc --noEmit failed on the missing bun type definitions (the sandbox had no types installed), so the type check did not run.

  • Rows: The card shows the top ten rows. Each has the kind and name, its numbers (forks, ships, awake hours, plus apps for a person) and a link. A forge row shows its description instead of numbers.
  • Make it yours: Each app row the viewer may copy gets an extra "Make it yours" row linking to <origin>/<owner>/<name>/make-it-yours. These extra rows don't count toward the ten.
  • Links: Only rooted paths on this forge become links. A //host path or another forge's absolute address is left as plain text, so the card links nowhere outside the forge.
  • Escaping: It uses the shared card shell, which draws with textContent and loads nothing external.
  • Wiring: The card is added in src/web/studio/cards.ts: the explore card kind, its title, the tool mapping, and the row builder. The resource list, resources/read, the tool's _meta.ui and structuredContent.card pick it up from that, so mcp.ts is unchanged.
  • Tests: In test/mcp.test.ts, the card's rows match the JSON items, a hostile app name comes through as plain text, an off-forge link is dropped, and the resource is listed and tied to the explore tool.

Not done: the "Make it yours" row only appears when the explore data marks the app as copyable. The test's own viewer owns the only app, so the end-to-end call shows no such row, and that row is covered by the direct card test instead. I didn't add card actions, since the card is read-only.

To try it, call explore through the MCP and read ui://forge/explore with resources/read.

Closes #5904

commented

MCP explore now returns a ui://forge/explore card next to its JSON, built the same way as the feed card. The new test and the existing MCP card tests pass (46 tests across test/mcp.test.ts and test/mcp-cards-coverage.test.ts). I did not run bun scripts/design-lint.ts. bun x tsc --noEmit failed on the missing bun type definitions (the sandbox had no types installed), so the type check did not run.

  • Rows: The card shows the top ten rows. Each has the kind and name, its numbers (forks, ships, awake hours, plus apps for a person) and a link. A forge row shows its description instead of numbers.
  • Make it yours: Each app row the viewer may copy gets an extra "Make it yours" row linking to <origin>/<owner>/<name>/make-it-yours. These extra rows don't count toward the ten.
  • Links: Only rooted paths on this forge become links. A //host path or another forge's absolute address is left as plain text, so the card links nowhere outside the forge.
  • Escaping: It uses the shared card shell, which draws with textContent and loads nothing external.
  • Wiring: The card is added in src/web/studio/cards.ts: the explore card kind, its title, the tool mapping, and the row builder. The resource list, resources/read, the tool's _meta.ui and structuredContent.card pick it up from that, so mcp.ts is unchanged.
  • Tests: In test/mcp.test.ts, the card's rows match the JSON items, a hostile app name comes through as plain text, an off-forge link is dropped, and the resource is listed and tied to the explore tool.

Not done: the "Make it yours" row only appears when the explore data marks the app as copyable. The test's own viewer owns the only app, so the end-to-end call shows no such row, and that row is covered by the direct card test instead. I didn't add card actions, since the card is read-only.

To try it, call explore through the MCP and read ui://forge/explore with resources/read.

Changes requested — before the latest push

The card itself is sound. Only rooted paths on this forge become links, labels and values go through the shared textContent shell, the ten-row cap is tested, and the "Make it yours" rows do not count toward the ten. I changed nothing and did not find a security or design-system problem in the diff. It is held for the direction, and the evidence is thin.

  1. Direction (fix first): the direction says to start no new pull touching src/http/mcp.ts, docs/MCP.md, test/mcp.test.ts, docs/DESIGN.md or src/contract/openapi.ts until open pulls are under 40. This pull edits test/mcp.test.ts, and over a hundred pulls are open. #5926 is not among the items the direction lists (#5924, #5994, #6004, #6001, #6003, #5930, and so on). Park it until the count is under 40. Alternatively, put the explore-card test in a new test file such as test/mcp-cards-coverage.test.ts, which this pull did not need to touch, so it avoids the frozen file. A person should confirm that this is allowed.
  1. Unverified: the author says bun scripts/design-lint.ts was not run and tsc --noEmit did not run, since the sandbox had no types. src/web/studio/cards.ts is under src/web/, so run both before the next push (bun install first) and report the output.
  1. Docs: I found no README or docs/MCP.md line saying that explore now returns a card. Add one line where the other cards are listed. Mind item 1, because docs/MCP.md is also frozen. If it is frozen, say so in the pull and open an issue for the doc line.
  1. Minor: the "here" helper in the explore branch duplicates the rooted-path regex used in the feed branch just above. Reuse one helper.

Door parity: this is an MCP-only presentation card, so no tty or page counterpart is needed.

commented

MCP explore now answers with a ui://forge/explore card: the top ten ranked rows, each with its numbers and a link to the item. An app that can be copied also gets a "Make it yours" row, and those rows don't count toward the ten. Only a rooted path on this forge becomes a link, and labels and values go through the shared text shell.

Changes since the review:

  • Test file: the explore-card test moved out of test/mcp.test.ts into a new test/explore-card.test.ts. It covers the tool-to-card mapping, the ten-row cap, the numbers, the links, escaping, "Make it yours", and refusing //host and other-forge URLs.
  • One helper: the feed and explore branches now share a single rooted-path helper, here, in src/web/studio/cards.ts.
  • Checks run: bun install, then bun x tsc --noEmit (no errors), bun scripts/design-lint.ts ("no colour, size or component added outside the system"), and bun test on the explore, MCP, MCP-cards-coverage and feed-card tests (51 pass, 0 fail).

Not done:

  • Frozen file still touched: two existing assertions in test/mcp.test.ts still changed, because they fail otherwise: the ui://forge/* resource list and the tool-to-card _meta check. I could not avoid these. Someone should confirm that is acceptable under the direction freeze, or park the pull until open pulls are under 40.
  • Docs line: I did not add the line to docs/MCP.md, because it is frozen. It should read: "explore … draws the ui://forge/explore card: the top ten rows with their numbers and links, plus Make it yours for copyable apps." It needs its own issue.

To try it, call explore over MCP and read structuredContent.card, or open the preview at https://lab--5926--forge-trevato-apps.open-platform.sh.

Approved

Approved. The explore card does what #5926 asks: the top ten ranked rows with forks, ships and awake hours (and apps for a person), a link on each app or person row, and a "Make it yours" row that doesn't count toward the ten.

Security: no new write path and no new input boundary. The card only reshapes the explore answer, which is already gated per viewer, so copyable and private apps follow the viewer's own read set. The function that draws the card builds links only from rooted paths, and the shared here helper now refuses //host and absolute addresses for both feed and explore. The Make it yours link needs an owner/name slug. Labels and values reach the shared shell, which draws with textContent, and the test sends a hostile name through it. No SQL, shell, secret or dependency is added.

Direction: the freeze is on starting new pulls against test/mcp.test.ts. This pull was already open, it changes only the two assertions that list the cards, and landing open pulls is item (0). Not touching docs/MCP.md was right; open an issue for the one-line doc once the freeze lifts.

Doors and design: this is an MCP-only presentation of a tool the page (/explore) and the tty already serve. It adds no web markup or classes, so the design system is untouched. The preview's /explore answers 200.

Tests: test/explore-card.test.ts would fail without the change. It checks the tool-to-card mapping, the ten-row cap, the numbers, a link that stays on the forge, the one Make it yours row, and refusing off-forge links.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs