@@ -3,18 +3,14 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3
3
import { z } from "zod" ;
4
4
5
5
import express , { Request , Response } from "express" ;
6
- import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse .js" ;
6
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp .js" ;
7
7
import http from "http" ;
8
8
import WebSocket , { WebSocketServer } from "ws"
9
9
10
10
// Create mcpServer instance
11
11
const mcpServer = new McpServer ( {
12
- name : "winccoa" ,
13
- version : "1.0.0" ,
14
- capabilities : {
15
- resources : { } ,
16
- tools : { } ,
17
- } ,
12
+ name : "winccoa-mcp-streamable-http" ,
13
+ version : "1.0.0"
18
14
} ) ;
19
15
20
16
@@ -50,60 +46,79 @@ async function mainStdio() {
50
46
async function mainSse ( )
51
47
{
52
48
const app = express ( ) ;
53
- // Attach WebSocket server to the HTTP server
54
- const wss = new WebSocketServer ( { noServer :true } ) ;
49
+ app . use ( express . json ( ) ) ;
55
50
56
- const PORT = process . env . PORT || 3001 ;
51
+ const transport : StreamableHTTPServerTransport =
52
+ new StreamableHTTPServerTransport ( {
53
+ sessionIdGenerator : undefined , // set to undefined for stateless servers
54
+ } ) ;
55
+
56
+ // Setup routes for the mcp server
57
+ const setupServer = async ( ) => {
58
+ await mcpServer . connect ( transport ) ;
59
+ } ;
60
+
61
+ app . post ( "/mcp" , async ( req : Request , res : Response ) => {
62
+ console . log ( "Received MCP request:" , req . body ) ;
63
+ try {
64
+ await transport . handleRequest ( req , res , req . body ) ;
65
+ } catch ( error ) {
66
+ console . error ( "Error handling MCP request:" , error ) ;
67
+ if ( ! res . headersSent ) {
68
+ res . status ( 500 ) . json ( {
69
+ jsonrpc : "2.0" ,
70
+ error : {
71
+ code : - 32603 ,
72
+ message : "Internal server error" ,
73
+ } ,
74
+ id : null ,
75
+ } ) ;
76
+ }
77
+ }
78
+ } ) ;
57
79
58
- const server = app . listen ( PORT , ( ) => {
59
- //console.log(`✅ Server is running at http://localhost:${PORT}`);
80
+ app . get ( "/mcp" , async ( req : Request , res : Response ) => {
81
+ console . log ( "Received GET MCP request" ) ;
82
+ res . writeHead ( 405 ) . end (
83
+ JSON . stringify ( {
84
+ jsonrpc : "2.0" ,
85
+ error : {
86
+ code : - 32000 ,
87
+ message : "Method not allowed." ,
88
+ } ,
89
+ id : null ,
90
+ } )
91
+ ) ;
92
+ } ) ;
93
+
94
+ app . delete ( "/mcp" , async ( req : Request , res : Response ) => {
95
+ console . log ( "Received DELETE MCP request" ) ;
96
+ res . writeHead ( 405 ) . end (
97
+ JSON . stringify ( {
98
+ jsonrpc : "2.0" ,
99
+ error : {
100
+ code : - 32000 ,
101
+ message : "Method not allowed." ,
102
+ } ,
103
+ id : null ,
104
+ } )
105
+ ) ;
60
106
} ) ;
61
107
62
- server . on ( 'upgrade' , ( request , socket , head ) => {
63
- const pathname = new URL ( request . url ! , `http://${ request . headers . host } ` ) . pathname ;
64
- if ( pathname === '/ws' ) {
108
+ // Create HTTP server with websocket support
109
+ const serverHttp = http . createServer ( app ) ;
110
+ serverHttp . on ( "upgrade" , ( request , socket , head ) => {
111
+ if ( request . url === "/ws" ) {
65
112
wss . handleUpgrade ( request , socket , head , ( ws ) => {
66
- wss . emit ( ' connection' , ws , request ) ;
113
+ wss . emit ( " connection" , ws , request ) ;
67
114
} ) ;
68
115
} else {
69
116
socket . destroy ( ) ;
70
117
}
71
118
} ) ;
72
119
73
- // to support multiple simultaneous connections we have a lookup object from
74
- // sessionId to transport
75
- const transports : { [ sessionId : string ] : SSEServerTransport } = { } ;
76
-
77
- app . get ( "/sse" , async ( req : Request , res : Response ) => {
78
- // Get the full URI from the request
79
- const host = req . get ( "host" ) ;
80
-
81
- const fullUri = `https://${ host } /jokes` ;
82
- const transport = new SSEServerTransport ( fullUri , res ) ;
83
-
84
- transports [ transport . sessionId ] = transport ;
85
- res . on ( "close" , ( ) => {
86
- delete transports [ transport . sessionId ] ;
87
- } ) ;
88
- await mcpServer . connect ( transport ) ;
89
- } ) ;
90
-
91
- app . post ( "/jokes" , async ( req : Request , res : Response ) => {
92
- const sessionId = req . query . sessionId as string ;
93
- const transport = transports [ sessionId ] ;
94
- if ( transport ) {
95
- await transport . handlePostMessage ( req , res ) ;
96
- } else {
97
- res . status ( 400 ) . send ( "No transport found for sessionId" ) ;
98
- }
99
- } ) ;
100
-
101
- app . get ( "/" , ( _req , res ) => {
102
- res . send ( "The WinCC OA MCP server is running!" ) ;
103
- } ) ;
104
-
105
-
106
-
120
+ // WebSocket server setup
121
+ const wss = new WebSocketServer ( { server : serverHttp } ) ;
107
122
108
123
// Événement déclenché lorsque le serveur WebSocket reçoit une connexion
109
124
wss . on ( 'connection' , ( ws : WebSocket ) => {
@@ -134,6 +149,18 @@ async function mainSse()
134
149
} ) ;
135
150
} ) ;
136
151
152
+ // Start the server
153
+ const PORT = process . env . PORT || 3001 ;
154
+ setupServer ( )
155
+ . then ( ( ) => {
156
+ serverHttp . listen ( PORT , ( ) => {
157
+ console . log ( `MCP Streamable HTTP Server listening on port ${ PORT } ` ) ;
158
+ } ) ;
159
+ } )
160
+ . catch ( ( error ) => {
161
+ console . error ( "Failed to set up the server:" , error ) ;
162
+ process . exit ( 1 ) ;
163
+ } ) ;
137
164
138
165
}
139
166
0 commit comments