Files
PaperClipAI/doc/public-mcp.md
T
DottaandPaperclip e34abee670 feat(mcp): connect assistants to a team with user OAuth (#14846)
## Thinking Path

> - Paperclip gives teams durable tasks, agent execution, budgets, and
approvals.
> - People also use assistants in Codex, Claude, and other MCP clients.
> - Those assistants need a scoped connection that preserves the
person’s permissions and attribution.
> - Delegating a task must not turn the assistant into the assigned
agent.
> - This PR adds opt-in user OAuth, ten first-party tools, browser
consent, and workflow packages.
> - Paid product evals verify the resulting tasks, documents,
attribution, retries, and access boundaries.
> - The team keeps working after the assistant conversation ends.

## Linked Issues or Issue Description

**Problem or motivation**

A person cannot connect an external assistant to an existing team
through browser consent and safely delegate durable work as themselves.

**Proposed solution**

Expose an opt-in `/mcp/paperclip` endpoint with individually described
first-party operations. Bind every connection to a person, client,
company, resource, and scopes. Reuse domain authorization and
scheduling. Package shared team-review, delegation, and follow-up
workflows for OpenAI/Codex and Claude.

**Alternatives considered**

Related PRs #9393 and #12549 cover earlier remote MCP and board-operator
approaches. This change uses user OAuth and a bounded public catalog. It
does not expose a generic executor, operator administration, static
shared board credentials, or external agent execution. Registry listing
work in #9851 is a separate distribution step.

**Roadmap alignment**

This maintainer-requested implementation extends the governed MCP
gateway, activity attribution, durable work products, and hosted
deployment direction in `ROADMAP.md`. It implements the first release of
the saved design plan; external agent participation and granted
third-party tools remain later releases.

## What Changed

- Add MCP 2.0 discovery and task status/comment/document Events on the
same authenticated endpoint. Persist subscriptions and delivery
receipts, verify HTTPS callbacks, sign Standard Webhooks, encrypt
callback material, recheck permissions/Cloud membership, and bound
retries/expiry. Older MCP clients keep their existing tools.
- Add discovery, dynamic client registration, S256 PKCE, resource
validation, rotating refresh tokens, revocation, and company consent.
Store credentials as hashes and recheck membership at execution.
- Add tools for connection identity, agents/projects, task
search/read/create, human comments, documents/deliverables, and
pending-approval links. Preserve current domain permissions and
scheduling.
- Add durable mutation receipts across reconnects. Matching retries
replay results; uncertain outcomes keep the same request ID and require
inspection.
- Add consent and connection-management pages, OAuth log redaction,
shared plugin workflows, and separate OpenAI/Codex and Claude package
outputs.
- Add eight paid Product E2E cases across three models, independent
durable-state grading, usage evidence, cleanup, and report integration.
Add task-document guidance and regenerate the runner capability
inventories.
- Add migrations 0301 and 0302, the dated implementation plan, result
notes, and direct-client setup instructions in `doc/public-mcp.md`.

## Verification

- Merge integration `e180b1948`: resolved conflicts with current master,
preserved both eval registries, regenerated capability catalogs, and
regenerated migrations as 0301/0302 while keeping the original
replay-safe SQL byte-identical. Local migration safety/snapshot tests
(26), MCP/OAuth tests (38), redaction/OpenAPI tests (71), and eval
catalog/grading tests (198) pass. Token and capability gates pass. Full
recursive typecheck passed. Fresh Greptile review is 5/5 with no
unresolved findings. CI is green on this exact head (55 successes, two
intentional skips, one neutral result): one unchanged Cursor sandbox
test timed out at 10 seconds, then passed locally in 856 ms. A single
retry of that failed shard and the aggregate workflow passed. Merge
remains blocked on the repository code-owner approval rule.

Earlier checks passed at `6aa0962d4fb715f2190bb7bb22efacab2e58495d`: 55
successes, two intentional skips and one neutral result. [The earlier CI
run](https://github.com/paperclipai/paperclip/actions/runs/36901592350)
includes all test shards, browser tests, typecheck, build and canary dry
run. Greptile was 5/5 on that commit with no unresolved review threads.
GitHub still requires code-owner review under the repository merge
rules; passing checks do not bypass that approval. Paid source
fingerprints remain separate below and in the dated result note.

- Paid Events qualification passes **3/3**: GPT-5.4 Mini, Claude Haiku
4.5 and Claude Sonnet 4.6. Each uses a real public HTTPS callback,
signature verification and report retrieval in a fresh conversation. A
final Mini regression passes after the quota/status fixes. All evidence
validates. Bounded tunnel startup retries occur before provider calls
and remain visible; failed earlier attempts retain their original
grades.
- The earlier complete seven-case matrix passes **21/21**, with a
separate **3/3** delegation regression. Two preceding matrices also
passed 21/21 each. A complete 24-cell matrix including Events has not
been run. [The dated
results](doc/plans/2026-10-01-public-mcp-paid-eval-results.md) retain
exact source fingerprints, failures, model IDs and partial costs.
- Node 24: repository-wide `pnpm -r typecheck` and `pnpm build` pass
after merging master. Server typecheck passes after the final
quota/status changes. Eval typecheck and all 892 eval-support tests
pass.
- All 33 real MCP/OAuth tests pass. The preceding combined MCP,
redaction, private-address and DNS-rebinding run passed 129 tests; two
later MCP regressions cover quota reuse and unchanged-status
suppression. All 28 adjacent issue-tree/stale-lock route tests pass. CI
then found a null checkout result in the existing concurrent-workspace
path; logging now uses optional status access. All 12 closed-workspace
tests and all 33 MCP tests pass after that correction. The exact-start
event calibration exposed a timestamp gap; scanning now includes the
subscription start, with all 33 MCP tests and server typecheck passing.
These two narrow corrections follow the paid regression.
- A real Core → Cloud → Core authority round trip passes OAuth, MCP 2.0
subscription/delivery, current membership loss, unsubscribe, legacy SDK
tools, refresh and revocation. Its callback transport is a fixture with
independent HMAC verification. The paid Events campaigns separately
prove public HTTPS delivery.
- Earlier component qualification passed UI 7,117 tests, CLI 502, shared
832, skills catalog 20, database 160 and OpenAPI 10. Token gates, module
boundaries, migration order and plugin regeneration passed. CI covers
general/serialized suites, eight browser shards, runner checks,
typecheck, build and canary dry run.
- **Local full-suite limitation:** the earlier monolithic run was not
clean. It encountered overlapping schema rebuilding, Mac database
shared-memory limits and isolated CLI/fixture failures. Targeted reruns
passed. The existing >32 MiB Git filename stress test still hit its
300-second Mac timeout. The additional serialized sweep stopped after 62
passing suites once CI passed. Original failures and partial logs
remain; this PR does not claim a wholly green local monolithic run.
- Local Codex CLI and Claude Code OAuth login and MCP SDK
interoperability were verified. Public-store installation, actual
ChatGPT Work Cloud Events UI, staging HTTPS client behavior and hosted
newcomer provisioning remain release gates.

Enablement is moving to **Settings → Experimental → Assistant
connections (MCP)** in the stacked follow-up
[#14933](https://github.com/paperclipai/paperclip/pull/14933). Merge
both for the intended setup experience. This foundation branch alone
still uses `PAPERCLIP_PUBLIC_MCP_ENABLED=true`. After deployment, set
`PAPERCLIP_PUBLIC_URL` to the authenticated instance's HTTPS origin, and
connect to `/mcp/paperclip`. Select a team and allow writes in browser
consent. Configure an available agent and budget, then delegate and
retrieve results later. For Events, rescan the deployed plugin catalog
in ChatGPT Work Cloud; the host supplies its webhook credentials when
the user asks to watch a task. See [the setup
runbook](doc/public-mcp.md).

## Risks

- Events are at-least-once and may arrive out of order. No replay cursor
is advertised. Clients must refresh finite subscriptions, read current
state and avoid comment feedback loops. Callback material uses the
instance secrets master key; hosted subscriptions require the updated
Cloud broker and are bounded to five minutes/the access proof expiry.
- ChatGPT Work Cloud/dot event UI, plugin rescan and a hosted staging
subscription remain deployment gates. Local signed-webhook and paid
model evidence does not claim those surfaces have been exercised.
- Disabled by default. Merging adds schema and opt-in code; it does not
deploy a public endpoint, publish a store listing, create a team, or
start paid agents.
- Migrations 0301 and 0302 are additive and idempotent. Their SQL is
unchanged from the earlier preview numbers, so hash-aware upgrade
reconciliation preserves prior staging applications. Normal instance
upgrades must apply it before enabling MCP.
- Task creation and comments can schedule paid agent work. Consent and
tool descriptions disclose that effect. Revocation blocks future calls
but does not undo delegated work.
- Public deployments need edge rate limits and credential-safe logging.
Internal dispatch is restricted to the closed catalog and carries a
request-local verified actor.
- Hosted onboarding requires the companion Cloud broker, encryption-key
configuration, and tenant rollout. Self-hosted direct connections can
use this PR alone.
- Store acceptance and agent-mode participation are not claimed.
Checked-in plugin endpoints are development defaults; rebuild packages
for a real deployment before installation.

## Model Used

OpenAI GPT-6 in Codex, with reasoning, tool use, and code execution. A
more specific serving version and context-window size were not exposed
by the session. Paid eval models: `gpt-5.4-mini-2026-03-17`,
`claude-haiku-4-5-20251001`, and `claude-sonnet-4-6`.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (targeted/component checks;
full local-run limitations are recorded above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-06 11:48:53 -05:00

14 KiB

Public Paperclip MCP connection

The first-release implementation connects an external assistant as a person to one explicitly selected company. It exposes first-party task operations and keeps normal Paperclip authorization, scheduling, attribution, budgets and approvals. The existing named agent gateways and native runner checks remain separate. The accepted roadmap is in the implementation plan.

Enable an instance

Apply database migrations with the normal instance upgrade workflow. Set:

PAPERCLIP_PUBLIC_MCP_ENABLED=true
PAPERCLIP_PUBLIC_URL=https://YOUR-PAPERCLIP-HOST

The URL must be an origin without a path, credentials, query or fragment. HTTP is allowed only for localhost/loopback development. The feature is disabled by default. Use authenticated deployment with real user accounts and company memberships; local implicit board authority and agent/board API keys cannot approve user OAuth connections. Configure TRUST_PROXY correctly at your edge.

The endpoint is POST /mcp/paperclip, using stateless Streamable HTTP with JSON responses. GET/SSE sessions are unnecessary. Each invocation verifies its bearer token again; normal API endpoints do not accept these OAuth tokens. Public installation requires a reachable HTTPS deployment. Private self-hosted instances require a directly reachable endpoint; no managed relay is included.

Connect an assistant directly

After the instance is enabled and reachable, an existing team member can connect without a store listing. For Codex CLI:

codex mcp add paperclip --url https://YOUR-PAPERCLIP-HOST/mcp/paperclip
codex mcp login paperclip --scopes paperclip:read,paperclip:write,offline_access

For Claude Code:

claude mcp add --transport http paperclip https://YOUR-PAPERCLIP-HOST/mcp/paperclip

Open Claude Code's /mcp menu and authenticate the Paperclip server. Both flows open browser sign-in and consent: select a team and explicitly enable task and comment writes when wanted. Read-only consent cannot delegate work.

Ask the assistant to identify the connected team and list its agents, then ask it to delegate a small task to an available agent. The returned task link is the durable reference. In a later conversation, ask for that task's progress and report. Configure the agent's provider credentials, execution environment and budget in Paperclip before expecting it to run; the assistant connection does not supply them. Revocation is available at /assistant-connections.

The optional workflow packages teach team review, delegation and result retrieval. Build them for the same endpoint before installing locally. Public ChatGPT/Codex and Claude directory installation requires the separate deployment and submission work below.

  • Protected-resource discovery: /.well-known/oauth-protected-resource/mcp/paperclip.
  • Authorization-server discovery: /.well-known/oauth-authorization-server.
  • Public-client registration: /mcp/oauth/register.
  • Authorization, token and revocation endpoints: /mcp/oauth/authorize, /mcp/oauth/token, /mcp/oauth/revoke.
  • Browser consent: /mcp-connect/:requestId.
  • User connection management: /assistant-connections.

Dynamic registration uses public clients, exact registered HTTPS redirect URIs (or HTTP loopback), authorization code flow, S256 PKCE and exact resource binding to the endpoint. Authorization requests expire in ten minutes; codes expire one minute after consent and are single-use. Access tokens expire in fifteen minutes. offline_access issues a thirty-day rotating refresh token; replaying a consumed refresh token revokes its entire grant. Tokens and codes are hashed at rest. paperclip:read is required; paperclip:write adds only task creation and comments. Scope expansion requires a new consent flow.

Each grant records the person, client, company, resource and scopes. Membership and company availability are rechecked at execution. Instance admin status does not elevate a grant beyond that company's role. Consent/revocation require an authenticated browser and the configured origin. Client registration does not fetch redirect URLs or accept arbitrary tool destinations. Rate limiting at the public edge is required in addition to the bounded per-process auth limiter. Registration also has a database-enforced limit of 60 new clients per minute and 10,000 unconsented clients shared across replicas. Expired authorization requests and never-consented clients older than one hour are collected during registration. Clients with grants are retained, preserving their connections and audit/mutation history.

Revocation blocks future calls; it does not cancel already delegated work or undo in-flight mutations. Manage existing tasks and execution in Paperclip. Audit records identify the human caller and connection/client for mutations. OAuth credential bodies and redirect locations are redacted from HTTP logs.

Tool surface

Tool Effect
paperclip_connection Person, company, scopes, connection management link
paperclip_list_agents Safe agent summary and availability
paperclip_list_projects Safe project summary
paperclip_search_tasks Bounded task search with offset pagination
paperclip_read_task Current task plus recent comments/history
paperclip_create_task Assigned task, submitted to existing scheduling
paperclip_add_comment Human feedback; may wake or queue work
paperclip_list_deliverables Documents and work-product references
paperclip_read_document Durable document body
paperclip_pending_approvals Pending approvals and existing decision links

Every company-scoped call requires its explicit authorized company ID. The server emits bounded projections rather than agent configurations or upstream credentials. URLs include the company's prefix so unrelated browser company selection cannot redirect the user to a different team's approval interface.

Writes require a UUID requestId, unique per intended action. A durable receipt is reserved before dispatch, keyed by person, company, operation and request ID (with the originating grant recorded for audit). Matching retries, including after a new authorization grant, replay the recorded result; changed arguments are rejected. A concurrent or unconfirmed result is reported as outcome: unknown. Inspect the task and comments before another action; never retry with a new ID to force success. A known HTTP rejection is recorded and replayed as outcome: rejected.

The REST bridge dispatches only paths constructed by the closed tool catalog, with a request-local verified actor. Existing handlers enforce all domain checks and own their transaction/scheduling semantics. Receipts do not turn existing asynchronous scheduling into an exactly-once execution guarantee. Creating a task is not proof that an agent started or finished it.

Hosted onboarding and release gates

When PAPERCLIP_CLOUD_API_ORIGIN is present, consent links to the existing Cloud /orgs/new flow in a separate tab. Provisioning, mission/template selection, model credentials, execution capacity and spending remain owned by Cloud. Installing a plugin never provisions a company or starts paid agents.

This repository implements the instance-side connection and vendor packages. The companion Cloud implementation supplies the stable public resource, an account-to-stack OAuth broker, explicit organization selection and a return from hosted organization creation. Its public connection screen resumes normal sign-in, lists authorized organizations, reports provisioning/sleeping states, and links to tenant setup for mission, templates, execution and spending.

The Cloud broker forwards the original PKCE challenge to tenant OAuth, validates the resulting person, and wraps tenant credentials in encrypted tokens bound to client, workspace and resource. Every call rechecks current Cloud membership and verified routing; the tenant rechecks company permissions and revocation. Cloud stores request metadata and code hashes, not raw tenant tokens. Unknown mutation outcomes preserve the existing request-ID receipt contract.

Deploy both sides before hosted use. Cloud's tenant front door forwards only exact discovery, OAuth protocol and MCP paths without minting human authority; consent and management retain normal browser entry. The Cloud broker remains opt-in and requires its own durable OAuth state and encryption key from the provider secret store. Installing these source packages does not deploy an endpoint, open signup, register a listing, or provision execution capacity.

Before release, exercise actual ChatGPT/Codex and Claude connections against a staging HTTPS deployment, including client registration, consent, refresh, revocation, reconnect, task delegation and retrieval from another conversation. Prove scheduled execution on a controlled agent and the new-user Cloud return journey. Local OAuth interoperability has been verified with Codex CLI 0.153.4 and Claude Code 2.1.245, using disposable Cloud/tenant fixtures. Protocol tests, CLI login and local package validation do not replace these release gates.

External sessions acting as agents, task leases and third-party granted tools remain the second/third releases; do not add generic executors to this public catalog to implement them.

Registration also enforces shared source quotas (6 per minute and 30 unconsented clients) using a resource-bound hash of the trusted request IP; raw addresses are not stored. Configure trusted proxies correctly. Authorization starts atomically remove expired requests and enforce 10 pending-consent requests per client and 1,000 instance-wide, independently of further client registrations. Existing grants remain usable when anonymous registration or authorization is throttled.

Task monitoring with MCP Events

The same authenticated endpoint now supports MCP 2.0 (2026-07-28) alongside legacy MCP. It advertises events through server/discover and implements events/list, events/subscribe, and events/unsubscribe. MCP 2.0 requests include matching MCP-Protocol-Version/Mcp-Method headers, per-request version and client-capability metadata, and Mcp-Name for tool calls. Existing initialize-based clients keep the ten-tool connection.

Event Required filters Payload
paperclip.task.status_changed companyId, taskId; optional statuses Task ID, status, company ID and task link
paperclip.task.comment_created companyId, taskId Task/company IDs, comment ID and task link
paperclip.task.document_updated companyId, taskId Task/company IDs, document key, revision and task link

In an Events-capable ChatGPT Work Cloud chat or dot, ask, for example: “Watch this task. When it finishes, read its report and tell me the result.” The host supplies a callback URL and signing secret and owns refresh/unsubscribe. Rescan the plugin's MCP server to discover the event catalog. Installing or connecting alone does not start monitoring. Claude and other clients without Events support can continue retrieving results through the read tools.

Callback and hosted-authority verification reserve durable capacity before any remote request. Across replicas, at most 2 verifications per grant, 8 per company and 32 per instance can run concurrently. Attempts are bounded to 30 per grant, 200 per company and 1,000 per instance per minute, including failed verification. New monitors reserve subscription quota before verification; leases expire after one minute. Network waits hold no database transaction, and expired, cancelled or revoked requests cannot finalize a subscription.

Delivery uses a verified HTTPS callback, Standard Webhooks HMAC signatures, public-address DNS pinning on every connection, and no redirects. Callback URLs, current/previous signing keys and hosted authorization proofs are encrypted with the existing instance secrets master key. Back up that key with the database. Callback bodies contain bounded references, not comment/document text; clients must read current authorized state before responding or taking an action.

Subscriptions last at most 24 hours (default), with a 30-second minimum. Hosted subscriptions last at most five minutes and never outlive the broker access proof: refresh the OAuth token before refreshing a subscription when necessary. The tenant verifies that proof through the fixed PAPERCLIP_CLOUD_API_ORIGIN broker before each delivery, checking current Cloud membership as well as local company membership, grant revocation and task access. A compatible Cloud broker must be deployed first for hosted Events. Direct connections to a Cloud tenant without a broker authority proof cannot create event subscriptions.

Subscriptions and delivery receipts persist across restarts. Activity is scanned without a moving timestamp high-water mark; unique receipts prevent duplicate queue entries and concurrent workers claim deliveries atomically. Delivery is at least once, with up to six attempts and exponential backoff. IDs stay stable across retries while signatures receive fresh timestamps. HTTP 410 stops a monitor; 413 and other permanent failures are not retried. Secret rotation signs with both keys for five minutes. Expired subscriptions and their receipts are removed on the next admission or after seven days; active quotas are 20 per grant, 100 per company and 1,000 per instance. Unsubscribe frees the subscription and its receipts.

This release returns cursor: null: it does not offer protocol replay after an expired/stopped subscription. Use task history and document tools to recover missed changes. In-flight requests may finish during unsubscribe/revocation; subsequent attempts recheck access. Events are data, and may be duplicated or out of order. Do not post comments merely to acknowledge comments or documents, which would risk a feedback loop. Approval decisions remain in Paperclip.

See OpenAI's MCP Events guide for currently supported client surfaces. Actual staging ChatGPT subscription, plugin rescan and event-triggered response are still deployment acceptance gates; local protocol and paid model tests do not establish store/UI readiness.