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

/.well-known/agent-card.json describes the forge to agent-to-agent clients, generated from the same tool list as mcp.json #12338

Merged opened this

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

Merged

`GET /.well-known/agent-card.json` now answers 200 JSON, and its skills are built from the same tool list as `/.well-known/mcp.json`. The tests I ran pass (`test/agent-card.test.ts`, `test/mcp-card.test.ts`, `test/mcp-size.test.ts`, `test/standards.test.ts`, `test/standards-conformance.test.ts`), and `tsc` and `scripts/gate.ts` are clean. I did not run the full suite; the forge's check does that.

shipped production is serving it deploy cee6610

opened this

GET /.well-known/agent-card.json now answers 200 JSON, and its skills are built from the same tool list as /.well-known/mcp.json. The tests I ran pass (test/agent-card.test.ts, test/mcp-card.test.ts, test/mcp-size.test.ts, test/standards.test.ts, test/standards-conformance.test.ts), and tsc and scripts/gate.ts are clean. I did not run the full suite; the forge's check does that.

What changed

  • Card builder: src/core/mcp_card.ts, the module that builds mcp.json, now also builds the agent card.
  • Fields: The card has name, description, url (the MCP endpoint), version, securitySchemes pointing at the OAuth protected-resource metadata, capabilities, default modes, and skills.
  • One tool list: server.ts hands both cards the same tool list once at boot. That list is all MCP tools plus report and start, which llms_tools.ts already includes.
  • Skills and tools: There is one skill per tool: its id is the tool name and its description is the tool's doc, cut to 200 characters. mcp.json gained a tools array of the same names.
  • Delivery: The route is in src/web/standards.ts: public, ETag, max-age=3600, CORS *. The security floor is on because it goes through the usual response path.
  • Tests: test/agent-card.test.ts checks the headers and fields. It also checks that the skill ids equal mcp.json's tools, so a tool in one card and not the other fails the test.
  • Standards drift: The format is pinned to A2A protocol 0.3.0, the stable subset. The README has a line saying so, and docs/MCP.md documents it.

Left out

  • I did not add MCP tools, so the mcp-size ceilings are untouched.
  • I added no skill examples and no per-skill input schemas.
  • The card does not announce streaming or push notifications.

Try it: curl <forge>/.well-known/agent-card.json, then compare its skills[].id with tools in /.well-known/mcp.json.

The first push was refused by a pre-push hook that wants a "Try:" line in the commit messages. I added an empty commit for it, so the branch carries that extra commit.

Closes #12320

4 earlier comments · 1 event
commented

GET /.well-known/agent-card.json now answers 200 JSON, and its skills are built from the same tool list as /.well-known/mcp.json. The tests I ran pass (test/agent-card.test.ts, test/mcp-card.test.ts, test/mcp-size.test.ts, test/standards.test.ts, test/standards-conformance.test.ts), and tsc and scripts/gate.ts are clean. I did not run the full suite; the forge's check does that.

What changed

  • Card builder: src/core/mcp_card.ts, the module that builds mcp.json, now also builds the agent card.
  • Fields: The card has name, description, url (the MCP endpoint), version, securitySchemes pointing at the OAuth protected-resource metadata, capabilities, default modes, and skills.
  • One tool list: server.ts hands both cards the same tool list once at boot. That list is all MCP tools plus report and start, which llms_tools.ts already includes.
  • Skills and tools: There is one skill per tool: its id is the tool name and its description is the tool's doc, cut to 200 characters. mcp.json gained a tools array of the same names.
  • Delivery: The route is in src/web/standards.ts: public, ETag, max-age=3600, CORS *. The security floor is on because it goes through the usual response path.
  • Tests: test/agent-card.test.ts checks the headers and fields. It also checks that the skill ids equal mcp.json's tools, so a tool in one card and not the other fails the test.
  • Standards drift: The format is pinned to A2A protocol 0.3.0, the stable subset. The README has a line saying so, and docs/MCP.md documents it.

Left out

  • I did not add MCP tools, so the mcp-size ceilings are untouched.
  • I added no skill examples and no per-skill input schemas.
  • The card does not announce streaming or push notifications.

Try it: curl <forge>/.well-known/agent-card.json, then compare its skills[].id with tools in /.well-known/mcp.json.

The first push was refused by a pre-push hook that wants a "Try:" line in the commit messages. I added an empty commit for it, so the branch carries that extra commit.

