Step-by-step guide to building an MCP server with Next.js App Router. Covers TypeScript types, sequential thinking patterns, Playwright integration, and Claude Code MCP server config.
Next.js has become one of the most common environments for building MCP servers. The reasons are practical: App Router makes HTTP endpoints trivial to define, TypeScript is first-class, and deploying to Vercel takes one command. If you're already building in the Next.js ecosystem, adding an MCP server to your project is a natural extension — not a separate infrastructure problem.
This guide covers building a Next.js MCP server from scratch: transport options, tool definition, sequential thinking patterns, Playwright integration, and the Claude Code MCP server config you'll need to connect it all together.
Before writing any code, understand the transport your use case requires. MCP supports two transport modes and they have very different deployment models:
stdio transport
HTTP/SSE transport
For a Next.js MCP server, you'll use the HTTP/SSE transport. This means your MCP server lives at a route like /api/mcp and AI clients connect to it over HTTP rather than spawning it as a subprocess.
# Create Next.js project (skip if adding to existing)
npx create-next-app@latest my-mcp-server --typescript --app
# Install the MCP SDK
npm install @modelcontextprotocol/sdk zodCreate the MCP route handler. This file handles the SSE connection and tool dispatch:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
import { z } from "zod";
const server = new Server(
{ name: "my-nextjs-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Register a tool
server.setRequestHandler("tools/list", async () => ({
tools: [
{
name: "fetch_page",
description: "Fetch a URL and return its title and text content",
inputSchema: {
type: "object",
properties: {
url: { type: "string", description: "The URL to fetch" },
},
required: ["url"],
},
},
],
}));
server.setRequestHandler("tools/call", async (request) => {
if (request.params.name === "fetch_page") {
const { url } = request.params.arguments as { url: string };
const res = await fetch(url);
const html = await res.text();
// Extract title (simplified)
const title = html.match(/<title>(.*?)</title>/i)?.[1] ?? "No title";
return {
content: [{ type: "text", text: `Title: ${title}
URL: ${url}` }],
};
}
throw new Error("Unknown tool");
});
export async function GET(req: Request) {
const transport = new SSEServerTransport("/api/mcp", new Response());
await server.connect(transport);
return transport.response;
}Sequential thinking in MCP refers to designing tools that work well in chained tool call sequences — where each tool's output naturally feeds the next step. This is different from calling one tool and getting a complete answer. It mirrors how humans research: search, read, extract, summarize.
The sequential thinking MCP server (a popular community server) implements this as an explicit tool that lets the model reason step-by-step through a problem, storing intermediate conclusions before committing to a final answer. You can implement the same pattern in your Next.js MCP server by designing tools around data hand-off:
Example sequential chain
search_webList of URLs relevant to queryfetch_pageFull content of most relevant URLextract_entitiesStructured data from contentwrite_summaryFinal artifact saved to memoryEach tool in the chain should return structured, consistent output that a model can parse and pass to the next step without reformatting. Use Zod to validate both inputs and shape your outputs as deterministic JSON.
The official @playwright/mcp server gives AI agents browser automation capabilities: navigate pages, click elements, fill forms, screenshot, and scrape dynamic content that raw HTTP fetching misses.
You can run Playwright MCP alongside your Next.js MCP server as a separate process — they can share the same AI client config. Add it as a second entry in your config:
{
"mcpServers": {
"my-nextjs-mcp": {
"url": "http://localhost:3000/api/mcp"
},
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
}To connect your Next.js MCP server to Claude Code specifically, you need to add it to your Claude Code settings rather than the desktop config. Run your Next.js dev server first, then:
# Add your local Next.js MCP server to Claude Code
claude mcp add my-nextjs-mcp --url http://localhost:3000/api/mcp
# Verify it connected
claude mcp list
# Or add to project-level .claude/settings.json directly:
# {
# "mcpServers": {
# "my-nextjs-mcp": {
# "url": "http://localhost:3000/api/mcp"
# }
# }
# }MCP server connection refused
Your Next.js dev server isn't running. Start it with npm run dev before connecting Claude Code.
CORS error on tool call
Add Access-Control-Allow-Origin: * to your route handler response headers. MCP clients send requests from different origins.
appwrite docs mcp server error / SDK version mismatch
MCP SDK versions between client and server must be compatible. Pin @modelcontextprotocol/sdk to the same minor version in both.
Tools not appearing in Claude
Restart Claude Code after adding the MCP server. The tool list is fetched on startup.
Building your own Next.js MCP server makes sense when you need custom business logic, proprietary data access, or tight integration with an existing Next.js app. But for the standard toolkit — web search, code analysis, memory, GitHub operations — you don't need to build anything.
AgenticStore ships 31 of these capabilities as a free, open-source MCP server you can connect in under two minutes. If you're starting out, that's the faster path. Build your custom server for the use cases that actually require it.
31 tools. One config. Two minutes.
Free and open source. Works with Claude Code, Cursor, Windsurf, and Claude Desktop. Docker or Python.