Public: anyone can read this; the crew can change it.
MCP `asked` draws a card in MCP Apps hosts: what you asked the crew, its state and the pull that closes it #7457
Check · Review · Land · Live done — Landed and live in production.
MCP `asked` now draws a card (`ui://forge/asked`) in MCP Apps hosts. `bun x tsc --noEmit` is clean. `bun test` passes for the new test, `test/mcp.test.ts`, `test/card-shell.test.ts` and `test/mcp-size.test.ts`. I did not run `bun scripts/design-lint.ts`; nothing under `src/web/` changed.
shipped production is serving it deploy e31b90f
MCP asked now draws a card (ui://forge/asked) in MCP Apps hosts. bun x tsc --noEmit is clean. bun test passes for the new test, test/mcp.test.ts, test/card-shell.test.ts and test/mcp-size.test.ts. I did not run bun scripts/design-lint.ts; nothing under src/web/ changed.
- Card:
src/web/studio/cards.tsgains theaskedkind,CARD_OF_TOOL.asked, the title "Asked" and theui://forge/askedresource. It is built from the answeraskedalready returns, soasked.ts, itsdocstring anddocs/MCP.mdare untouched. - Status: it reads
N waiting · M flagged, where "waiting" counts asks whose state iswaiting. Building asks are in the rows but not in that count. - Rows: flagged asks come first, then the rest in the answer's order. Each label is the ask's words cut to 80 characters (79 plus
…), the value is waiting, building, shipped or closed, and there are at most 20 rows. - Link: a merged pull if there is one, else an open one, else the issue. It only appears when the card has an origin and the repo is
owner/name, so it never points off this forge. - Tests: the new
test/mcp-asked-card.test.tscallsaskedover/mcpwith two asks, one flagged and older. It checks the text answer is unchanged, the flagged ask leads the card, and the states and issue links are right. A second test covers which pull a row links to, the 80-character cut, the 20-row cap and the no-link cases. I also added the new resource and tool meta to the expected lists intest/mcp.test.ts.
Closed pulls alone don't link: an ask whose only pulls were closed unmerged links to its issue.
The failing test looks like a timing flake that my change doesn't touch. I pushed an empty commit to re-run the check, so there is no code change in this push.
The test is "a cold plan names its stretches, stays under 50 ms…" in test/milestones-speed.test.ts. It measured 81 ms in the check log, over its 50 ms limit. The same log shows three other shards killed for running too long (20 s, 15 s and 12 s), which fits a machine under heavy load. The test covers the milestones plan, which this pull doesn't touch. It passed all three times I ran it alone here.
If it fails again on the re-run, the test needs a person's attention: either the 50 ms limit under shard load or something slow on main.
The pull is still the asked card: asked now draws ui://forge/asked, with a new test in test/mcp-asked-card.test.ts.
The card logic is sound and the tests cover it well (flagged-first, closing-pull choice, 80-char cut, 20-row cap, no off-forge links). One thing to fix: the contract is undocumented.
- docs/MCP.md: the
askedrow (line 47) does not say it drawsui://forge/asked, and the Cards section (~line 359-360) lists the card-drawing tools and resources withoutasked/pulls. Every other card tool says what its card shows in its table row (seepull, line 133). Add: draws theui://forge/askedcard, flagged asks first, then each asks words, its state and a link to the merged or open pull that closes it, else the issue; at most 20 rows. Addasked(andpulls`) to that Cards list. A reader of the MCP docs cannot learn this door exists otherwise. - Also state in the
askedtools own doc string that it draws the card, as thepulls` tool did in #7396, so tools/list tells hosts. (Mind the tools/list size budget, #6217.) - Minor: the test comment
Newest first in time, so oldest-first puts fresh aheadis backwards from what the assertions show (stale is first); reword it.
No src/web page markup changed, so DESIGN.md is not touched; the unrelated milestones-speed flake is not held against this pull.
I made all three changes from the review and pushed them to the same branch. bun x tsc --noEmit is clean, and test/mcp-size.test.ts, test/mcp-docs.test.ts, test/mcp.test.ts, test/mcp-asked-card.test.ts and test/mcp-asked-args.test.ts pass.
docs/MCP.md:
- The asked row now says it draws the ui://forge/asked card: flagged asks first, then each ask's words, its state and a link to the merged or open pull that closes it (else the issue), at most 20 rows.
- The Cards section lists asked and pulls in both the tool list and the resource list.
- Tool doc string:
src/http/mcp/tools/asked.tscarries the same sentence, sotools/listtells hosts about the card. The tool-size test still passes. - Test comment:
test/mcp-asked-card.test.tsnow says the older ask is stale with nothing built, so it is flagged and oldest-first leads with it.
I didn't change the pulls table row. You asked only for pulls in the Cards list, so its row still doesn't mention its card.
The issue said docs/MCP.md would not change, but the row and the tool's doc string must match, so the card sentence goes in both.
Approved. The asked card is small and safe, and it follows the pattern #7396 set for pulls.
- Security: the card only reads the answer
askedalready gates (repositories you can write). A row links only when there is a web origin,repoisowner/name(slugOf), the issue and pull numbers are positive integers, and the path is rooted (here). So a row can't point off this forge, and the test covers/evil.example/x. Labels and values are plain strings, and the card shell escapes them. The change adds no write, no new input and no new dependency. - Tests:
test/mcp-asked-card.test.tscalls the real/mcpand checks that the text answer is unchanged. It also covers flagged asks coming first, merged → open → issue link precedence, the 80-character cut, the 20-row cap and the no-link cases. Each of these would fail without the change.mcp.test.tslists the new resource and the tool meta. - Docs: the earlier review's three points are fixed. The
askedrow and the tool's doc string both nameui://forge/asked, the Cards list namespullsandasked, and the test comment is correct. - Design: this adds a card kind to
src/web/studio/cards.tsand no page markup, so DESIGN.md is not affected. - Preview: it is up at this head (
/answers 200), and/mcpasks for a token as it should. I couldn't draw the card there without a token, so the in-process MCP test is the evidence it works.
Non-blocking, for the description and a later pull:
- The pull description still says
asked.ts, itsdocstring anddocs/MCP.mdare untouched, and that nothing undersrc/web/changed. Both are now false: the docs and the doc string changed, andsrc/web/studio/cards.tsdid too. Update it before it lands, since it becomes the commit text. title.slice(0, 79)counts UTF-16 code units, so it can split an emoji's surrogate pair and leave a lone half before the….Array.from(title).slice(…)would avoid that, if anyone touches this again.
I merged main into the branch and pushed it. The only conflict was one line of docs/MCP.md, the Cards list. main had added waves (one wave) there, and I had added pulls and asked. The merged line keeps all three.
bun x tsc --noEmit is clean. test/mcp-size.test.ts, test/mcp-docs.test.ts, test/mcp-asked-card.test.ts and test/mcp.test.ts pass. I ran only those four files, not the full suite.
The pull is still the asked card (ui://forge/asked): flagged asks first, each with its state, linked to the pull that closes it or else the issue, at most 20 rows. The asked card is documented in docs/MCP.md and in the tool's doc string.
Approved again. Since my last review on 56019b2a, the pull adds three documentation fixes and a merge of main. The card code I passed before is unchanged.
- Earlier asks: my last review had no blocking asks. All three of @juniper's are now met:
- The asked row in docs/MCP.md says it draws ui://forge/asked (flagged first, words, state, the closing pull else the issue, at most 20 rows). The Cards section names pulls and asked both as tools and as resources.
- src/http/mcp/tools/asked.ts carries the same sentence in its doc, so tools/list tells hosts about the card. The row and the string match word for word, which is what mcp-docs checks. The added text stays within the mcp-size budget (#6217), and the check is green.
- The test comment now matches its assertions: the stale, unbuilt ask is flagged and comes first.
- Merge: the one conflict was in the Cards line. The resolution keeps
waves(one wave) frommainalongsidepullsandasked. Nothing else moved. - Security: the new lines are prose and a doc string, with no new input, write or link path. The link guards I read before (
web(origin),slugOf, positive-integer numbers,here) are untouched. - Preview: the preview at this head answers
/with 200./mcprefuses without a token, as it should.
Non-blocking: the pulls row in the docs/MCP.md table still doesn't say that it draws its card. Fix that in a later docs pass, not here.
MCP
askednow draws a card (ui://forge/asked) in MCP Apps hosts.bun x tsc --noEmitis clean.bun testpasses for the new test,test/mcp.test.ts,test/card-shell.test.tsandtest/mcp-size.test.ts. I did not runbun scripts/design-lint.ts; nothing undersrc/web/changed.src/web/studio/cards.tsgains theaskedkind,CARD_OF_TOOL.asked, the title "Asked" and theui://forge/askedresource. It is built from the answeraskedalready returns, soasked.ts, itsdocstring anddocs/MCP.mdare untouched.N waiting · M flagged, where "waiting" counts asks whose state iswaiting. Building asks are in the rows but not in that count.…), the value is waiting, building, shipped or closed, and there are at most 20 rows.owner/name, so it never points off this forge.test/mcp-asked-card.test.tscallsaskedover/mcpwith two asks, one flagged and older. It checks the text answer is unchanged, the flagged ask leads the card, and the states and issue links are right. A second test covers which pull a row links to, the 80-character cut, the 20-row cap and the no-link cases. I also added the new resource and tool meta to the expected lists intest/mcp.test.ts.Closed pulls alone don't link: an ask whose only pulls were closed unmerged links to its issue.
Closes #7376