Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/evil-things-check.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@vercel/mcp-adapter": minor
"mcp-handler": minor
---

Refactor packaging and make withMcpAuth stable
2 changes: 1 addition & 1 deletion .changeset/ripe-mails-doubt.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
"@vercel/mcp-adapter": minor
"mcp-handler": minor
---

Add RFC 9728 OAuth Protected Resource Metadata handler
5 changes: 5 additions & 0 deletions .changeset/violet-squids-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"mcp-handler": major
---

Move package from @vercle/mcp-adapter to mcp-handler
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# @vercel/mcp-adapter
# mcp-handler

## 0.11.2

Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# @vercel/mcp-adapter
# mcp-handler

A Vercel adapter for the Model Context Protocol (MCP), enabling real-time communication between your applications and AI models. Currently supports Next.js with more framework adapters coming soon.

## Installation

```bash
npm install @vercel/mcp-adapter @modelcontextprotocol/sdk
npm install mcp-handler @modelcontextprotocol/sdk
# or
yarn add @vercel/mcp-adapter @modelcontextprotocol/sdk
yarn add mcp-handler @modelcontextprotocol/sdk
# or
pnpm add @vercel/mcp-adapter @modelcontextprotocol/sdk
pnpm add mcp-handler @modelcontextprotocol/sdk
# or
bun add @vercel/mcp-adapter @modelcontextprotocol/sdk
bun add mcp-handler @modelcontextprotocol/sdk
```

## Next.js Usage

```typescript
// app/api/[transport]/route.ts
import { createMcpHandler } from "@vercel/mcp-adapter";
import { createMcpHandler } from "mcp-handler";
const handler = createMcpHandler(
(server) => {
server.tool(
Expand Down Expand Up @@ -159,7 +159,7 @@ The MCP adapter supports the [MCP Authorization Specification](https://modelcont

```typescript
// app/api/[transport]/route.ts
import { createMcpHandler, withMcpAuth } from "@vercel/mcp-adapter";
import { createMcpHandler, withMcpAuth } from "mcp-handler";

// Create your handler as normal
const handler = createMcpHandler(
Expand Down Expand Up @@ -235,7 +235,7 @@ Create a new file at `app/.well-known/oauth-protected-resource/route.ts`:
import {
protectedResourceHandler,
metadataCorsOptionsRequestHandler,
} from "@vercel/mcp-adapter";
} from "mcp-handler";

const handler = protectedResourceHandler({
// Specify the Issuer URL of the associated Authorization Server
Expand Down
90 changes: 48 additions & 42 deletions examples/auth/route.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { AuthInfo } from "@modelcontextprotocol/sdk/server/auth/types";
import { createMcpHandler, experimental_withMcpAuth as withMcpAuth } from "@vercel/mcp-adapter";
import {
createMcpHandler,
experimental_withMcpAuth as withMcpAuth,
} from "mcp-handler";
import { z } from "zod";

// Define the handler with proper parameter validation
const handler = createMcpHandler(
server => {
(server) => {
server.tool(
'echo',
'Echo a message back with authentication info',
"echo",
"Echo a message back with authentication info",
{
message: z.string().describe('The message to echo back')
message: z.string().describe("The message to echo back"),
},
async ({ message }, extra) => {
return {
content: [
{
type: 'text',
text: `Echo: ${message}${extra.authInfo?.token ? ` (from ${extra.authInfo.clientId})` : ''}`,
type: "text",
text: `Echo: ${message}${
extra.authInfo?.token
? ` (from ${extra.authInfo.clientId})`
: ""
}`,
},
],
};
Expand All @@ -27,17 +34,17 @@ const handler = createMcpHandler(
{
capabilities: {
auth: {
type: 'bearer',
type: "bearer",
required: true,
},
},
},
// Route configuration
{
streamableHttpEndpoint: '/mcp',
sseEndpoint: '/sse',
sseMessageEndpoint: '/message',
basePath: '/api/mcp',
streamableHttpEndpoint: "/mcp",
sseEndpoint: "/sse",
sseMessageEndpoint: "/message",
basePath: "/api/mcp",
redisUrl: process.env.REDIS_URL,
}
);
Expand All @@ -46,38 +53,37 @@ const handler = createMcpHandler(
* Verify the bearer token and return auth information
* In a real implementation, this would validate against your auth service
*/
const verifyToken = async (req: Request, bearerToken?: string): Promise<AuthInfo | undefined> => {
if (!bearerToken) return undefined;

// TODO: Replace with actual token verification logic
// This is just an example implementation
const isValid = bearerToken.startsWith('__TEST_VALUE__');

if (!isValid) return undefined;

return {
token: bearerToken,
scopes: ['read:messages', 'write:messages'],
clientId: 'example-client',
extra: {
userId: 'user-123',
// Add any additional user/client information here
permissions: ['user'],
timestamp: new Date().toISOString()
}
};
}
const verifyToken = async (
req: Request,
bearerToken?: string
): Promise<AuthInfo | undefined> => {
if (!bearerToken) return undefined;

// TODO: Replace with actual token verification logic
// This is just an example implementation
const isValid = bearerToken.startsWith("__TEST_VALUE__");

if (!isValid) return undefined;

return {
token: bearerToken,
scopes: ["read:messages", "write:messages"],
clientId: "example-client",
extra: {
userId: "user-123",
// Add any additional user/client information here
permissions: ["user"],
timestamp: new Date().toISOString(),
},
};
};

// Create the auth handler with required scopes
const authHandler = withMcpAuth(
handler,
verifyToken,
{
required: true,
requiredScopes: ['read:messages'],
resourceMetadataPath: '/.well-known/oauth-protected-resource'
}
);
const authHandler = withMcpAuth(handler, verifyToken, {
required: true,
requiredScopes: ["read:messages"],
resourceMetadataPath: "/.well-known/oauth-protected-resource",
});

// Export the handler for both GET and POST methods
export { authHandler as GET, authHandler as POST };
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "@vercel/mcp-adapter",
"name": "mcp-handler",
"version": "0.11.2",
"description": "Vercel MCP Adapter for Next.js and other frameworks",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "commonjs",
"bin": {
"create-mcp-route": "./dist/cli/index.js",
"mcp-handler": "./dist/cli/index.js",
"@vercel/mcp-adapter": "./dist/cli/index.js"
},
"exports": {
Expand Down
6 changes: 3 additions & 3 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import chalk from "chalk";

const program = new Command();

const ROUTE_TEMPLATE = `import { createMcpHandler } from '@vercel/mcp-adapter';
const ROUTE_TEMPLATE = `import { createMcpHandler } from 'mcp-handler';
import { z } from 'zod';

const handler = createMcpHandler(
Expand Down Expand Up @@ -66,7 +66,7 @@ async function installDependencies(
packageManager: "npm" | "pnpm" | "yarn" | "bun"
) {
const execSync = (await import("node:child_process")).execSync;
const dependencies = ["@vercel/mcp-adapter", "zod"];
const dependencies = ["mcp-handler", "zod"];

const commands = {
npm: `npm install ${dependencies.join(" ")}`,
Expand Down Expand Up @@ -125,7 +125,7 @@ async function init() {
}

program
.name("@vercel/mcp-adapter")
.name("mcp-handler")
.description("Initialize MCP route handler in your Next.js project")
.action(init);

Expand Down