focusreactive / focusreactive/payload-plugins

Add a shared multi-tenant MCP connector for preview sandboxes

Open
#112 0 comments 0 reactions 0 assignees View on GitHub
enhancement
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.