Skip to content

P15a: MCP grant store + connection-bound (cnf) JWT #53

Description

@ehsan6sha

P15a — MCP grant store + connection-bound JWT (pinning-webui)

Server-side channel that lets a user grant a paired AI (MCP) scoped access to their REAL files, delivered to the stateless MCP via a fetchable store (NOT bundle re-injection).

Background

A grant = a ShareToken (JSON; path_scope+permissions+expiry+id are PLAINTEXT, only the DEK is HPKE-sealed to the MCP X25519 pubkey) PLUS a matching Capability{scope,permissions} the MCP adds to its bundle. FxFiles mints one token PER FILE for a folder/tag, sealed to the MCP pubkey, and publishes them here. The MCP later GETs its grants and merges them. Storing the sealed token server-side is safe (only the MCP secret unwraps).

Scope (additive, backward-compatible — extends P11)

  1. Connection-bound JWT. mintMcpToken + POST /api/mcp/tokens accept an OPTIONAL mcp_pub_b64 (base64 of a 32-byte X25519 pubkey); when present it is embedded as a top-level cnf claim (cnf: { mcp_pub_b64 }, RFC-7800 key-binding) SIBLING of mcp. Absent ⇒ no cnf (older flow unchanged). verifyMcpToken exposes cnf.mcp_pub_b64 (validated 32-byte b64). Additive: the P12 gateway ignores unknown claims.
  2. mcp_grants table + helpers (postgres.ts, mirrors mcp_revoked_tokens): insertMcpGrants (bulk), listActiveGrantsForConnection(userId, mcpPubB64), revokeMcpGrant, gcExpiredGrants.
  3. Endpoints (app.ts):
    • POST /api/mcp/grants — USER session/bearer; bulk insert (cap ≤1000).
    • GET /api/mcp/grantsMCP scoped JWT auth; returns ONLY listActiveGrantsForConnection(sub, cnf.mcp_pub_b64). No cnf ⇒ empty. THIS FILTER IS THE SECURITY BOUNDARY (closes cross-agent metadata leak).
    • POST /api/mcp/grants/revoke — USER session/bearer.
    • Audit-log issue/revoke counts (no token_json, no secrets).

Tests

vitest: always-green unit (cnf mint/verify, missing-cnf handling, payload-shape validation, ≤1000 cap) + pg-gated integration (insert; A-vs-B isolation; revoke; unauth → 401).

PR INTO feat/fula-mcp (NOT main).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions