├── .gitignore ├── README.md ├── app └── pages │ └── index.vue ├── eslint.config.mjs ├── nuxt.config.ts ├── package.json ├── pnpm-lock.yaml ├── public ├── favicon.ico └── robots.txt ├── scripts └── test-client.mjs ├── server ├── routes │ └── mcp │ │ └── [transport].ts └── tsconfig.json └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nuxt MCP Server on Vercel 2 | 3 | This is a simple Nuxt application that serves as a MCP server on Vercel using `@vercel/mcp-adapter`. 4 | 5 | ## Usage 6 | 7 | This sample app uses the [Vercel MCP Adapter](https://www.npmjs.com/package/@vercel/mcp-adapter) that allows you to drop in an MCP server on a group of routes in any Nuxt project. 8 | 9 | Update `server/routes/mcp/[transport].ts` with your tools, prompts, and resources following the [MCP TypeScript SDK documentation](https://github.com/modelcontextprotocol/typescript-sdk/tree/main?tab=readme-ov-file#server). 10 | 11 | The MCP server is mounted on `/mcp/[transport]` (ex: `/mcp/sse`). 12 | 13 | ## Setup 14 | 15 | Make sure to install dependencies: 16 | 17 | ```bash 18 | pnpm install 19 | ``` 20 | 21 | ## Development Server 22 | 23 | Make sure to have Redis running locally: 24 | 25 | ```bash 26 | redis-server 27 | ``` 28 | 29 | Start the development server on another terminal on `http://localhost:3000`: 30 | 31 | ```bash 32 | pnpm dev 33 | ``` 34 | 35 | ## Production 36 | 37 | Build the application for production: 38 | 39 | ```bash 40 | pnpm build 41 | ``` 42 | 43 | Locally preview production build: 44 | 45 | ```bash 46 | pnpm preview 47 | ``` 48 | 49 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. 50 | 51 | ## Notes for running on Vercel 52 | 53 | - To use the SSE transport, requires a Redis attached to the project under `process.env.REDIS_URL` 54 | - Make sure you have [Fluid compute](https://vercel.com/docs/functions/fluid-compute) enabled for efficient execution 55 | - After enabling Fluid compute, open `server/routes/mcp/[transport].ts` and adjust `maxDuration` to 800 if you using a Vercel Pro or Enterprise account 56 | - [Deploy the Nuxt MCP template](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fatinux%2Fmcp-with-nuxt-vercel&integration-ids=oac_V3R1GIpkoJorr6fqyiwdhl17) 57 | 58 | 59 | ## Sample Client 60 | 61 | `script/test-client.mjs` contains a sample client to try invocations. 62 | 63 | ```sh 64 | node scripts/test-client.mjs http://localhost:3000 65 | ``` 66 | 67 | ## Credits 68 | 69 | This project is based on the [Next.js MCP template](https://github.com/vercel-labs/mcp-for-next.js). 70 | -------------------------------------------------------------------------------- /app/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import withNuxt from './.nuxt/eslint.config.mjs' 3 | 4 | export default withNuxt( 5 | // Your custom configs here 6 | ) 7 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | export default defineNuxtConfig({ 3 | modules: ['@nuxt/eslint'], 4 | devtools: { enabled: true }, 5 | future: { 6 | compatibilityVersion: 4 7 | }, 8 | compatibilityDate: '2024-11-01', 9 | eslint: { 10 | config: { 11 | stylistic: { 12 | quotes: 'single', 13 | commaDangle: 'never' 14 | } 15 | } 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-app", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "nuxt build", 7 | "dev": "nuxt dev", 8 | "generate": "nuxt generate", 9 | "preview": "nuxt preview", 10 | "postinstall": "nuxt prepare", 11 | "lint": "eslint --fix ." 12 | }, 13 | "dependencies": { 14 | "@vercel/mcp-adapter": "^0.3.1", 15 | "nuxt": "^3.17.2", 16 | "vue": "^3.5.13", 17 | "vue-router": "^4.5.1", 18 | "zod": "^3.24.4" 19 | }, 20 | "devDependencies": { 21 | "@modelcontextprotocol/sdk": "^1.11.1", 22 | "@nuxt/eslint": "1.3.0", 23 | "eslint": "^9.26.0", 24 | "typescript": "^5.8.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/atinux/mcp-with-nuxt-vercel/5b45c6b3ebcc5ccd02ef592224ab4b1d6fb6af22/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /scripts/test-client.mjs: -------------------------------------------------------------------------------- 1 | import { Client } from '@modelcontextprotocol/sdk/client/index.js' 2 | import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js' 3 | 4 | const origin = process.argv[2] || 'https://mcp-with-nuxt.vercel.app' 5 | 6 | async function main() { 7 | const transport = new SSEClientTransport(new URL(`${origin}/mcp/sse`)) 8 | 9 | const client = new Client( 10 | { 11 | name: 'example-client', 12 | version: '1.0.0' 13 | }, 14 | { 15 | capabilities: { 16 | prompts: {}, 17 | resources: {}, 18 | tools: {} 19 | } 20 | } 21 | ) 22 | 23 | console.log('Connecting to', origin) 24 | await client.connect(transport) 25 | 26 | console.log('Connected', client.getServerCapabilities()) 27 | 28 | const result = await client.listTools() 29 | console.log(result) 30 | client.close() 31 | } 32 | 33 | main() 34 | -------------------------------------------------------------------------------- /server/routes/mcp/[transport].ts: -------------------------------------------------------------------------------- 1 | import { createMcpHandler } from '@vercel/mcp-adapter' 2 | import { z } from 'zod' 3 | 4 | const handler = createMcpHandler( 5 | (server) => { 6 | server.tool( 7 | 'echo', 8 | 'Echo a message', 9 | { message: z.string() }, 10 | async ({ message }) => ({ 11 | content: [{ type: 'text', text: `Tool echo: ${message}` }] 12 | }) 13 | ) 14 | }, 15 | { 16 | capabilities: { 17 | tools: { 18 | echo: { 19 | description: 'Echo a message' 20 | } 21 | } 22 | } 23 | }, 24 | { 25 | redisUrl: process.env.REDIS_URL, 26 | basePath: '/mcp', 27 | verboseLogs: true, 28 | maxDuration: 60 29 | } 30 | ) 31 | 32 | export default fromWebHandler(handler) 33 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | --------------------------------------------------------------------------------