zuplo 6.70.56 → 6.70.59
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/limits.mdx +1 -1
- package/docs/articles/mcp-quickstart-local.mdx +99 -0
- package/docs/articles/mcp-quickstart.mdx +2 -2
- package/docs/articles/step-1-setup-basic-gateway-local.mdx +60 -84
- package/docs/articles/step-2-add-rate-limiting-local.mdx +46 -77
- package/docs/articles/step-2-add-rate-limiting.mdx +0 -5
- package/docs/articles/step-3-add-api-key-auth-local.mdx +80 -130
- package/docs/articles/step-3-add-api-key-auth.mdx +0 -5
- package/docs/articles/step-4-deploying-to-the-edge-local.mdx +106 -0
- package/docs/articles/step-5-dynamic-rate-limiting-local.mdx +180 -0
- package/docs/articles/support.mdx +8 -8
- package/docs/dev-portal/zudoku/components/callout.mdx +126 -8
- package/docs/dev-portal/zudoku/components/head.mdx +2 -12
- package/docs/dev-portal/zudoku/customization/colors-theme.mdx +19 -0
- package/docs/dev-portal/zudoku/markdown/admonitions.md +79 -0
- package/docs/mcp-gateway/code-config/overview.mdx +13 -28
- package/docs/mcp-gateway/how-to/connect-upstream-api-key.mdx +146 -0
- package/docs/mcp-gateway/how-to/curate-tools-local.mdx +288 -0
- package/docs/mcp-gateway/how-to/curate-tools.mdx +103 -257
- package/docs/mcp-gateway/quickstart-local.mdx +291 -0
- package/docs/mcp-gateway/quickstart.mdx +208 -189
- package/docs/policies/monetization-inbound/schema.json +11 -1
- package/package.json +4 -4
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "MCP Gateway quickstart (Local Dev)"
|
|
3
|
+
sidebar_label: "Quickstart (Local Dev)"
|
|
4
|
+
description:
|
|
5
|
+
Build an MCP Gateway locally with the Zuplo CLI. Register the plugin, add one
|
|
6
|
+
upstream MCP server, run it with the loopback dev-login shortcut, and connect
|
|
7
|
+
Claude Desktop. No identity provider setup required to start.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<QuickstartPicker mode="local" alternateLink="/mcp-gateway/quickstart" />
|
|
11
|
+
|
|
12
|
+
Build a Zuplo MCP Gateway fronting Linear, running locally at
|
|
13
|
+
`http://127.0.0.1:9000/mcp/linear-v1`. By the end, Claude Desktop connects over
|
|
14
|
+
the gateway's per-user OAuth flow and answers "list my open Linear issues" with
|
|
15
|
+
real results.
|
|
16
|
+
|
|
17
|
+
Any Zuplo project becomes a gateway by adding a plugin, a couple of policies,
|
|
18
|
+
and a route. This guide uses Linear as the upstream and the built-in
|
|
19
|
+
**dev-login** shortcut for sign-in, so you skip identity-provider setup to try
|
|
20
|
+
it out. For production, swap in your provider: the gateway wraps Auth0, Okta,
|
|
21
|
+
Microsoft Entra, Google, Clerk, Cognito, Keycloak, Logto, OneLogin, PingOne, and
|
|
22
|
+
WorkOS, plus a generic OIDC fallback. See the
|
|
23
|
+
[provider catalog](./auth/overview.mdx#identity-providers).
|
|
24
|
+
|
|
25
|
+
Prefer the browser with no local setup? The
|
|
26
|
+
[Portal quickstart](./quickstart.mdx) reaches the same result through the Zuplo
|
|
27
|
+
Portal UI.
|
|
28
|
+
|
|
29
|
+
## Prerequisites
|
|
30
|
+
|
|
31
|
+
- [Node.js](https://nodejs.org/en/download) 20 or higher.
|
|
32
|
+
- A local Zuplo project. Create an empty one with:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx create-zuplo-api@latest --empty
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then `cd` into the new directory. See
|
|
39
|
+
[`create-zuplo-api`](../cli/create-zuplo-api.mdx) for other options, or
|
|
40
|
+
[import an existing portal project](../articles/local-development.mdx#import-your-existing-project)
|
|
41
|
+
by connecting it to Git and cloning it.
|
|
42
|
+
|
|
43
|
+
:::note
|
|
44
|
+
|
|
45
|
+
New projects created with `create-zuplo-api` ship a recent `compatibilityDate`,
|
|
46
|
+
so MCP Gateway features work out of the box. If you're adding the gateway to an
|
|
47
|
+
older project and the build complains about the compatibility date, see
|
|
48
|
+
[Compatibility dates](./code-config/compatibility-dates.mdx).
|
|
49
|
+
|
|
50
|
+
:::
|
|
51
|
+
|
|
52
|
+
<Stepper>
|
|
53
|
+
|
|
54
|
+
1. **Register the MCP Gateway plugin**
|
|
55
|
+
|
|
56
|
+
Open `modules/zuplo.runtime.ts` (create it if it doesn't exist) and register
|
|
57
|
+
`McpGatewayPlugin`:
|
|
58
|
+
|
|
59
|
+
```ts title="modules/zuplo.runtime.ts"
|
|
60
|
+
import { RuntimeExtensions } from "@zuplo/runtime";
|
|
61
|
+
import { McpGatewayPlugin } from "@zuplo/runtime/mcp-gateway";
|
|
62
|
+
|
|
63
|
+
export function runtimeInit(runtime: RuntimeExtensions) {
|
|
64
|
+
runtime.addPlugin(new McpGatewayPlugin());
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The plugin registers the OAuth metadata, authorization endpoints, consent
|
|
69
|
+
page, and upstream connect callbacks the gateway needs.
|
|
70
|
+
|
|
71
|
+
2. **Add an OAuth policy with the dev-login shortcut**
|
|
72
|
+
|
|
73
|
+
Setting up a real identity provider for local development is friction. You'd
|
|
74
|
+
register a loopback callback, manage test users, and so on. The gateway
|
|
75
|
+
exposes a loopback-only shortcut that skips the IdP round-trip entirely and
|
|
76
|
+
signs you in as a fixed `dev-browser-user`.
|
|
77
|
+
|
|
78
|
+
Open `config/policies.json` and add the generic OAuth policy pointed at the
|
|
79
|
+
dev-login URL:
|
|
80
|
+
|
|
81
|
+
```json title="config/policies.json"
|
|
82
|
+
{
|
|
83
|
+
"name": "dev-oauth",
|
|
84
|
+
"policyType": "mcp-oauth-inbound",
|
|
85
|
+
"handler": {
|
|
86
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
87
|
+
"export": "McpOAuthInboundPolicy",
|
|
88
|
+
"options": {
|
|
89
|
+
"oidc": {
|
|
90
|
+
"issuer": "http://127.0.0.1:9000",
|
|
91
|
+
"jwksUrl": "http://127.0.0.1:9000/.well-known/jwks.json"
|
|
92
|
+
},
|
|
93
|
+
"browserLogin": {
|
|
94
|
+
"url": "http://127.0.0.1:9000/oauth/dev-login"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
:::caution
|
|
102
|
+
|
|
103
|
+
`/oauth/dev-login` returns `403 Forbidden` for any request that doesn't
|
|
104
|
+
arrive over loopback, so it's safe to leave configured, but only useful in
|
|
105
|
+
local dev. Production deployments should use a real OIDC provider through one
|
|
106
|
+
of the [IdP wrappers](./auth/overview.mdx#identity-providers). A common
|
|
107
|
+
pattern is keeping two OAuth policies (one for production, one for dev) and
|
|
108
|
+
selecting between them in `routes.oas.json` by environment.
|
|
109
|
+
|
|
110
|
+
:::
|
|
111
|
+
|
|
112
|
+
When you do switch to a real provider, its policy reads credentials from
|
|
113
|
+
`$env(...)` references. Define those values in a `.env` file at the project
|
|
114
|
+
root:
|
|
115
|
+
|
|
116
|
+
```bash title=".env"
|
|
117
|
+
MCP_AUTH0_DOMAIN=your-tenant.us.auth0.com
|
|
118
|
+
MCP_AUTH0_CLIENT_ID=your-auth0-web-app-client-id
|
|
119
|
+
MCP_AUTH0_CLIENT_SECRET=your-auth0-web-app-client-secret
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`.env` is read when `npm run dev` starts, so restart the dev server after
|
|
123
|
+
adding or changing a variable. Never commit `.env`. Check in a `.env.example`
|
|
124
|
+
with placeholder values instead. The dev-login shortcut above needs no
|
|
125
|
+
environment variables, so you can skip this until you wire up a provider.
|
|
126
|
+
|
|
127
|
+
3. **Add a token-exchange policy for the upstream**
|
|
128
|
+
|
|
129
|
+
Each OAuth-protected upstream gets its own `mcp-token-exchange-inbound`
|
|
130
|
+
policy. It looks up the user's upstream credential and attaches it as the
|
|
131
|
+
upstream `Authorization` header. Add this entry to `config/policies.json`:
|
|
132
|
+
|
|
133
|
+
```json title="config/policies.json"
|
|
134
|
+
{
|
|
135
|
+
"name": "mcp-token-exchange-linear",
|
|
136
|
+
"policyType": "mcp-token-exchange-inbound",
|
|
137
|
+
"handler": {
|
|
138
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
139
|
+
"export": "McpTokenExchangeInboundPolicy",
|
|
140
|
+
"options": {
|
|
141
|
+
"displayName": "Linear",
|
|
142
|
+
"protectedResourceMetadataUrl": "https://mcp.linear.app/.well-known/oauth-protected-resource",
|
|
143
|
+
"authMode": "user-oauth",
|
|
144
|
+
"scopes": [],
|
|
145
|
+
"clientRegistration": { "mode": "auto" }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`authMode: "user-oauth"` means each user connects their own Linear account
|
|
152
|
+
the first time they call the route. `clientRegistration: { "mode": "auto" }`
|
|
153
|
+
lets the gateway register itself with Linear's OAuth server on demand, so no
|
|
154
|
+
upstream client credentials in source control.
|
|
155
|
+
|
|
156
|
+
4. **Add the route**
|
|
157
|
+
|
|
158
|
+
Open `config/routes.oas.json` and add an MCP route. The handler points at
|
|
159
|
+
Linear's MCP server URL; the inbound policy chain runs the OAuth policy
|
|
160
|
+
followed by the token-exchange policy:
|
|
161
|
+
|
|
162
|
+
```json title="config/routes.oas.json"
|
|
163
|
+
{
|
|
164
|
+
"openapi": "3.1.0",
|
|
165
|
+
"info": { "title": "MCP Gateway", "version": "0.1.0" },
|
|
166
|
+
"paths": {
|
|
167
|
+
"/mcp/linear-v1": {
|
|
168
|
+
"get,post": {
|
|
169
|
+
"operationId": "linear-mcp-server",
|
|
170
|
+
"summary": "Linear MCP Proxy",
|
|
171
|
+
"x-zuplo-route": {
|
|
172
|
+
"corsPolicy": "none",
|
|
173
|
+
"handler": {
|
|
174
|
+
"module": "$import(@zuplo/runtime/mcp-gateway)",
|
|
175
|
+
"export": "McpProxyHandler",
|
|
176
|
+
"options": {
|
|
177
|
+
"rewritePattern": "https://mcp.linear.app/mcp"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"policies": {
|
|
181
|
+
"inbound": ["dev-oauth", "mcp-token-exchange-linear"]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`operationId` is the stable identifier for the route. It appears in analytics
|
|
191
|
+
and is part of the per-user upstream connection key, so pick it once and
|
|
192
|
+
don't change it. The path is whatever you set; `/mcp/<provider>-v<n>` is the
|
|
193
|
+
convention.
|
|
194
|
+
|
|
195
|
+
5. **Run the gateway**
|
|
196
|
+
|
|
197
|
+
From the project root:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm run dev
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The route is now reachable at `http://127.0.0.1:9000/mcp/linear-v1`.
|
|
204
|
+
|
|
205
|
+
:::tip{title="Checkpoint: confirm the OAuth policy is wired up"}
|
|
206
|
+
|
|
207
|
+
Send an unauthenticated POST and expect a `401`:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
curl -i -X POST http://127.0.0.1:9000/mcp/linear-v1 \
|
|
211
|
+
-H "Content-Type: application/json" \
|
|
212
|
+
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The response should be `401 Unauthorized` with a `WWW-Authenticate: Bearer`
|
|
216
|
+
header pointing at `/.well-known/oauth-protected-resource/mcp/linear-v1`.
|
|
217
|
+
That 401 confirms the OAuth policy is loaded. If you see a 200, 404, or 500
|
|
218
|
+
instead, the OAuth policy isn't attached to the route.
|
|
219
|
+
|
|
220
|
+
:::
|
|
221
|
+
|
|
222
|
+
:::caution{title="Use 127.0.0.1, not localhost"}
|
|
223
|
+
|
|
224
|
+
OAuth metadata and callback URLs key off the request origin. Other loopback
|
|
225
|
+
aliases (`localhost`, `::1`) can break OAuth subtly in local dev. See
|
|
226
|
+
[Local development](./code-config/local-development.mdx) for the full set of
|
|
227
|
+
local-only details, including the known `workerd` restart quirk.
|
|
228
|
+
|
|
229
|
+
:::
|
|
230
|
+
|
|
231
|
+
6. **Connect Claude Desktop**
|
|
232
|
+
|
|
233
|
+
Open Claude Desktop, go to **Settings → Connectors**, scroll to the bottom,
|
|
234
|
+
and click **Add custom connector**. Paste
|
|
235
|
+
`http://127.0.0.1:9000/mcp/linear-v1` and click **Add**.
|
|
236
|
+
|
|
237
|
+
Claude Desktop opens the gateway's OAuth flow in a browser:
|
|
238
|
+
1. The dev-login shortcut signs you in without any IdP prompt.
|
|
239
|
+
2. The gateway's consent page lists Linear with a **Connect** button.
|
|
240
|
+
3. Click **Connect**, complete Linear's OAuth flow, then click **Authorize**
|
|
241
|
+
to finish.
|
|
242
|
+
|
|
243
|
+
:::tip{title="Checkpoint: Claude is connected"}
|
|
244
|
+
|
|
245
|
+
Back in Claude Desktop, the new connector appears in **Settings →
|
|
246
|
+
Connectors** marked as connected. Subsequent requests reuse the tokens the
|
|
247
|
+
gateway just issued.
|
|
248
|
+
|
|
249
|
+
:::
|
|
250
|
+
|
|
251
|
+
For per-client setup details, see
|
|
252
|
+
[Connect MCP clients](./connect-clients/overview.mdx).
|
|
253
|
+
|
|
254
|
+
7. **Test it**
|
|
255
|
+
|
|
256
|
+
In Claude Desktop, prompt the model with something that requires Linear.
|
|
257
|
+
"list my open issues" works well. Claude asks for permission to call the
|
|
258
|
+
tool, then returns results proxied through the gateway.
|
|
259
|
+
|
|
260
|
+
</Stepper>
|
|
261
|
+
|
|
262
|
+
You now have a working MCP Gateway in front of Linear, running locally: Claude
|
|
263
|
+
Desktop signs in through the dev-login shortcut, the gateway exchanges that for
|
|
264
|
+
a per-user Linear token, and every call is proxied through. The same shape (one
|
|
265
|
+
OAuth policy, one token-exchange policy per upstream, one route per upstream)
|
|
266
|
+
scales out to as many upstream MCP servers as you want to front.
|
|
267
|
+
|
|
268
|
+
:::caution{title="Deploy to production before sharing"}
|
|
269
|
+
|
|
270
|
+
The local gateway on `127.0.0.1` is for development only, and the dev-login
|
|
271
|
+
shortcut works over loopback alone. Before giving others access, swap in a real
|
|
272
|
+
identity provider and ship the gateway through the Zuplo Portal. See
|
|
273
|
+
[environments](../articles/environments.mdx) for setting up a production
|
|
274
|
+
deployment.
|
|
275
|
+
|
|
276
|
+
:::
|
|
277
|
+
|
|
278
|
+
## Next steps
|
|
279
|
+
|
|
280
|
+
- [Deploy from the Portal](./quickstart.mdx): swap the dev-login shortcut for a
|
|
281
|
+
real identity provider and ship the gateway through the Zuplo Portal.
|
|
282
|
+
- [Local development](./code-config/local-development.mdx): the dev-login
|
|
283
|
+
shortcut in depth, environment variables, and local-only quirks.
|
|
284
|
+
- [Connect more clients](./connect-clients/overview.mdx): Claude Code, Cursor,
|
|
285
|
+
VS Code, ChatGPT, and any other MCP client.
|
|
286
|
+
- [How it works](./how-it-works.mdx): the request lifecycle and the two OAuth
|
|
287
|
+
surfaces.
|
|
288
|
+
- [Add more upstreams](./code-config/multi-upstream.mdx): front several upstream
|
|
289
|
+
MCP servers from one Zuplo project.
|
|
290
|
+
- [Capability filtering](./capability-filtering.mdx): curate the tools, prompts,
|
|
291
|
+
and resources each route exposes.
|