zuplo 7.4.4 → 7.4.6
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/articles/ci-cd-azure/local-testing.mdx +22 -4
- package/docs/articles/ci-cd-bitbucket/local-testing.mdx +22 -4
- package/docs/articles/ci-cd-circleci/local-testing.mdx +21 -4
- package/docs/articles/ci-cd-github/deploy-and-test.mdx +28 -13
- package/docs/articles/ci-cd-github/local-testing.mdx +36 -16
- package/docs/articles/ci-cd-gitlab/local-testing.mdx +22 -4
- package/docs/articles/github-deployment-testing.mdx +118 -31
- package/docs/articles/testing-getting-started.mdx +220 -0
- package/docs/articles/testing-preview-environments.mdx +148 -0
- package/docs/articles/testing-recipes.mdx +429 -0
- package/docs/articles/testing.mdx +138 -408
- package/docs/mcp-gateway/auth/configuring-auth0.mdx +6 -5
- package/docs/mcp-gateway/auth/configuring-clerk.mdx +4 -4
- package/docs/mcp-gateway/auth/configuring-cognito.mdx +5 -4
- package/docs/mcp-gateway/auth/configuring-entra.mdx +5 -4
- package/docs/mcp-gateway/auth/configuring-generic-oidc.mdx +8 -8
- package/docs/mcp-gateway/auth/configuring-google.mdx +4 -4
- package/docs/mcp-gateway/auth/configuring-keycloak.mdx +4 -3
- package/docs/mcp-gateway/auth/configuring-logto.mdx +4 -4
- package/docs/mcp-gateway/auth/configuring-okta.mdx +3 -3
- package/docs/mcp-gateway/auth/configuring-onelogin.mdx +3 -3
- package/docs/mcp-gateway/auth/configuring-ping.mdx +3 -3
- package/docs/mcp-gateway/auth/configuring-workos.mdx +5 -4
- package/docs/mcp-gateway/auth/manual-oauth-testing.mdx +8 -8
- package/docs/mcp-gateway/auth/overview.mdx +17 -17
- package/docs/mcp-gateway/auth/upstream-oauth.mdx +5 -5
- package/docs/mcp-gateway/code-config/local-development.mdx +14 -12
- package/docs/mcp-gateway/code-config/overview.mdx +9 -4
- package/docs/mcp-gateway/connect-clients/chatgpt.mdx +114 -56
- package/docs/mcp-gateway/how-it-works.mdx +11 -9
- package/docs/mcp-gateway/introduction.mdx +3 -1
- package/docs/mcp-gateway/quickstart-local.mdx +7 -7
- package/docs/mcp-gateway/reference.mdx +58 -25
- package/docs/mcp-gateway/server-registry.mdx +179 -0
- package/docs/mcp-gateway/test-clients.mdx +2 -2
- package/docs/mcp-server/custom-tools.mdx +32 -0
- package/docs/programmable-api/mcp-gateway-plugin.mdx +137 -0
- package/docs/programmable-api/mcp-sdk.mdx +240 -0
- package/docs/self-hosted/overview.md +2 -0
- package/package.json +5 -5
|
@@ -56,13 +56,14 @@ tokens that bind to MCP routes. The Auth0 application you create represents the
|
|
|
56
56
|
### Configure callback and origin URLs
|
|
57
57
|
|
|
58
58
|
The gateway completes browser login by redirecting back to its own
|
|
59
|
-
`/oauth/callback` endpoint, so Auth0 needs that URL on its allow-list.
|
|
59
|
+
`/__zuplo/oauth/callback` endpoint, so Auth0 needs that URL on its allow-list.
|
|
60
60
|
|
|
61
61
|
On the same **Settings** tab:
|
|
62
62
|
|
|
63
63
|
1. Set **Allowed Callback URLs** to your gateway's
|
|
64
|
-
`https://<gateway-host>/oauth/callback`. For local development
|
|
65
|
-
`zuplo dev`, add `http://localhost:9000/oauth/callback` as
|
|
64
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. For local development
|
|
65
|
+
against `zuplo dev`, add `http://localhost:9000/__zuplo/oauth/callback` as
|
|
66
|
+
well.
|
|
66
67
|
2. Set **Allowed Web Origins** to the gateway origin `https://<gateway-host>`
|
|
67
68
|
(plus `http://localhost:9000` for local dev).
|
|
68
69
|
3. Save changes.
|
|
@@ -194,8 +195,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
194
195
|
- **"Invalid Auth0 domain" at boot.** The `auth0Domain` value includes a scheme
|
|
195
196
|
prefix or doesn't contain a dot. Use `my-tenant.us.auth0.com`.
|
|
196
197
|
- **Browser login redirects but the callback fails.** The
|
|
197
|
-
`https://<gateway-host>/oauth/callback` URL isn't on the **Allowed
|
|
198
|
-
URLs** list for the Auth0 application.
|
|
198
|
+
`https://<gateway-host>/__zuplo/oauth/callback` URL isn't on the **Allowed
|
|
199
|
+
Callback URLs** list for the Auth0 application.
|
|
199
200
|
- **Token endpoint returns `invalid_audience`.** The MCP client is reusing a
|
|
200
201
|
token bound to a different route. Each gateway-issued token binds to one
|
|
201
202
|
`operationId`; the client must obtain a separate token per route.
|
|
@@ -29,8 +29,8 @@ to MCP routes.
|
|
|
29
29
|
then open **Configure → OAuth Applications**.
|
|
30
30
|
2. Click **Add OAuth application**.
|
|
31
31
|
3. Give the application a name (for example, `Zuplo MCP Gateway`).
|
|
32
|
-
4. Set **Redirect URIs** to `https://<gateway-host>/oauth/callback`. Add
|
|
33
|
-
`http://localhost:9000/oauth/callback` for local development with
|
|
32
|
+
4. Set **Redirect URIs** to `https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
33
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development with
|
|
34
34
|
`zuplo dev`.
|
|
35
35
|
5. Select the OIDC scopes the gateway needs — `openid`, `profile`, and `email`
|
|
36
36
|
are enough.
|
|
@@ -143,8 +143,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
143
143
|
- **The policy rejects `frontendApiUrl` at boot.** The value includes a path,
|
|
144
144
|
query string, or fragment. Use only the origin (`https://clerk.example.com`).
|
|
145
145
|
- **Browser login redirects but the callback fails.** The
|
|
146
|
-
`https://<gateway-host>/oauth/callback` URL isn't on the OAuth
|
|
147
|
-
redirect URIs allow-list in Clerk.
|
|
146
|
+
`https://<gateway-host>/__zuplo/oauth/callback` URL isn't on the OAuth
|
|
147
|
+
application's redirect URIs allow-list in Clerk.
|
|
148
148
|
|
|
149
149
|
## Related
|
|
150
150
|
|
|
@@ -44,8 +44,9 @@ wrapper handles both.
|
|
|
44
44
|
1. Under **App integration → App clients**, click **Create app client**.
|
|
45
45
|
2. Choose **Confidential client**. The client must have a client secret — the
|
|
46
46
|
gateway needs it for the federated token exchange.
|
|
47
|
-
3. Set **Allowed callback URLs** to
|
|
48
|
-
`
|
|
47
|
+
3. Set **Allowed callback URLs** to
|
|
48
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
49
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development.
|
|
49
50
|
4. Enable **Authorization code grant** under allowed OAuth flows.
|
|
50
51
|
5. Enable the OIDC scopes the gateway needs — `openid`, `profile`, and `email`.
|
|
51
52
|
6. Click **Create app client**.
|
|
@@ -115,8 +116,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
115
116
|
`https://`, a trailing slash, or an OAuth path. Strip those — use only
|
|
116
117
|
`auth.example.com` or `my-pool.auth.us-east-1.amazoncognito.com`.
|
|
117
118
|
- **Browser login lands on a Cognito error page.** The callback URL on the app
|
|
118
|
-
client doesn't match. Set it to
|
|
119
|
-
exactly.
|
|
119
|
+
client doesn't match. Set it to
|
|
120
|
+
`https://<gateway-host>/__zuplo/oauth/callback` exactly.
|
|
120
121
|
- **`invalid_client` from Cognito's token endpoint.** The app client doesn't
|
|
121
122
|
have a client secret, or the secret value doesn't match. Cognito confidential
|
|
122
123
|
clients require both ID and secret.
|
|
@@ -41,7 +41,7 @@ to MCP routes.
|
|
|
41
41
|
directory only (single tenant)**. The wrapper does not support multi-tenant
|
|
42
42
|
modes.
|
|
43
43
|
4. Under **Redirect URI**, choose **Web** and set the value to
|
|
44
|
-
`https://<gateway-host>/oauth/callback`. Click **Register**.
|
|
44
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. Click **Register**.
|
|
45
45
|
5. On the application's **Overview** page, note the **Application (client) ID**
|
|
46
46
|
and the **Directory (tenant) ID**. Both are UUIDs.
|
|
47
47
|
|
|
@@ -55,7 +55,8 @@ to MCP routes.
|
|
|
55
55
|
### Add the local development redirect URI
|
|
56
56
|
|
|
57
57
|
1. Open **Authentication** on the application.
|
|
58
|
-
2. Add `http://localhost:9000/oauth/callback` under **Web → Redirect
|
|
58
|
+
2. Add `http://localhost:9000/__zuplo/oauth/callback` under **Web → Redirect
|
|
59
|
+
URIs**.
|
|
59
60
|
3. Save.
|
|
60
61
|
|
|
61
62
|
### Optional: restrict access
|
|
@@ -121,8 +122,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
121
122
|
verified domain, `common`, `organizations`, or `consumers`. Look up the tenant
|
|
122
123
|
ID under **Overview** in the Entra admin center.
|
|
123
124
|
- **`AADSTS50011` redirect URI mismatch.** The redirect URI on the app
|
|
124
|
-
registration doesn't match `https://<gateway-host>/oauth/callback`
|
|
125
|
-
Match scheme, host, and path.
|
|
125
|
+
registration doesn't match `https://<gateway-host>/__zuplo/oauth/callback`
|
|
126
|
+
exactly. Match scheme, host, and path.
|
|
126
127
|
- **`AADSTS700016` application not found.** The client ID doesn't belong to the
|
|
127
128
|
tenant the wrapper is configured with. Make sure `tenantId` and `clientId`
|
|
128
129
|
come from the same app registration.
|
|
@@ -53,8 +53,8 @@ at the same place:
|
|
|
53
53
|
|
|
54
54
|
1. Create a new OIDC web application (or "regular web application", "OIDC
|
|
55
55
|
client", "confidential client" — terminology varies).
|
|
56
|
-
2. Set the **redirect URI** to `https://<gateway-host>/oauth/callback`.
|
|
57
|
-
`http://localhost:9000/oauth/callback` for local development with
|
|
56
|
+
2. Set the **redirect URI** to `https://<gateway-host>/__zuplo/oauth/callback`.
|
|
57
|
+
Add `http://localhost:9000/__zuplo/oauth/callback` for local development with
|
|
58
58
|
`zuplo dev`.
|
|
59
59
|
3. Note the **client ID** and **client secret**.
|
|
60
60
|
4. Restrict the application to the users or groups who should be able to
|
|
@@ -144,15 +144,15 @@ to the loopback dev-login endpoint:
|
|
|
144
144
|
"jwksUrl": "http://localhost:9000/dev/jwks"
|
|
145
145
|
},
|
|
146
146
|
"browserLogin": {
|
|
147
|
-
"url": "http://127.0.0.1:9000/oauth/dev-login"
|
|
147
|
+
"url": "http://127.0.0.1:9000/__zuplo/oauth/dev-login"
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
When `browserLogin.url` points at `/oauth/dev-login`, you don't need
|
|
154
|
-
`clientId`, or `clientSecret`. The endpoint is only served on
|
|
155
|
-
production deployments cannot reach it.
|
|
153
|
+
When `browserLogin.url` points at `/__zuplo/oauth/dev-login`, you don't need
|
|
154
|
+
`tokenUrl`, `clientId`, or `clientSecret`. The endpoint is only served on
|
|
155
|
+
loopback origins; production deployments cannot reach it.
|
|
156
156
|
|
|
157
157
|
See the [local development guide](../code-config/local-development.mdx) for the
|
|
158
158
|
rest of the local setup.
|
|
@@ -166,7 +166,7 @@ rest of the local setup.
|
|
|
166
166
|
| `oidc.issuer` | yes | — | The OIDC issuer URL. Must include the scheme. |
|
|
167
167
|
| `oidc.jwksUrl` | yes | — | JWKS endpoint that publishes the IdP's signing keys. |
|
|
168
168
|
| `oidc.audience` | no | unset | Optional ID-token audience override. Leave unset when ID tokens use the OIDC `client_id` as their audience. |
|
|
169
|
-
| `browserLogin.url` | yes | — | The IdP's `/authorize` endpoint. The loopback `/oauth/dev-login` shortcut works for local dev.
|
|
169
|
+
| `browserLogin.url` | yes | — | The IdP's `/authorize` endpoint. The loopback `/__zuplo/oauth/dev-login` shortcut works for local dev. |
|
|
170
170
|
| `browserLogin.tokenUrl` | for federated OIDC | — | The IdP's token endpoint. Required for the federated authorization-code exchange. |
|
|
171
171
|
| `browserLogin.clientId` | for federated OIDC | — | OIDC client_id registered with the IdP. |
|
|
172
172
|
| `browserLogin.clientSecret` | for federated OIDC | — | OIDC client_secret. Use `$env(...)`. |
|
|
@@ -231,7 +231,7 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
231
231
|
is attached to the route in `routes.oas.json` and the `McpGatewayPlugin` is
|
|
232
232
|
registered in `modules/zuplo.runtime.ts`.
|
|
233
233
|
- **Browser login redirects but the callback fails.** The
|
|
234
|
-
`https://<gateway-host>/oauth/callback` URL isn't on the application's
|
|
234
|
+
`https://<gateway-host>/__zuplo/oauth/callback` URL isn't on the application's
|
|
235
235
|
redirect URI allow-list at the IdP.
|
|
236
236
|
|
|
237
237
|
## Related
|
|
@@ -34,8 +34,8 @@ to MCP routes.
|
|
|
34
34
|
3. Choose **Web application** as the application type.
|
|
35
35
|
4. Give the client a name (for example, `Zuplo MCP Gateway`).
|
|
36
36
|
5. Under **Authorized redirect URIs**, add
|
|
37
|
-
`https://<gateway-host>/oauth/callback`. Add
|
|
38
|
-
`http://localhost:9000/oauth/callback` for local development with
|
|
37
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
38
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development with
|
|
39
39
|
`zuplo dev`.
|
|
40
40
|
6. Click **Create**.
|
|
41
41
|
|
|
@@ -104,8 +104,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
104
104
|
Google's OAuth client ID shape — issuer URLs, API hostnames, project numbers.
|
|
105
105
|
Use the full `123456789012-abc123def456.apps.googleusercontent.com` form.
|
|
106
106
|
- **`redirect_uri_mismatch` from Google.** The redirect URI on the OAuth client
|
|
107
|
-
doesn't match `https://<gateway-host>/oauth/callback` exactly. Match
|
|
108
|
-
host, and path.
|
|
107
|
+
doesn't match `https://<gateway-host>/__zuplo/oauth/callback` exactly. Match
|
|
108
|
+
scheme, host, and path.
|
|
109
109
|
- **`access_denied` for Google Workspace users.** The OAuth consent screen is
|
|
110
110
|
set to **Internal** but the user belongs to a different workspace, or the user
|
|
111
111
|
isn't on the **Test users** list during pre-verification.
|
|
@@ -36,8 +36,9 @@ bind to MCP routes.
|
|
|
36
36
|
roles** and **Direct access grants** — the gateway only needs the browser
|
|
37
37
|
code flow.
|
|
38
38
|
5. Click **Next**.
|
|
39
|
-
6. Set **Valid redirect URIs** to
|
|
40
|
-
`
|
|
39
|
+
6. Set **Valid redirect URIs** to
|
|
40
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
41
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development.
|
|
41
42
|
7. Set **Web origins** to `https://<gateway-host>` (and `http://localhost:9000`
|
|
42
43
|
for local dev).
|
|
43
44
|
8. Click **Save**.
|
|
@@ -113,7 +114,7 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
113
114
|
- **`keycloakBaseUrl` rejected at boot.** The value includes `/realms/...`.
|
|
114
115
|
Strip the realm path; pass the realm name on the `realm` option instead.
|
|
115
116
|
- **`Invalid redirect_uri` from Keycloak.** The callback URL on the client
|
|
116
|
-
doesn't match `https://<gateway-host>/oauth/callback`.
|
|
117
|
+
doesn't match `https://<gateway-host>/__zuplo/oauth/callback`.
|
|
117
118
|
- **`Invalid client credentials`.** The client isn't a confidential client
|
|
118
119
|
(Client authentication off), or the secret value doesn't match. Re-copy the
|
|
119
120
|
secret from the **Credentials** tab.
|
|
@@ -32,8 +32,8 @@ to MCP routes.
|
|
|
32
32
|
3. Give the application a name (for example, `Zuplo MCP Gateway`) and click
|
|
33
33
|
**Create application**.
|
|
34
34
|
4. On the application's **Settings** tab, set **Redirect URIs** to
|
|
35
|
-
`https://<gateway-host>/oauth/callback`. Add
|
|
36
|
-
`http://localhost:9000/oauth/callback` for local development.
|
|
35
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
36
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development.
|
|
37
37
|
5. Save.
|
|
38
38
|
|
|
39
39
|
Note the **App ID** (= client ID) and **App secret** (= client secret) from the
|
|
@@ -106,8 +106,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
106
106
|
`/.well-known/openid-configuration`, or another path. Use the bare tenant
|
|
107
107
|
endpoint origin.
|
|
108
108
|
- **`redirect_uri` rejected by Logto.** The redirect URI on the application
|
|
109
|
-
doesn't match `https://<gateway-host>/oauth/callback`. Match scheme,
|
|
110
|
-
path.
|
|
109
|
+
doesn't match `https://<gateway-host>/__zuplo/oauth/callback`. Match scheme,
|
|
110
|
+
host, and path.
|
|
111
111
|
|
|
112
112
|
## Related
|
|
113
113
|
|
|
@@ -40,8 +40,8 @@ that bind to MCP routes. The Okta application you create represents the
|
|
|
40
40
|
not need refresh tokens from Okta — it uses Okta only for browser identity,
|
|
41
41
|
not as a long-running token source.
|
|
42
42
|
5. Set **Sign-in redirect URIs** to your gateway's
|
|
43
|
-
`https://<gateway-host>/oauth/callback`. Add
|
|
44
|
-
`http://localhost:9000/oauth/callback` for local development with
|
|
43
|
+
`https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
44
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development with
|
|
45
45
|
`zuplo dev`.
|
|
46
46
|
6. Under **Assignments**, restrict access to the groups or users who should be
|
|
47
47
|
able to authenticate against the gateway.
|
|
@@ -180,7 +180,7 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
180
180
|
- **"Invalid Okta domain" at boot.** `oktaDomain` includes a scheme prefix,
|
|
181
181
|
trailing slash, or path. Use `acme.okta.com`.
|
|
182
182
|
- **Browser login redirects but the callback fails.** The
|
|
183
|
-
`https://<gateway-host>/oauth/callback` URL isn't on the application's
|
|
183
|
+
`https://<gateway-host>/__zuplo/oauth/callback` URL isn't on the application's
|
|
184
184
|
**Sign-in redirect URIs** allow-list in Okta.
|
|
185
185
|
- **`invalid_audience` from the gateway's token endpoint.** The MCP client is
|
|
186
186
|
reusing a token bound to a different route. Each gateway-issued token binds to
|
|
@@ -31,8 +31,8 @@ bind to MCP routes.
|
|
|
31
31
|
3. Give the application a display name (for example, `Zuplo MCP Gateway`) and
|
|
32
32
|
click **Save**.
|
|
33
33
|
4. Open the application's **Configuration** tab.
|
|
34
|
-
5. Set **Redirect URIs** to `https://<gateway-host>/oauth/callback`. Add
|
|
35
|
-
`http://localhost:9000/oauth/callback` for local development.
|
|
34
|
+
5. Set **Redirect URIs** to `https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
35
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development.
|
|
36
36
|
6. Set **Login Url** to your gateway origin (`https://<gateway-host>`).
|
|
37
37
|
7. Save.
|
|
38
38
|
|
|
@@ -111,7 +111,7 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
111
111
|
- **`oneLoginSubdomain` rejected at boot.** The value includes `https://`,
|
|
112
112
|
`.onelogin.com`, or a trailing path. Pass only the subdomain (`acme`).
|
|
113
113
|
- **`invalid_request: redirect_uri`.** The redirect URI on the OIDC application
|
|
114
|
-
doesn't match `https://<gateway-host>/oauth/callback`.
|
|
114
|
+
doesn't match `https://<gateway-host>/__zuplo/oauth/callback`.
|
|
115
115
|
- **`invalid_client` from the token endpoint.** **Token Endpoint Authentication
|
|
116
116
|
Method** isn't set to **POST** on the application's SSO tab.
|
|
117
117
|
|
|
@@ -38,8 +38,8 @@ bind to MCP routes.
|
|
|
38
38
|
2. Click **+ Add Application**, name it (for example, `Zuplo MCP Gateway`),
|
|
39
39
|
choose **OIDC Web App** as the application type, and click **Save**.
|
|
40
40
|
3. Open the application's **Configuration** tab.
|
|
41
|
-
4. Set **Redirect URIs** to `https://<gateway-host>/oauth/callback`. Add
|
|
42
|
-
`http://localhost:9000/oauth/callback` for local development.
|
|
41
|
+
4. Set **Redirect URIs** to `https://<gateway-host>/__zuplo/oauth/callback`. Add
|
|
42
|
+
`http://localhost:9000/__zuplo/oauth/callback` for local development.
|
|
43
43
|
5. Set **Grant Types** to **Authorization Code**.
|
|
44
44
|
6. Save.
|
|
45
45
|
|
|
@@ -144,7 +144,7 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
144
144
|
- **`environmentId` rejected at boot.** The wrapper expects a UUID. Don't pass
|
|
145
145
|
the issuer URL, the auth domain, or the client ID.
|
|
146
146
|
- **Browser login lands on a PingOne error page.** The redirect URI on the
|
|
147
|
-
application doesn't match `https://<gateway-host>/oauth/callback`.
|
|
147
|
+
application doesn't match `https://<gateway-host>/__zuplo/oauth/callback`.
|
|
148
148
|
- **`invalid_client`.** The application is set to **Public** instead of
|
|
149
149
|
**Confidential**. Confidential is required so the gateway can authenticate
|
|
150
150
|
with the client secret.
|
|
@@ -33,9 +33,9 @@ that bind to MCP routes.
|
|
|
33
33
|
### Add the redirect URI
|
|
34
34
|
|
|
35
35
|
1. Open **Redirects** in the WorkOS Dashboard.
|
|
36
|
-
2. Add `https://<gateway-host>/oauth/callback` as an allowed redirect
|
|
37
|
-
`http://localhost:9000/oauth/callback` for local development
|
|
38
|
-
`zuplo dev`.
|
|
36
|
+
2. Add `https://<gateway-host>/__zuplo/oauth/callback` as an allowed redirect
|
|
37
|
+
URI. Add `http://localhost:9000/__zuplo/oauth/callback` for local development
|
|
38
|
+
with `zuplo dev`.
|
|
39
39
|
3. Save.
|
|
40
40
|
|
|
41
41
|
### Note the API credentials
|
|
@@ -102,7 +102,8 @@ endpoint with `curl` so you can see the raw responses.
|
|
|
102
102
|
## Common issues
|
|
103
103
|
|
|
104
104
|
- **`Invalid redirect URI`.** The redirect URI on **Redirects** in the WorkOS
|
|
105
|
-
Dashboard doesn't match `https://<gateway-host>/oauth/callback`
|
|
105
|
+
Dashboard doesn't match `https://<gateway-host>/__zuplo/oauth/callback`
|
|
106
|
+
exactly.
|
|
106
107
|
- **`invalid_client`.** The client secret value doesn't match. WorkOS shows the
|
|
107
108
|
secret only once after creation — regenerate it from **API Keys** if you've
|
|
108
109
|
lost it.
|
|
@@ -108,10 +108,10 @@ REDIRECT_URI="http://localhost:8765/callback"
|
|
|
108
108
|
```json
|
|
109
109
|
{
|
|
110
110
|
"issuer": "https://gateway.example.com/mcp/linear-v1",
|
|
111
|
-
"authorization_endpoint": "https://gateway.example.com/oauth/authorize/mcp/linear-v1",
|
|
112
|
-
"token_endpoint": "https://gateway.example.com/oauth/token",
|
|
113
|
-
"registration_endpoint": "https://gateway.example.com/oauth/register",
|
|
114
|
-
"revocation_endpoint": "https://gateway.example.com/oauth/revoke",
|
|
111
|
+
"authorization_endpoint": "https://gateway.example.com/__zuplo/oauth/authorize/mcp/linear-v1",
|
|
112
|
+
"token_endpoint": "https://gateway.example.com/__zuplo/oauth/token",
|
|
113
|
+
"registration_endpoint": "https://gateway.example.com/__zuplo/oauth/register",
|
|
114
|
+
"revocation_endpoint": "https://gateway.example.com/__zuplo/oauth/revoke",
|
|
115
115
|
"scopes_supported": ["mcp:tools"],
|
|
116
116
|
"response_types_supported": ["code"],
|
|
117
117
|
"grant_types_supported": ["authorization_code", "refresh_token"],
|
|
@@ -209,7 +209,7 @@ REDIRECT_URI="http://localhost:8765/callback"
|
|
|
209
209
|
Open the URL in a browser. The flow is:
|
|
210
210
|
1. The gateway redirects you to your IdP's login page.
|
|
211
211
|
2. You authenticate at the IdP.
|
|
212
|
-
3. The IdP redirects back to the gateway's `/oauth/callback`.
|
|
212
|
+
3. The IdP redirects back to the gateway's `/__zuplo/oauth/callback`.
|
|
213
213
|
4. The gateway renders the consent setup page.
|
|
214
214
|
5. You click **Authorize**.
|
|
215
215
|
6. The gateway redirects to your `redirect_uri` with `?code=...&state=...`.
|
|
@@ -231,8 +231,8 @@ REDIRECT_URI="http://localhost:8765/callback"
|
|
|
231
231
|
|
|
232
232
|
1. **Exchange the code for tokens.**
|
|
233
233
|
|
|
234
|
-
`POST /oauth/token` with the authorization-code grant. Public clients
|
|
235
|
-
`client_id` in the form body; confidential clients use HTTP Basic.
|
|
234
|
+
`POST /__zuplo/oauth/token` with the authorization-code grant. Public clients
|
|
235
|
+
send `client_id` in the form body; confidential clients use HTTP Basic.
|
|
236
236
|
|
|
237
237
|
```bash
|
|
238
238
|
TOKEN_RESPONSE=$(curl -s -X POST "${TOKEN_ENDPOINT}" \
|
|
@@ -360,7 +360,7 @@ REDIRECT_URI="http://localhost:8765/callback"
|
|
|
360
360
|
When you're done testing, revoke the grant.
|
|
361
361
|
|
|
362
362
|
```bash
|
|
363
|
-
curl -s -i -X POST "${GATEWAY}/oauth/revoke" \
|
|
363
|
+
curl -s -i -X POST "${GATEWAY}/__zuplo/oauth/revoke" \
|
|
364
364
|
-H "content-type: application/x-www-form-urlencoded" \
|
|
365
365
|
--data-urlencode "token=${NEW_REFRESH_TOKEN}" \
|
|
366
366
|
--data-urlencode "token_type_hint=refresh_token" \
|
|
@@ -45,8 +45,8 @@ OAuth flow:
|
|
|
45
45
|
route.
|
|
46
46
|
- An RFC 7591 Dynamic Client Registration endpoint.
|
|
47
47
|
- An OAuth Client ID Metadata Document (CIMD) acceptor.
|
|
48
|
-
- `/oauth/authorize`, `/oauth/token`, `/oauth/revoke`,
|
|
49
|
-
endpoints.
|
|
48
|
+
- `/__zuplo/oauth/authorize`, `/__zuplo/oauth/token`, `/__zuplo/oauth/revoke`,
|
|
49
|
+
and `/__zuplo/oauth/callback` endpoints.
|
|
50
50
|
|
|
51
51
|
Browser identity is delegated to an OIDC identity provider you configure —
|
|
52
52
|
Auth0, Okta, or any OIDC discovery-compatible IdP. The IdP authenticates the
|
|
@@ -89,16 +89,16 @@ The gateway implements the following standards in their MCP-mandated subsets.
|
|
|
89
89
|
| [RFC 8414 — Authorization Server Metadata](https://datatracker.ietf.org/doc/html/rfc8414) | Published at `/.well-known/oauth-authorization-server[/{routePath}]`. |
|
|
90
90
|
| [OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html) | Accepted alongside RFC 8414 as authorization-server discovery (added in the `2025-11-25` MCP revision). |
|
|
91
91
|
| [RFC 9728 — Protected Resource Metadata](https://datatracker.ietf.org/doc/html/rfc9728) | Published at `/.well-known/oauth-protected-resource/{routePath}` per MCP route. |
|
|
92
|
-
| [RFC 7591 — Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) | Accepted at `/oauth/register`.
|
|
92
|
+
| [RFC 7591 — Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591) | Accepted at `/__zuplo/oauth/register`. |
|
|
93
93
|
| [OAuth Client ID Metadata Documents (CIMD)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-00) | Recommended client identification path per the `2025-11-25` MCP revision. The gateway advertises `client_id_metadata_document_supported: true` and accepts URLs as `client_id` values when CIMD is enabled. |
|
|
94
94
|
| [RFC 8707 — Resource Indicators](https://datatracker.ietf.org/doc/html/rfc8707) | MCP clients **MUST** include the `resource` parameter on every authorization and token request. The gateway validates that incoming bearer tokens were minted for the route's canonical resource URI. |
|
|
95
95
|
| [RFC 6750 — Bearer tokens](https://datatracker.ietf.org/doc/html/rfc6750) | `Authorization: Bearer ...` only, header position only — tokens in query strings are rejected. |
|
|
96
|
-
| [RFC 7009 — Token Revocation](https://datatracker.ietf.org/doc/html/rfc7009) | Published at `/oauth/revoke`.
|
|
96
|
+
| [RFC 7009 — Token Revocation](https://datatracker.ietf.org/doc/html/rfc7009) | Published at `/__zuplo/oauth/revoke`. |
|
|
97
97
|
|
|
98
98
|
CIMD is the recommended client identification path going forward; DCR is
|
|
99
99
|
retained for backwards compatibility with older MCP clients. Both work against
|
|
100
|
-
the same `/oauth/register` and AS metadata surface — clients that
|
|
101
|
-
are accommodated.
|
|
100
|
+
the same `/__zuplo/oauth/register` and AS metadata surface — clients that
|
|
101
|
+
support either are accommodated.
|
|
102
102
|
|
|
103
103
|
## Downstream flow
|
|
104
104
|
|
|
@@ -123,7 +123,7 @@ plus the MCP `resource` parameter binding.
|
|
|
123
123
|
|
|
124
124
|
The flow is the standard MCP authorization handshake. The
|
|
125
125
|
[`McpGatewayPlugin`](../code-config/overview.mdx) registers the
|
|
126
|
-
`/.well-known/...` and `/oauth/...` endpoints automatically.
|
|
126
|
+
`/.well-known/...` and `/__zuplo/oauth/...` endpoints automatically.
|
|
127
127
|
|
|
128
128
|
## Upstream flow
|
|
129
129
|
|
|
@@ -282,16 +282,16 @@ full URL catalog.
|
|
|
282
282
|
| `/.well-known/oauth-authorization-server` | GET | RFC 8414 AS metadata (gateway-wide). |
|
|
283
283
|
| `/.well-known/oauth-authorization-server/{routePath}` | GET | RFC 8414 AS metadata (per route, rebinds `issuer`). |
|
|
284
284
|
| `/.well-known/oauth-protected-resource/{routePath}` | GET | RFC 9728 PRM (per route). |
|
|
285
|
-
| `/oauth/register`
|
|
286
|
-
| `/oauth/authorize`
|
|
287
|
-
| `/oauth/authorize/{routePath}`
|
|
288
|
-
| `/oauth/callback`
|
|
289
|
-
| `/oauth/setup`
|
|
290
|
-
| `/oauth/token`
|
|
291
|
-
| `/oauth/revoke`
|
|
292
|
-
|
|
|
293
|
-
| `/auth/connections/{connection}/connect`
|
|
294
|
-
| `/auth/connections/{connection}/callback`
|
|
285
|
+
| `/__zuplo/oauth/register` | POST | RFC 7591 Dynamic Client Registration. |
|
|
286
|
+
| `/__zuplo/oauth/authorize` | GET | Gateway-wide authorize endpoint. Requires the `resource` parameter. |
|
|
287
|
+
| `/__zuplo/oauth/authorize/{routePath}` | GET | Per-route authorize endpoint. |
|
|
288
|
+
| `/__zuplo/oauth/callback` | GET | Browser-login callback from the IdP. |
|
|
289
|
+
| `/__zuplo/oauth/setup` | GET, POST | Consent and multi-upstream connect page. |
|
|
290
|
+
| `/__zuplo/oauth/token` | POST | Token endpoint. Accepts `authorization_code` and `refresh_token` grants. |
|
|
291
|
+
| `/__zuplo/oauth/revoke` | POST | RFC 7009 revocation. |
|
|
292
|
+
| `/__zuplo/.well-known/oauth-client/{connection}` | GET | OIDC Client ID Metadata Document for the upstream OAuth client (per upstream). |
|
|
293
|
+
| `/__zuplo/auth/connections/{connection}/connect` | GET | Start the upstream OAuth flow. |
|
|
294
|
+
| `/__zuplo/auth/connections/{connection}/callback` | GET | Upstream OAuth callback. |
|
|
295
295
|
|
|
296
296
|
The well-known metadata endpoints serve CORS-permissive responses
|
|
297
297
|
(`Access-Control-Allow-Origin: *`) because browser-resident MCP clients fetch
|
|
@@ -77,9 +77,9 @@ can request tokens. The `clientRegistration` option controls how:
|
|
|
77
77
|
- **CIMD with DCR fallback (`{ "mode": "auto" }`)** — the default. The gateway
|
|
78
78
|
publishes a per-upstream
|
|
79
79
|
[OAuth Client ID Metadata Document](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-client-id-metadata-document-00)
|
|
80
|
-
at
|
|
81
|
-
upstream that URL is the client ID. If the upstream doesn't accept
|
|
82
|
-
gateway falls back to
|
|
80
|
+
at `/__zuplo/.well-known/oauth-client/{connection}?authProfileId=...` and
|
|
81
|
+
tells the upstream that URL is the client ID. If the upstream doesn't accept
|
|
82
|
+
CIMD, the gateway falls back to
|
|
83
83
|
[RFC 7591 Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591).
|
|
84
84
|
Auto mode requires nothing from the upstream provider beyond standard MCP
|
|
85
85
|
authorization spec support and has no client secrets to rotate.
|
|
@@ -139,7 +139,7 @@ message; the user copies it into a browser.
|
|
|
139
139
|
|
|
140
140
|
Each MCP route proxies to exactly one upstream, so the consent page typically
|
|
141
141
|
shows one upstream to connect. The consent page is part of the gateway and
|
|
142
|
-
renders automatically whenever a user lands at `/oauth/setup` mid-flow.
|
|
142
|
+
renders automatically whenever a user lands at `/__zuplo/oauth/setup` mid-flow.
|
|
143
143
|
|
|
144
144
|
## Connect-required states
|
|
145
145
|
|
|
@@ -165,7 +165,7 @@ The full JSON-RPC error payload looks like:
|
|
|
165
165
|
"state": "authenticating",
|
|
166
166
|
"upstreamServerId": "linear",
|
|
167
167
|
"operationId": "linear-mcp-server",
|
|
168
|
-
"authUrl": "https://gateway.example.com/auth/connections/linear/connect?browserTicket=eyJ...&operationId=linear-mcp-server",
|
|
168
|
+
"authUrl": "https://gateway.example.com/__zuplo/auth/connections/linear/connect?browserTicket=eyJ...&operationId=linear-mcp-server",
|
|
169
169
|
"nextAction": "redirect",
|
|
170
170
|
"authProfileId": "linear:user-oauth",
|
|
171
171
|
},
|
|
@@ -3,8 +3,9 @@ title: "Local development"
|
|
|
3
3
|
sidebar_label: "Local development"
|
|
4
4
|
description:
|
|
5
5
|
Run the Zuplo MCP Gateway locally with zuplo dev, bypass your identity
|
|
6
|
-
provider with the loopback /oauth/dev-login shortcut, wire up an MCP
|
|
7
|
-
against 127.0.0.1, and recover cleanly from the known workerd restart
|
|
6
|
+
provider with the loopback /__zuplo/oauth/dev-login shortcut, wire up an MCP
|
|
7
|
+
client against 127.0.0.1, and recover cleanly from the known workerd restart
|
|
8
|
+
quirk.
|
|
8
9
|
---
|
|
9
10
|
|
|
10
11
|
The MCP Gateway runs the same way locally as any Zuplo project — `zuplo dev`,
|
|
@@ -44,7 +45,7 @@ When configuring an MCP client locally, use `127.0.0.1`:
|
|
|
44
45
|
The same applies to any callback or redirect URI you configure with an identity
|
|
45
46
|
provider for local testing.
|
|
46
47
|
|
|
47
|
-
## Bypass your IdP with `/oauth/dev-login`
|
|
48
|
+
## Bypass your IdP with `/__zuplo/oauth/dev-login`
|
|
48
49
|
|
|
49
50
|
Setting up a real OIDC provider for local development is friction — you'd have
|
|
50
51
|
to register a localhost callback, manage test users, and so on. The gateway
|
|
@@ -68,24 +69,24 @@ OAuth policy:
|
|
|
68
69
|
"jwksUrl": "http://127.0.0.1:9000/.well-known/jwks.json",
|
|
69
70
|
},
|
|
70
71
|
"browserLogin": {
|
|
71
|
-
"url": "http://127.0.0.1:9000/oauth/dev-login",
|
|
72
|
+
"url": "http://127.0.0.1:9000/__zuplo/oauth/dev-login",
|
|
72
73
|
},
|
|
73
74
|
},
|
|
74
75
|
},
|
|
75
76
|
}
|
|
76
77
|
```
|
|
77
78
|
|
|
78
|
-
When `browserLogin.url` points at `/oauth/dev-login`, the
|
|
79
|
+
When `browserLogin.url` points at `/__zuplo/oauth/dev-login`, the
|
|
79
80
|
`browserLogin.tokenUrl`, `browserLogin.clientId`, and
|
|
80
81
|
`browserLogin.clientSecret` options aren't required. The consent page renders
|
|
81
82
|
normally.
|
|
82
83
|
|
|
83
84
|
:::caution
|
|
84
85
|
|
|
85
|
-
The `/oauth/dev-login` route returns `403 Forbidden` for any request
|
|
86
|
-
doesn't arrive over loopback. It's not a security risk to leave configured
|
|
87
|
-
production, but it's also not useful — production deployments should use a
|
|
88
|
-
OIDC provider through one of the
|
|
86
|
+
The `/__zuplo/oauth/dev-login` route returns `403 Forbidden` for any request
|
|
87
|
+
that doesn't arrive over loopback. It's not a security risk to leave configured
|
|
88
|
+
for production, but it's also not useful — production deployments should use a
|
|
89
|
+
real OIDC provider through one of the
|
|
89
90
|
[IdP-specific wrappers](../auth/overview.mdx#identity-providers).
|
|
90
91
|
|
|
91
92
|
:::
|
|
@@ -136,9 +137,10 @@ example, with Claude Desktop:
|
|
|
136
137
|
```
|
|
137
138
|
|
|
138
139
|
The client triggers the gateway's OAuth flow on first connect. With
|
|
139
|
-
`/oauth/dev-login` configured, the browser tab opens, lands on the
|
|
140
|
-
without any IdP login, and you connect each upstream through its
|
|
141
|
-
OAuth flow. Subsequent calls reuse the issued tokens until they
|
|
140
|
+
`/__zuplo/oauth/dev-login` configured, the browser tab opens, lands on the
|
|
141
|
+
consent page without any IdP login, and you connect each upstream through its
|
|
142
|
+
normal browser OAuth flow. Subsequent calls reuse the issued tokens until they
|
|
143
|
+
expire.
|
|
142
144
|
|
|
143
145
|
See [Connect MCP clients](../connect-clients/overview.mdx) for client-specific
|
|
144
146
|
snippets and the connect URL format.
|
|
@@ -31,9 +31,12 @@ export function runtimeInit(runtime: RuntimeExtensions) {
|
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
The plugin registers the OAuth metadata, authorization endpoints, consent page,
|
|
34
|
-
and upstream connect callbacks the gateway needs. It
|
|
35
|
-
MCP
|
|
36
|
-
gateway
|
|
34
|
+
and upstream connect callbacks the gateway needs. It also serves the read-only
|
|
35
|
+
[MCP Server Registry](../server-registry.mdx) by default. See the
|
|
36
|
+
[`McpGatewayPlugin` reference](../../programmable-api/mcp-gateway-plugin.mdx)
|
|
37
|
+
for all configuration options. The plugin is a no-op when no MCP-related policy
|
|
38
|
+
is present, so adding it to projects that don't yet use the gateway has zero
|
|
39
|
+
runtime cost.
|
|
37
40
|
|
|
38
41
|
## 2. Define one OAuth policy
|
|
39
42
|
|
|
@@ -185,10 +188,12 @@ For a worked example with two upstreams and the full file layout, see
|
|
|
185
188
|
|
|
186
189
|
- [`McpProxyHandler` reference](./mcp-proxy-handler.mdx) — every option and
|
|
187
190
|
every behavior of the route handler.
|
|
191
|
+
- [ZuploMcpSdk](../../programmable-api/mcp-sdk.mdx) — programmatically control
|
|
192
|
+
MCP tool results from custom handler modules.
|
|
188
193
|
- [Compatibility dates](./compatibility-dates.mdx) — why `2026-03-01` is
|
|
189
194
|
required and what older dates break.
|
|
190
195
|
- [Local development](./local-development.mdx) — dev-loop, loopback URLs, the
|
|
191
|
-
`/oauth/dev-login` shortcut, and the `workerd` restart quirk.
|
|
196
|
+
`/__zuplo/oauth/dev-login` shortcut, and the `workerd` restart quirk.
|
|
192
197
|
- [Add multiple upstream MCP servers](./multi-upstream.mdx) — one project, many
|
|
193
198
|
upstream MCP servers.
|
|
194
199
|
- [Curate the tools an upstream exposes](../how-to/curate-tools.mdx) — restrict
|