From OpenAPI Spec to MCP Server: A Practical Guide with Kubb and Next.js

Learn how we built an OpenAPI-driven MCP server using Kubb, custom code generators, and Vercel’s Next.js MCP adapter.

Author

Alexis Rico

Date published

Model Context Protocol (MCP) is an emerging standard that lets AI models securely interact with tools and APIs in real time. Building an MCP server means exposing a set of "tools" (operations) that a Large Language Model (LLM) can call to perform tasks, for example, fetching data or triggering actions via your backend. If you already have an OpenAPI specification for your API, you can generate an MCP server directly from that spec, using your schema as a single source of truth. This OpenAPI-driven approach promises quick development and consistency, but it comes with design considerations.

On one hand, auto-generating tools directly from a REST API spec is very appealing. You've already documented your API thoroughly, so why not transform those endpoints into AI-accessible functions? It saves time and keeps the API and MCP definitions in sync, avoiding duplicate work. On the other hand, a naive one-to-one mapping of every endpoint to an MCP tool can overwhelm an LLM. LLMs struggle to choose the right action from so many low-level options, leading to frequent errors or unpredictable calls, especially if several endpoints have similar purposes.

The solution lies in a balanced approach. Writing an MCP server entirely by hand for a large API would be a massive time sink, manually crafting each tool's schema and handler is tedious and error-prone, especially when a well-defined OpenAPI spec already exists. Instead, we can autogenerate the groundwork from OpenAPI, then curate it. In practice, this means using codegen to produce a set of tool definitions and client calls, then trimming or augmenting the OpenAPI spec that generates the tools to align with real-world usage.

This post walks through the full approach: OpenAPI codegen with Kubb, custom generation of MCP tools, and a Next.js server implementation.

We'll cover three parts:

  1. Migrating to Kubb for OpenAPI code generation. Why Kubb is a strong choice and the benefits it brings.
  2. Customizing Kubb with custom generators. How to generate a TypeScript API client and a suite of MCP tools from your OpenAPI spec.
  3. Creating the MCP Server with Next.js. Wiring it all together using Vercel's MCP adapter, route handlers, authentication middleware, and initializing the generated tools.

Why Kubb for OpenAPI Code Generation

If you're using a traditional OpenAPI code generator to produce a TypeScript client for your REST API, you've probably hit the limits: rigid output, hard to customize, and adding new formats means wrestling with post-processing scripts. Kubb is a more flexible alternative, designed specifically for TypeScript projects.

Kubb can generate TypeScript types, API clients, React Query hooks, Zod validators, MSW handlers, and even MCP integration code, all from an OpenAPI spec.

The key advantage is its plugin and generator architecture. Kubb's code generation process is highly customizable: you can plug in predefined generators or write your own to tailor the output. Instead of treating your OpenAPI spec as just input for a one-size-fits-all client generator, you can leverage it to produce multiple outputs, like a low-level API client and a set of MCP tools in one go.

Kubb Configuration

Setting up Kubb is straightforward. Add a kubb.config.ts to your project, point it at your OpenAPI spec, and declare which plugins/generators to use. Here's a simplified version:

The @kubb/plugin-oas plugin handles reading the OpenAPI spec and iterating over its contents. The custom generators in the generators array build the API client and MCP tool definitions. The plugin-ts outputs TypeScript interfaces/types for your API schemas (useful for strong typing of request and response bodies). Kubb orchestrates all these plugins in one run, parsing the spec once and feeding the data to each generator.

With the config in place, a simple command (e.g. pnpm kubb generate) triggers the code generation.

Custom Generators: API Client and MCP Tools

Using Kubb's extensibility, you can write custom generators to produce two key outputs from the OpenAPI spec: (a) a TypeScript API client and (b) MCP tool handlers that map onto those API endpoints. Generating these from the spec ensures consistency and saves a ton of manual coding.

1. Generating a Typed API Client from OpenAPI

The first generator, clientGenerator, creates a lightweight API client library. While Kubb offers a default client generator (using Axios by default), you can customize it to better fit your needs, for example, to use fetch, handle your auth scheme, and match the conventions already in your codebase.

The client generator iterates over each operation in the OpenAPI spec and emits a function that calls that endpoint. For each operation, it uses the operation ID (or a modified version of it) as the function name, and generates a TypeScript function signature based on the operation's parameters and response schema.

