[v2] Decouple server from express and hono - http framework-agnostic MCP server (#1326)

This commit is contained in:
Konstantin Konstantinov 2026-01-16 12:13:25 +02:00 • committed by GitHub
commit f495077e08
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
69 changed files with 8193 additions and 15757 deletions

View file

@ -1,7 +1,7 @@
{
"name": "@modelcontextprotocol/client",
"version": "2.0.0-alpha.0",
"description": "Model Context Protocol implementation for TypeScript",
"description": "Model Context Protocol implementation for TypeScript - Client package",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
@ -18,7 +18,8 @@
"packageManager": "pnpm@10.24.0",
"keywords": [
"modelcontextprotocol",
"mcp"
"mcp",
"client"
],
"exports": {
".": {

View file

@ -1,6 +1,7 @@
import type { FetchLike, JSONRPCMessage, Transport } from '@modelcontextprotocol/core';
import { createFetchWithInit, JSONRPCMessageSchema, normalizeHeaders } from '@modelcontextprotocol/core';
import { type ErrorEvent, EventSource, type EventSourceInit } from 'eventsource';
import type { ErrorEvent, EventSourceInit } from 'eventsource';
import { EventSource } from 'eventsource';
import type { AuthResult, OAuthClientProvider } from './auth.js';
import { auth, extractWWWAuthenticateParams, UnauthorizedError } from './auth.js';

View file

@ -2,7 +2,7 @@
"name": "@modelcontextprotocol/core",
"private": true,
"version": "2.0.0-alpha.0",
"description": "Model Context Protocol implementation for TypeScript",
"description": "Model Context Protocol implementation for TypeScript - Core package",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
@ -19,7 +19,8 @@
"packageManager": "pnpm@10.24.0",
"keywords": [
"modelcontextprotocol",
"mcp"
"mcp",
"core"
],
"scripts": {
"typecheck": "tsgo -p tsconfig.json --noEmit",

View file

@ -292,14 +292,14 @@ export type RequestHandlerExtra<SendRequestT extends Request, SendNotificationT
/**
* Closes the SSE stream for this request, triggering client reconnection.
* Only available when using StreamableHTTPServerTransport with eventStore configured.
* Only available when using a StreamableHTTPServerTransport with eventStore configured.
* Use this to implement polling behavior during long-running operations.
*/
closeSSEStream?: () => void;
/**
* Closes the standalone GET SSE stream, triggering client reconnection.
* Only available when using StreamableHTTPServerTransport with eventStore configured.
* Only available when using a StreamableHTTPServerTransport with eventStore configured.
* Use this to implement polling behavior for server-initiated notifications.
*/
closeStandaloneSSEStream?: () => void;

View file

@ -2415,13 +2415,13 @@ export interface MessageExtraInfo {
/**
* Callback to close the SSE stream for this request, triggering client reconnection.
* Only available when using StreamableHTTPServerTransport with eventStore configured.
* Only available when using NodeStreamableHTTPServerTransport with eventStore configured.
*/
closeSSEStream?: () => void;
/**
* Callback to close the standalone GET SSE stream, triggering client reconnection.
* Only available when using StreamableHTTPServerTransport with eventStore configured.
* Only available when using NodeStreamableHTTPServerTransport with eventStore configured.
*/
closeStandaloneSSEStream?: () => void;
}

View file

@ -2095,7 +2095,7 @@ describe('Request Cancellation vs Task Cancellation', () => {
let wasAborted = false;
const TestRequestSchema = z.object({
method: z.literal('test/longRunning'),
params: z.optional(z.record(z.unknown()))
params: z.optional(z.record(z.string(), z.unknown()))
});
protocol.setRequestHandler(TestRequestSchema, async (_request, extra) => {
// Simulate a long-running operation
@ -2310,7 +2310,7 @@ describe('Request Cancellation vs Task Cancellation', () => {
let requestCompleted = false;
const TestMethodSchema = z.object({
method: z.literal('test/method'),
params: z.optional(z.record(z.unknown()))
params: z.optional(z.record(z.string(), z.unknown()))
});
protocol.setRequestHandler(TestMethodSchema, async () => {
await new Promise(resolve => setTimeout(resolve, 50));
@ -3690,7 +3690,7 @@ describe('Message Interception', () => {
method: z.literal('test/taskRequest'),
params: z
.object({
_meta: z.optional(z.record(z.unknown()))
_meta: z.optional(z.record(z.string(), z.unknown()))
})
.passthrough()
});
@ -3737,7 +3737,7 @@ describe('Message Interception', () => {
method: z.literal('test/taskRequestError'),
params: z
.object({
_meta: z.optional(z.record(z.unknown()))
_meta: z.optional(z.record(z.string(), z.unknown()))
})
.passthrough()
});
@ -3817,7 +3817,7 @@ describe('Message Interception', () => {
// Set up a request handler
const TestRequestSchema = z.object({
method: z.literal('test/normalRequest'),
params: z.optional(z.record(z.unknown()))
params: z.optional(z.record(z.string(), z.unknown()))
});
protocol.setRequestHandler(TestRequestSchema, async () => {

View file

@ -0,0 +1,24 @@
# Middleware packages
The packages in `packages/middleware/*` are **thin integration layers** that help you expose an MCP server in a specific runtime, platform, or web framework.
They intentionally **do not** add new MCP features or “business logic”. MCP functionality (tools, resources, prompts, transports, auth primitives, etc.) lives in `@modelcontextprotocol/server` (and other core packages). Middleware packages should primarily:
- adapt request/response types to the SDK (e.g. Node.js `IncomingMessage`/`ServerResponse`)
- provide small framework helpers (e.g. wiring, body parsing hooks)
- supply safe defaults for common deployment pitfalls (e.g. localhost DNS rebinding protection)
## Packages
- `@modelcontextprotocol/express` — Express helpers (app defaults + Host header validation for DNS rebinding protection).
- `@modelcontextprotocol/hono` — Hono helpers (app defaults + JSON body parsing hook + Host header validation).
- `@modelcontextprotocol/node` — Node.js Streamable HTTP transport wrapper for `IncomingMessage`/`ServerResponse`.
## Typical usage
Most servers use:
- `@modelcontextprotocol/server` for the MCP server implementation
- one middleware package for framework/runtime integration (this folder)
- (optionally) additional platform/framework dependencies (Express, Hono, etc.)

View file

@ -0,0 +1,62 @@
# `@modelcontextprotocol/express`
Express adapters for the MCP TypeScript server SDK.
This package is a thin Express integration layer for [`@modelcontextprotocol/server`](../../server/).
It does **not** implement MCP itself. Instead, it helps you:
- create an Express app with sensible defaults for MCP servers
- add DNS rebinding protection via Host header validation (recommended for localhost servers)
## Install
```bash
npm install @modelcontextprotocol/server @modelcontextprotocol/express express
# For MCP Streamable HTTP over Node.js (IncomingMessage/ServerResponse):
npm install @modelcontextprotocol/node
```
## Exports
- `createMcpExpressApp(options?)`
- `hostHeaderValidation(allowedHostnames)`
- `localhostHostValidation()`
## Usage
### Create an Express app (localhost DNS rebinding protection by default)
```ts
import { createMcpExpressApp } from '@modelcontextprotocol/express';
const app = createMcpExpressApp(); // default host is 127.0.0.1; protection enabled
```
### Streamable HTTP endpoint (Express)
```ts
import { createMcpExpressApp } from '@modelcontextprotocol/express';
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
import { McpServer } from '@modelcontextprotocol/server';
const app = createMcpExpressApp();
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
app.post('/mcp', async (req, res) => {
// Stateless example: create a transport per request.
// For stateful mode (sessions), keep a transport instance around and reuse it.
const transport = new NodeStreamableHTTPServerTransport({ sessionIdGenerator: undefined });
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
```
### Host header validation (DNS rebinding protection)
```ts
import { hostHeaderValidation } from '@modelcontextprotocol/express';
app.use(hostHeaderValidation(['localhost', '127.0.0.1', '[::1]']));
```

View file

@ -0,0 +1,12 @@
// @ts-check
import baseConfig from '@modelcontextprotocol/eslint-config';
export default [
...baseConfig,
{
settings: {
'import/internal-regex': '^@modelcontextprotocol/(server|core)'
}
}
];

View file

@ -0,0 +1,69 @@
{
"name": "@modelcontextprotocol/express",
"private": false,
"version": "2.0.0-alpha.0",
"description": "Express adapters for the Model Context Protocol TypeScript server SDK - Express middleware",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git"
},
"engines": {
"node": ">=20",
"pnpm": ">=10.24.0"
},
"packageManager": "pnpm@10.24.0",
"keywords": [
"modelcontextprotocol",
"mcp",
"express",
"middleware"
],
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs"
}
},
"files": [
"dist"
],
"scripts": {
"typecheck": "tsgo -p tsconfig.json --noEmit",
"build": "tsdown",
"build:watch": "tsdown --watch",
"prepack": "npm run build",
"lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .",
"lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .",
"check": "npm run typecheck && npm run lint",
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {},
"peerDependencies": {
"@modelcontextprotocol/server": "workspace:^",
"express": "catalog:runtimeServerOnly"
},
"devDependencies": {
"@modelcontextprotocol/server": "workspace:^",
"@modelcontextprotocol/tsconfig": "workspace:^",
"@modelcontextprotocol/vitest-config": "workspace:^",
"@modelcontextprotocol/eslint-config": "workspace:^",
"@eslint/js": "catalog:devTools",
"@types/express": "catalog:devTools",
"@types/express-serve-static-core": "catalog:devTools",
"@typescript/native-preview": "catalog:devTools",
"eslint": "catalog:devTools",
"eslint-config-prettier": "catalog:devTools",
"eslint-plugin-n": "catalog:devTools",
"prettier": "catalog:devTools",
"tsdown": "catalog:devTools",
"typescript": "catalog:devTools",
"typescript-eslint": "catalog:devTools",
"vitest": "catalog:devTools"
}
}

View file

@ -0,0 +1,76 @@
import type { Express } from 'express';
import express from 'express';
import { hostHeaderValidation, localhostHostValidation } from './middleware/hostHeaderValidation.js';
/**
* Options for creating an MCP Express application.
*/
export interface CreateMcpExpressAppOptions {
/**
* The hostname to bind to. Defaults to '127.0.0.1'.
* When set to '127.0.0.1', 'localhost', or '::1', DNS rebinding protection is automatically enabled.
*/
host?: string;
/**
* List of allowed hostnames for DNS rebinding protection.
* If provided, host header validation will be applied using this list.
* For IPv6, provide addresses with brackets (e.g., '[::1]').
*
* This is useful when binding to '0.0.0.0' or '::' but still wanting
* to restrict which hostnames are allowed.
*/
allowedHosts?: string[];
}
/**
* Creates an Express application pre-configured for MCP servers.
*
* When the host is '127.0.0.1', 'localhost', or '::1' (the default is '127.0.0.1'),
* DNS rebinding protection middleware is automatically applied to protect against
* DNS rebinding attacks on localhost servers.
*
* @param options - Configuration options
* @returns A configured Express application
*
* @example
* ```typescript
* // Basic usage - defaults to 127.0.0.1 with DNS rebinding protection
* const app = createMcpExpressApp();
*
* // Custom host - DNS rebinding protection only applied for localhost hosts
* const app = createMcpExpressApp({ host: '0.0.0.0' }); // No automatic DNS rebinding protection
* const app = createMcpExpressApp({ host: 'localhost' }); // DNS rebinding protection enabled
*
* // Custom allowed hosts for non-localhost binding
* const app = createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['myapp.local', 'localhost'] });
* ```
*/
export function createMcpExpressApp(options: CreateMcpExpressAppOptions = {}): Express {
const { host = '127.0.0.1', allowedHosts } = options;
const app = express();
app.use(express.json());
// If allowedHosts is explicitly provided, use that for validation
if (allowedHosts) {
app.use(hostHeaderValidation(allowedHosts));
} else {
// Apply DNS rebinding protection automatically for localhost hosts
const localhostHosts = ['127.0.0.1', 'localhost', '::1'];
if (localhostHosts.includes(host)) {
app.use(localhostHostValidation());
} else if (host === '0.0.0.0' || host === '::') {
// Warn when binding to all interfaces without DNS rebinding protection
// eslint-disable-next-line no-console
console.warn(
`Warning: Server is binding to ${host} without DNS rebinding protection. ` +
'Consider using the allowedHosts option to restrict allowed hosts, ' +
'or use authentication to protect your server.'
);
}
}
return app;
}

View file

@ -0,0 +1,2 @@
export * from './express.js';
export * from './middleware/hostHeaderValidation.js';

View file

@ -0,0 +1,52 @@
import { localhostAllowedHostnames, validateHostHeader } from '@modelcontextprotocol/server';
import type { NextFunction, Request, RequestHandler, Response } from 'express';
/**
* Express middleware for DNS rebinding protection.
* Validates Host header hostname (port-agnostic) against an allowed list.
*
* This is particularly important for servers without authorization or HTTPS,
* such as localhost servers or development servers. DNS rebinding attacks can
* bypass same-origin policy by manipulating DNS to point a domain to a
* localhost address, allowing malicious websites to access your local server.
*
* @param allowedHostnames - List of allowed hostnames (without ports).
* For IPv6, provide the address with brackets (e.g., '[::1]').
* @returns Express middleware function
*
* @example
* ```typescript
* const middleware = hostHeaderValidation(['localhost', '127.0.0.1', '[::1]']);
* app.use(middleware);
* ```
*/
export function hostHeaderValidation(allowedHostnames: string[]): RequestHandler {
return (req: Request, res: Response, next: NextFunction) => {
const result = validateHostHeader(req.headers.host, allowedHostnames);
if (!result.ok) {
res.status(403).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: result.message
},
id: null
});
return;
}
next();
};
}
/**
* Convenience middleware for localhost DNS rebinding protection.
* Allows only localhost, 127.0.0.1, and [::1] (IPv6 localhost) hostnames.
*
* @example
* ```typescript
* app.use(localhostHostValidation());
* ```
*/
export function localhostHostValidation(): RequestHandler {
return hostHeaderValidation(localhostAllowedHostnames());
}

View file

@ -0,0 +1,182 @@
import type { NextFunction, Request, Response } from 'express';
import { vi } from 'vitest';
import { createMcpExpressApp } from '../src/express.js';
import { hostHeaderValidation, localhostHostValidation } from '../src/middleware/hostHeaderValidation.js';
// Helper to create mock Express request/response/next
function createMockReqResNext(host?: string) {
const req = {
headers: {
host
}
} as Request;
const res = {
status: vi.fn().mockReturnThis(),
json: vi.fn().mockReturnThis()
} as unknown as Response;
const next = vi.fn() as NextFunction;
return { req, res, next };
}
describe('@modelcontextprotocol/express', () => {
describe('hostHeaderValidation', () => {
test('should block invalid Host header', () => {
const middleware = hostHeaderValidation(['localhost']);
const { req, res, next } = createMockReqResNext('evil.com:3000');
middleware(req, res, next);
expect(res.status).toHaveBeenCalledWith(403);
expect(res.json).toHaveBeenCalledWith(
expect.objectContaining({
jsonrpc: '2.0',
error: expect.objectContaining({
code: -32000
}),
id: null
})
);
expect(next).not.toHaveBeenCalled();
});
test('should allow valid Host header', () => {
const middleware = hostHeaderValidation(['localhost']);
const { req, res, next } = createMockReqResNext('localhost:3000');
middleware(req, res, next);
expect(res.status).not.toHaveBeenCalled();
expect(res.json).not.toHaveBeenCalled();
expect(next).toHaveBeenCalled();
});
test('should handle multiple allowed hostnames', () => {
const middleware = hostHeaderValidation(['localhost', '127.0.0.1', 'myapp.local']);
const { req: req1, res: res1, next: next1 } = createMockReqResNext('127.0.0.1:8080');
const { req: req2, res: res2, next: next2 } = createMockReqResNext('myapp.local');
middleware(req1, res1, next1);
middleware(req2, res2, next2);
expect(next1).toHaveBeenCalled();
expect(next2).toHaveBeenCalled();
});
});
describe('localhostHostValidation', () => {
test('should allow localhost', () => {
const middleware = localhostHostValidation();
const { req, res, next } = createMockReqResNext('localhost:3000');
middleware(req, res, next);
expect(next).toHaveBeenCalled();
});
test('should allow 127.0.0.1', () => {
const middleware = localhostHostValidation();
const { req, res, next } = createMockReqResNext('127.0.0.1:3000');
middleware(req, res, next);
expect(next).toHaveBeenCalled();
});
test('should allow [::1] (IPv6 localhost)', () => {
const middleware = localhostHostValidation();
const { req, res, next } = createMockReqResNext('[::1]:3000');
middleware(req, res, next);
expect(next).toHaveBeenCalled();
});
test('should block non-localhost hosts', () => {
const middleware = localhostHostValidation();
const { req, res, next } = createMockReqResNext('evil.com:3000');
middleware(req, res, next);
expect(res.status).toHaveBeenCalledWith(403);
expect(next).not.toHaveBeenCalled();
});
});
describe('createMcpExpressApp', () => {
test('should enable localhost DNS rebinding protection by default', () => {
const app = createMcpExpressApp();
// The app should be a valid Express application
expect(app).toBeDefined();
expect(typeof app.use).toBe('function');
expect(typeof app.get).toBe('function');
expect(typeof app.post).toBe('function');
});
test('should apply DNS rebinding protection for localhost host', () => {
const app = createMcpExpressApp({ host: 'localhost' });
expect(app).toBeDefined();
});
test('should apply DNS rebinding protection for ::1 host', () => {
const app = createMcpExpressApp({ host: '::1' });
expect(app).toBeDefined();
});
test('should use allowedHosts when provided', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
const app = createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['myapp.local'] });
warn.mockRestore();
expect(app).toBeDefined();
});
test('should warn when binding to 0.0.0.0 without allowedHosts', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
createMcpExpressApp({ host: '0.0.0.0' });
expect(warn).toHaveBeenCalledWith(
expect.stringContaining('Warning: Server is binding to 0.0.0.0 without DNS rebinding protection')
);
warn.mockRestore();
});
test('should warn when binding to :: without allowedHosts', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
createMcpExpressApp({ host: '::' });
expect(warn).toHaveBeenCalledWith(expect.stringContaining('Warning: Server is binding to :: without DNS rebinding protection'));
warn.mockRestore();
});
test('should not warn for 0.0.0.0 when allowedHosts is provided', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
createMcpExpressApp({ host: '0.0.0.0', allowedHosts: ['myapp.local'] });
expect(warn).not.toHaveBeenCalled();
warn.mockRestore();
});
test('should not apply host validation for non-localhost hosts without allowedHosts', () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
// For arbitrary hosts (not 0.0.0.0 or ::), no validation is applied and no warning
const app = createMcpExpressApp({ host: '192.168.1.1' });
expect(warn).not.toHaveBeenCalled();
expect(app).toBeDefined();
warn.mockRestore();
});
});
});

View file

@ -0,0 +1,14 @@
{
"extends": "@modelcontextprotocol/tsconfig",
"include": ["./"],
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"paths": {
"*": ["./*"],
"@modelcontextprotocol/server": ["./node_modules/@modelcontextprotocol/server/src/index.ts"],
"@modelcontextprotocol/core": [
"./node_modules/@modelcontextprotocol/server/node_modules/@modelcontextprotocol/core/src/index.ts"
]
}
}
}

View file

@ -0,0 +1,21 @@
import { defineConfig } from 'tsdown';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
outDir: 'dist',
clean: true,
sourcemap: true,
target: 'esnext',
platform: 'node',
shims: true,
dts: {
resolver: 'tsc',
compilerOptions: {
baseUrl: '.',
paths: {
'@modelcontextprotocol/server': ['../server/src/index.ts']
}
}
}
});

View file

@ -0,0 +1,3 @@
import baseConfig from '@modelcontextprotocol/vitest-config';
export default baseConfig;

View file

@ -0,0 +1,48 @@
# `@modelcontextprotocol/hono`
Hono adapters for the MCP TypeScript server SDK.
This package is a thin Hono integration layer for [`@modelcontextprotocol/server`](../../server/).
It does **not** implement MCP itself. Instead, it helps you:
- create a Hono app with sensible defaults for MCP servers
- parse JSON request bodies and expose them as `c.get('parsedBody')` for Streamable HTTP transports
- add DNS rebinding protection via Host header validation (recommended for localhost servers)
## Install
```bash
npm install @modelcontextprotocol/server @modelcontextprotocol/hono hono
```
## Exports
- `createMcpHonoApp(options?)`
- `hostHeaderValidation(allowedHostnames)`
- `localhostHostValidation()`
## Usage
### Streamable HTTP endpoint (Hono)
```ts
import { McpServer, WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server';
import { createMcpHonoApp } from '@modelcontextprotocol/hono';
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined });
await server.connect(transport);
const app = createMcpHonoApp();
app.all('/mcp', c => transport.handleRequest(c.req.raw, { parsedBody: c.get('parsedBody') }));
```
### Host header validation (DNS rebinding protection)
```ts
import { localhostHostValidation } from '@modelcontextprotocol/hono';
const app = createMcpHonoApp();
app.use('*', localhostHostValidation());
```

View file

@ -0,0 +1,12 @@
// @ts-check
import baseConfig from '@modelcontextprotocol/eslint-config';
export default [
...baseConfig,
{
settings: {
'import/internal-regex': '^@modelcontextprotocol/(server|core)'
}
}
];

View file

@ -0,0 +1,67 @@
{
"name": "@modelcontextprotocol/hono",
"private": false,
"version": "2.0.0-alpha.0",
"description": "Hono adapters for the Model Context Protocol TypeScript server SDK - Hono middleware",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/typescript-sdk/issues",
"type": "module",
"repository": {
"type": "git",
"url": "git+https://github.com/modelcontextprotocol/typescript-sdk.git"
},
"engines": {
"node": ">=20",
"pnpm": ">=10.24.0"
},
"packageManager": "pnpm@10.24.0",
"keywords": [
"modelcontextprotocol",
"mcp",
"hono",
"middleware"
],
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs"
}
},
"files": [
"dist"
],
"scripts": {
"typecheck": "tsgo -p tsconfig.json --noEmit",
"build": "tsdown",
"build:watch": "tsdown --watch",
"prepack": "npm run build",
"lint": "eslint src/ && prettier --ignore-path ../../.prettierignore --check .",
"lint:fix": "eslint src/ --fix && prettier --ignore-path ../../.prettierignore --write .",
"check": "npm run typecheck && npm run lint",
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {},
"peerDependencies": {
"@modelcontextprotocol/server": "workspace:^",
"hono": "catalog:runtimeServerOnly"
},
"devDependencies": {
"@modelcontextprotocol/server": "workspace:^",
"@modelcontextprotocol/tsconfig": "workspace:^",
"@modelcontextprotocol/vitest-config": "workspace:^",
"@modelcontextprotocol/eslint-config": "workspace:^",
"@eslint/js": "catalog:devTools",
"@typescript/native-preview": "catalog:devTools",
"eslint": "catalog:devTools",
"eslint-config-prettier": "catalog:devTools",
"eslint-plugin-n": "catalog:devTools",
"prettier": "catalog:devTools",
"tsdown": "catalog:devTools",
"typescript": "catalog:devTools",
"typescript-eslint": "catalog:devTools",
"vitest": "catalog:devTools"
}
}

Some files were not shown because too many files have changed in this diff Show more