MCP: permissions management, per-wallet activity, published tool list - #363
Merged
Merged
Conversation
…ed tool list Three connected changes: users can now see what the tools are, control what each client may do, and audit what it actually did. **Permissions are now enforceable, not just displayed.** The MCP endpoint previously trusted the access token's `scope` claim. Those tokens are self-contained and live an hour, so removing a permission — or revoking a connection outright — did nothing until the token happened to expire, which makes a permissions UI a lie. `resolveMcpCaller` now reads the stored OAuthGrant on every request: a missing grant is a 401, and the token's scopes are *intersected* with the grant's, so a change applies on the very next call and a token can never gain reach it was not issued with. Costs one indexed lookup, on the same path that already does one for bots. The profile card gains per-scope checkboxes and a save action. `updateConnectionScopes` moves the grant and its live refresh tokens in one transaction, so a refresh cannot re-widen what was just narrowed. Emptying a grant is refused: a connection that authenticates but can do nothing reads as broken, and revoking is the honest action. **Tool calls are now recorded.** Every invocation writes an AuditLog row from the single wrapper in `createMcpServer` — tool, client, scope, status, duration — keyed to the wallet it touched, so the per-wallet view is an indexed lookup rather than a scan. Only the walletId is read from the arguments: tool inputs carry user-authored prose (rationales, descriptions) that has no place in an audit row. Writes are fire-and-forget; an audit miss must never break a tool call. **Wallet overview gains an AI client activity card**, listing the clients that used *this* wallet with call counts and failures, expandable to the individual calls. The profile answers "what have I connected"; this answers "what has touched this wallet", which is the question a co-signer asks. **The landing page lists the tools**, grouped by the permission each needs. The list lives in `src/data/mcp-tools.ts` rather than importing the registry, which would drag the API handlers and Mesh WASM into the client bundle; a test asserts the two match name-for-name and scope-for-scope. A second test pins the audit action string the tRPC router hard-codes for the same reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three connected changes: users can see what the tools are, control what each client may do, and audit what it actually did.
Permissions are now enforceable, not just displayed
The MCP endpoint trusted the access token's
scopeclaim. Those tokens are self-contained and live an hour, so removing a permission — or revoking a connection outright — did nothing until the token expired. A permissions UI on top of that would have been a lie.resolveMcpCallernow reads the storedOAuthGranton every request:Costs one indexed lookup, on a path that already does one for bot callers. Three tests pin this: revoked → 401, narrowed grant drops the tool even though the token still claims the scope, widened grant does not widen the token.
The profile card gains per-scope checkboxes and a save action.
updateConnectionScopesmoves the grant and its live refresh tokens in one transaction, so a refresh can't re-widen what was just narrowed. Emptying a grant is refused — a connection that authenticates but can do nothing reads as broken; revoking is the honest action.Tool calls are recorded
Every invocation writes an
AuditLogrow from the single wrapper increateMcpServer— tool, client, scope, status, duration — keyed to the wallet it touched, so the per-wallet view is an indexed lookup rather than a scan.Only the
walletIdis read from the arguments: tool inputs carry user-authored prose (rationales, descriptions) that has no place in an audit row. Writes are fire-and-forget; an audit miss must never break a tool call.Wallet overview: AI client activity
A new card lists the clients that used this wallet, with call counts and failures, expandable to individual calls. The profile card answers "what have I connected"; this answers "what has touched this wallet", which is the question a co-signer asks.
Landing page lists the tools
All 13, grouped by the permission each needs. The list lives in
src/data/mcp-tools.tsrather than importing the registry — that would drag the API handlers and Mesh WASM into the client bundle — and a test asserts the two match name-for-name and scope-for-scope. A second test pins the audit action string the tRPC router hard-codes for the same reason, since a drift there would silently empty the activity view.Verification
tscclean, build green, 821 + 85 tests. Tool list verified rendering in a browser (13 tools, correctly grouped).Not verified visually: the permissions checkboxes and the wallet activity card both need a wallet session and a database, neither available locally. Their procedures are unit-tested — including that
walletClientsrefuses a wallet the caller isn't a signer of.Based on #362, since the tool list includes
ballot_publish_rationale. GitHub retargets topreprodonce that merges.🤖 Generated with Claude Code