# How to build an MCP server with Nuxt

**Author:** Hugo Richard, Ben Sabic

---

The [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) lets AI assistants call functions, read data, and use prompt templates from your application. With the Nuxt MCP Toolkit (`@nuxtjs/mcp-toolkit`), you can add an MCP server directly to your Nuxt app and expose your application's features to tools like Cursor, VS Code, and Claude Desktop. The module handles protocol details, input validation, and auto-discovery so you can focus on building what your MCP server does.

This guide walks you through installing the module, creating tools, resources, and prompt templates, connecting your IDE, debugging with the built-in MCP Inspector, and adding authentication to protect your endpoints.

## Prerequisites

Before you begin, make sure you have:

- A Nuxt 3.x or 4.x project.
  
- Node.js 18 or higher.
  
- The `zod` package installed in your project.
  

## Quick start with an AI coding agent

If you're working with an AI coding agent like Claude Code or Cursor, you can scaffold the starter project and hand off implementation with this prompt:

`You are an expert at creating MCP servers. I'm using the Nuxt MCP starter from nuxt-modules/mcp-toolkit (apps/mcp-starter). Scaffold it with npx giget@latest gh:nuxt-modules/mcp-toolkit/apps/mcp-starter my-app, then pnpm install and pnpm dev. The documentation can be found at https://mcp-toolkit.nuxt.dev. Use the 'site:' operator when calling your Web Search tool, so you only discover information from the docs. Tools, resources, and prompts go under server/mcp/. Use defineMcpTool, defineMcpResource, and defineMcpPrompt from @nuxtjs/mcp-toolkit/server, with Zod for schemas — same style as the existing files. Once my project is ready, ask me what I want this MCP server to do, then please help me implement it.`

### Agent skill

Add the agent skill to teach your AI coding agent about the toolkit:

`npx skills add https://mcp-toolkit.nuxt.dev`

### Documentation MCP

Use the [add-mcp CLI](https://npmx.dev/package/add-mcp#user-content-supported-agents) to add the documentation MCP to your agent:

`npx add-mcp https://mcp-toolkit.nuxt.dev/mcp`

## How it works

The Nuxt MCP Toolkit adds an HTTP endpoint (by default at `/mcp`) to your Nuxt application. AI clients connect to this endpoint using the MCP protocol. The module scans your `server/mcp/` directory for tool, resource, and prompt definitions, then registers them automatically. When an AI assistant sends a request, the module validates inputs with Zod, runs your handler, and returns the result.

Your project structure looks like this after setup:

`your-project/ ├── server/ │ └── mcp/ │ ├── tools/ # Functions that AI assistants can call │ ├── resources/ # Read-only data for AI context │ └── prompts/ # Reusable prompt templates ├── nuxt.config.ts └── package.json`

Files placed in these directories are discovered and registered without any manual wiring.

## 1\. Install the module

Run the automatic installer, which adds the package and updates your Nuxt config:

`npx nuxt module add mcp-toolkit`

If you prefer manual setup, install `@nuxtjs/mcp-toolkit` and its peer dependency `zod`:

`pnpm add @nuxtjs/mcp-toolkit zod`

Then add the module to your `nuxt.config.ts`:

`export default defineNuxtConfig({ modules: ['@nuxtjs/mcp-toolkit'], })` ## 2\. Configure the module The module works with defaults that cover most cases. To customize the server name, endpoint route, or file directory, pass options under the `mcp` key: `export default defineNuxtConfig({ modules: ['@nuxtjs/mcp-toolkit'], mcp: { name: 'My MCP Server', route: '/mcp', dir: 'mcp', }, })` Here's what each option does: | Option            | Type                | Default   | Description                                                                | | ----------------- | ------------------- | --------- | -------------------------------------------------------------------------- | | `enabled`         | `boolean`           | `true`    | Enable or disable the MCP server                                           | | `route`           | `string`            | `'/mcp'`  | HTTP route where the MCP server is accessible                              | | `name`            | `string`            | `''`      | Server name used in the MCP protocol handshake                             | | `version`         | `string`            | `'1.0.0'` | Server version (semantic versioning)                                       | | `dir`             | `string`            | `'mcp'`   | Base directory for definitions, relative to `server/`                      | | `browserRedirect` | `string`            | `'/'`     | URL to redirect browsers visiting the MCP endpoint                         | | `autoImports`     | `boolean`           | `true`    | Auto-import `defineMcpTool`, `defineMcpResource`, and other helpers        | | `sessions`        | `boolean \| object` | `false`   | Enable stateful session management for SSE streaming and per-session state | ## 3\. Create a tool Tools are functions that AI assistants can call to perform actions or retrieve information. Each tool validates its input with Zod and returns a result. Create a file in `server/mcp/tools/`: ``import { z } from 'zod' import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server' export default defineMcpTool({ name: 'echo', description: 'Echo back a message', inputSchema: { message: z.string().describe('The message to echo back'), }, handler: async ({ message }) => `Echo: ${message}`, })`` The `name` and `title` fields are optional. If you omit them, the module generates both from the filename. A file named `list-users.ts` becomes `name: 'list-users'` and `title: 'List Users'`. Your handler receives the validated input object and can return a string, number, boolean, object, or a full `CallToolResult`. For error cases, throw an error with `createError` from `h3`: `import { z } from 'zod' import { createError } from 'h3' import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server' export default defineMcpTool({ description: 'Look up a user by ID', inputSchema: { userId: z.string().describe('The user ID to look up'), }, handler: async ({ userId }) => { const user = await db.query.users.findFirst({ where: (users, { eq }) => eq(users.id, userId), }) if (!user) { throw createError({ statusCode: 404, message: 'User not found' }) } return { name: user.name, email: user.email } }, })` ## 4\. Create a resource Resources expose read-only data that AI assistants can use as context. Unlike tools, resources are application-driven: the host application (or user) decides when to include resource content in a conversation, not the AI model. The quickest way to expose a file is with the `file` property: `import { defineMcpResource } from '@nuxtjs/mcp-toolkit/server' export default defineMcpResource({ name: 'readme', description: 'Project README file', file: 'README.md', })` The module handles URI generation, MIME type detection, and file reading automatically. For custom data sources, define a `uri` and `handler` manually: `import { defineMcpResource } from '@nuxtjs/mcp-toolkit/server' export default defineMcpResource({ name: 'db-schema', description: 'Database schema definition', uri: 'app://schema/database', mimeType: 'application/json', handler: async (uri) => { const schema = await getDbSchema() return { contents: [{ uri: uri.toString(), text: JSON.stringify(schema, null, 2), mimeType: 'application/json', }], } }, })` Use resources for files, configs, database schemas, and logs. Use tools when the AI needs to perform an action or modify state. ## 5\. Create a prompt Prompts are reusable message templates that appear in your IDE when you type `/` in the chat. They standardize how you interact with AI assistants for common tasks. ```import { z } from 'zod' import { defineMcpPrompt } from '@nuxtjs/mcp-toolkit/server' export default defineMcpPrompt({ name: 'review-code', title: 'Code Review', description: 'Generate a code review prompt', inputSchema: { code: z.string().describe('Code to review'), language: z.string().describe('Programming language'), focus: z.enum(['performance', 'security', 'style', 'all']).default('all'), }, handler: async ({ code, language, focus }) => { const focusArea = focus === 'all' ? 'performance, security, and style' : focus return `Please review this ${language} code focusing on ${focusArea}:\n\n\`\`\`${language}\n${code}\n\`\`\`` }, })``` Handlers can return a plain string (auto-wrapped as a user message) or a full `GetPromptResult` with a `messages` array for multi-turn conversations. Prompt arguments must be strings since the MCP protocol requires it. ## 6\. Connect your IDE Start your Nuxt dev server, then connect your AI assistant to the MCP endpoint. ### add-mcp Use the [add-mcp CLI](https://npmx.dev/package/add-mcp#user-content-supported-agents) to add your MCP to Claude Code, OpenCode, and more.

`npx add-mcp http://localhost:3000/mcp`

### Cursor

Add the server to `~/.cursor/mcp.json`:

`{ "mcpServers": { "my-nuxt-app": { "url": "http://localhost:3000/mcp" } } }`

### VS Code

Add the server to `.vscode/mcp.json` in your project:

`{ "servers": { "my-nuxt-app": { "type": "http", "url": "http://localhost:3000/mcp" } } }`

Replace `my-nuxt-app` with your project name and update the URL if you changed the `route` or port.

## 7\. Test with the MCP Inspector

The module includes an integration with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), a visual debugging tool built into Nuxt DevTools. To use it:

