focusreactive / focusreactive/payload-plugins
Add a shared multi-tenant MCP connector for preview sandboxes
- Dominant language
- TypeScript
- Stars
- 19
- Forks
- 0
- Avg merge
- 16h 54m
- Merged PRs (30d)
- 19
Description
## Goal
Let someone evaluating a preview sandbox point their own AI tool (Claude, ChatGPT) at that sandbox's CMS by pasting a single URL, with no sign-in, and without standing up a throwaway deployment for every sandbox.
## Why a preview deployment cannot serve this itself
Chat applications add a custom connector from their own cloud, and the first thing they do is probe the **origin** for auth-discovery documents with no query string attached:
- `/.well-known/oauth-protected-resource`
- `/.well-known/oauth-authorization-server`
- `/register`
On a deployment-protected preview all three answer `302` to the SSO login instead of `404`. The client concludes the server has a sign-in service, its dynamic client registration then fails, and the user sees an error along the lines of "couldn't register with the sign-in service".
Two consequences worth stating explicitly, because both cost time to rediscover:
- **a protection-bypass query parameter does not help.** It works under `curl` because curl carries the parameter; the discovery probes do not
- **the connector host must not be behind deployment protection at all**
Since production (`main`) is not protection-protected, it can host the connector, and the connector forwards to the protected preview using the bypass secret server-side.
## Proposal
One connector served from the production deployment, multi-tenant rather than one per sandbox:
- endpoint at `/`, where the segment identifies the tenant
- the segment maps to that tenant's upstream sandbox URL and API key, held server-side
- the connector forwards MCP traffic upstream, adding the protection-bypass header itself
- forward only the MCP transport headers (`content-type`, `accept`, `mcp-session-id`, `mcp-protocol-version`), never the caller's full header set
- an unknown or wrong path segment returns `404`, same as any other unknown path
Onboarding a sandbox becomes adding a config entry; retiring one becomes removing it. Nothing is deployed or torn down per sandbox.
## Security constraints, please do not skip these
Satisfying dynamic client registration requires answering the OAuth endpoints, but **that OAuth layer is protocol compliance, not access control.** A working implementation of this pattern auto-approves every authorization request: the tokens it issues carry no identity and grant nothing beyond what the URL already grants. Real cryptography is still worth having (HMAC-signed stateless tokens, PKCE S256 verified, expiry enforced, malformed tokens rejected with a 4xx rather than throwing), but none of it authenticates anybody.
So the actual security boundary is only these two things, and both must hold:
1. **the unguessable path segment** - anyone holding the URL is authorized, so it must be long, random, and kept out of query strings and logs
2. **a capability-limited tool surface** - the exposed tools must not be able to publish or delete. Writes should land as drafts for a human to review
Which leads to the hard requirement:
> **This connector must only ever target an isolated preview sandbox with its own database. It must never be pointed at production.** In front of production it is an open door for anyone who has the link.
A guard that refuses to start, or refuses a tenant entry, when the configured upstream is the production deployment would be worth having rather than relying on configuration discipline.
Note this interacts with the shared media store: until preview media is isolated, a connector that can write media can affect production. Keeping media write and image upload out of the tool surface avoids that until then.
## Acceptance criteria
- one deployment serves connectors for many sandboxes, distinguished by path segment
- adding or removing a sandbox is a configuration change, with nothing to deploy or delete
- all auth-discovery paths return `404` when probed without a valid path segment
- the exposed tool list contains no publish and no delete operation, verified by a test
- pointing a tenant at the production deployment is rejected
Contributor guide
No contributing guide indexed for this repository
Research direction
No files or tests are named; start by locating the production deployment entry point and any existing MCP or OAuth integration. Done means one deployment serves path-segment tenants, rejects production upstreams, returns 404 for invalid discovery paths, forwards only the specified MCP headers, and verifies that publish and delete tools are absent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100