MCP: connection management, governance tools, vendor-neutral setup - #358
Conversation
Approving an AI client on the consent screen was a one-way door: the OAuthGrant row was written but never read back, so a user had no way to see what they had connected, and no way to disconnect it. Adds a "Connected AI clients" card to the profile, next to the bot-key card it mirrors — bots authenticate with a key minted there, MCP clients with an OAuth grant approved on the consent screen, and both now live in one place. Each entry shows the client name, the client id it was actually verified as (the name is self-declared), the granted scopes in plain language, and whether any session is still live. Revoking drops the grant and revokes every refresh token under it in one transaction — a deleted grant with live refresh tokens would let the client keep renewing silently. Access tokens already issued are self-contained JWTs and stay valid until they expire within the hour, which is the trade-off for stateless verification; the dialog says so rather than implying instant cutoff. Also fixes a real gap the first live connection exposed: the 401 challenge advertised only `wallets:read`, and clients request exactly the challenge's `scope` rather than `scopes_supported` from the metadata document. Two of the nine tools were therefore unreachable by any client following the spec. The challenge now advertises both read scopes; `ballots:write` stays out so the one scope that writes anything remains opt-in. Expands the landing "Connect an AI agent" card into three numbered setup steps, and links to the profile for managing connections. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Pushed a second commit ( Three governance tools
Two handler changes
Vendor-neutral, hero-levelThe hero leads with MCP rather than one vendor: the endpoint and a plain 805 + 76 tests, Still to comeRationale → IPFS publishing is not in this PR. |
Follow-up to #357, from connecting a real client to preprod and finding two gaps.
Connections are now visible and revocable
Approving an AI client on the consent screen was a one-way door: the
OAuthGrantrow was written but never read back, so there was no way to see what was connected and no way to disconnect it.Adds a "Connected AI clients" card to the profile, next to the bot-key card it mirrors — bots authenticate with a key minted there, MCP clients with an OAuth grant approved on the consent screen. Each entry shows:
verified metadatabadge for CIMD clientsRevoking drops the grant and revokes every refresh token under it in one transaction — a deleted grant with live refresh tokens would let the client keep renewing silently. Access tokens already issued are self-contained JWTs and stay valid until they expire within the hour; the confirmation dialog says so rather than implying an instant cutoff.
Fixes: two tools were unreachable
The first live connection came back with only
wallets:read, sogovernance_list_active_proposalsandballot_upsertnever appeared in the client's tool list.Cause: the 401 challenge advertised
scope="wallets:read", and clients request exactly the challenge'sscoperather thanscopes_supportedfrom the metadata document. Anything omitted there is unreachable in practice, however well documented.The challenge now advertises both read scopes.
ballots:writestays out deliberately — it's the only scope that writes anything, so a client must ask for it explicitly. Pinned by a test so it can't drift back.Landing page
The "Connect an AI agent" card is now three numbered setup steps — add the server, authorize with your wallet, ask it something — plus a read-only callout linking to the profile.
Verification
tsc --noEmitclean,npm run buildgreen, 801 + 76 tests. Nine new tests for the router, covering the authorization boundary: revoke refuses an address the wallet session doesn't hold, refuses with no session at all, looks the grant up by(subject, client)rather than client alone, and 404s on a missing grant. Landing section verified in a browser.Not verified visually: the profile card itself needs a wallet session and a database, so I couldn't render it locally — it self-hides without an address (confirmed no tRPC request fires). Its router is unit-tested, and the card will have real data to show on preprod.
Note the router tests live in the ESM jest project: importing a tRPC router pulls
superjson, which is ESM-only and cannot load in the CJS project.🤖 Generated with Claude Code