1. Enable DevTools in your Nuxt config:
   

`export default defineNuxtConfig({ modules: ['@nuxtjs/mcp-toolkit'], devtools: { enabled: true }, })` 1. Open Nuxt DevTools and navigate to the **MCP Inspector** tab under the **Server** section.     2. Click **Launch Inspector** to browse your tools, resources, and prompts, test them with custom parameters, and view request/response history.     The inspector connects to your MCP server automatically with the correct configuration. ## 8\. Add authentication (optional) To secure your MCP endpoints, add Bearer token validation through the module's middleware system. `import { getHeader } from 'h3' export default defineMcpHandler({ middleware: async (event) => { const authHeader = getHeader(event, 'authorization') if (!authHeader?.startsWith('Bearer ')) { return } const token = authHeader.slice(7) const user = await validateToken(token) if (user) { event.context.user = user event.context.userId = user.id } }, })` MCP middleware should not throw errors when authentication is missing or invalid. Throwing a 401 causes MCP clients to enter OAuth discovery mode, looking for `.well-known/oauth-*` endpoints that don't exist. Instead, set context when auth succeeds and let requests continue otherwise. Your tools can then check for user context: `import { useEvent, createError } from 'h3' import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server' export default defineMcpTool({ description: 'List todos for the authenticated user', inputSchema: {}, handler: async () => { const event = useEvent() const userId = event.context.userId as string if (!userId) { throw createError({ statusCode: 401, message: 'Authentication required. Provide a valid API key.', }) } return await db.query.todos.findMany({ where: (todos, { eq }) => eq(todos.userId, userId), }) }, })` To use `useEvent()` inside tool handlers, enable `asyncContext` in your Nuxt config: `export default defineNuxtConfig({ nitro: { experimental: { asyncContext: true, }, }, })` Configure MCP clients to send the token in request headers (e.g., Cursor): `{ "mcpServers": { "my-app": { "url": "http://localhost:3000/mcp", "headers": { "Authorization": "Bearer your_api_key_here" } } } }` ## Troubleshooting ### MCP endpoint returns a redirect instead of a response If you visit the MCP endpoint in a browser, you'll be redirected to the `browserRedirect` URL (by default `/`). MCP endpoints are designed for programmatic access by AI clients, not browsers. Use the MCP Inspector or your IDE to interact with the server. ### Auto-imports aren't working Confirm that `autoImports` isn't set to `false` in your MCP config. If you've disabled auto-imports, import helpers explicitly: `import { defineMcpTool } from '@nuxtjs/mcp-toolkit/server'` ### Tools don't appear in your IDE Make sure your tool files are in the correct directory (`server/mcp/tools/` by default) and that each file has a default export using `defineMcpTool`. Restart your dev server after adding new files. ### `useEvent()` is undefined in tool handlers Enable `asyncContext` in your Nitro configuration. Without it, `useEvent()` won't have access to the current request context inside async handlers. * * * ## Related resources - [Nuxt MCP Toolkit documentation](https://mcp-toolkit.nuxt.dev/)
  
- [Model Context Protocol specification](https://modelcontextprotocol.io/)
  
- [Vercel Functions documentation](https://vercel.com/docs/functions)
  
- [Nuxt deployment guide](https://nuxt.com/docs/getting-started/deployment)

---

[View full KB sitemap](/kb/sitemap.md)
