zuplo 7.4.4 → 7.4.5

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.
Files changed (38) hide show
  1. package/docs/articles/ci-cd-azure/local-testing.mdx +22 -4
  2. package/docs/articles/ci-cd-bitbucket/local-testing.mdx +22 -4
  3. package/docs/articles/ci-cd-circleci/local-testing.mdx +21 -4
  4. package/docs/articles/ci-cd-github/deploy-and-test.mdx +28 -13
  5. package/docs/articles/ci-cd-github/local-testing.mdx +36 -16
  6. package/docs/articles/ci-cd-gitlab/local-testing.mdx +22 -4
  7. package/docs/articles/github-deployment-testing.mdx +118 -31
  8. package/docs/articles/testing-getting-started.mdx +220 -0
  9. package/docs/articles/testing-preview-environments.mdx +148 -0
  10. package/docs/articles/testing-recipes.mdx +429 -0
  11. package/docs/articles/testing.mdx +138 -408
  12. package/docs/mcp-gateway/auth/configuring-auth0.mdx +6 -5
  13. package/docs/mcp-gateway/auth/configuring-clerk.mdx +4 -4
  14. package/docs/mcp-gateway/auth/configuring-cognito.mdx +5 -4
  15. package/docs/mcp-gateway/auth/configuring-entra.mdx +5 -4
  16. package/docs/mcp-gateway/auth/configuring-generic-oidc.mdx +8 -8
  17. package/docs/mcp-gateway/auth/configuring-google.mdx +4 -4
  18. package/docs/mcp-gateway/auth/configuring-keycloak.mdx +4 -3
  19. package/docs/mcp-gateway/auth/configuring-logto.mdx +4 -4
  20. package/docs/mcp-gateway/auth/configuring-okta.mdx +3 -3
  21. package/docs/mcp-gateway/auth/configuring-onelogin.mdx +3 -3
  22. package/docs/mcp-gateway/auth/configuring-ping.mdx +3 -3
  23. package/docs/mcp-gateway/auth/configuring-workos.mdx +5 -4
  24. package/docs/mcp-gateway/auth/manual-oauth-testing.mdx +8 -8
  25. package/docs/mcp-gateway/auth/overview.mdx +17 -17
  26. package/docs/mcp-gateway/auth/upstream-oauth.mdx +5 -5
  27. package/docs/mcp-gateway/code-config/local-development.mdx +14 -12
  28. package/docs/mcp-gateway/code-config/overview.mdx +9 -4
  29. package/docs/mcp-gateway/how-it-works.mdx +11 -9
  30. package/docs/mcp-gateway/introduction.mdx +3 -1
  31. package/docs/mcp-gateway/quickstart-local.mdx +7 -7
  32. package/docs/mcp-gateway/reference.mdx +58 -25
  33. package/docs/mcp-gateway/server-registry.mdx +179 -0
  34. package/docs/mcp-gateway/test-clients.mdx +2 -2
  35. package/docs/mcp-server/custom-tools.mdx +32 -0
  36. package/docs/programmable-api/mcp-gateway-plugin.mdx +137 -0
  37. package/docs/programmable-api/mcp-sdk.mdx +240 -0
  38. package/package.json +5 -5
