From 04779becab7062e034dd5d202e63e8bd12e41dab Mon Sep 17 00:00:00 2001 From: Matvii Nesterenko <51422901+kapustazh@users.noreply.github.com> Date: Sun, 13 Sep 2026 00:37:49 +0200 Subject: [PATCH 1/2] docs: plan personal MCP payments --- .../PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md diff --git a/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md b/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md new file mode 100644 index 0000000..b84b997 --- /dev/null +++ b/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md @@ -0,0 +1,94 @@ +# Personal OneShot MCP and Privy agent payments + +## Summary + +Add a remote OneShot MCP server at `https://oneshot.kapustazh.dev/mcp` with one tool, `arc_payment`. Each Privy user receives an isolated workspace, a policy-bound embedded wallet, private request history, and one revocable MCP bearer token. + +Payments execute autonomously after one-time signer enablement. Privy, rather than OneShot, enforces the Arc network, USDC contract, recipient allowlist, and per-payment cap through an additional signer policy. + +## Identity, tokens, and request privacy + +- Replace the current authorization-only result with an authenticated principal containing the credential kind, Privy subject, opaque workspace ID, and MCP token ID when applicable. +- Create one personal workspace automatically for each verified Privy DID. +- Allow one active MCP token per user. Return the complete 32-byte random token only when generated, store only an HMAC-SHA-256 digest using a deployment pepper, and revoke it immediately when deleted. +- Limit MCP tokens to `/mcp`. Use Privy JWTs for browser and profile routes. Keep `SERVICE_BEARER_TOKEN` for internal and legacy operations only, and remove its machine-token input from the public workspace. +- Add workspace-bound storage for direct Arc payments and enforce workspace ownership for jobs, paid APIs, intents, recovery, activity, results, and payment proofs. +- Return `404` for cross-user identifiers so the API does not disclose whether another user's request exists. +- Keep existing unattributed data unchanged in a reserved legacy/service workspace. Never return it to ordinary Privy users. +- Replace the Requests tab's job-only query with a unified personal request feed covering Arc payments, service jobs, and paid APIs. + +## Privy wallet and workspace experience + +- Configure Privy to create an Ethereum embedded wallet for every authenticated user. +- Add an **Agents** workspace tab containing: + - Embedded Arc wallet address and funding/readiness status. + - Recipient allowlist and maximum USDC-per-payment controls. + - One-time enable/disable state for the OneShot agent signer. + - MCP token generation, immediate copy, metadata, and deletion. + - Links to MCP documentation and Privy Dashboard team management. +- Create one user-owned Privy override policy for the OneShot signer. Permit only: + - `eth_sendTransaction`. + - Arc chain ID `5042002`. + - Arc USDC contract `0x3600000000000000000000000000000000000000`. + - ERC-20 `transfer` calls. + - Recipients in the configured allowlist, up to 100 addresses. + - Amounts less than or equal to the configured per-payment cap. +- Let unmatched methods default to deny. Attach this policy only to the OneShot additional signer so the user's normal wallet access remains unchanged. +- Make **Enable agent payments** call Privy's `addSigners` once, then verify the signer and policy attachment through the API. Use the user's Privy authorization for later policy changes. +- Resolve wallet and policy configuration per workspace in the payment worker, then construct the existing authorization and settlement adapters for that identity. Retain the global execution-wallet path only for legacy service requests. +- Configure the OneShot P-256 signer ID and private key through deployment configuration and secret storage. +- Keep teammate invitations and roles in Privy Dashboard. Do not reproduce Privy team administration in OneShot. + +## MCP, API, documentation, and skill + +- Mount the official stateless Streamable HTTP MCP handler in the existing Cloud Run API and proxy `/mcp` through the Cloudflare Worker. Do not create another deployment. +- Build a fresh MCP server for each authenticated request and expose exactly one tool: + +```text +arc_payment({ + request_key: string, + recipient: 0x-address, + amount_usdc: decimal-string, + purpose: string +}) +``` + +- Derive the internal intent identity from workspace plus `request_key`. An identical replay returns the existing payment; the same key with changed payment fields returns a conflict. +- Wait briefly for durable processing, then return structured output containing request ID, authoritative state, wallet, recipient, decimal and atomic amounts, transaction hash and explorer link when available, and the safe next action. +- Treat repeating the identical tool call as a status refresh. `SUBMITTING` or `UNKNOWN` must never create or broadcast a replacement payment. +- Add these browser APIs: + - `GET /v1/me` + - `PUT /v1/me/agent-policy` + - `POST /v1/me/agent-access/verify` + - `POST /v1/me/mcp-token` + - `DELETE /v1/me/mcp-token` + - `GET /v1/requests` +- Add a public `/docs/mcp` page modeled on the [Arc MCP setup page](https://docs.arc.io/ai/mcp), with copy-ready setup for Codex, Claude Code/Desktop, Cursor, VS Code, and generic Streamable HTTP clients. Use environment-variable placeholders rather than embedding the token in static documentation. +- Add an installable `oneshot-arc-payment` skill containing `SKILL.md` and `agents/openai.yaml`. Teach stable request keys, policy-denial handling, authoritative state interpretation, proof retrieval, and the prohibition on replacement payments after uncertainty. + +## Tests and acceptance scenarios + +- Verify Privy JWT principals, valid/invalid/revoked MCP tokens, MCP-token route restrictions, and legacy service-token isolation. +- Verify two users can use the same request key while seeing only their own data; all cross-user status, proof, result, reconcile, and payment lookups return `404`. +- Verify one-active-token behavior, show-once secret handling, digest-only storage, copy flow, revocation, and concurrent generation. +- Verify embedded-wallet discovery, canonical policy creation and update, signer attachment, invalid allowlists/caps, and safe denial for missing or drifted policy configuration. +- Verify MCP initialization, `tools/list` exposing only `arc_payment`, authenticated calls, input validation, and structured results. +- Verify concurrent identical calls create one intent and one submission; changed payloads conflict; policy rejection broadcasts nothing; committed replay returns the original transaction; timeout or `UNKNOWN` never resubmits. +- Verify legacy records remain hidden, the unified Requests feed remains personal, bearer tokens are not persisted in browser storage, and the Agents and documentation pages pass browser and accessibility tests. +- Run focused package tests, PostgreSQL integration tests, the full unit suite, typecheck, lint, formatting check, production build, and browser tests. + +## Assumptions and intentional exclusions + +- Arc Testnet and Arc USDC remain the only enabled network and asset. +- Agent payments require one initial Privy signer authorization but no per-payment approval inside the configured policy. +- This release does not add daily/rolling caps, an arbitrary policy editor, MCP OAuth, multiple active API tokens, or OneShot team CRUD. +- Privy Dashboard remains responsible for account teammates. Privy Organizations can be considered later if shared-wallet or quorum behavior becomes necessary. +- The Privy application uses TEE wallet execution and has a registered OneShot authorization-key quorum. +- Existing recovery and session changes in the original worktree remain separate and untouched. + +## References + +- [Arc MCP setup](https://docs.arc.io/ai/mcp) +- [MCP Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports) +- [Privy server signers](https://docs.privy.io/recipes/wallets/user-and-server-signers) +- [Privy policy capabilities](https://docs.privy.io/controls/policies/overview) From 985f74110cf43e432bd1a337143bf03858c1c235 Mon Sep 17 00:00:00 2001 From: Matvii Nesterenko <51422901+kapustazh@users.noreply.github.com> Date: Sun, 13 Sep 2026 04:18:27 +0200 Subject: [PATCH 2/2] docs: restructure the MCP arc_payment plan One remote MCP tool first (arc_payment) on the existing policy-bound execution wallet and Arc settlement worker; personal wallets stay a separately gated milestone. Tasks carry dependencies, concrete work, and exit conditions. --- ...60913T021012Z-clarify-personal-mcp-plan.md | 76 +++++ .../PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md | 306 +++++++++++++----- 2 files changed, 305 insertions(+), 77 deletions(-) create mode 100644 .agent/context/20260913T021012Z-clarify-personal-mcp-plan.md diff --git a/.agent/context/20260913T021012Z-clarify-personal-mcp-plan.md b/.agent/context/20260913T021012Z-clarify-personal-mcp-plan.md new file mode 100644 index 0000000..45a5386 --- /dev/null +++ b/.agent/context/20260913T021012Z-clarify-personal-mcp-plan.md @@ -0,0 +1,76 @@ +# Session Context: clarify-personal-mcp-plan + +## Date/time + +- UTC: 2026-09-13T02:10:12Z + +## User goal + +Split the PR #112 plan into clear, ordered subtasks and reduce ambiguity about +the first deliverable. + +## Original prompt/request + +"Раздели md plan, сделай четче на подзадачи." Follow-up: keep the plan focused +only on the direct `arc_payment` flow. + +## Assumptions + +- The first release exposes exactly one MCP tool, `arc_payment`. +- The first release reuses the existing Privy server execution wallet and Arc + settlement worker. +- Personal wallets and additional signers are a later milestone. + +## Plan + +1. Rewrite the plan around one minimal server-wallet MCP milestone. +2. Give every task dependencies, concrete work, and an exit condition. +3. Preserve personal-wallet architecture as a separately gated milestone. +4. Validate Markdown, obtain Gate A, update PR #112, wait for CI, then obtain + Gate B. + +## Key decisions + +- `arc_payment` is a direct Arc USDC transfer. +- Browser and MetaMask wallets do not participate in milestone 1 payment + execution. +- The MCP handler reuses existing durable intent and settlement paths. +- Aggregate exposure needs a rolling cap or one-intent demo quota; a + per-payment cap alone is insufficient. + +## Files/components touched + +- `docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md` +- `.agent/context/20260913T021012Z-clarify-personal-mcp-plan.md` + +## Commands/checks + +- `markdownlint-cli2` for the plan and context: PASS, 0 errors. +- `git diff --check`: PASS. +- Prettier check for the plan and context: PASS. + +## External-doc findings + +- Privy supports additional signers with per-signer override policies; this is + retained for milestone 2 rather than milestone 1. +- Privy policy evaluation defaults to deny when no rule matches. + +## Unresolved questions + +- Choose a Privy rolling cap or a one-intent quota before the MCP endpoint is + exposed beyond a controlled demo. + +## Git and PR state + +- Branch: `plan/personal-mcp-privy-agent-payments` +- Base: current `origin/develop` merged before editing. +- PR: #112, draft. + +## Gate A/B state + +- Gate A: pending for the rewritten candidate tree. +- Gate B: pending after push and CI. + +## Handoff/next steps + +- Complete Gate A, commit, push, CI, and Gate B. diff --git a/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md b/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md index b84b997..b3f0f37 100644 --- a/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md +++ b/docs/PERSONAL_MCP_PRIVY_AGENT_PAYMENTS_PLAN.md @@ -1,48 +1,8 @@ -# Personal OneShot MCP and Privy agent payments - -## Summary - -Add a remote OneShot MCP server at `https://oneshot.kapustazh.dev/mcp` with one tool, `arc_payment`. Each Privy user receives an isolated workspace, a policy-bound embedded wallet, private request history, and one revocable MCP bearer token. - -Payments execute autonomously after one-time signer enablement. Privy, rather than OneShot, enforces the Arc network, USDC contract, recipient allowlist, and per-payment cap through an additional signer policy. - -## Identity, tokens, and request privacy - -- Replace the current authorization-only result with an authenticated principal containing the credential kind, Privy subject, opaque workspace ID, and MCP token ID when applicable. -- Create one personal workspace automatically for each verified Privy DID. -- Allow one active MCP token per user. Return the complete 32-byte random token only when generated, store only an HMAC-SHA-256 digest using a deployment pepper, and revoke it immediately when deleted. -- Limit MCP tokens to `/mcp`. Use Privy JWTs for browser and profile routes. Keep `SERVICE_BEARER_TOKEN` for internal and legacy operations only, and remove its machine-token input from the public workspace. -- Add workspace-bound storage for direct Arc payments and enforce workspace ownership for jobs, paid APIs, intents, recovery, activity, results, and payment proofs. -- Return `404` for cross-user identifiers so the API does not disclose whether another user's request exists. -- Keep existing unattributed data unchanged in a reserved legacy/service workspace. Never return it to ordinary Privy users. -- Replace the Requests tab's job-only query with a unified personal request feed covering Arc payments, service jobs, and paid APIs. - -## Privy wallet and workspace experience - -- Configure Privy to create an Ethereum embedded wallet for every authenticated user. -- Add an **Agents** workspace tab containing: - - Embedded Arc wallet address and funding/readiness status. - - Recipient allowlist and maximum USDC-per-payment controls. - - One-time enable/disable state for the OneShot agent signer. - - MCP token generation, immediate copy, metadata, and deletion. - - Links to MCP documentation and Privy Dashboard team management. -- Create one user-owned Privy override policy for the OneShot signer. Permit only: - - `eth_sendTransaction`. - - Arc chain ID `5042002`. - - Arc USDC contract `0x3600000000000000000000000000000000000000`. - - ERC-20 `transfer` calls. - - Recipients in the configured allowlist, up to 100 addresses. - - Amounts less than or equal to the configured per-payment cap. -- Let unmatched methods default to deny. Attach this policy only to the OneShot additional signer so the user's normal wallet access remains unchanged. -- Make **Enable agent payments** call Privy's `addSigners` once, then verify the signer and policy attachment through the API. Use the user's Privy authorization for later policy changes. -- Resolve wallet and policy configuration per workspace in the payment worker, then construct the existing authorization and settlement adapters for that identity. Retain the global execution-wallet path only for legacy service requests. -- Configure the OneShot P-256 signer ID and private key through deployment configuration and secret storage. -- Keep teammate invitations and roles in Privy Dashboard. Do not reproduce Privy team administration in OneShot. - -## MCP, API, documentation, and skill - -- Mount the official stateless Streamable HTTP MCP handler in the existing Cloud Run API and proxy `/mcp` through the Cloudflare Worker. Do not create another deployment. -- Build a fresh MCP server for each authenticated request and expose exactly one tool: +# OneShot MCP `arc_payment` implementation plan + +## Decision + +Ship one remote MCP tool first: ```text arc_payment({ @@ -53,38 +13,230 @@ arc_payment({ }) ``` -- Derive the internal intent identity from workspace plus `request_key`. An identical replay returns the existing payment; the same key with changed payment fields returns a conflict. -- Wait briefly for durable processing, then return structured output containing request ID, authoritative state, wallet, recipient, decimal and atomic amounts, transaction hash and explorer link when available, and the safe next action. -- Treat repeating the identical tool call as a status refresh. `SUBMITTING` or `UNKNOWN` must never create or broadcast a replacement payment. -- Add these browser APIs: - - `GET /v1/me` - - `PUT /v1/me/agent-policy` - - `POST /v1/me/agent-access/verify` - - `POST /v1/me/mcp-token` - - `DELETE /v1/me/mcp-token` - - `GET /v1/requests` -- Add a public `/docs/mcp` page modeled on the [Arc MCP setup page](https://docs.arc.io/ai/mcp), with copy-ready setup for Codex, Claude Code/Desktop, Cursor, VS Code, and generic Streamable HTTP clients. Use environment-variable placeholders rather than embedding the token in static documentation. -- Add an installable `oneshot-arc-payment` skill containing `SKILL.md` and `agents/openai.yaml`. Teach stable request keys, policy-denial handling, authoritative state interpretation, proof retrieval, and the prohibition on replacement payments after uncertainty. - -## Tests and acceptance scenarios - -- Verify Privy JWT principals, valid/invalid/revoked MCP tokens, MCP-token route restrictions, and legacy service-token isolation. -- Verify two users can use the same request key while seeing only their own data; all cross-user status, proof, result, reconcile, and payment lookups return `404`. -- Verify one-active-token behavior, show-once secret handling, digest-only storage, copy flow, revocation, and concurrent generation. -- Verify embedded-wallet discovery, canonical policy creation and update, signer attachment, invalid allowlists/caps, and safe denial for missing or drifted policy configuration. -- Verify MCP initialization, `tools/list` exposing only `arc_payment`, authenticated calls, input validation, and structured results. -- Verify concurrent identical calls create one intent and one submission; changed payloads conflict; policy rejection broadcasts nothing; committed replay returns the original transaction; timeout or `UNKNOWN` never resubmits. -- Verify legacy records remain hidden, the unified Requests feed remains personal, bearer tokens are not persisted in browser storage, and the Agents and documentation pages pass browser and accessibility tests. -- Run focused package tests, PostgreSQL integration tests, the full unit suite, typecheck, lint, formatting check, production build, and browser tests. - -## Assumptions and intentional exclusions - -- Arc Testnet and Arc USDC remain the only enabled network and asset. -- Agent payments require one initial Privy signer authorization but no per-payment approval inside the configured policy. -- This release does not add daily/rolling caps, an arbitrary policy editor, MCP OAuth, multiple active API tokens, or OneShot team CRUD. -- Privy Dashboard remains responsible for account teammates. Privy Organizations can be considered later if shared-wallet or quorum behavior becomes necessary. -- The Privy application uses TEE wallet execution and has a registered OneShot authorization-key quorum. -- Existing recovery and session changes in the original worktree remain separate and untouched. +The first release uses the existing policy-bound Privy server execution wallet +and the existing Arc settlement worker. Privy login authenticates the browser; +it does not select the payer. The MCP tool does not use MetaMask, an embedded +browser wallet, or a per-payment wallet popup. + +Personal Privy wallets and delegated agent signers remain a separate milestone. +They must not block the first working `arc_payment` demo. + +## Non-negotiable behavior + +- Arc Testnet (`eip155:5042002`) and Arc USDC are the only network and asset. +- One stable `request_key` maps to one stable Business Intent. +- Repeating the same request returns the existing intent and settlement. +- Reusing the key with different immutable fields returns a conflict. +- `SUBMITTING` and `UNKNOWN` never create a replacement payment. +- Privy policy and OneShot both validate the amount and transaction scope. +- The tool returns authoritative OneShot state, not an inferred success. +- A real demo payment is complete only after a verified Arc receipt is durable. + +## Delivery order + +| Order | Task | Depends on | Exit condition | +| ----- | --------------------------------------- | ---------- | ----------------------------------------------- | +| 1 | Freeze the tool contract | None | Input and output schemas are approved | +| 2 | Add MCP-only authentication | Task 1 | `/mcp` accepts only the dedicated credential | +| 3 | Mount Streamable HTTP MCP | Task 2 | `initialize` and `tools/list` expose one tool | +| 4 | Connect `arc_payment` to the ledger | Task 3 | Calls create or replay one durable intent | +| 5 | Enforce payment scope and spend bounds | Task 4 | Invalid or excessive requests broadcast nothing | +| 6 | Return status and proof | Task 4 | Replays report the same authoritative state | +| 7 | Verify failure and concurrency behavior | Tasks 4-6 | Required payment tests pass | +| 8 | Document and run one demo | Task 7 | One real Arc Testnet settlement is verified | + +## Task 1: freeze the tool contract + +### Work + +- Accept only `request_key`, `recipient`, `amount_usdc`, and `purpose`. +- Parse `amount_usdc` as a six-decimal string into integer atomic units. Never + use JavaScript floating point. +- Reject malformed addresses, zero amounts, excess precision, empty purposes, + and oversized strings before creating an intent. +- Define a structured result with: + - request and Business Intent IDs; + - authoritative payment state; + - payer, recipient, decimal amount, and atomic amount; + - transaction hash and ArcScan link when known; + - one safe next action: `WAIT`, `CHECK_STATUS`, `VIEW_PROOF`, or + `FIX_REQUEST`. + +### Done when + +- The JSON schemas and examples cover accepted, rejected, pending, unknown, + and committed results. + +## Task 2: add MCP-only authentication + +### Work + +- Add one dedicated high-entropy bearer credential in deployment secret + storage for the first release. +- Accept it only on `/mcp`; do not let it authorize `/v1/*` routes. +- Keep Privy JWT authentication for the browser and the existing internal + service credential for internal or legacy routes. +- Bind the MCP principal to one explicit demo workspace. +- Compare credentials in constant time and never log or return them. + +### Done when + +- Missing, invalid, and browser credentials fail on `/mcp`. +- The MCP credential succeeds on `/mcp` and fails on browser/API routes. + +Self-service token generation, token tables, HMAC peppers, and per-user token +rotation are deferred until there is more than one MCP user. + +## Task 3: mount the MCP transport + +### Work + +- Mount the official stateless Streamable HTTP MCP handler in the existing + Cloud Run API. +- Proxy `/mcp` through the existing Cloudflare Worker without creating another + deployment. +- Expose exactly one tool named `arc_payment`. +- Return protocol errors as MCP errors without leaking provider responses or + credentials. + +### Done when + +- `initialize` succeeds through `https://oneshot.kapustazh.dev/mcp`. +- `tools/list` returns only `arc_payment` with the frozen schema from Task 1. + +## Task 4: reuse the durable payment path + +### Work + +- Derive the Business Intent identity from the workspace and normalized + `request_key` with one versioned deterministic function. +- Convert the tool input into the existing Arc USDC intent contract. +- Call the existing create-or-replay ledger path and existing worker. Do not + add a second settlement implementation inside the MCP handler. +- Preserve the existing submission lease, provider idempotency key, receipt + verification, `UNKNOWN` handling, and recovery behavior. +- Treat another call with the same key as create-or-read, never as a new + payment command. + +### Done when + +- One valid tool call reaches the existing `SERVER_PRIVY` payment mode. +- Identical replay returns the same Business Intent. +- Changed recipient, amount, asset, network, or purpose conflicts explicitly. + +## Task 5: enforce payment scope and total exposure + +### Work + +- Keep Privy rules for Arc chain ID `5042002`, the Arc USDC contract, + zero native value, ERC-20 `transfer`, and the approved per-payment cap. +- Validate the recipient as an EVM address even when the current policy permits + any recipient. +- Keep the application settlement cap equal to or lower than the Privy cap. +- Add a cumulative control before allowing repeated unique requests. Choose + one: + - a Privy rolling USDC spending cap for normal use; or + - a one-intent quota for a literal single-payment demo. +- Fail readiness when the attached wallet, policy, digest, network, token, or + cap differs from the reviewed deployment baseline. + +### Done when + +- Above-cap and exhausted-quota requests create zero broadcasts and zero + settlements. +- Policy drift makes the tool unavailable before submission. + +## Task 6: return authoritative status and proof + +### Work + +- Wait only for a short bounded interval after create-or-replay. +- Return the current durable state when settlement is still processing. +- Include an ArcScan link only for a stored transaction hash. +- Return the original result for a committed replay. +- For `UNKNOWN`, instruct the caller to repeat the same tool call or inspect the + proof. Never suggest a new `request_key`. + +### Done when + +- Every non-final response gives a safe next action. +- No response claims payment from queue acceptance alone. + +## Task 7: test the payment boundary + +### Required tests + +- Valid and invalid MCP authentication; route isolation. +- `tools/list` exposes exactly one tool. +- Input validation and exact decimal-to-atomic conversion. +- One normal request produces exactly one committed settlement. +- Ten sequential identical calls produce one settlement. +- Ten parallel identical calls produce one settlement. +- Same key with changed immutable payload returns a conflict. +- Privy denial, amount above cap, and exhausted quota produce zero broadcasts. +- Crash or lost response after possible submission enters `UNKNOWN`, then + reconciliation finds the original payment without resubmission. +- Committed replay returns the original transaction and result. + +### Validation commands + +- Focused MCP, API, worker, Privy adapter, and storage tests. +- PostgreSQL integration tests. +- Full unit suite, typecheck, lint, formatting check, production build, and + browser tests. + +## Task 8: document and demonstrate + +### Work + +- Add one short `/docs/mcp` page with generic Streamable HTTP configuration and + one copy-ready client example. +- Use an environment-variable placeholder for the bearer credential. +- Demonstrate one real `arc_payment` call, one identical replay, and one proof + view. +- Record the Business Intent ID, verified Arc transaction, policy identity, + and zero-duplicate result without recording secrets. + +### Done when + +- A fresh client can connect using the page and list `arc_payment`. +- The demo shows one real Arc Testnet USDC settlement and no replacement + settlement on replay. + +Client-specific setup pages and an installable `oneshot-arc-payment` skill are +deferred until the tool contract is stable. + +## Milestone 2: personal Privy wallets + +Start this milestone only after the server-wallet MCP path is working. + +1. Replace the fixed MCP principal with a principal containing credential kind, + Privy subject, opaque workspace ID, and MCP token ID. +2. Create one isolated workspace and one revocable MCP token per Privy user. +3. Store only a SHA-256 digest of each random 32-byte token and enforce + one-active-token generation atomically. +4. Bind jobs, intents, recovery, activity, results, and proofs to the workspace; + return `404` for cross-workspace identifiers. +5. Discover the user's embedded Ethereum wallet and show funding/readiness. +6. Create a user-owned Privy override policy and add the OneShot P-256 key + quorum as an additional signer after one explicit user authorization. +7. Resolve wallet and signer policy per workspace in the worker while keeping + the existing global execution wallet only for legacy service requests. +8. Add the **Agents** tab for wallet status, signer enable/disable, policy + controls, and MCP token lifecycle. +9. Replace the current request list with a workspace-bound unified feed. +10. Add multi-user isolation, concurrent token generation, signer attachment, + policy update, and browser accessibility tests. + +## Explicitly excluded from the first release + +- MetaMask or browser-wallet payment execution. +- Personal embedded-wallet settlement. +- Arbitrary policy editor. +- MCP OAuth. +- Multiple active MCP credentials. +- OneShot team or Privy teammate administration. +- Multiple MCP tools, assets, or networks. ## References