How OpenSEO Server Functions Share the ToolContext Contract and Zod Validation
OpenSEO leverages TanStack React-Start Server Functions to enforce a unified authentication contract through a shared ToolContext type and guarantees runtime type safety by attaching reusable Zod schemas via the .validator() method.
Every server function in the OpenSEO codebase follows a standardized architectural pattern that eliminates boilerplate while ensuring complete type safety. By centralizing the ToolContext definition and Zod validation schemas in single source files, the codebase guarantees that all API handlers receive consistently shaped authentication data and validated inputs without duplicating logic.
The ToolContext Contract in OpenSEO Server Functions
All OpenSEO server functions rely on a common ToolContext type that standardizes how authentication data flows through the application. This contract ensures that every handler receives the same structured information about the requesting user, their organization, and their permissions.
Defining the Shared Type
The ToolContext type is exported from src/server/mcp/context.ts and serves as the single source of truth for authentication context across the entire API:
// src/server/mcp/context.ts
export type ToolContext = {
auth: {
userId: string;
userEmail: string;
organizationId: string;
role: string;
orgScope: "pinned" | "user";
scopes: string[];
clientId: string | null;
baseUrl: string;
};
turnId?: string; // present only for in‑app agent turns
};
This type describes every field required for authorization decisions, including the user's organizationId, their role within that organization, and an array of scopes defining their permissions. The optional turnId field supports in-app agent interactions, allowing server functions to track conversation state when called by AI agents.
Middleware Injection Pattern
Server functions do not manually construct this context. Instead, they import middleware such as requireAuthenticatedContext or requireProjectContext from src/serverFunctions/middleware.ts. These middleware functions extract authentication headers, validate session tokens, and inject a fully populated ToolContext into the handler's context argument.
Because the context type is shared, middleware guarantees that every protected endpoint receives identical authentication shaping, eliminating the risk of field mismatches between different API routes.
Centralizing Zod Validation Across OpenSEO Server Functions
Runtime type safety is enforced through Zod schemas stored in src/types/schemas/*.ts. By centralizing validation logic, OpenSEO ensures that input constraints remain consistent across production code, tests, and any future API consumers.
Schema Reuse Strategy
Rather than defining validation rules inline, developers import schemas from central files like src/types/schemas/projects.ts:
// src/types/schemas/projects.ts
import { z } from "zod";
export const createProjectSchema = z.object({
name: z.string().min(1),
website: z.string().url().optional(),
// …other fields…
});
These schemas are reused across multiple server functions and test suites. When business rules change, updating the central schema automatically propagates validation changes to every function that consumes it.
The Validation Chain
Server functions attach Zod schemas using the .validator() method provided by createServerFn. This method parses and validates incoming JSON payloads before the handler executes, ensuring that the data object inside the handler is fully typed and safe to use:
// src/serverFunctions/projects.ts
import { createServerFn } from "@tanstack/react-start";
import { requireAuthenticatedContext } from "@/serverFunctions/middleware";
import { createProjectSchema } from "@/types/schemas/projects";
export const createProject = createServerFn({ method: "POST" })
.middleware(requireAuthenticatedContext) // injects ToolContext
.validator(createProjectSchema) // Zod validation
.handler(async ({ data, context }) => {
// `context` is a ToolContext – auth info is guaranteed present
// `data` conforms to `createProjectSchema`
return ProjectService.createProject(context.auth.organizationId, data);
});
In this implementation, the handler receives a context object typed as ToolContext and a data object validated against createProjectSchema. This pattern eliminates defensive coding inside handlers since type safety is guaranteed at the framework level.
Testing Server Functions with Mock ToolContext
The shared contract simplifies unit testing by allowing developers to inject valid authentication contexts without spinning up full request lifecycle simulations. The makeToolContext utility in src/server/mcp/tools/tool-test-support.ts generates compliant mock contexts for test isolation:
// src/server/mcp/tools/tool-test-support.ts
import type { ToolAuthContext, ToolContext } from "@/server/mcp/context";
export function makeToolContext(
overrides?: Partial<ToolAuthContext>
): ToolContext {
const defaultAuth: ToolAuthContext = {
userId: "test‑user",
userEmail: "user@example.com",
organizationId: "org‑123",
role: "owner",
orgScope: "pinned",
scopes: [],
clientId: null,
baseUrl: "https://example.com",
};
return { auth: { ...defaultAuth, ...overrides } };
}
This helper allows tests to override specific auth fields—such as testing admin-only endpoints by setting role: "admin"—while maintaining the full ToolContext structure required by the server function. Combined with the centralized Zod schemas, tests can validate both business logic and input constraints using the same definitions as production code.
Summary
-
Unified Authentication: The
ToolContexttype insrc/server/mcp/context.tsdefines a single contract for user identity, organization membership, and permissions that every protected server function receives through middleware likerequireAuthenticatedContext. -
Centralized Validation: All Zod schemas reside in
src/types/schemas/*.tsand are attached to server functions via.validator(), ensuring runtime type checking matches TypeScript definitions. -
Type-Safe Handlers: The combination of injected
ToolContextand validateddataobjects eliminates manual type guarding inside business logic handlers. -
Testable Architecture: The
makeToolContextutility provides a factory for creating valid authentication contexts, enabling isolated unit tests without mocking HTTP requests.
Frequently Asked Questions
What is the ToolContext contract in OpenSEO?
The ToolContext contract is a TypeScript type defined in src/server/mcp/context.ts that standardizes the shape of authentication data passed to every server function. It contains an auth object with fields like userId, organizationId, role, and scopes, plus an optional turnId for agent-based interactions. This contract ensures that all API handlers receive identically structured authentication information.
Where are Zod validation schemas stored in the OpenSEO codebase?
Zod schemas are centralized in src/types/schemas/*.ts, with specific domains separated into files like projects.ts and search-performance.ts. This location allows schemas to be imported by multiple server functions and test files, ensuring that validation rules remain consistent across the entire application.
How does middleware inject ToolContext into server functions?
Middleware functions such as requireAuthenticatedContext (defined in src/serverFunctions/middleware.ts) intercept incoming requests, validate session tokens, and construct a ToolContext object. They then attach this context to the request pipeline, making it available as the context argument in the server function handler. This injection happens before the Zod validator runs.
Can OpenSEO server functions be tested without a full HTTP request?
Yes. The makeToolContext helper in src/server/mcp/tools/tool-test-support.ts generates mock ToolContext objects that satisfy the type requirements for any server function. Developers can override specific auth fields for test scenarios and pass these contexts directly to service layers or handler logic, bypassing the HTTP layer and middleware stack entirely.
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 →