How OpenSEO Validates and Formats MCP Output Schemas
OpenSEO validates and formats MCP output schemas by wrapping tool handlers with instrumentMcpToolHandler, which normalizes Zod schemas, validates structuredContent using safeParseAsync, captures validation errors to PostHog, and formats successful responses via the mcpResponse helper to ensure type-safe Model-Context-Protocol interactions.
Every MCP tool in the OpenSEO codebase declares its return shape through a Zod schema defined in the outputSchema field. When instrumented, these tools undergo a rigorous validation pipeline that enforces data integrity while providing comprehensive error tracking and consistent response formatting for both structured and text-based clients.
The MCP Output Schema Validation Pipeline
The validation logic is centralized in src/server/mcp/instrumentation.ts within the instrumentMcpToolHandler function. This wrapper implements a five-step process that intercepts tool execution to guarantee schema compliance before responses reach consumers.
Schema Normalization with normalizeObjectSchema
Before handler execution, the raw output schema undergoes normalization via normalizeObjectSchema (lines 71-77). This step ensures that the system accepts both plain Zod object definitions and class instances from the Model-Context SDK, creating a uniform validation target regardless of how the schema was initially constructed.
Execution and Async Validation
The wrapper executes the original handler and receives a CallToolResult. If the tool configuration includes an outputSchema and the handler hasn't returned an error, the pipeline validates the result's structuredContent field using Zod's safeParseAsync method (lines 84-93). This asynchronous validation approach prevents blocking while verifying that the returned data conforms exactly to the declared schema shape.
Error Handling and Analytics Integration
When safeParseAsync detects a schema mismatch, the system immediately records a MCP_OUTPUT_VALIDATION error to PostHog (lines 99-108). The error message is generated using getParseErrorMessage to provide actionable debugging information, and the call is marked as failed. Regardless of validation outcome, the wrapper invokes captureMcpToolCall (lines 111-118) to log analytics, distinguishing between external OAuth clients and the in-app agent for accurate usage tracking.
Formatting Validated Responses with mcpResponse
Once validation succeeds, response formatting is handled by the mcpResponse helper in src/server/mcp/formatters.ts (lines 12-36). This utility constructs a standardized CallToolResult that satisfies diverse client requirements:
- Mandatory text content – Always includes a plain-text
contentblock for text-only MCP clients - Metadata merging – Combines optional
metaobjects with the structured payload when both are present - Standardized metadata placement – Places final metadata in the
_metafield for downstream consumers
This formatting ensures that every MCP endpoint returns a consistent shape capable of serving both human-readable interfaces and structured data consumers.
Implementing Output Schemas in Practice
Tools define their contracts by importing shared schema fragments from src/server/mcp/output-schemas.ts. The optionalMetaOutputSchema export (lines 33-35) provides a reusable metadata shape that tools spread into their output schemas to maintain consistency.
The following implementation from src/server/mcp/tools/whoami.ts demonstrates the complete pattern:
// Tool definition with Zod output schema
export const whoamiTool = {
name: "whoami",
config: {
title: "Who am I",
description: "Returns auth context and credit balance.",
inputSchema: {} as Record<string, never>,
outputSchema: {
userId: z.string(),
userEmail: z.string(),
organizationId: z.string(),
scopes: z.array(z.string()),
mode: z.enum(["hosted", "self-hosted"]),
creditsRemaining: z.number().nullable(),
...optionalMetaOutputSchema, // Reusable meta schema
},
},
handler: async (_args, extra) => {
const auth = getAuth(extra);
return mcpResponse({
text: `User: ${auth.userId}`,
meta: { organizationId: auth.organizationId },
structuredContent: {
userId: auth.userId,
userEmail: auth.userEmail,
organizationId: auth.organizationId,
scopes: auth.scopes,
mode: "hosted",
creditsRemaining: null,
},
});
},
};
// Instrumentation applies validation and formatting automatically
export const whoami = instrumentMcpToolHandler(
whoamiTool.name,
whoamiTool.config.outputSchema,
whoamiTool.handler,
);
Summary
- Validation entry point –
instrumentMcpToolHandlerinsrc/server/mcp/instrumentation.tswraps all MCP tools to enforce schema compliance transparently - Normalization and validation – Schemas are normalized with
normalizeObjectSchemaand validated usingsafeParseAsyncagainst the tool'sstructuredContent - Error observability – Validation failures trigger
MCP_OUTPUT_VALIDATIONerrors in PostHog with detailed messages fromgetParseErrorMessage - Response standardization –
mcpResponseinsrc/server/mcp/formatters.tsensures consistent output shapes with mandatory text content and optional metadata - Schema reusability – Tools leverage
optionalMetaOutputSchemafromsrc/server/mcp/output-schemas.tsto maintain uniform metadata handling across endpoints
Frequently Asked Questions
What happens when an MCP tool's output fails schema validation in OpenSEO?
When validation fails, the wrapper records a MCP_OUTPUT_VALIDATION error to PostHog using getParseErrorMessage to generate human-readable details, marks the call as failed, and prevents the malformed data from reaching the client. This ensures strict type safety while providing observability into schema mismatches.
How does OpenSEO format successful MCP tool responses?
OpenSEO uses the mcpResponse helper to build standardized CallToolResult objects that always include a plain-text content block, merge optional metadata with structured payloads, and place final metadata in the _meta field. This dual-format approach supports both text-only and structured-content MCP clients.
Can MCP tools return responses that don't match their declared output schemas?
No, instrumented tools cannot return non-conforming data. The instrumentMcpToolHandler wrapper enforces that all structuredContent validates against the declared Zod schema before the response is sent. Any deviation triggers a validation error and blocks the non-compliant output.
Where are reusable MCP output schema fragments defined in OpenSEO?
Reusable schema fragments, including optionalMetaOutputSchema, are defined in src/server/mcp/output-schemas.ts. Tools import these fragments and spread them into their outputSchema definitions to ensure consistent metadata handling and validation across the entire MCP tool suite.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →