zuplo 6.70.53 → 6.70.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/mcp-gateway/auth/configuring-auth0.mdx +216 -0
- package/docs/mcp-gateway/auth/configuring-clerk.mdx +153 -0
- package/docs/mcp-gateway/auth/configuring-cognito.mdx +128 -0
- package/docs/mcp-gateway/auth/configuring-entra.mdx +134 -0
- package/docs/mcp-gateway/auth/configuring-generic-oidc.mdx +242 -0
- package/docs/mcp-gateway/auth/configuring-google.mdx +117 -0
- package/docs/mcp-gateway/auth/configuring-keycloak.mdx +125 -0
- package/docs/mcp-gateway/auth/configuring-logto.mdx +116 -0
- package/docs/mcp-gateway/auth/configuring-okta.mdx +199 -0
- package/docs/mcp-gateway/auth/configuring-onelogin.mdx +122 -0
- package/docs/mcp-gateway/auth/configuring-ping.mdx +157 -0
- package/docs/mcp-gateway/auth/configuring-workos.mdx +117 -0
- package/docs/mcp-gateway/auth/manual-oauth-testing.mdx +528 -0
- package/docs/mcp-gateway/auth/overview.mdx +314 -0
- package/docs/mcp-gateway/auth/upstream-oauth.mdx +221 -0
- package/docs/mcp-gateway/capability-filtering.mdx +162 -0
- package/docs/mcp-gateway/code-config/compatibility-dates.mdx +33 -0
- package/docs/mcp-gateway/code-config/local-development.mdx +198 -0
- package/docs/mcp-gateway/code-config/mcp-proxy-handler.mdx +186 -0
- package/docs/mcp-gateway/code-config/multi-upstream.mdx +293 -0
- package/docs/mcp-gateway/code-config/overview.mdx +210 -0
- package/docs/mcp-gateway/connect-clients/chatgpt.mdx +127 -0
- package/docs/mcp-gateway/connect-clients/claude-code.mdx +184 -0
- package/docs/mcp-gateway/connect-clients/claude-desktop.mdx +160 -0
- package/docs/mcp-gateway/connect-clients/cursor.mdx +100 -0
- package/docs/mcp-gateway/connect-clients/other-clients.mdx +207 -0
- package/docs/mcp-gateway/connect-clients/overview.mdx +137 -0
- package/docs/mcp-gateway/connect-clients/vs-code.mdx +128 -0
- package/docs/mcp-gateway/how-it-works.mdx +266 -0
- package/docs/mcp-gateway/how-to/connect-upstream-oauth.mdx +268 -0
- package/docs/mcp-gateway/how-to/curate-tools.mdx +278 -0
- package/docs/mcp-gateway/introduction.mdx +151 -0
- package/docs/mcp-gateway/observability/analytics.mdx +191 -0
- package/docs/mcp-gateway/observability/logging.mdx +191 -0
- package/docs/mcp-gateway/quickstart.mdx +266 -0
- package/docs/mcp-gateway/reference.mdx +148 -0
- package/docs/mcp-gateway/test-clients.mdx +130 -0
- package/docs/mcp-gateway/troubleshooting.mdx +228 -0
- package/docs/mcp-server/introduction.mdx +10 -0
- package/docs/mcp-server/openai-apps-sdk.mdx +12 -0
- package/docs/policies/_index.md +14 -0
- package/docs/policies/akamai-ai-firewall/schema.json +1 -0
- package/docs/policies/akamai-firewall-for-ai-inbound/schema.json +1 -0
- package/docs/policies/akamai-firewall-for-ai-outbound/schema.json +1 -0
- package/docs/policies/amberflo-metering-inbound/schema.json +1 -0
- package/docs/policies/api-key-inbound/schema.json +1 -0
- package/docs/policies/audit-log-inbound/schema.json +1 -0
- package/docs/policies/auth0-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/authzen-inbound/schema.json +1 -0
- package/docs/policies/axiomatics-authz-inbound/schema.json +1 -0
- package/docs/policies/basic-auth-inbound/schema.json +1 -0
- package/docs/policies/bot-detection-inbound/schema.json +1 -0
- package/docs/policies/brownout-inbound/schema.json +1 -0
- package/docs/policies/caching-inbound/schema.json +1 -0
- package/docs/policies/change-method-inbound/schema.json +1 -0
- package/docs/policies/clear-headers-inbound/schema.json +1 -0
- package/docs/policies/clear-headers-outbound/schema.json +1 -0
- package/docs/policies/clerk-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/cognito-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/comet-opik-tracing-inbound/schema.json +1 -0
- package/docs/policies/complex-rate-limit-inbound/schema.json +1 -0
- package/docs/policies/composite-inbound/schema.json +1 -0
- package/docs/policies/composite-outbound/schema.json +1 -0
- package/docs/policies/curity-phantom-token-inbound/schema.json +1 -0
- package/docs/policies/firebase-jwt-inbound/schema.json +1 -0
- package/docs/policies/formdata-to-json-inbound/schema.json +1 -0
- package/docs/policies/galileo-tracing-inbound/schema.json +1 -0
- package/docs/policies/geo-filter-inbound/schema.json +1 -0
- package/docs/policies/graphql-complexity-limit-inbound/schema.json +1 -0
- package/docs/policies/graphql-disable-introspection-inbound/schema.json +1 -0
- package/docs/policies/graphql-introspection-filter-outbound/schema.json +1 -0
- package/docs/policies/http-deprecation-outbound/schema.json +1 -0
- package/docs/policies/jwt-scopes-inbound/schema.json +1 -0
- package/docs/policies/ldap-auth-inbound/schema.json +1 -0
- package/docs/policies/mcp-auth0-oauth-inbound/doc.md +54 -0
- package/docs/policies/mcp-auth0-oauth-inbound/intro.md +7 -0
- package/docs/policies/mcp-auth0-oauth-inbound/schema.json +135 -0
- package/docs/policies/mcp-capability-filter-inbound/doc.md +58 -0
- package/docs/policies/mcp-capability-filter-inbound/intro.md +9 -0
- package/docs/policies/mcp-capability-filter-inbound/schema.json +212 -0
- package/docs/policies/mcp-clerk-oauth-inbound/doc.md +34 -0
- package/docs/policies/mcp-clerk-oauth-inbound/intro.md +1 -0
- package/docs/policies/mcp-clerk-oauth-inbound/schema.json +134 -0
- package/docs/policies/mcp-cognito-oauth-inbound/doc.md +52 -0
- package/docs/policies/mcp-cognito-oauth-inbound/intro.md +7 -0
- package/docs/policies/mcp-cognito-oauth-inbound/schema.json +152 -0
- package/docs/policies/mcp-entra-oauth-inbound/doc.md +51 -0
- package/docs/policies/mcp-entra-oauth-inbound/intro.md +6 -0
- package/docs/policies/mcp-entra-oauth-inbound/schema.json +131 -0
- package/docs/policies/mcp-google-oauth-inbound/doc.md +52 -0
- package/docs/policies/mcp-google-oauth-inbound/intro.md +6 -0
- package/docs/policies/mcp-google-oauth-inbound/schema.json +125 -0
- package/docs/policies/mcp-keycloak-oauth-inbound/doc.md +43 -0
- package/docs/policies/mcp-keycloak-oauth-inbound/intro.md +2 -0
- package/docs/policies/mcp-keycloak-oauth-inbound/schema.json +140 -0
- package/docs/policies/mcp-logto-oauth-inbound/doc.md +52 -0
- package/docs/policies/mcp-logto-oauth-inbound/intro.md +6 -0
- package/docs/policies/mcp-logto-oauth-inbound/schema.json +131 -0
- package/docs/policies/mcp-oauth-inbound/doc.md +70 -0
- package/docs/policies/mcp-oauth-inbound/intro.md +11 -0
- package/docs/policies/mcp-oauth-inbound/schema.json +177 -0
- package/docs/policies/mcp-okta-oauth-inbound/doc.md +61 -0
- package/docs/policies/mcp-okta-oauth-inbound/intro.md +7 -0
- package/docs/policies/mcp-okta-oauth-inbound/schema.json +137 -0
- package/docs/policies/mcp-onelogin-oauth-inbound/doc.md +50 -0
- package/docs/policies/mcp-onelogin-oauth-inbound/intro.md +6 -0
- package/docs/policies/mcp-onelogin-oauth-inbound/schema.json +131 -0
- package/docs/policies/mcp-ping-oauth-inbound/doc.md +80 -0
- package/docs/policies/mcp-ping-oauth-inbound/intro.md +7 -0
- package/docs/policies/mcp-ping-oauth-inbound/schema.json +151 -0
- package/docs/policies/mcp-token-exchange-inbound/doc.md +135 -0
- package/docs/policies/mcp-token-exchange-inbound/intro.md +6 -0
- package/docs/policies/mcp-token-exchange-inbound/schema.json +134 -0
- package/docs/policies/mcp-workos-oauth-inbound/doc.md +50 -0
- package/docs/policies/mcp-workos-oauth-inbound/intro.md +6 -0
- package/docs/policies/mcp-workos-oauth-inbound/schema.json +125 -0
- package/docs/policies/mock-api-inbound/schema.json +1 -0
- package/docs/policies/moesif-inbound/schema.json +1 -0
- package/docs/policies/monetization-inbound/schema.json +1 -0
- package/docs/policies/mtls-auth-inbound/schema.json +1 -0
- package/docs/policies/okta-fga-authz-inbound/schema.json +1 -0
- package/docs/policies/okta-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/open-id-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/openfga-authz-inbound/schema.json +1 -0
- package/docs/policies/openmeter-inbound/schema.json +1 -0
- package/docs/policies/prompt-injection-outbound/schema.json +1 -0
- package/docs/policies/propel-auth-jwt-inbound/schema.json +1 -0
- package/docs/policies/query-param-to-header-inbound/schema.json +1 -0
- package/docs/policies/quota-inbound/schema.json +1 -0
- package/docs/policies/rate-limit-inbound/schema.json +1 -0
- package/docs/policies/readme-metrics-inbound/schema.json +1 -0
- package/docs/policies/remove-headers-inbound/schema.json +1 -0
- package/docs/policies/remove-headers-outbound/schema.json +1 -0
- package/docs/policies/remove-query-params-inbound/schema.json +1 -0
- package/docs/policies/replace-string-outbound/schema.json +1 -0
- package/docs/policies/request-size-limit-inbound/schema.json +1 -0
- package/docs/policies/request-validation-inbound/schema.json +1 -0
- package/docs/policies/require-origin-inbound/schema.json +1 -0
- package/docs/policies/secret-masking-outbound/schema.json +1 -0
- package/docs/policies/semantic-cache-inbound/schema.json +1 -0
- package/docs/policies/set-body-inbound/schema.json +1 -0
- package/docs/policies/set-headers-inbound/schema.json +1 -0
- package/docs/policies/set-headers-outbound/schema.json +1 -0
- package/docs/policies/set-query-params-inbound/schema.json +1 -0
- package/docs/policies/set-status-outbound/schema.json +1 -0
- package/docs/policies/set-upstream-api-key-inbound/schema.json +1 -0
- package/docs/policies/sleep-inbound/schema.json +1 -0
- package/docs/policies/stripe-webhook-verification-inbound/schema.json +1 -0
- package/docs/policies/supabase-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/upstream-azure-ad-service-auth-inbound/schema.json +1 -0
- package/docs/policies/upstream-firebase-admin-auth-inbound/schema.json +1 -0
- package/docs/policies/upstream-firebase-user-auth-inbound/schema.json +1 -0
- package/docs/policies/upstream-gcp-federated-auth-inbound/schema.json +1 -0
- package/docs/policies/upstream-gcp-jwt-inbound/schema.json +1 -0
- package/docs/policies/upstream-gcp-service-auth-inbound/schema.json +1 -0
- package/docs/policies/upstream-zuplo-jwt-auth-inbound/schema.json +1 -0
- package/docs/policies/validate-json-schema-inbound/schema.json +1 -0
- package/docs/policies/web-bot-auth-inbound/schema.json +1 -0
- package/docs/policies/xml-to-json-outbound/schema.json +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Add multiple upstream MCP servers"
|
|
3
|
+
sidebar_label: "Multi-upstream"
|
|
4
|
+
description:
|
|
5
|
+
Front many upstream MCP servers from one Zuplo project. Share a single OAuth
|
|
6
|
+
policy across every route, add one token exchange policy per upstream, and let
|
|
7
|
+
each user maintain independent per-upstream connections.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
A single Zuplo deployment can front any number of upstream MCP servers. One
|
|
11
|
+
OAuth policy authenticates inbound MCP clients across every route; one
|
|
12
|
+
`mcp-token-exchange-inbound` policy lives per upstream; one route per upstream
|
|
13
|
+
wires them together.
|
|
14
|
+
|
|
15
|
+
This page is a worked example: a single gateway project that exposes Linear and
|
|
16
|
+
Stripe as two separate MCP endpoints, with the full `zuplo.jsonc`,
|
|
17
|
+
`policies.json`, `routes.oas.json`, and runtime-init files you can copy into
|
|
18
|
+
your own project.
|
|
19
|
+
|
|
20
|
+
## The pattern
|
|
21
|
+
|
|
22
|
+
Three rules form the pattern:
|
|
23
|
+
|
|
24
|
+
1. **One MCP OAuth policy, project-wide.** The gateway allows exactly one MCP
|
|
25
|
+
OAuth policy per project, regardless of which
|
|
26
|
+
[IdP wrapper](../auth/overview.mdx#identity-providers) you pick. Every MCP
|
|
27
|
+
route attaches the same policy.
|
|
28
|
+
2. **One `mcp-token-exchange-*` policy per upstream.** Each upstream MCP server
|
|
29
|
+
gets its own policy with its own `displayName`, `authMode`, `scopes`, and
|
|
30
|
+
optional `protectedResourceMetadataUrl`. The policy's `id` (or the `id`
|
|
31
|
+
inferred from its name) identifies the upstream — pick it once and don't
|
|
32
|
+
change it.
|
|
33
|
+
3. **One `/mcp/<slug>` route per upstream.** Each route uses
|
|
34
|
+
[`McpProxyHandler`](./mcp-proxy-handler.mdx) with the upstream URL as
|
|
35
|
+
`rewritePattern`, and lists the shared OAuth policy plus the matching token
|
|
36
|
+
exchange policy in its inbound chain.
|
|
37
|
+
|
|
38
|
+
A typical path convention is `/mcp/<provider>-v<n>`. The `-v<n>` suffix lets you
|
|
39
|
+
publish a v2 alongside a v1 without breaking existing client configs.
|
|
40
|
+
|
|
41
|
+
## Worked example: Linear and Stripe
|
|
42
|
+
|
|
43
|
+
The configuration below exposes two upstream MCP servers — Linear and Stripe —
|
|
44
|
+
behind one Auth0-protected gateway. Each user authenticates once to the gateway,
|
|
45
|
+
then connects to Linear and Stripe independently the first time they call each.
|
|
46
|
+
|
|
47
|
+
### `zuplo.jsonc`
|
|
48
|
+
|
|
49
|
+
```jsonc
|
|
50
|
+
{
|
|
51
|
+
"version": 1,
|
|
52
|
+
"compatibilityDate": "2026-03-01",
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### `modules/zuplo.runtime.ts`
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { RuntimeExtensions } from "@zuplo/runtime";
|
|
60
|
+
import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway";
|
|
61
|
+
|
|
62
|
+
export function runtimeInit(runtime: RuntimeExtensions) {
|
|
63
|
+
runtime.addPlugin(new McpGatewayPlugin());
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `config/policies.json`
|
|
68
|
+
|
|
69
|
+
```jsonc
|
|
70
|
+
{
|
|
71
|
+
"policies": [
|
|
72
|
+
{
|
|
73
|
+
"name": "auth0-managed-oauth",
|
|
74
|
+
"policyType": "mcp-auth0-oauth-inbound",
|
|
75
|
+
"handler": {
|
|
76
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
77
|
+
"export": "McpAuth0OAuthInboundPolicy",
|
|
78
|
+
"options": {
|
|
79
|
+
"auth0Domain": "$env(AUTH0_DOMAIN)",
|
|
80
|
+
"clientId": "$env(AUTH0_CLIENT_ID)",
|
|
81
|
+
"clientSecret": "$env(AUTH0_CLIENT_SECRET)",
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name": "mcp-token-exchange-linear",
|
|
87
|
+
"policyType": "mcp-token-exchange-inbound",
|
|
88
|
+
"handler": {
|
|
89
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
90
|
+
"export": "McpTokenExchangeInboundPolicy",
|
|
91
|
+
"options": {
|
|
92
|
+
"displayName": "Linear",
|
|
93
|
+
"summary": "Linear MCP upstream, per-user OAuth.",
|
|
94
|
+
"protectedResourceMetadataUrl": "https://mcp.linear.app/.well-known/oauth-protected-resource",
|
|
95
|
+
"authMode": "user-oauth",
|
|
96
|
+
"scopes": [],
|
|
97
|
+
"clientRegistration": { "mode": "auto" },
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "mcp-token-exchange-stripe",
|
|
103
|
+
"policyType": "mcp-token-exchange-inbound",
|
|
104
|
+
"handler": {
|
|
105
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
106
|
+
"export": "McpTokenExchangeInboundPolicy",
|
|
107
|
+
"options": {
|
|
108
|
+
"displayName": "Stripe",
|
|
109
|
+
"summary": "Stripe MCP upstream, per-user OAuth.",
|
|
110
|
+
"authMode": "user-oauth",
|
|
111
|
+
"scopes": ["mcp"],
|
|
112
|
+
"clientRegistration": { "mode": "auto" },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A few notes on what's set per upstream:
|
|
121
|
+
|
|
122
|
+
- **`protectedResourceMetadataUrl`** is explicit for Linear because Linear
|
|
123
|
+
publishes its PRM at the root well-known path
|
|
124
|
+
(`/.well-known/oauth-protected-resource`) instead of the per-route default
|
|
125
|
+
(`/.well-known/oauth-protected-resource/mcp`). For Stripe the default works,
|
|
126
|
+
so the option is omitted.
|
|
127
|
+
- **`scopes: []`** for Linear means the gateway falls back to the upstream's
|
|
128
|
+
`WWW-Authenticate` `scope` value, then to the PRM's `scopes_supported`, then
|
|
129
|
+
to no scope parameter. For Stripe the explicit `["mcp"]` is what the provider
|
|
130
|
+
expects.
|
|
131
|
+
- **`clientRegistration: { mode: "auto" }`** lets the gateway register a client
|
|
132
|
+
with each upstream on demand using OIDC Client ID Metadata Document discovery
|
|
133
|
+
first, then RFC 7591 Dynamic Client Registration as a fallback. No client
|
|
134
|
+
credentials need to live in source control.
|
|
135
|
+
|
|
136
|
+
### `config/routes.oas.json`
|
|
137
|
+
|
|
138
|
+
```jsonc
|
|
139
|
+
{
|
|
140
|
+
"openapi": "3.1.0",
|
|
141
|
+
"info": { "title": "MCP Gateway", "version": "0.1.0" },
|
|
142
|
+
"paths": {
|
|
143
|
+
"/mcp/linear-v1": {
|
|
144
|
+
"get,post": {
|
|
145
|
+
"operationId": "linear-mcp-server",
|
|
146
|
+
"summary": "Linear MCP Proxy",
|
|
147
|
+
"x-zuplo-route": {
|
|
148
|
+
"corsPolicy": "none",
|
|
149
|
+
"handler": {
|
|
150
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
151
|
+
"export": "McpProxyHandler",
|
|
152
|
+
"options": { "rewritePattern": "https://mcp.linear.app/mcp" },
|
|
153
|
+
},
|
|
154
|
+
"policies": {
|
|
155
|
+
"inbound": ["auth0-managed-oauth", "mcp-token-exchange-linear"],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
"/mcp/stripe-v1": {
|
|
161
|
+
"get,post": {
|
|
162
|
+
"operationId": "stripe-mcp-server",
|
|
163
|
+
"summary": "Stripe MCP Proxy",
|
|
164
|
+
"x-zuplo-route": {
|
|
165
|
+
"corsPolicy": "none",
|
|
166
|
+
"handler": {
|
|
167
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
168
|
+
"export": "McpProxyHandler",
|
|
169
|
+
"options": { "rewritePattern": "https://mcp.stripe.com/mcp" },
|
|
170
|
+
},
|
|
171
|
+
"policies": {
|
|
172
|
+
"inbound": ["auth0-managed-oauth", "mcp-token-exchange-stripe"],
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Once deployed (or running locally via `zuplo dev`), this gives clients two MCP
|
|
182
|
+
server URLs to add to their config:
|
|
183
|
+
|
|
184
|
+
- `https://<your-gateway>/mcp/linear-v1`
|
|
185
|
+
- `https://<your-gateway>/mcp/stripe-v1`
|
|
186
|
+
|
|
187
|
+
Both authenticate against the same Auth0 tenant; both produce one set of
|
|
188
|
+
analytics events distinguishable by `virtualServerName` and
|
|
189
|
+
`upstreamServerName`.
|
|
190
|
+
|
|
191
|
+
## What each user sees on first connect
|
|
192
|
+
|
|
193
|
+
A user only signs in to the gateway once. From there, each upstream needs its
|
|
194
|
+
own one-time connect:
|
|
195
|
+
|
|
196
|
+
- The first time the user calls `/mcp/linear-v1`, the client opens a browser to
|
|
197
|
+
authorize Linear. The next call succeeds.
|
|
198
|
+
- Calling `/mcp/stripe-v1` for the first time produces a separate browser prompt
|
|
199
|
+
for Stripe. Authorizing Linear doesn't grant access to Stripe.
|
|
200
|
+
|
|
201
|
+
Each user's connection to each upstream is independent — one user authorizing
|
|
202
|
+
Linear has no effect on any other user.
|
|
203
|
+
|
|
204
|
+
## Adding a per-route capability filter
|
|
205
|
+
|
|
206
|
+
To curate the tools a specific upstream exposes — say, restrict Linear to four
|
|
207
|
+
read tools — add a `mcp-capability-filter-inbound` policy and attach it to one
|
|
208
|
+
route's inbound chain:
|
|
209
|
+
|
|
210
|
+
```jsonc
|
|
211
|
+
// config/policies.json — add to the policies array
|
|
212
|
+
{
|
|
213
|
+
"name": "filter-linear-read-only",
|
|
214
|
+
"policyType": "mcp-capability-filter-inbound",
|
|
215
|
+
"handler": {
|
|
216
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
217
|
+
"export": "McpCapabilityFilterInboundPolicy",
|
|
218
|
+
"options": {
|
|
219
|
+
"tools": ["list_issues", "get_issue", "list_projects", "list_teams"],
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Then update the Linear route's policy chain so the filter runs **after** the
|
|
226
|
+
token exchange policy:
|
|
227
|
+
|
|
228
|
+
```jsonc
|
|
229
|
+
"/mcp/linear-v1": {
|
|
230
|
+
"get,post": {
|
|
231
|
+
"operationId": "linear-mcp-server",
|
|
232
|
+
"x-zuplo-route": {
|
|
233
|
+
"policies": {
|
|
234
|
+
"inbound": [
|
|
235
|
+
"auth0-managed-oauth",
|
|
236
|
+
"mcp-token-exchange-linear",
|
|
237
|
+
"filter-linear-read-only"
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Only the four named tools appear in `tools/list` responses on `/mcp/linear-v1`.
|
|
246
|
+
Any `tools/call` for an unlisted tool returns a JSON-RPC `MethodNotFound` error
|
|
247
|
+
before the request reaches the upstream. The Stripe route is unaffected —
|
|
248
|
+
capability filters are per-route.
|
|
249
|
+
|
|
250
|
+
## Path and id conventions
|
|
251
|
+
|
|
252
|
+
The corp dogfood deployment uses these conventions, and they generalize well:
|
|
253
|
+
|
|
254
|
+
- **Route path**: `/mcp/<provider>-v<n>` — e.g., `/mcp/linear-v1`,
|
|
255
|
+
`/mcp/stripe-v1`, `/mcp/notion-v1`.
|
|
256
|
+
- **`operationId`**: `<provider>-mcp-server` — e.g., `linear-mcp-server`,
|
|
257
|
+
`stripe-mcp-server`.
|
|
258
|
+
- **Token-exchange policy name**: `mcp-token-exchange-<provider>` — the
|
|
259
|
+
`<provider>` portion is what becomes the upstream `id` (and the
|
|
260
|
+
`upstreamServerName` in analytics).
|
|
261
|
+
- **OAuth policy name**: pick one and reuse it; `auth0-managed-oauth` or
|
|
262
|
+
`oidc-managed-oauth` are clear choices.
|
|
263
|
+
|
|
264
|
+
The `-v<n>` suffix on the route path matters more than it looks: it gives you a
|
|
265
|
+
clean upgrade path when an upstream provider releases a new MCP server URL with
|
|
266
|
+
breaking changes. Add a new `/mcp/linear-v2` route with a new token exchange
|
|
267
|
+
policy (and a new id), publish the v2 endpoint, migrate clients, then retire v1
|
|
268
|
+
once the last client is off it.
|
|
269
|
+
|
|
270
|
+
## Don't share an upstream id
|
|
271
|
+
|
|
272
|
+
The upstream `id` (either set explicitly via `options.id` or inferred from the
|
|
273
|
+
policy name) identifies each user's upstream connection. Two policies sharing
|
|
274
|
+
one id is a configuration error, and **changing** an id on a policy that already
|
|
275
|
+
has stored connections silently disconnects every existing user.
|
|
276
|
+
|
|
277
|
+
Pick the id once, document it, and treat it as part of the public contract of
|
|
278
|
+
the upstream just like the route path is part of the public contract of the
|
|
279
|
+
gateway.
|
|
280
|
+
|
|
281
|
+
## Related
|
|
282
|
+
|
|
283
|
+
- [`McpProxyHandler` reference](./mcp-proxy-handler.mdx) — the full handler
|
|
284
|
+
contract.
|
|
285
|
+
- [Local development](./local-development.mdx) — run the multi-upstream
|
|
286
|
+
configuration locally without setting up Auth0.
|
|
287
|
+
- [Connect a gateway to an upstream OAuth provider](../how-to/connect-upstream-oauth.mdx)
|
|
288
|
+
— every per-upstream option, including manual client registration and
|
|
289
|
+
shared-OAuth mode.
|
|
290
|
+
- [Curate the tools an upstream exposes](../how-to/curate-tools.mdx) — add a
|
|
291
|
+
capability filter to one of the routes.
|
|
292
|
+
- [Connect MCP clients](../connect-clients/overview.mdx) — add multiple gateway
|
|
293
|
+
routes to a single client config.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Set up an MCP Gateway"
|
|
3
|
+
sidebar_label: "Set up the gateway"
|
|
4
|
+
description:
|
|
5
|
+
Wire up the Zuplo MCP Gateway in routes.oas.json and policies.json — pin the
|
|
6
|
+
compatibility date, register the runtime plugin, configure one OAuth policy
|
|
7
|
+
and one token-exchange policy per upstream, and add an MCP route.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
To turn any Zuplo project into an MCP Gateway, configure five things in source
|
|
11
|
+
control: the compatibility date in `zuplo.jsonc`, the runtime plugin in
|
|
12
|
+
`modules/zuplo.runtime.ts`, one MCP OAuth policy in `config/policies.json`, one
|
|
13
|
+
`mcp-token-exchange-inbound` policy per OAuth-protected upstream, and one route
|
|
14
|
+
per upstream in `config/routes.oas.json`. This guide walks through each piece
|
|
15
|
+
for a single-upstream gateway.
|
|
16
|
+
|
|
17
|
+
For the conceptual model — what each piece does and why the pieces are split the
|
|
18
|
+
way they are — see [How the MCP Gateway works](../how-it-works.mdx).
|
|
19
|
+
|
|
20
|
+
## 1. Pin the compatibility date
|
|
21
|
+
|
|
22
|
+
MCP Gateway features require `compatibilityDate >= 2026-03-01` in `zuplo.jsonc`:
|
|
23
|
+
|
|
24
|
+
```jsonc title="zuplo.jsonc"
|
|
25
|
+
{
|
|
26
|
+
"version": 1,
|
|
27
|
+
"compatibilityDate": "2026-03-01",
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
New Zuplo projects default to a recent compatibility date, so this only applies
|
|
32
|
+
to existing projects being upgraded to use the MCP Gateway. See
|
|
33
|
+
[Compatibility dates](./compatibility-dates.mdx) for details.
|
|
34
|
+
|
|
35
|
+
## 2. Register the MCP Gateway plugin
|
|
36
|
+
|
|
37
|
+
Add a `modules/zuplo.runtime.ts` file that registers `McpGatewayPlugin`:
|
|
38
|
+
|
|
39
|
+
```ts title="modules/zuplo.runtime.ts"
|
|
40
|
+
import { RuntimeExtensions } from "@zuplo/runtime";
|
|
41
|
+
import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway";
|
|
42
|
+
|
|
43
|
+
export function runtimeInit(runtime: RuntimeExtensions) {
|
|
44
|
+
runtime.addPlugin(new McpGatewayPlugin());
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The plugin registers the OAuth metadata, authorization endpoints, consent page,
|
|
49
|
+
and upstream connect callbacks the gateway needs. It's a no-op when no
|
|
50
|
+
MCP-related policy is present, so adding it to projects that don't yet use the
|
|
51
|
+
gateway has zero runtime cost.
|
|
52
|
+
|
|
53
|
+
## 3. Define one OAuth policy
|
|
54
|
+
|
|
55
|
+
The OAuth policy authenticates inbound MCP requests against your identity
|
|
56
|
+
provider. Pick the first-class wrapper for your IdP — the
|
|
57
|
+
[provider catalog](../auth/overview.mdx#identity-providers) lists every
|
|
58
|
+
supported IdP. The Auth0 case looks like this:
|
|
59
|
+
|
|
60
|
+
```jsonc title="config/policies.json"
|
|
61
|
+
{
|
|
62
|
+
"name": "auth0-managed-oauth",
|
|
63
|
+
"policyType": "mcp-auth0-oauth-inbound",
|
|
64
|
+
"handler": {
|
|
65
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
66
|
+
"export": "McpAuth0OAuthInboundPolicy",
|
|
67
|
+
"options": {
|
|
68
|
+
"auth0Domain": "$env(AUTH0_DOMAIN)",
|
|
69
|
+
"clientId": "$env(AUTH0_CLIENT_ID)",
|
|
70
|
+
"clientSecret": "$env(AUTH0_CLIENT_SECRET)",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Each wrapper takes a small set of provider-specific options (a domain, a tenant
|
|
77
|
+
ID, a subdomain, and so on) and derives the OIDC URLs from them. For IdPs
|
|
78
|
+
without a dedicated wrapper — Ory Hydra, Authentik, FusionAuth, PingFederate, a
|
|
79
|
+
custom OIDC server — use the generic `mcp-oauth-inbound` policy. See
|
|
80
|
+
[Configuring a generic OIDC provider](../auth/configuring-generic-oidc.mdx) for
|
|
81
|
+
the worked example.
|
|
82
|
+
|
|
83
|
+
:::caution
|
|
84
|
+
|
|
85
|
+
A project can have only one MCP OAuth policy. The gateway rejects any
|
|
86
|
+
configuration with two, regardless of variant. The same policy is attached to
|
|
87
|
+
every MCP route in the project — every route authenticates against the same
|
|
88
|
+
identity provider.
|
|
89
|
+
|
|
90
|
+
:::
|
|
91
|
+
|
|
92
|
+
## 4. Define one token-exchange policy per upstream
|
|
93
|
+
|
|
94
|
+
Each OAuth-protected upstream gets its own `mcp-token-exchange-inbound` policy:
|
|
95
|
+
|
|
96
|
+
```jsonc title="config/policies.json"
|
|
97
|
+
{
|
|
98
|
+
"name": "mcp-token-exchange-linear",
|
|
99
|
+
"policyType": "mcp-token-exchange-inbound",
|
|
100
|
+
"handler": {
|
|
101
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
102
|
+
"export": "McpTokenExchangeInboundPolicy",
|
|
103
|
+
"options": {
|
|
104
|
+
"displayName": "Linear",
|
|
105
|
+
"protectedResourceMetadataUrl": "https://mcp.linear.app/.well-known/oauth-protected-resource",
|
|
106
|
+
"authMode": "user-oauth",
|
|
107
|
+
"scopes": [],
|
|
108
|
+
"clientRegistration": { "mode": "auto" },
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Name each policy `mcp-token-exchange-<id>`. The id after the prefix identifies
|
|
115
|
+
the upstream in analytics and connect URLs. Changing the id strands any existing
|
|
116
|
+
user-to-upstream connections, so pick it once and keep it.
|
|
117
|
+
|
|
118
|
+
For per-mode reference and worked examples per provider, see
|
|
119
|
+
[Connect a gateway to an upstream OAuth provider](../how-to/connect-upstream-oauth.mdx).
|
|
120
|
+
|
|
121
|
+
## 5. Define one route per upstream
|
|
122
|
+
|
|
123
|
+
Each upstream gets a route in `routes.oas.json`. The handler points at the
|
|
124
|
+
upstream URL; the inbound policy chain attaches the OAuth policy followed by the
|
|
125
|
+
matching token exchange policy:
|
|
126
|
+
|
|
127
|
+
```jsonc title="config/routes.oas.json"
|
|
128
|
+
{
|
|
129
|
+
"openapi": "3.1.0",
|
|
130
|
+
"info": { "title": "MCP Gateway", "version": "0.1.0" },
|
|
131
|
+
"paths": {
|
|
132
|
+
"/mcp/linear-v1": {
|
|
133
|
+
"get,post": {
|
|
134
|
+
"operationId": "linear-mcp-server",
|
|
135
|
+
"summary": "Linear MCP Proxy",
|
|
136
|
+
"x-zuplo-route": {
|
|
137
|
+
"corsPolicy": "none",
|
|
138
|
+
"handler": {
|
|
139
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
140
|
+
"export": "McpProxyHandler",
|
|
141
|
+
"options": {
|
|
142
|
+
"rewritePattern": "https://mcp.linear.app/mcp",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
"policies": {
|
|
146
|
+
"inbound": ["auth0-managed-oauth", "mcp-token-exchange-linear"],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The path is yours to choose — `/mcp/<provider>-v<n>` is the recommended
|
|
156
|
+
convention because it makes the path self-describing and reserves room for
|
|
157
|
+
versioned upgrades, but the gateway works with any path the OpenAPI router
|
|
158
|
+
accepts.
|
|
159
|
+
|
|
160
|
+
`get,post` is Zuplo's multi-method shorthand. The handler rejects GET with
|
|
161
|
+
`405 Method Not Allowed` because the gateway only speaks stateless Streamable
|
|
162
|
+
HTTP over POST — see [`McpProxyHandler`](./mcp-proxy-handler.mdx) for the full
|
|
163
|
+
handler reference.
|
|
164
|
+
|
|
165
|
+
Every MCP route must set `operationId`. Across the project, no two MCP routes
|
|
166
|
+
can share an `operationId` or a path, and no two `mcp-token-exchange-*` policies
|
|
167
|
+
can share an upstream `id`. If `operationId` is missing or duplicated, the
|
|
168
|
+
gateway returns a configuration error on the first matching request.
|
|
169
|
+
|
|
170
|
+
## Verify the gateway is wired up
|
|
171
|
+
|
|
172
|
+
Start the project with `zuplo dev` and the gateway is reachable at
|
|
173
|
+
`http://127.0.0.1:9000/mcp/linear-v1`. A quick sanity check is to send an
|
|
174
|
+
unauthenticated POST:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
curl -i -X POST http://127.0.0.1:9000/mcp/linear-v1 \
|
|
178
|
+
-H "Content-Type: application/json" \
|
|
179
|
+
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The gateway should return `401 Unauthorized` with a `WWW-Authenticate` header
|
|
183
|
+
that points at the Protected Resource Metadata URL. If you see that, the OAuth
|
|
184
|
+
policy is wired up correctly. See [Local development](./local-development.mdx)
|
|
185
|
+
for the dev-loop specifics, including the loopback-only login shortcut that
|
|
186
|
+
skips your IdP during development.
|
|
187
|
+
|
|
188
|
+
## Add more upstreams
|
|
189
|
+
|
|
190
|
+
The pattern is the same for each additional upstream: one MCP OAuth policy stays
|
|
191
|
+
shared across the project, and one `mcp-token-exchange-*` policy and one route
|
|
192
|
+
get added per new upstream MCP server. Per-user state is keyed by
|
|
193
|
+
`(subjectId, upstreamServerId)`, so each user maintains independent connections
|
|
194
|
+
to each upstream they consent to.
|
|
195
|
+
|
|
196
|
+
For a worked example with two upstreams and the full file layout, see
|
|
197
|
+
[Add multiple upstream MCP servers](./multi-upstream.mdx).
|
|
198
|
+
|
|
199
|
+
## Related
|
|
200
|
+
|
|
201
|
+
- [`McpProxyHandler` reference](./mcp-proxy-handler.mdx) — every option and
|
|
202
|
+
every behavior of the route handler.
|
|
203
|
+
- [Compatibility dates](./compatibility-dates.mdx) — why `2026-03-01` is
|
|
204
|
+
required and what older dates break.
|
|
205
|
+
- [Local development](./local-development.mdx) — dev-loop, loopback URLs, the
|
|
206
|
+
`/oauth/dev-login` shortcut, and the `workerd` restart quirk.
|
|
207
|
+
- [Add multiple upstream MCP servers](./multi-upstream.mdx) — one project, many
|
|
208
|
+
upstream MCP servers.
|
|
209
|
+
- [Curate the tools an upstream exposes](../how-to/curate-tools.mdx) — restrict
|
|
210
|
+
and re-project the tools, prompts, and resources a route exposes.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Connect ChatGPT"
|
|
3
|
+
sidebar_label: "ChatGPT"
|
|
4
|
+
description:
|
|
5
|
+
Connect ChatGPT to a Zuplo MCP Gateway as a custom connector using Developer
|
|
6
|
+
Mode, complete the OAuth flow, and start using your tools in conversation.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
ChatGPT connects to remote MCP servers as **custom connectors**. To add a custom
|
|
10
|
+
connector that exposes general-purpose MCP tools, you need to enable **Developer
|
|
11
|
+
Mode** on your ChatGPT account. Once enabled, paste the gateway URL into
|
|
12
|
+
ChatGPT's connector settings and complete the OAuth flow.
|
|
13
|
+
|
|
14
|
+
:::note
|
|
15
|
+
|
|
16
|
+
ChatGPT's general-purpose custom-connector support runs through Developer Mode,
|
|
17
|
+
which is available on Pro, Team, Enterprise, and Edu plans. Before Developer
|
|
18
|
+
Mode shipped, connector support in ChatGPT was limited to read-only Deep
|
|
19
|
+
Research connectors. Use Developer Mode to expose the full range of tools the
|
|
20
|
+
Zuplo MCP Gateway provides.
|
|
21
|
+
|
|
22
|
+
:::
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
- A Zuplo project with the MCP Gateway plugin configured and at least one MCP
|
|
27
|
+
route. See the [quickstart](../quickstart.mdx) if you haven't set one up yet.
|
|
28
|
+
- A ChatGPT Pro, Team, Enterprise, or Edu subscription.
|
|
29
|
+
- Developer Mode enabled on your ChatGPT account. The toggle lives in
|
|
30
|
+
**Settings** → **Connectors** → **Advanced** (the exact location varies by
|
|
31
|
+
plan; see OpenAI's
|
|
32
|
+
[Apps SDK documentation](https://developers.openai.com/apps-sdk/) for current
|
|
33
|
+
instructions).
|
|
34
|
+
|
|
35
|
+
## Get the route URL
|
|
36
|
+
|
|
37
|
+
Each MCP route in `config/routes.oas.json` is reachable at
|
|
38
|
+
`https://{deploymentUrl}/{routePath}` once deployed — for example
|
|
39
|
+
`https://{deploymentUrl}/mcp/linear-v1`.
|
|
40
|
+
|
|
41
|
+
## Add the connector
|
|
42
|
+
|
|
43
|
+
<Stepper>
|
|
44
|
+
|
|
45
|
+
1. **Open Connectors settings in ChatGPT.**
|
|
46
|
+
|
|
47
|
+
In the ChatGPT web app, open **Settings** → **Connectors**.
|
|
48
|
+
|
|
49
|
+
2. **Add a custom connector.**
|
|
50
|
+
|
|
51
|
+
Click the option to add a custom connector. Depending on your plan, this may
|
|
52
|
+
be **Add custom connector**, **Create**, or **Advanced** → **Add MCP
|
|
53
|
+
server**.
|
|
54
|
+
|
|
55
|
+
3. **Enter the gateway URL.**
|
|
56
|
+
|
|
57
|
+
Paste the route URL. Give the connector a name and description — these are
|
|
58
|
+
what ChatGPT shows in the conversation interface.
|
|
59
|
+
|
|
60
|
+
4. **Authenticate against the gateway.**
|
|
61
|
+
|
|
62
|
+
Save the connector. ChatGPT opens the gateway's OAuth flow. Sign in with the
|
|
63
|
+
identity provider you configured for the gateway.
|
|
64
|
+
|
|
65
|
+
5. **Complete the upstream connection.**
|
|
66
|
+
|
|
67
|
+
The gateway shows a consent page with the upstream MCP server the route
|
|
68
|
+
proxies to. Click **Connect** next to the upstream, complete its OAuth flow,
|
|
69
|
+
then click **Authorize** to finish.
|
|
70
|
+
|
|
71
|
+
6. **Enable the connector for chats.**
|
|
72
|
+
|
|
73
|
+
Back in ChatGPT, enable the connector for the conversations or assistants
|
|
74
|
+
where you want it active. Tools from the gateway then appear when ChatGPT
|
|
75
|
+
needs them.
|
|
76
|
+
|
|
77
|
+
</Stepper>
|
|
78
|
+
|
|
79
|
+
## What ChatGPT supports
|
|
80
|
+
|
|
81
|
+
ChatGPT registers itself with the gateway through
|
|
82
|
+
[Dynamic Client Registration (DCR)](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization)
|
|
83
|
+
and the newer
|
|
84
|
+
[Client ID Metadata Documents (CIMD)](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization)
|
|
85
|
+
flow. It supports:
|
|
86
|
+
|
|
87
|
+
- **Tools** — invoke gateway-exposed tools from the conversation.
|
|
88
|
+
- **MCP Apps** — render interactive HTML widgets inline. This is the same
|
|
89
|
+
surface that powers the OpenAI Apps SDK, which is built directly on top of MCP
|
|
90
|
+
Apps.
|
|
91
|
+
|
|
92
|
+
ChatGPT doesn't currently consume prompts, resources, roots, sampling, or
|
|
93
|
+
elicitation from a remote MCP server.
|
|
94
|
+
|
|
95
|
+
## Build an Apps SDK app on top of the gateway
|
|
96
|
+
|
|
97
|
+
If you're authoring an MCP server intended to render rich UI inside ChatGPT,
|
|
98
|
+
read OpenAI's [Apps SDK documentation](https://developers.openai.com/apps-sdk/)
|
|
99
|
+
— the Apps SDK builds on the MCP Apps extension, so an Apps SDK app **is** an
|
|
100
|
+
MCP server with UI conventions on top. The Zuplo MCP Gateway forwards
|
|
101
|
+
Apps-related metadata (`_meta.ui.*`) from upstream MCP servers unchanged. Tool
|
|
102
|
+
authors who want to ship UI to ChatGPT should follow the Apps SDK guide; the
|
|
103
|
+
gateway transparently relays the additional metadata to the client.
|
|
104
|
+
|
|
105
|
+
For more background on Apps SDK and Zuplo-hosted MCP servers, see
|
|
106
|
+
[OpenAI Apps SDK with Zuplo](../../mcp-server/openai-apps-sdk.mdx).
|
|
107
|
+
|
|
108
|
+
## Troubleshooting
|
|
109
|
+
|
|
110
|
+
- **"Custom connector" option isn't visible.** Confirm your plan supports
|
|
111
|
+
Developer Mode (Pro, Team, Enterprise, or Edu) and that Developer Mode is
|
|
112
|
+
enabled in your settings.
|
|
113
|
+
- **Sign-in succeeds but no tools appear.** Tools only appear when ChatGPT
|
|
114
|
+
decides to invoke them. Try a prompt that mentions the action you want to
|
|
115
|
+
take. If the connector itself is disabled in a conversation, ChatGPT doesn't
|
|
116
|
+
see any of its tools.
|
|
117
|
+
- **OAuth fails with a redirect error.** ChatGPT registers its redirect URI
|
|
118
|
+
dynamically. The gateway accepts dynamic registration by default. If you've
|
|
119
|
+
locked down DCR on your identity provider, switch to a provider that supports
|
|
120
|
+
DCR, or pre-register an OAuth app for ChatGPT.
|
|
121
|
+
|
|
122
|
+
## Related
|
|
123
|
+
|
|
124
|
+
- [Connect MCP clients overview](./overview.mdx)
|
|
125
|
+
- OpenAI's [Apps SDK documentation](https://developers.openai.com/apps-sdk/)
|
|
126
|
+
- [OpenAI Apps SDK with Zuplo](../../mcp-server/openai-apps-sdk.mdx)
|
|
127
|
+
- [Authentication overview](../auth/overview.mdx)
|