@@ -7,18 +7,40 @@ import type {
77} from './types.js'
88import { McpServer as OfficialMcpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
99import { z } from 'zod'
10+ import express , { type Express } from 'express'
1011
1112export class McpServer {
1213 private server : OfficialMcpServer
1314 private config : ServerConfig
14- private expressApp ?: any
15+ private app : Express
16+ private mcpMounted = false
1517
1618 constructor ( config : ServerConfig ) {
1719 this . config = config
1820 this . server = new OfficialMcpServer ( {
1921 name : config . name ,
2022 version : config . version ,
2123 } )
24+ this . app = express ( )
25+
26+ // Enable CORS by default
27+ this . app . use ( ( req , res , next ) => {
28+ res . header ( 'Access-Control-Allow-Origin' , '*' )
29+ res . header ( 'Access-Control-Allow-Methods' , 'GET, POST, DELETE, OPTIONS' )
30+ res . header ( 'Access-Control-Allow-Headers' , 'Content-Type' )
31+ next ( )
32+ } )
33+
34+ // Proxy all Express methods to the underlying app
35+ return new Proxy ( this , {
36+ get ( target , prop ) {
37+ if ( prop in target ) {
38+ return ( target as any ) [ prop ]
39+ }
40+ const value = ( target . app as any ) [ prop ]
41+ return typeof value === 'function' ? value . bind ( target . app ) : value
42+ }
43+ } ) as McpServer
2244 }
2345
2446 /**
@@ -126,83 +148,56 @@ export class McpServer {
126148 }
127149
128150 /**
129- * Set the Express app for SSE transport
130- */
131- setExpressApp ( app : any ) : this {
132- this . expressApp = app
133- return this
134- }
135-
136- /**
137- * Start the MCP server with configurable transport
138- * @param options - Transport options (defaults to HTTP)
151+ * Mount MCP server endpoints at /mcp
139152 */
140- async serve ( options ?: { transport ?: 'http' | 'stdio' , port ?: number , endpoint ?: string } ) : Promise < void > {
141- const transport = options ?. transport || ( process . env . MCP_TRANSPORT as 'http' | 'stdio' ) || 'http'
142-
143- if ( transport === 'stdio' ) {
144- // Use stdio transport (for traditional MCP clients)
145- const { StdioServerTransport } = await import ( '@modelcontextprotocol/sdk/server/stdio.js' )
146- const stdioTransport = new StdioServerTransport ( )
147- await this . server . connect ( stdioTransport )
148- console . log ( '📡 MCP server connected via stdio transport' )
149- } else {
150- // Default to StreamableHTTPServerTransport (for HTTP/web access)
151- const { StreamableHTTPServerTransport } = await import ( '@modelcontextprotocol/sdk/server/streamableHttp.js' )
152- const endpoint = options ?. endpoint || '/mcp'
153-
154- if ( ! this . expressApp ) {
155- // Create a standalone Express server if no app provided
156- const express = await import ( 'express' )
157- this . expressApp = express . default ( )
158-
159- // Enable CORS
160- this . expressApp . use ( ( req : any , res : any , next : any ) => {
161- res . header ( 'Access-Control-Allow-Origin' , '*' )
162- res . header ( 'Access-Control-Allow-Methods' , 'GET, POST, DELETE, OPTIONS' )
163- res . header ( 'Access-Control-Allow-Headers' , 'Content-Type' )
164- next ( )
165- } )
166-
167- const port = options ?. port || 3001
168- this . expressApp . listen ( port , ( ) => {
169- console . log ( `📡 MCP HTTP server listening on http://localhost:${ port } ${ endpoint } ` )
170- } )
171- }
172-
173- console . log ( `📡 Registering HTTP endpoints on Express app...` )
153+ private async mountMcp ( ) : Promise < void > {
154+ if ( this . mcpMounted ) return
155+
156+ const { StreamableHTTPServerTransport } = await import ( '@modelcontextprotocol/sdk/server/streamableHttp.js' )
157+
158+ // Create StreamableHTTPServerTransport in stateless mode
159+ const httpTransport = new StreamableHTTPServerTransport ( {
160+ sessionIdGenerator : undefined // Stateless mode
161+ } )
174162
175- // Create StreamableHTTPServerTransport in stateless mode
176- const httpTransport = new StreamableHTTPServerTransport ( {
177- sessionIdGenerator : undefined // Stateless mode
178- } )
163+ // Connect the MCP server to the transport
164+ await this . server . connect ( httpTransport )
179165
180- // Connect the MCP server to the transport
181- await this . server . connect ( httpTransport )
166+ const endpoint = '/mcp'
182167
183- // Add HTTP endpoints for StreamableHTTPServerTransport
184- const express = await import ( 'express' )
168+ // GET endpoint for SSE streaming
169+ this . app . get ( endpoint , async ( req , res ) => {
170+ console . log ( `📡 HTTP GET request received at ${ endpoint } ` )
171+ await httpTransport . handleRequest ( req , res )
172+ } )
185173
186- // GET endpoint for SSE streaming
187- this . expressApp . get ( endpoint , async ( req : any , res : any ) => {
188- console . log ( `📡 HTTP GET request received at ${ endpoint } ` )
189- await httpTransport . handleRequest ( req , res )
190- } )
174+ // POST endpoint for messages
175+ this . app . post ( endpoint , express . json ( ) , async ( req , res ) => {
176+ console . log ( `📡 HTTP POST request received at ${ endpoint } ` )
177+ await httpTransport . handleRequest ( req , res , req . body )
178+ } )
191179
192- // POST endpoint for messages
193- this . expressApp . post ( endpoint , express . json ( ) , async ( req : any , res : any ) => {
194- console . log ( `📡 HTTP POST request received at ${ endpoint } ` )
195- await httpTransport . handleRequest ( req , res , req . body )
196- } )
180+ // DELETE endpoint for session cleanup
181+ this . app . delete ( endpoint , async ( req , res ) => {
182+ console . log ( `📡 HTTP DELETE request received at ${ endpoint } ` )
183+ await httpTransport . handleRequest ( req , res )
184+ } )
197185
198- // DELETE endpoint for session cleanup (if using stateful mode)
199- this . expressApp . delete ( endpoint , async ( req : any , res : any ) => {
200- console . log ( `📡 HTTP DELETE request received at ${ endpoint } ` )
201- await httpTransport . handleRequest ( req , res )
202- } )
186+ this . mcpMounted = true
187+ console . log ( `📡 MCP server mounted at ${ endpoint } ` )
188+ }
203189
204- console . log ( `📡 MCP server HTTP endpoints registered at ${ endpoint } ` )
205- }
190+ /**
191+ * Start the Express server with MCP endpoints
192+ * @param port - Port to listen on (defaults to 3001)
193+ */
194+ async listen ( port ?: number ) : Promise < void > {
195+ await this . mountMcp ( )
196+ const serverPort = port || 3001
197+ this . app . listen ( serverPort , ( ) => {
198+ console . log ( `📡 Server listening on http://localhost:${ serverPort } ` )
199+ console . log ( `📡 MCP endpoints available at http://localhost:${ serverPort } /mcp` )
200+ } )
206201 }
207202
208203 /**
@@ -304,13 +299,16 @@ export class McpServer {
304299 }
305300}
306301
302+ export type McpServerInstance = Omit < McpServer , keyof Express > & Express
303+
307304/**
308305 * Create a new MCP server instance
309306 */
310- export function createMCPServer ( name : string , config : Partial < ServerConfig > = { } ) : McpServer {
311- return new McpServer ( {
307+ export function createMCPServer ( name : string , config : Partial < ServerConfig > = { } ) : McpServerInstance {
308+ const instance = new McpServer ( {
312309 name,
313310 version : config . version || '1.0.0' ,
314311 description : config . description ,
315312 } )
313+ return instance as unknown as McpServerInstance
316314}
0 commit comments