# How OpenSEO Validates and Formats MCP Output Schemas

> Discover how OpenSEO validates and formats MCP output schemas using instrumentMcpToolHandler for Zod schema normalization, safeParseAsync validation, error capture, and type-safe response formatting.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: internals
- Published: 2026-07-21

---

**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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/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 `content` block for text-only MCP clients
- **Metadata merging** – Combines optional `meta` objects with the structured payload when both are present
- **Standardized metadata placement** – Places final metadata in the `_meta` field 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`](https://github.com/every-app/open-seo/blob/main/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`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/whoami.ts) demonstrates the complete pattern:

```typescript
// 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** – `instrumentMcpToolHandler` in [`src/server/mcp/instrumentation.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/instrumentation.ts) wraps all MCP tools to enforce schema compliance transparently
- **Normalization and validation** – Schemas are normalized with `normalizeObjectSchema` and validated using `safeParseAsync` against the tool's `structuredContent`
- **Error observability** – Validation failures trigger `MCP_OUTPUT_VALIDATION` errors in PostHog with detailed messages from `getParseErrorMessage`
- **Response standardization** – `mcpResponse` in [`src/server/mcp/formatters.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/formatters.ts) ensures consistent output shapes with mandatory text content and optional metadata
- **Schema reusability** – Tools leverage `optionalMetaOutputSchema` from [`src/server/mcp/output-schemas.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/output-schemas.ts) to 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`](https://github.com/every-app/open-seo/blob/main/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.