Because this client code is generated, it stays up-to-date with your API. If you add a new endpoint or change a parameter in the OpenAPI spec, re-running Kubb updates the client functions accordingly. No more hand-writing HTTP calls for each new feature, no risk of typos or forgotten headers. The OpenAPI spec remains the single source of truth, and the API client is a direct reflection of it.

2. Generating MCP Tool Definitions from OpenAPI

The second generator, mcpGenerator, bridges the gap between your API and the MCP tool interface that an AI agent can use. Although Kubb has support to build a default MCP server, you can customize the generator to produce an initMcpTools function that you call from Vercel's MCP Adapter.

Tool curation and descriptions: You don't have to expose every endpoint. Omit internal or less useful endpoints from the MCP interface to avoid cluttering the AI with too many options. You can also edit tool descriptions for clarity, adjusting an OpenAPI description meant for developers to be more instructive for an AI agent.

Using Zod for input validation: Zod schemas work well for tool input definitions. Kubb can generate Zod schemas from the OpenAPI spec (via @kubb/plugin-zod), which you can leverage for complex data structures. Zod serves two purposes: it defines the input format for the AI (so that the AI knows what arguments to provide), and it validates any incoming request at runtime, adding a safety net. If an AI somehow provides an incorrect type, the MCP server rejects it before hitting your API.

Building the MCP Server as a Next.js App

With the client and tool code generated, the final step is to stand up the MCP server itself. Next.js with Vercel's @vercel/mcp-adapter is one solid option. Here's why:

  • Vercel Deployment: If you're already on Vercel, Next.js is a first-class citizen. The MCP adapter drops into a Next.js API route, making deployment and scaling straightforward.
  • Serverless and Fluid Compute: Next.js on Vercel can take advantage of the "Fluid" Node.js runtime, which is well-suited for long-lived connections like SSE (Server-Sent Events) and can yield cost savings for AI workloads.
  • Routing & Middleware: Next's API route and Middleware features handle authentication and request routing cleanly.

Route Handling with @vercel/mcp-adapter

Create a dedicated API route for MCP under the Next.js app directory. Use a dynamic route [transport] to support both SSE and HTTP transports. In your project, create a file like app/api/[transport]/route.ts. This dynamic segment means the route will match /api/mcp and /api/sse:

createMcpHandler creates a Next.js request handler that speaks the MCP protocol. The callback receives a server object where you register your tools. Rather than manually listing each tool, the generated initMcpTools(server) helper invokes all the server.tool(name, desc, schema, impl) definitions that were generated from the OpenAPI spec. This populates the MCP server with your full toolkit.

The withAuth wrapper verifies the token provided by the MCP Host. If no token is found, return a 401 and prompt the MCP Host to start the OAuth Dynamic Client Registration against your authentication server.

Both GET and POST are exported because the MCP client may use either for different phases of the handshake and tool calling.

The redisUrl in the configuration handles Server-Sent Events (SSE) transport state. SSE (used by Claude and some clients) is stateful, and the Vercel adapter uses Redis to store session state so that multiple function calls in a session share context.

With this route set up, the Next.js app is a fully functional MCP server. When an AI agent connects (via an MCP client), the adapter handles the initial handshake and advertises all registered tools. The AI can invoke any of those tools, the adapter calls your implementations (which call your API), and the results are sent back to the AI.

MCP vs traditional API: Instead of the client calling specific endpoints directly, the AI does a handshake to discover available tools and then calls them by name. Think of it as a capabilities-based RPC system. Rather than hitting a /users REST endpoint, the AI asks "what tools do you have?" and the server replies with something like "I have a list_users tool, a create_project tool," etc. The AI decides which tool to use and sends a request like "invoke list_users with workspace=X". The MCP server executes the function, which calls the real API, and returns the result.

Conclusion

By leaning into an OpenAPI schema, you give your MCP server the ability to evolve at the speed of your API, with the confidence of strong typing and validation at every step. This hybrid approach (auto-generate then polish) lets you stand up a powerful AI integration in a fraction of the time it would take to code from scratch. Treat the API spec as executable knowledge, not just documentation.

As AI continues to weave into developer platforms, this pattern will become increasingly common. Any team with a well-maintained OpenAPI spec can use it to build an MCP server in days, not weeks. The tooling is there: Kubb for codegen, Zod for validation, Vercel's adapter for the protocol layer.

At Xata, we're building a managed Postgres platform with copy-on-write branching and PII anonymization. If you're working with Postgres at scale and want to see how branching can improve your development workflow, check out our platform.

Related Posts