ZuploZuplo
LoginStart for Free
  • Documentation
  • API Reference
Introduction
Getting Started
    Develop in the portal
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
    Develop locally with the CLI
      1 - Setup Your Gateway2 - Rate Limiting3 - API Key Auth4 - Deploy5 - Dynamic Rate LimitingDynamic MCP Server - Quickstart
Concepts
Development
Policies
Handlers
API Keys
Rate Limiting
Caching
MCP Server
MCP Gateway
AI Gateway
Developer Portal
Monetization
GraphQL
Deploying & Source Control
Analytics
Observability
Networking & Infrastructure
Account Management
Programming API
    Overview
    Request & Context
    Configuration
    Caching APIs
    Data Management
    Extensions & Hooks
    Error Handling
    Logging & Observability
    Types and Interfaces
    Web Standards
    MCP
      MCP SDKMCP Gateway Plugin
    Advanced Topics
Build with AI
Zuplo CLI
Migration Guides
Platform LimitsVersion Support PolicySecuritySupportTrust & ComplianceChangelog
powered by Zudoku
MCP

ZuploMcpSdk

The ZuploMcpSdk class provides a helper API for custom MCP tool handlers to interact with the MCP runtime. Use it to read metadata from the incoming tools/call request and to override fields of the tool result the gateway sends back to the AI client.

Code
import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const sdk = new ZuploMcpSdk(context); // Read the incoming tool call request const mcpRequest = sdk.getRawCallToolRequest(); context.log.info(`Tool called: ${mcpRequest?.params.name}`); // Invoke a route on your gateway const response = await context.invokeRoute("/todos"); // Override the content the model sees, keeping auto-derived structuredContent sdk.setRawCallToolResult({ content: [{ type: "text", text: "Fetched the todo list" }], }); return response; }

ZuploMcpSdk is available in custom tool handlers for both the MCP Server handler and the MCP Gateway. It is exported from @zuplo/runtime.

Methods

setRawCallToolResult(result)

Overrides fields of the MCP tool result the gateway is about to send to the AI client. Every field is independently optional — an absent field keeps the value the gateway derives from the downstream response.

Code
setRawCallToolResult(result: ZuploMcpToolResultOverride): void

Parameters

The result argument is a ZuploMcpToolResultOverride object with the following optional fields:

FieldTypeDescription
contentCallToolResult["content"]Content blocks the model reads. Replaces the gateway's default (the serialized downstream body in a text block).
structuredContentRecord<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.
_metaRecord<string, unknown>Per-call metadata. Replaces the gateway's default of {}.

Compact summary example

The most useful combination is content alone: a human-readable summary replaces the raw serialized body in the model's context, while structuredContent is still auto-derived from the downstream response. This reduces token consumption without losing data.

Code
import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const response = await context.invokeRoute("/todos"); new ZuploMcpSdk(context).setRawCallToolResult({ content: [{ type: "text", text: "Fetched the todo list" }], }); return response; }

The model sees "Fetched the todo list" instead of the full JSON body, but the structuredContent field still carries the complete payload for spec-compliant clients that read it.

Full override example

Override all available fields at once:

Code
import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const response = await context.invokeRoute("/orders"); const orders = await response.json(); new ZuploMcpSdk(context).setRawCallToolResult({ content: [ { type: "text", text: `Found ${orders.length} orders totaling $${orders.total}`, }, ], structuredContent: { orders: orders.items, count: orders.length }, _meta: { source: "order-service", version: "2.0" }, }); return response; }

isError is not overridable. It follows the HTTP status of the response your handler returns, so upstream failures cannot be masked. If the downstream route returns a non-2xx status, the tool result carries isError: true regardless of any override.

Single-use — consumed once

The override is consumed when the gateway assembles the tool result. It is read and deleted from the context at that point, so calling setRawCallToolResult twice in the same request replaces the first value before the gateway reads it.

How context lookup works

setRawCallToolResult writes the override to the context that carried the matching tools/call request. The lookup travels exactly one context.invokeRoute generation up from the context passed to the constructor.

This means:

  • In a typical custom tool handler that calls context.invokeRoute, the override is written to the parent context (the one carrying the tools/call request), which is correct.
  • If your handler calls invokeRoute to a route that also calls invokeRoute, and you construct ZuploMcpSdk in that grandchild invocation, the override is stored on the immediate parent — not the grandparent that carries the tool call. The gateway never reads it. Construct ZuploMcpSdk in the handler that is one level below the MCP route.

getRawCallToolRequest()

Retrieves the original MCP tools/call request object from the context. Use this to access metadata like the _meta field from the incoming tool call.

Code
getRawCallToolRequest(): CallToolRequest | null

Returns the CallToolRequest object, or null if no MCP tool call is in flight on the current or parent context.

Code
import { ZuploContext, ZuploMcpSdk, ZuploRequest } from "@zuplo/runtime"; export default async function (request: ZuploRequest, context: ZuploContext) { const sdk = new ZuploMcpSdk(context); const mcpRequest = sdk.getRawCallToolRequest(); if (mcpRequest) { const meta = mcpRequest.params._meta; context.log.info(`Incoming _meta: ${JSON.stringify(meta)}`); } // ... handle the tool call }

Unlike setRawCallToolResult, this method can be called any number of times — the request object is not consumed.

Output schema enforcement

When a tool advertises an outputSchema (via includeOutputSchema on the handler or route config), the gateway validates the tool result's structuredContent against that schema before sending it to the client. A result whose structuredContent does not conform to the advertised schema fails the call with a diagnostic isError result instead of a raw protocol error.

This enforcement is skipped on the error path (isError: true), matching the MCP SDK's own behavior.

includeOutputSchema implies includeStructuredContent

Advertising an outputSchema while returning no structuredContent makes the advertised schema inaccurate — spec-compliant clients reject the call. When includeOutputSchema resolves to true, the gateway automatically forces includeStructuredContent to true as well, and logs a warning naming the route where the override kicked in.

You can set both explicitly to avoid the warning:

Code
{ "x-zuplo-route": { "handler": { "export": "mcpServerHandler", "module": "$import(@zuplo/runtime)", "options": { "includeOutputSchema": true, "includeStructuredContent": true } } } }

Type reference

ZuploMcpToolResultOverride

Code
interface ZuploMcpToolResultOverride { content?: CallToolResult["content"]; structuredContent?: Record<string, unknown>; _meta?: Record<string, unknown>; }

The subset of a tools/call result that a module author may override via setRawCallToolResult. Every field is independently optional.

See also

  • MCP Server custom tools — how to build custom MCP tool handlers with TypeScript
  • MCP Server handler — handler configuration reference including includeOutputSchema and includeStructuredContent
  • MCP Gateway introduction — overview of the MCP Gateway product
  • MCP specification — the canonical protocol reference
Edit this page
Last modified on August 20, 2026
Web CryptoMCP Gateway Plugin
On this page
  • Methods
    • setRawCallToolResult(result)
    • getRawCallToolRequest()
  • Output schema enforcement
    • includeOutputSchema implies includeStructuredContent
  • Type reference
    • ZuploMcpToolResultOverride
  • See also
TypeScript
TypeScript
TypeScript
TypeScript
TypeScript
TypeScript
JSON
TypeScript