@@ -0,0 +1,240 @@
1
+ ---
2
+ title: ZuploMcpSdk
3
+ sidebar_label: MCP SDK
4
+ description:
5
+ Reference for the ZuploMcpSdk class, which gives custom MCP tool handlers
6
+ access to the incoming tool call request and control over the tool result sent
7
+ back to the AI client.
8
+ ---
9
+
10
+ The `ZuploMcpSdk` class provides a helper API for custom MCP tool handlers to
11
+ interact with the MCP runtime. Use it to read metadata from the incoming
12
+ `tools/call` request and to override fields of the tool result the gateway sends
13
+ back to the AI client.
14
+
15
+ ```ts
16
+ import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime";
17
+
18
+ export default async function (request: ZuploRequest, context: ZuploContext) {
19
+ const sdk = new ZuploMcpSdk(context);
20
+
21
+ // Read the incoming tool call request
22
+ const mcpRequest = sdk.getRawCallToolRequest();
23
+ context.log.info(`Tool called: ${mcpRequest?.params.name}`);
24
+
25
+ // Invoke a route on your gateway
26
+ const response = await context.invokeRoute("/todos");
27
+
28
+ // Override the content the model sees, keeping auto-derived structuredContent
29
+ sdk.setRawCallToolResult({
30
+ content: [{ type: "text", text: "Fetched the todo list" }],
31
+ });
32
+
33
+ return response;
34
+ }
35
+ ```
36
+
37
+ `ZuploMcpSdk` is available in custom tool handlers for both the
38
+ [MCP Server handler](../handlers/mcp-server.mdx) and the
39
+ [MCP Gateway](../mcp-gateway/introduction.mdx). It is exported from
40
+ `@zuplo/runtime`.
41
+
42
+ ## Methods
43
+
44
+ ### `setRawCallToolResult(result)`
45
+
46
+ Overrides fields of the MCP tool result the gateway is about to send to the AI
47
+ client. Every field is independently optional — an absent field keeps the value
48
+ the gateway derives from the downstream response.
49
+
50
+ ```ts
51
+ setRawCallToolResult(result: ZuploMcpToolResultOverride): void
52
+ ```
53
+
54
+ #### Parameters
55
+
56
+ The `result` argument is a `ZuploMcpToolResultOverride` object with the
57
+ following optional fields:
58
+
59
+ | Field | Type | Description |
60
+ | ------------------- | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
61
+ | `content` | `CallToolResult["content"]` | Content blocks the model reads. Replaces the gateway's default (the serialized downstream body in a text block). |
62
+ | `structuredContent` | `Record<string, unknown>` | The structured form of the tool's output. Must be a JSON object — the MCP 2025-11-25 wire format rejects arrays and scalars. |
63
+ | `_meta` | `Record<string, unknown>` | Per-call metadata. Replaces the gateway's default of `{}`. |
64
+
65
+ #### Compact summary example
66
+
67
+ The most useful combination is `content` alone: a human-readable summary
68
+ replaces the raw serialized body in the model's context, while
69
+ `structuredContent` is still auto-derived from the downstream response. This
70
+ reduces token consumption without losing data.
71
+
72
+ ```ts
73
+ import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime";
74
+
75
+ export default async function (request: ZuploRequest, context: ZuploContext) {
76
+ const response = await context.invokeRoute("/todos");
77
+ new ZuploMcpSdk(context).setRawCallToolResult({
78
+ content: [{ type: "text", text: "Fetched the todo list" }],
79
+ });
80
+ return response;
81
+ }
82
+ ```
83
+
84
+ The model sees `"Fetched the todo list"` instead of the full JSON body, but the
85
+ `structuredContent` field still carries the complete payload for spec-compliant
86
+ clients that read it.
87
+
88
+ #### Full override example
89
+
90
+ Override all available fields at once:
91
+
92
+ ```ts
93
+ import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime";
94
+
95
+ export default async function (request: ZuploRequest, context: ZuploContext) {
96
+ const response = await context.invokeRoute("/orders");
97
+ const orders = await response.json();
98
+
99
+ new ZuploMcpSdk(context).setRawCallToolResult({
100
+ content: [
101
+ {
102
+ type: "text",
103
+ text: `Found ${orders.length} orders totaling $${orders.total}`,
104
+ },
105
+ ],
106
+ structuredContent: { orders: orders.items, count: orders.length },
107
+ _meta: { source: "order-service", version: "2.0" },
108
+ });
109
+
110
+ return response;
111
+ }
112
+ ```
113
+
114
+ :::note
115
+
116
+ **`isError` is not overridable.** It follows the HTTP status of the response
117
+ your handler returns, so upstream failures cannot be masked. If the downstream
118
+ route returns a non-2xx status, the tool result carries `isError: true`
119
+ regardless of any override.
120
+
121
+ :::
122
+
123
+ :::caution{title="Single-use — consumed once"}
124
+
125
+ The override is **consumed** when the gateway assembles the tool result. It is
126
+ read and deleted from the context at that point, so calling
127
+ `setRawCallToolResult` twice in the same request replaces the first value before
128
+ the gateway reads it.
129
+
130
+ :::
131
+
132
+ #### How context lookup works
133
+
134
+ `setRawCallToolResult` writes the override to the context that carried the
135
+ matching `tools/call` request. The lookup travels exactly one
136
+ `context.invokeRoute` generation up from the context passed to the constructor.
137
+
138
+ This means:
139
+
140
+ - In a typical custom tool handler that calls `context.invokeRoute`, the
141
+ override is written to the parent context (the one carrying the `tools/call`
142
+ request), which is correct.
143
+ - If your handler calls `invokeRoute` to a route that **also** calls
144
+ `invokeRoute`, and you construct `ZuploMcpSdk` in that grandchild invocation,
145
+ the override is stored on the immediate parent — not the grandparent that
146
+ carries the tool call. The gateway never reads it. Construct `ZuploMcpSdk` in
147
+ the handler that is one level below the MCP route.
148
+
149
+ ### `getRawCallToolRequest()`
150
+
151
+ Retrieves the original MCP `tools/call` request object from the context. Use
152
+ this to access metadata like the `_meta` field from the incoming tool call.
153
+
154
+ ```ts
155
+ getRawCallToolRequest(): CallToolRequest | null
156
+ ```
157
+
158
+ Returns the `CallToolRequest` object, or `null` if no MCP tool call is in flight
159
+ on the current or parent context.
160
+
161
+ ```ts
162
+ import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime";
163
+
164
+ export default async function (request: ZuploRequest, context: ZuploContext) {
165
+ const sdk = new ZuploMcpSdk(context);
166
+ const mcpRequest = sdk.getRawCallToolRequest();
167
+
168
+ if (mcpRequest) {
169
+ const meta = mcpRequest.params._meta;
170
+ context.log.info(`Incoming _meta: ${JSON.stringify(meta)}`);
171
+ }
172
+
173
+ // ... handle the tool call
174
+ }
175
+ ```
176
+
177
+ Unlike `setRawCallToolResult`, this method can be called any number of times —
178
+ the request object is not consumed.
179
+
180
+ ## Output schema enforcement
181
+
182
+ When a tool advertises an `outputSchema` (via `includeOutputSchema` on the
183
+ handler or route config), the gateway validates the tool result's
184
+ `structuredContent` against that schema before sending it to the client. A
185
+ result whose `structuredContent` does not conform to the advertised schema fails
186
+ the call with a diagnostic `isError` result instead of a raw protocol error.
187
+
188
+ This enforcement is skipped on the error path (`isError: true`), matching the
189
+ MCP SDK's own behavior.
190
+
191
+ ### `includeOutputSchema` implies `includeStructuredContent`
192
+
193
+ Advertising an `outputSchema` while returning no `structuredContent` makes the
194
+ advertised schema inaccurate — spec-compliant clients reject the call. When
195
+ `includeOutputSchema` resolves to `true`, the gateway automatically forces
196
+ `includeStructuredContent` to `true` as well, and logs a warning naming the
197
+ route where the override kicked in.
198
+
199
+ You can set both explicitly to avoid the warning:
200
+
201
+ ```json
202
+ {
203
+ "x-zuplo-route": {
204
+ "handler": {
205
+ "export": "mcpServerHandler",
206
+ "module": "$import(@zuplo/runtime)",
207
+ "options": {
208
+ "includeOutputSchema": true,
209
+ "includeStructuredContent": true
210
+ }
211
+ }
212
+ }
213
+ }
214
+ ```
215
+
216
+ ## Type reference
217
+
218
+ ### `ZuploMcpToolResultOverride`
219
+
220
+ ```ts
221
+ interface ZuploMcpToolResultOverride {
222
+ content?: CallToolResult["content"];
223
+ structuredContent?: Record<string, unknown>;
224
+ _meta?: Record<string, unknown>;
225
+ }
226
+ ```
227
+
228
+ The subset of a `tools/call` result that a module author may override via
229
+ `setRawCallToolResult`. Every field is independently optional.
230
+
231
+ ## See also
232
+
233
+ - [MCP Server custom tools](../mcp-server/custom-tools.mdx) — how to build
234
+ custom MCP tool handlers with TypeScript
235
+ - [MCP Server handler](../handlers/mcp-server.mdx) — handler configuration
236
+ reference including `includeOutputSchema` and `includeStructuredContent`
237
+ - [MCP Gateway introduction](../mcp-gateway/introduction.mdx) — overview of the
238
+ MCP Gateway product
239
+ - [MCP specification](https://modelcontextprotocol.io/specification/) — the
240
+ canonical protocol reference
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "7.4.4",
3
+ "version": "7.4.5",
4
4
  "type": "module",
5
5
  "description": "The programmable API Gateway",
6
6
  "author": "Zuplo, Inc.",
@@ -19,9 +19,9 @@
19
19
  "zuplo": "zuplo.js"
20
20
  },
21
21
  "dependencies": {
22
- "@zuplo/cli": "7.4.4",
23
- "@zuplo/core": "7.4.4",
24
- "@zuplo/runtime": "7.4.4",
25
- "@zuplo/test": "7.4.4"
22
+ "@zuplo/cli": "7.4.5",
23
+ "@zuplo/core": "7.4.5",
24
+ "@zuplo/runtime": "7.4.5",
25
+ "@zuplo/test": "7.4.5"
26
26
  }
27
27
  }