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,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Connect MCP clients"
|
|
3
|
+
sidebar_label: "Overview"
|
|
4
|
+
description:
|
|
5
|
+
Learn how MCP clients connect to a Zuplo MCP Gateway, where to find the
|
|
6
|
+
connection URL, what the OAuth flow looks like on first use, and which clients
|
|
7
|
+
support which spec features.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
The Zuplo MCP Gateway exposes each MCP route at a stable HTTPS URL that any
|
|
11
|
+
modern MCP client can connect to. Clients speak the Streamable HTTP transport,
|
|
12
|
+
complete an OAuth flow on first use, and then call tools, read resources, and
|
|
13
|
+
run prompts through the gateway just as they would against any other remote MCP
|
|
14
|
+
server.
|
|
15
|
+
|
|
16
|
+
This page covers the connection model and links to a step-by-step guide for each
|
|
17
|
+
of the major clients.
|
|
18
|
+
|
|
19
|
+
## The MCP route URL
|
|
20
|
+
|
|
21
|
+
Each MCP route in `config/routes.oas.json` is reachable at:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
https://{deploymentUrl}/{routePath}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The `{deploymentUrl}` is your project's deployment URL — for example
|
|
28
|
+
`acme-mcp-main-abc123.d2.zuplo.dev` for a default Zuplo deployment, or a custom
|
|
29
|
+
domain you configure for the project. The `{routePath}` is the path you set on
|
|
30
|
+
the route in `routes.oas.json`. A typical convention is `/mcp/<provider>-v<n>`,
|
|
31
|
+
so a Linear route looks like
|
|
32
|
+
`https://acme-mcp-main-abc123.d2.zuplo.dev/mcp/linear-v1`.
|
|
33
|
+
|
|
34
|
+
For local development with `zuplo dev`, the URL is
|
|
35
|
+
`http://127.0.0.1:9000/{routePath}` — for example
|
|
36
|
+
`http://127.0.0.1:9000/mcp/linear-v1`. See
|
|
37
|
+
[Local development](../code-config/local-development.mdx).
|
|
38
|
+
|
|
39
|
+
## Transport
|
|
40
|
+
|
|
41
|
+
The gateway uses the **Streamable HTTP** transport defined in the MCP
|
|
42
|
+
specification. Clients POST JSON-RPC requests to the MCP route URL. The gateway
|
|
43
|
+
does not currently accept GET requests for server-sent event streams — it
|
|
44
|
+
returns `405 Method Not Allowed` — so configure your client to use Streamable
|
|
45
|
+
HTTP, not the older two-endpoint HTTP+SSE transport.
|
|
46
|
+
|
|
47
|
+
For more on transports, see the
|
|
48
|
+
[MCP transports specification](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports).
|
|
49
|
+
|
|
50
|
+
## What happens on first connect
|
|
51
|
+
|
|
52
|
+
The first time a user connects, the gateway runs two distinct OAuth handshakes
|
|
53
|
+
before any tool call reaches an upstream MCP server.
|
|
54
|
+
|
|
55
|
+
1. **Discovery.** The client POSTs an MCP request to the route URL without an
|
|
56
|
+
`Authorization` header. The gateway responds with `401 Unauthorized` and a
|
|
57
|
+
`WWW-Authenticate` header that points at the gateway's
|
|
58
|
+
[Protected Resource Metadata document (RFC 9728)](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization).
|
|
59
|
+
2. **Gateway login.** The client opens the gateway's authorization endpoint in a
|
|
60
|
+
browser. The gateway redirects the user to your identity provider — Auth0,
|
|
61
|
+
Okta, Entra, Google, Cognito, or any of the other
|
|
62
|
+
[supported IdPs](../auth/overview.mdx#identity-providers) — to sign in. After
|
|
63
|
+
login, the gateway issues an access token bound to the route URL and returns
|
|
64
|
+
it to the client through the standard OAuth 2.1 Authorization Code with PKCE
|
|
65
|
+
flow.
|
|
66
|
+
3. **Upstream consent.** If the route's upstream MCP server requires per-user
|
|
67
|
+
OAuth (Linear, Notion, Stripe, GitHub, and so on), the gateway shows a
|
|
68
|
+
consent page with a **Connect** button for the upstream. Clicking **Connect**
|
|
69
|
+
opens the upstream provider's OAuth flow in the same browser. Once the
|
|
70
|
+
upstream is connected, the user clicks **Authorize** and the gateway returns
|
|
71
|
+
the access token to the client.
|
|
72
|
+
|
|
73
|
+
After the first connect, subsequent requests reuse the issued access token and
|
|
74
|
+
the stored upstream credentials. Tokens refresh automatically. If the gateway
|
|
75
|
+
needs the user to re-consent to an upstream — for example, when an upstream
|
|
76
|
+
provider revokes the gateway's credentials — the client receives a JSON-RPC
|
|
77
|
+
error with a URL to open in the browser to complete re-consent.
|
|
78
|
+
|
|
79
|
+
For the full authentication model, see
|
|
80
|
+
[Authentication overview](../auth/overview.mdx).
|
|
81
|
+
|
|
82
|
+
## Client compatibility
|
|
83
|
+
|
|
84
|
+
The table below summarizes which MCP spec features each major client supports
|
|
85
|
+
today. All clients listed here support remote Streamable HTTP and work with the
|
|
86
|
+
Zuplo MCP Gateway.
|
|
87
|
+
|
|
88
|
+
| Client | Tools | Prompts | Resources | Roots | Sampling | Elicitation | DCR | CIMD | Apps |
|
|
89
|
+
| -------------------------------------------------------------------- | :---: | :-----: | :-------: | :---: | :------: | :---------: | :-: | :--: | :--: |
|
|
90
|
+
| [Claude Desktop](./claude-desktop.mdx) | yes | yes | yes | yes | – | – | yes | – | yes |
|
|
91
|
+
| [Claude.ai (web)](./claude-desktop.mdx) | yes | yes | yes | – | – | – | yes | yes | yes |
|
|
92
|
+
| [Claude Code](./claude-code.mdx) | yes | yes | yes | yes | – | yes | yes | – | – |
|
|
93
|
+
| [ChatGPT](./chatgpt.mdx) | yes | – | – | – | – | – | yes | yes | yes |
|
|
94
|
+
| [Cursor](./cursor.mdx) | yes | yes | – | yes | – | yes | yes | – | yes |
|
|
95
|
+
| [VS Code (GitHub Copilot)](./vs-code.mdx) | yes | yes | yes | yes | yes | yes | yes | yes | yes |
|
|
96
|
+
| [Windsurf (Cascade)](./other-clients.mdx#windsurf) | yes | – | – | – | – | – | yes | – | – |
|
|
97
|
+
| [Goose](./other-clients.mdx#goose) | yes | yes | yes | yes | yes | yes | yes | – | yes |
|
|
98
|
+
| [Gemini CLI](./other-clients.mdx#gemini-cli) | yes | yes | – | – | – | – | yes | – | – |
|
|
99
|
+
| [GitHub Copilot CLI](./other-clients.mdx#github-copilot-cli) | yes | – | – | – | yes | yes | yes | – | – |
|
|
100
|
+
| [Postman](./other-clients.mdx#postman) | yes | yes | yes | – | yes | yes | – | – | yes |
|
|
101
|
+
| [MCPJam](./other-clients.mdx#mcpjam) | yes | yes | yes | – | – | yes | yes | yes | yes |
|
|
102
|
+
| [Continue](./other-clients.mdx#continue) | yes | yes | yes | – | – | – | – | – | yes |
|
|
103
|
+
| [LibreChat](./other-clients.mdx#librechat) | yes | – | – | – | – | – | yes | – | – |
|
|
104
|
+
| [JetBrains AI Assistant](./other-clients.mdx#jetbrains-ai-assistant) | yes | – | – | – | – | – | – | – | – |
|
|
105
|
+
|
|
106
|
+
Capability data is sourced from the
|
|
107
|
+
[official MCP clients page](https://modelcontextprotocol.io/clients). Clients
|
|
108
|
+
ship new features frequently; check the client's own documentation for the
|
|
109
|
+
latest support status.
|
|
110
|
+
|
|
111
|
+
:::note
|
|
112
|
+
|
|
113
|
+
The gateway exposes whatever capabilities the upstream MCP servers expose. If an
|
|
114
|
+
upstream server only ships tools, a client that supports resources won't see
|
|
115
|
+
anything in `resources/list` for that server. The compatibility matrix above
|
|
116
|
+
tracks **what each client can consume**, not what the gateway forwards.
|
|
117
|
+
|
|
118
|
+
:::
|
|
119
|
+
|
|
120
|
+
## Per-client guides
|
|
121
|
+
|
|
122
|
+
- [Claude Desktop](./claude-desktop.mdx) — add via `claude_desktop_config.json`.
|
|
123
|
+
- [Claude Code](./claude-code.mdx) — add via the `claude mcp add` CLI command.
|
|
124
|
+
- [ChatGPT](./chatgpt.mdx) — add via Settings → Connectors (Developer Mode
|
|
125
|
+
required).
|
|
126
|
+
- [Cursor](./cursor.mdx) — add via `.cursor/mcp.json` or the one-click install
|
|
127
|
+
link.
|
|
128
|
+
- [VS Code](./vs-code.mdx) — add via `.vscode/mcp.json` or the `code --add-mcp`
|
|
129
|
+
CLI command.
|
|
130
|
+
- [Other clients](./other-clients.mdx) — Windsurf, Goose, Gemini CLI, GitHub
|
|
131
|
+
Copilot CLI, Postman, MCPJam, Continue, LibreChat, JetBrains AI Assistant.
|
|
132
|
+
|
|
133
|
+
## Related
|
|
134
|
+
|
|
135
|
+
- [How the MCP Gateway works](../how-it-works.mdx)
|
|
136
|
+
- [Authentication overview](../auth/overview.mdx)
|
|
137
|
+
- [Configuring the MCP Gateway with code](../code-config/overview.mdx)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Connect VS Code (GitHub Copilot)"
|
|
3
|
+
sidebar_label: "VS Code"
|
|
4
|
+
description:
|
|
5
|
+
Connect VS Code with GitHub Copilot to a Zuplo MCP Gateway through
|
|
6
|
+
`.vscode/mcp.json`, the `code --add-mcp` CLI, or the Extensions view, and use
|
|
7
|
+
gateway tools in Copilot Chat's Agent mode.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
VS Code with GitHub Copilot connects to remote MCP servers and exposes their
|
|
11
|
+
tools to Copilot Chat's **Agent mode**. Add the Zuplo MCP Gateway through a
|
|
12
|
+
`.vscode/mcp.json` file in your workspace, the `code` CLI, or the Extensions
|
|
13
|
+
view.
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
- A Zuplo project with the MCP Gateway plugin configured and at least one MCP
|
|
18
|
+
route. See the [quickstart](../quickstart.mdx) if you haven't set one up yet.
|
|
19
|
+
- VS Code installed.
|
|
20
|
+
- The GitHub Copilot extension installed and signed in.
|
|
21
|
+
|
|
22
|
+
## Get the route URL
|
|
23
|
+
|
|
24
|
+
Each MCP route in `config/routes.oas.json` is reachable at
|
|
25
|
+
`https://{deploymentUrl}/{routePath}` once deployed — for example
|
|
26
|
+
`https://{deploymentUrl}/mcp/linear-v1`.
|
|
27
|
+
|
|
28
|
+
## Add the gateway
|
|
29
|
+
|
|
30
|
+
There are three supported ways to register the gateway.
|
|
31
|
+
|
|
32
|
+
### Option 1: `.vscode/mcp.json` in your workspace
|
|
33
|
+
|
|
34
|
+
Create or open `.vscode/mcp.json` at the root of your workspace, then add an
|
|
35
|
+
HTTP server entry pointing at the route URL:
|
|
36
|
+
|
|
37
|
+
```json title=".vscode/mcp.json"
|
|
38
|
+
{
|
|
39
|
+
"servers": {
|
|
40
|
+
"zuplo": {
|
|
41
|
+
"type": "http",
|
|
42
|
+
"url": "https://{deploymentUrl}/{routePath}"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Commit the file to source control to share the configuration with your team.
|
|
49
|
+
|
|
50
|
+
### Option 2: `code --add-mcp` CLI
|
|
51
|
+
|
|
52
|
+
Use the VS Code CLI to add a server to your user profile or to a workspace:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
code --add-mcp '{"name":"zuplo","type":"http","url":"https://{deploymentUrl}/{routePath}"}'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
VS Code prompts you to confirm the server registration and to choose between
|
|
59
|
+
user-profile and workspace scope.
|
|
60
|
+
|
|
61
|
+
### Option 3: Extensions view
|
|
62
|
+
|
|
63
|
+
1. Open the **Extensions** view in VS Code.
|
|
64
|
+
2. Type `@mcp` in the search field. VS Code shows the curated MCP server gallery
|
|
65
|
+
alongside any servers you've already registered.
|
|
66
|
+
3. To add a custom server (the Zuplo gateway), use the **MCP: Add Server**
|
|
67
|
+
command from the Command Palette and paste your route URL when prompted, or
|
|
68
|
+
open **MCP: Open User Configuration** to edit `mcp.json` directly.
|
|
69
|
+
|
|
70
|
+
## Authenticate
|
|
71
|
+
|
|
72
|
+
The first time VS Code talks to the gateway, the gateway returns
|
|
73
|
+
`401 Unauthorized` and VS Code opens the OAuth flow in your default browser.
|
|
74
|
+
|
|
75
|
+
<Stepper>
|
|
76
|
+
|
|
77
|
+
1. Sign in to the gateway with your identity provider.
|
|
78
|
+
2. On the gateway's consent page, click **Connect** next to the upstream MCP
|
|
79
|
+
server and complete its OAuth flow.
|
|
80
|
+
3. Click **Authorize** to finish. VS Code receives the access token and marks
|
|
81
|
+
the server as connected.
|
|
82
|
+
|
|
83
|
+
</Stepper>
|
|
84
|
+
|
|
85
|
+
Tokens refresh automatically. To revoke access, remove the server from
|
|
86
|
+
`mcp.json` (or from MCP settings) and re-add it to start over.
|
|
87
|
+
|
|
88
|
+
## Use tools in Copilot Chat
|
|
89
|
+
|
|
90
|
+
Once the server is connected, open Copilot Chat and switch to **Agent** mode
|
|
91
|
+
(the mode picker is at the top of the chat panel). Tools from the gateway appear
|
|
92
|
+
in the tool picker — click the tools icon to see them and to enable or disable
|
|
93
|
+
individual tools per chat. Reference resources from the gateway by typing `#` in
|
|
94
|
+
your prompt.
|
|
95
|
+
|
|
96
|
+
## What VS Code supports
|
|
97
|
+
|
|
98
|
+
VS Code's MCP client is one of the most feature-complete on the market. With the
|
|
99
|
+
Zuplo MCP Gateway it supports:
|
|
100
|
+
|
|
101
|
+
- **Tools** — invoke gateway-exposed tools from Agent mode.
|
|
102
|
+
- **Prompts** — surface prompts as slash commands.
|
|
103
|
+
- **Resources** — reference resources with `#` in prompts.
|
|
104
|
+
- **Roots** — declare workspace folders as roots.
|
|
105
|
+
- **Sampling** — handle server-initiated sampling requests, including the
|
|
106
|
+
`tools` and `toolChoice` parameters added in MCP `2025-11-25`.
|
|
107
|
+
- **Elicitation** — handle both form-mode and URL-mode elicitation requests,
|
|
108
|
+
including upstream re-authorization prompts.
|
|
109
|
+
- **MCP Apps** — render interactive HTML widgets inline in the chat.
|
|
110
|
+
- **DCR** and **CIMD** — both client registration paths are supported.
|
|
111
|
+
|
|
112
|
+
## Troubleshooting
|
|
113
|
+
|
|
114
|
+
- **Server stays in "Pending" state.** Confirm the URL in `mcp.json` is
|
|
115
|
+
reachable. VS Code shows server logs in the **Output** panel under **MCP** —
|
|
116
|
+
check there for the exact failure reason.
|
|
117
|
+
- **Tools do not appear in Copilot Chat.** Confirm Copilot Chat is in **Agent**
|
|
118
|
+
mode. Tool calling is gated to that mode.
|
|
119
|
+
- **OAuth flow does not start.** Some corporate proxies block the local
|
|
120
|
+
callback. Try connecting from outside the proxy or use the VS Code setting to
|
|
121
|
+
override the callback port.
|
|
122
|
+
|
|
123
|
+
## Related
|
|
124
|
+
|
|
125
|
+
- [Connect MCP clients overview](./overview.mdx)
|
|
126
|
+
- VS Code's docs:
|
|
127
|
+
[Add and manage MCP servers in VS Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers)
|
|
128
|
+
- [Authentication overview](../auth/overview.mdx)
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "How the MCP Gateway works"
|
|
3
|
+
sidebar_label: "How it works"
|
|
4
|
+
description:
|
|
5
|
+
Architecture overview — request lifecycle, the two OAuth surfaces, the
|
|
6
|
+
Streamable HTTP transport, and the configuration model.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
The MCP Gateway is a set of policies and a route handler that run inside any
|
|
10
|
+
Zuplo project. A single deployment hosts any number of public MCP routes, each
|
|
11
|
+
pointing at a different upstream MCP server. The gateway runs its own OAuth 2.1
|
|
12
|
+
authorization server for inbound clients and acts as an OAuth client to each
|
|
13
|
+
upstream provider.
|
|
14
|
+
|
|
15
|
+
## Request lifecycle
|
|
16
|
+
|
|
17
|
+
The diagram below shows a first-time call from an MCP client to a route that
|
|
18
|
+
wires a single OAuth-protected upstream. Once tokens are issued and the upstream
|
|
19
|
+
connection exists, the gateway skips the OAuth dance and goes straight from the
|
|
20
|
+
bearer-token check to the upstream proxy.
|
|
21
|
+
|
|
22
|
+
<Diagram height="h-72">
|
|
23
|
+
<DiagramNode id="client">MCP Client</DiagramNode>
|
|
24
|
+
<DiagramGroup id="gateway" label="Zuplo MCP Gateway">
|
|
25
|
+
<DiagramNode id="oauth" variant="zuplo">
|
|
26
|
+
OAuth endpoints
|
|
27
|
+
</DiagramNode>
|
|
28
|
+
<DiagramNode id="route" variant="zuplo">
|
|
29
|
+
MCP route
|
|
30
|
+
</DiagramNode>
|
|
31
|
+
</DiagramGroup>
|
|
32
|
+
<DiagramNode id="idp">Identity Provider</DiagramNode>
|
|
33
|
+
<DiagramNode id="upstream">Upstream MCP Server</DiagramNode>
|
|
34
|
+
<DiagramEdge from="client" to="oauth" label="Discover + auth" />
|
|
35
|
+
<DiagramEdge from="oauth" to="idp" label="Browser login" />
|
|
36
|
+
<DiagramEdge from="client" to="route" label="Bearer token" />
|
|
37
|
+
<DiagramEdge from="route" to="upstream" label="Proxied request" />
|
|
38
|
+
</Diagram>
|
|
39
|
+
|
|
40
|
+
The flow in detail, for the first call from a new client to an OAuth-protected
|
|
41
|
+
upstream:
|
|
42
|
+
|
|
43
|
+
1. The client POSTs to the MCP route with no token.
|
|
44
|
+
2. The gateway returns `401` with
|
|
45
|
+
`WWW-Authenticate: Bearer resource_metadata=...`.
|
|
46
|
+
3. The client fetches the Protected Resource Metadata document and discovers the
|
|
47
|
+
gateway's authorization server.
|
|
48
|
+
4. The client fetches the AS metadata, registers via DCR (or uses a CIMD client
|
|
49
|
+
ID), and starts the authorization flow with PKCE and a `resource` parameter.
|
|
50
|
+
5. The gateway redirects the user's browser to the configured identity provider
|
|
51
|
+
for login.
|
|
52
|
+
6. After login, the gateway renders a consent page that lists every upstream the
|
|
53
|
+
route requires.
|
|
54
|
+
7. The user completes upstream OAuth for each required upstream — the gateway
|
|
55
|
+
stores per-user tokens encrypted at rest.
|
|
56
|
+
8. The user approves consent. The gateway redirects the client back with an
|
|
57
|
+
authorization code.
|
|
58
|
+
9. The client exchanges the code at `/oauth/token` and receives an access token
|
|
59
|
+
scoped to `mcp:tools`.
|
|
60
|
+
10. The client POSTs to the MCP route with the bearer token. The gateway
|
|
61
|
+
validates the token, attaches the user's upstream credential, and proxies to
|
|
62
|
+
the upstream MCP server.
|
|
63
|
+
|
|
64
|
+
Once tokens are issued and the upstream connection exists, only step 10 runs on
|
|
65
|
+
subsequent calls.
|
|
66
|
+
|
|
67
|
+
Three details that come up during debugging:
|
|
68
|
+
|
|
69
|
+
- The `resource` parameter (RFC 8707) is required on `/oauth/authorize` and
|
|
70
|
+
`/oauth/token`. The gateway rejects tokens whose audience doesn't match the
|
|
71
|
+
route they're being used against.
|
|
72
|
+
- The consent screen lists the upstream the route depends on with a **Connect**
|
|
73
|
+
button. The user can't approve the grant until the upstream is connected.
|
|
74
|
+
- The upstream OAuth flow runs once per (user, upstream) pair. Subsequent
|
|
75
|
+
requests reuse the stored credential. If an upstream returns a 401 mid-call,
|
|
76
|
+
the gateway refreshes and retries once before propagating the error.
|
|
77
|
+
|
|
78
|
+
## Two OAuth surfaces
|
|
79
|
+
|
|
80
|
+
The gateway plays two OAuth roles simultaneously. The inbound role — as an OAuth
|
|
81
|
+
server for MCP clients — and the outbound role — as an OAuth client to each
|
|
82
|
+
upstream — use different policies and different credential stores.
|
|
83
|
+
|
|
84
|
+
### Downstream — gateway as OAuth 2.1 server
|
|
85
|
+
|
|
86
|
+
The gateway implements the MCP authorization spec from the perspective of a
|
|
87
|
+
Resource Server and an Authorization Server. MCP clients talk OAuth to the
|
|
88
|
+
gateway, not to the upstream providers. Standards observed:
|
|
89
|
+
|
|
90
|
+
- **RFC 8414** Authorization Server Metadata and **OpenID Connect Discovery
|
|
91
|
+
1.0** for AS discovery.
|
|
92
|
+
- **RFC 9728** Protected Resource Metadata for advertising the AS.
|
|
93
|
+
- **RFC 7591** Dynamic Client Registration and **OAuth Client ID Metadata
|
|
94
|
+
Documents** (CIMD) for client registration. CIMD is the recommended path; DCR
|
|
95
|
+
is supported for clients that don't speak it.
|
|
96
|
+
- **RFC 7636** PKCE with S256 required.
|
|
97
|
+
- **RFC 8707** Resource Indicators — the `resource` parameter is required on
|
|
98
|
+
every authorization and token request.
|
|
99
|
+
- **RFC 6750** Bearer tokens — the gateway issues opaque tokens carried in
|
|
100
|
+
`Authorization: Bearer` headers.
|
|
101
|
+
|
|
102
|
+
The gateway delegates user authentication to a configured OIDC identity provider
|
|
103
|
+
(Auth0 through `McpAuth0OAuthInboundPolicy` or generic OIDC through
|
|
104
|
+
`McpOAuthInboundPolicy`). The provider's tokens never leave the gateway — the
|
|
105
|
+
gateway issues its own opaque access tokens, scoped to `mcp:tools`, and binds
|
|
106
|
+
each to one specific MCP route. The route binding is a deliberate blast-radius
|
|
107
|
+
constraint: a token issued for `/mcp/linear-v1` can't be replayed against
|
|
108
|
+
`/mcp/stripe-v1`, so a stolen token from one upstream stays confined to that
|
|
109
|
+
upstream.
|
|
110
|
+
|
|
111
|
+
Token passthrough is explicitly forbidden by the spec, and the gateway enforces
|
|
112
|
+
it: inbound auth headers don't leak to the upstream.
|
|
113
|
+
|
|
114
|
+
### Upstream — gateway as OAuth client
|
|
115
|
+
|
|
116
|
+
For each upstream MCP server that requires OAuth, the gateway acts as a standard
|
|
117
|
+
OAuth client.
|
|
118
|
+
|
|
119
|
+
- **Per-user OAuth (`authMode: "user-oauth"`)** — every end user goes through a
|
|
120
|
+
one-time consent. The gateway stores their access and refresh tokens encrypted
|
|
121
|
+
at rest, keyed by user. Token refresh is automatic.
|
|
122
|
+
- **Shared OAuth (`authMode: "shared-oauth"`)** — one upstream connection shared
|
|
123
|
+
across every user of the gateway. The connection is established by an
|
|
124
|
+
administrator through a special connect flow.
|
|
125
|
+
|
|
126
|
+
Client registration with the upstream supports two modes:
|
|
127
|
+
|
|
128
|
+
- `clientRegistration: { mode: "auto" }` (the default) — the gateway publishes a
|
|
129
|
+
per-upstream OAuth Client ID Metadata Document at
|
|
130
|
+
`/.well-known/oauth-client/<connection>` and tells the upstream that URL is
|
|
131
|
+
the `client_id`. If the upstream doesn't support CIMD, the gateway falls back
|
|
132
|
+
to RFC 7591 Dynamic Client Registration.
|
|
133
|
+
- `clientRegistration: { mode: "manual" }` — supply a pre-registered `clientId`
|
|
134
|
+
and `clientSecret` (and optional auth method).
|
|
135
|
+
|
|
136
|
+
When the gateway needs an upstream connection it doesn't have yet, the gateway
|
|
137
|
+
returns a JSON-RPC error with a URL to open in a browser. Modern MCP clients pop
|
|
138
|
+
the browser automatically; older ones surface the URL for the user to open
|
|
139
|
+
manually.
|
|
140
|
+
|
|
141
|
+
## Transport — Streamable HTTP, POST only
|
|
142
|
+
|
|
143
|
+
Every MCP route uses the
|
|
144
|
+
[Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports)
|
|
145
|
+
defined in the MCP spec. The gateway accepts POST requests only:
|
|
146
|
+
|
|
147
|
+
- `POST` on the route path carries the JSON-RPC payload.
|
|
148
|
+
- `GET` on the same path returns `405 Method Not Allowed` with `Allow: POST`.
|
|
149
|
+
The gateway doesn't open SSE streams for server-initiated messages.
|
|
150
|
+
|
|
151
|
+
Route paths are whatever you set in `routes.oas.json` — `/mcp/<provider>-v<n>`
|
|
152
|
+
is the recommended convention (and what the dogfood gateway uses), but any path
|
|
153
|
+
the OpenAPI router accepts works.
|
|
154
|
+
|
|
155
|
+
The gateway is **stateless**. It does not maintain MCP sessions, doesn't track
|
|
156
|
+
subscriptions, and doesn't emit server-initiated notifications. Statelessness is
|
|
157
|
+
what lets the gateway run on Zuplo's edge runtime and scale horizontally without
|
|
158
|
+
session affinity — any node can serve any request. Stateful MCP features
|
|
159
|
+
(long-running subscriptions, server-initiated sampling) aren't supported through
|
|
160
|
+
the gateway today.
|
|
161
|
+
|
|
162
|
+
## Configuration model
|
|
163
|
+
|
|
164
|
+
The MCP Gateway is configured the same way as the rest of a Zuplo project: an
|
|
165
|
+
OpenAPI route file, a policy library, and a runtime plugin registration. Every
|
|
166
|
+
project that uses the gateway has the same shape:
|
|
167
|
+
|
|
168
|
+
| Piece | Lives in | Purpose |
|
|
169
|
+
| ---------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
170
|
+
| `compatibilityDate >= 2026-03-01` | `zuplo.jsonc` | Unlocks MCP Gateway features. Required. |
|
|
171
|
+
| `McpGatewayPlugin` | `modules/zuplo.runtime.ts` | Registers the OAuth metadata, authorization endpoints, consent page, and upstream connect callbacks. |
|
|
172
|
+
| One MCP OAuth policy | `config/policies.json` | Authenticates inbound MCP requests against your identity provider. One per project — pick the [wrapper for your IdP](./auth/overview.mdx#identity-providers) (Auth0, Cognito, Clerk, Entra, Google, Keycloak, Logto, Okta, OneLogin, Ping, WorkOS) or `mcp-oauth-inbound` for any other OIDC provider. |
|
|
173
|
+
| One `mcp-token-exchange-inbound` policy per upstream | `config/policies.json` | Resolves the user's upstream credential and attaches it as the upstream `Authorization` header. Omit for non-OAuth upstreams. |
|
|
174
|
+
| Optional `mcp-capability-filter-inbound` policy | `config/policies.json` | Curates the tools, prompts, resources, and resource templates the route exposes. |
|
|
175
|
+
| One route per upstream | `config/routes.oas.json` | Uses `McpProxyHandler` with the upstream URL as `rewritePattern`. Attaches the OAuth policy + token exchange policy. |
|
|
176
|
+
|
|
177
|
+
A minimal route looks like this:
|
|
178
|
+
|
|
179
|
+
```jsonc title="config/routes.oas.json"
|
|
180
|
+
"/mcp/linear-v1": {
|
|
181
|
+
"get,post": {
|
|
182
|
+
"operationId": "linear-mcp-server",
|
|
183
|
+
"x-zuplo-route": {
|
|
184
|
+
"corsPolicy": "none",
|
|
185
|
+
"handler": {
|
|
186
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
187
|
+
"export": "McpProxyHandler",
|
|
188
|
+
"options": { "rewritePattern": "https://mcp.linear.app/mcp" }
|
|
189
|
+
},
|
|
190
|
+
"policies": {
|
|
191
|
+
"inbound": ["auth0-managed-oauth", "mcp-token-exchange-linear"]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The plugin registration:
|
|
199
|
+
|
|
200
|
+
```ts title="modules/zuplo.runtime.ts"
|
|
201
|
+
import { RuntimeExtensions } from "@zuplo/runtime";
|
|
202
|
+
import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway";
|
|
203
|
+
|
|
204
|
+
export function runtimeInit(runtime: RuntimeExtensions) {
|
|
205
|
+
runtime.addPlugin(new McpGatewayPlugin());
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
The `operationId` on each MCP route is more than a label — it identifies the MCP
|
|
210
|
+
route and is the `virtualServerName` in analytics. Changing it strands all
|
|
211
|
+
stored tokens and per-user upstream connections.
|
|
212
|
+
|
|
213
|
+
:::caution
|
|
214
|
+
|
|
215
|
+
MCP Gateway features require `compatibilityDate >= 2026-03-01` in `zuplo.jsonc`.
|
|
216
|
+
See [Compatibility dates](./code-config/compatibility-dates.mdx).
|
|
217
|
+
|
|
218
|
+
:::
|
|
219
|
+
|
|
220
|
+
### Inbound policy chain
|
|
221
|
+
|
|
222
|
+
For each request to an MCP route, the policies run in this order:
|
|
223
|
+
|
|
224
|
+
1. **MCP OAuth policy** — one of the
|
|
225
|
+
[IdP-specific wrappers](./auth/overview.mdx#identity-providers)
|
|
226
|
+
(`mcp-auth0-oauth-inbound`, `mcp-okta-oauth-inbound`,
|
|
227
|
+
`mcp-entra-oauth-inbound`, and so on) or the generic `mcp-oauth-inbound`.
|
|
228
|
+
Validates the gateway-issued bearer token, asserts audience binding and
|
|
229
|
+
scope.
|
|
230
|
+
2. **MCP token-exchange policy** (`mcp-token-exchange-inbound`) — resolves the
|
|
231
|
+
right upstream credential for the authenticated user. If the user hasn't
|
|
232
|
+
connected this upstream yet, the policy returns a connect-required error.
|
|
233
|
+
3. **Capability filter policy** (`mcp-capability-filter-inbound`, optional) —
|
|
234
|
+
filters the upstream's `tools/list`, `prompts/list`, `resources/list`, and
|
|
235
|
+
`resources/templates/list` responses, and blocks calls to hidden capabilities
|
|
236
|
+
with `MethodNotFound`.
|
|
237
|
+
|
|
238
|
+
The handler — `McpProxyHandler` — runs after the policies, forwards the request
|
|
239
|
+
to the upstream URL, and emits capability analytics events.
|
|
240
|
+
|
|
241
|
+
## What the gateway does not do
|
|
242
|
+
|
|
243
|
+
A few capabilities are intentionally out of scope, at least today:
|
|
244
|
+
|
|
245
|
+
- **No stateful sessions.** The gateway doesn't open SSE streams, doesn't track
|
|
246
|
+
`MCP-Session-Id`, and doesn't proxy server-initiated requests.
|
|
247
|
+
- **No `tools/list` caching.** Every request goes upstream. If an upstream is
|
|
248
|
+
slow to list capabilities, callers feel it.
|
|
249
|
+
- **No prompt-injection or PII scanning at the policy level.** These belong in a
|
|
250
|
+
separate inbound policy and can be composed alongside the MCP policies through
|
|
251
|
+
Zuplo's standard policy model.
|
|
252
|
+
- **No rate limiting on OAuth endpoints out of the box.** Add Zuplo's built-in
|
|
253
|
+
`rate-limit-inbound` policy to those routes if needed.
|
|
254
|
+
|
|
255
|
+
## Related
|
|
256
|
+
|
|
257
|
+
- [Set up an MCP Gateway](./code-config/overview.mdx) — the how-to that puts
|
|
258
|
+
this conceptual model into practice.
|
|
259
|
+
- [Quickstart](./quickstart.mdx) — add the MCP Gateway plugin to a Zuplo project
|
|
260
|
+
and front your first upstream.
|
|
261
|
+
- [Authentication overview](./auth/overview.mdx) — the two OAuth layers expanded
|
|
262
|
+
with the full standards table.
|
|
263
|
+
- [Reference](./reference.mdx) — the full URL catalog, default TTLs,
|
|
264
|
+
compatibility date, and OAuth metadata extensions.
|
|
265
|
+
- [Troubleshooting](./troubleshooting.mdx) — the gotchas that catch most people
|
|
266
|
+
the first time.
|