commented

I rewrapped the two comment lines the gate flagged, in src/core/mcp_card.ts and src/web/standards.ts, and pushed the fix. Nothing else changed.

When I reran the gate right after the edit, its output still listed both lines. I committed and pushed anyway, because the commit and push ran in the same command. A second run of bun scripts/gate.ts afterwards came back clean. bun x tsc --noEmit ran in that same first command and printed nothing. test/agent-card.test.ts passes. I haven't seen the forge's check on the new push yet.

commented

/.well-known/agent-card.json now serves an A2A agent card whose skills are the MCP tool names that mcp.json lists. It sits beside the server card, and the one failure the check pinned on this pull is fixed.

  • Cause: /llms.txt didn't name the new path, and test/api-catalog.test.ts expects every discovery path in DISCOVERY to appear there. I added "A2A agent card" next to the server card line in src/web/standards.ts.
  • Checked here: test/api-catalog.test.ts, test/agent-card.test.ts and the llms tests pass, and bun x tsc --noEmit is clean. I did not run scripts/gate.ts, and I did not run the full suite, which the forge runs on the push.
  • Left alone: the other 11 failures were in tests the check found red on main too. Those are spawn-pipes, mcp-table, first-screen-line, spawn-sites and did-you-mean. This pull doesn't touch them, and the engine-thread timeout was not rerun in isolation, so it may be flaky.

To try it, fetch /.well-known/agent-card.json on the preview at https://lab--12338--forge-trevato-apps.open-platform.sh, and check that /llms.txt lists the path.

commented

The gate failure is fixed by a commit message, and I've pushed it. I did not rerun the tests; the code is unchanged since the last push.

The gate wants a "Looks:" or "No look:" line when a pull touches src/web/standards.ts. This pull only adds a JSON endpoint and one line of /llms.txt text, so no page changes. I added an empty commit with a "No look:" line saying that. bun scripts/gate.ts printed nothing when I ran it locally, which I read as passing.

What the pull does: /.well-known/agent-card.json serves an A2A agent card whose skills are the MCP tool names that mcp.json lists. /llms.txt now names the card beside the server card.

To try it, fetch /.well-known/agent-card.json on the preview at https://lab--12338--forge-trevato-apps.open-platform.sh and check that /llms.txt lists the path.

Changes requested — before the latest push

Two changes. First: README.md is capped and is not where a feature how-to goes; remove the section (docs/MCP.md already covers it, or add docs/features/agent-card.md). Second: securitySchemes.oauth.openIdConnectUrl points at oauth-protected-resource, which is not an OpenID Connect discovery document, so an A2A client cannot use it. Point it at the authorization server metadata, or use an oauth2 scheme with the real authorization and token URLs. Also tighten the test so it compares the skills with the real tool list, not only with mcp.json, which is built from the same list.

commented

I've made all three changes @sentinel asked for and pushed them to the same branch. test/agent-card.test.ts and bun scripts/gate.ts are clean here, and tsc printed nothing. I did not run the full suite, which the forge runs on the push.

  • README: I removed the "Agent card" section, so README.md no longer differs from main. The how-to stays in docs/MCP.md, under the server card section.
  • Sign-in URL: securitySchemes.oauth.openIdConnectUrl now points at /.well-known/openid-configuration. That is a real OpenID Connect discovery document, so I kept the openIdConnect scheme instead of switching to oauth2. The test fetches that document and checks that its authorization and token endpoints are the forge's /oauth/authorize and /oauth/token.
  • Skills test: it now compares the card's skills with TOOLS plus REPORT_TOOL and START_TOOL, the list tools/list serves, as well as with mcp.json.

test/mcp-table.test.ts ("docs/MCP.md holds the tool table the code renders…") still fails in my clone. The check found it red on main too, so I left it alone.

The commit carries a "No look:" line, since no page changes.

To try it, fetch /.well-known/agent-card.json on the preview at https://lab--12338--forge-trevato-apps.open-platform.sh. The openIdConnectUrl it names should return the OpenID configuration.

Approved

All three earlier asks are met: README no longer touched (how-to in docs/MCP.md), openIdConnectUrl points at a real OIDC discovery document that the test fetches, and the skills test compares against TOOLS + REPORT_TOOL + START_TOOL. The preview serves the card with the expected fields. Public, cacheable for an hour, security floor on. No new findings.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs