File tree Expand file tree Collapse file tree 7 files changed +135
-14
lines changed
Expand file tree Collapse file tree 7 files changed +135
-14
lines changed Original file line number Diff line number Diff line change @@ -13,6 +13,7 @@ export const {
1313 APP_VERSION ,
1414 TRANSPORT ,
1515 AUTHORIZATION_SERVER_HOST ,
16+ PORT ,
1617} = parseEnv ( process . env , {
1718 COUPLER_API_HOST : z . string ( ) . url ( ) . default ( 'https://app.coupler.io' ) ,
1819 COUPLER_ACCESS_TOKEN : z . string ( ) . trim ( ) . min ( 1 ) ,
@@ -21,5 +22,6 @@ export const {
2122 NODE_ENV : z . enum ( ENVS ) . default ( 'development' ) ,
2223 APP_VERSION : z . string ( ) . trim ( ) . min ( 1 ) ,
2324 TRANSPORT : z . enum ( TRANSPORTS ) . default ( 'stdio' ) ,
24- AUTHORIZATION_SERVER_HOST : z . string ( ) . url ( ) . default ( 'https://auth.coupler.io' )
25+ AUTHORIZATION_SERVER_HOST : z . string ( ) . url ( ) . default ( 'https://auth.coupler.io' ) ,
26+ PORT : z . number ( ) . default ( 3001 )
2527 } )
Original file line number Diff line number Diff line change 1- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js '
2- import { server } from '@/server'
3- import { logger } from '@/logger '
1+ import { TRANSPORT } from '@/env '
2+ import { stdioServer } from '@/server/transports/stdio '
3+ import { httpServer } from '@/server/transports/http '
44
55const main = ( ) => {
6- const transport = new StdioServerTransport ( )
7- server . connect ( transport )
8- . then ( ( ) => {
9- logger . info ( 'Coupler.io MCP Server started' )
10- server . sendLoggingMessage ( { level : 'info' , data : 'Coupler.io MCP Server started' } )
11- } )
12- . catch ( ( e ) => {
13- logger . error ( 'Fatal error: ' , e )
14- process . exit ( 1 )
15- } )
6+ const server = TRANSPORT === 'stdio' ? stdioServer : httpServer
7+
8+ server . start ( )
169}
1710
1811main ( )
Original file line number Diff line number Diff line change 1+ import express from 'express'
2+
3+ import { PORT } from '@/env'
4+ import { loggingMiddleware , logger } from '@/server/logging'
5+ import { router as mcpRouter } from '@/server/transports/http/routes/mcp'
6+ import { router as oauthRouter } from '@/server/transports/http/routes/oauth'
7+
8+ const app = express ( )
9+
10+ app . disable ( 'x-powered-by' )
11+
12+ app . use ( express . json ( ) )
13+ app . use ( loggingMiddleware )
14+
15+ app . use ( '/mcp' , mcpRouter )
16+ app . use ( '/oauth' , oauthRouter )
17+
18+ export const httpServer = {
19+ start ( ) {
20+ app . listen ( PORT , ( ) => {
21+ logger . info ( `Coupler.io MCP Server listening on port ${ PORT } ` )
22+ } )
23+ }
24+ }
Original file line number Diff line number Diff line change 1+ import type { Request , Response , NextFunction } from 'express'
2+
3+ export const authorize = ( req : Request , res : Response , next : NextFunction ) : void => {
4+ const token = req . header ( 'Authorization' ) ?. split ( / \s + / ) [ 1 ]
5+
6+ if ( ! token ) {
7+ res . status ( 401 ) . json ( { message : 'Unauthorized' } )
8+ return
9+ }
10+
11+ next ( )
12+ }
Original file line number Diff line number Diff line change 1+ import { Router } from 'express'
2+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
3+
4+ import { server } from '@/server/index'
5+ import { logger } from '@/server/logging'
6+ import { authorize } from '@/server/transports/http/middleware/authorize'
7+
8+ const methodNotAllowedResponse = {
9+ jsonrpc : '2.0' ,
10+ error : {
11+ code : - 32000 ,
12+ message : 'Method not allowed.'
13+ } ,
14+ }
15+
16+ const router = Router ( )
17+
18+ router . use ( authorize )
19+
20+ router . post ( '/' , async ( req , res ) => {
21+ try {
22+ const transport : StreamableHTTPServerTransport = new StreamableHTTPServerTransport ( {
23+ sessionIdGenerator : undefined ,
24+ } )
25+
26+ res . on ( 'close' , ( ) => {
27+ transport . close ( )
28+ server . close ( )
29+ } )
30+
31+ await server . connect ( transport )
32+ await transport . handleRequest ( req , res , req . body )
33+ } catch ( error ) {
34+ logger . error ( 'Error handling MCP request:' , error )
35+ if ( ! res . headersSent ) {
36+ res . status ( 500 ) . json ( {
37+ jsonrpc : '2.0' ,
38+ error : {
39+ code : - 32603 ,
40+ message : 'Internal server error' ,
41+ } ,
42+ id : null ,
43+ } )
44+ }
45+ }
46+ } )
47+
48+ router . use ( ( req , res ) => {
49+ if ( req . method != 'POST' ) {
50+ res . status ( 405 ) . json ( methodNotAllowedResponse )
51+ }
52+ } )
53+
54+ export { router }
Original file line number Diff line number Diff line change 1+ import { AUTHORIZATION_SERVER_HOST } from '@/env'
2+ import { Router } from 'express'
3+
4+ const router = Router ( )
5+
6+ const body = {
7+ registration_endpoint : `${ AUTHORIZATION_SERVER_HOST } /oauth2/applications` ,
8+ token_endpoint : `${ AUTHORIZATION_SERVER_HOST } /oauth2/token` ,
9+ authorization_endpoint : `${ AUTHORIZATION_SERVER_HOST } /oauth2/authorize`
10+ }
11+
12+ router . get ( '/.well-known/oauth-authorization-server' , ( _req , res ) => {
13+ res . json ( body )
14+ } )
15+
16+ export { router }
Original file line number Diff line number Diff line change 1+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
2+ import { server } from '@/server/index'
3+ import { logger } from '@/server/logging'
4+
5+ export const stdioServer = {
6+ start ( ) {
7+ const transport = new StdioServerTransport ( )
8+ server . connect ( transport )
9+ . then ( ( ) => {
10+ logger . info ( 'Coupler.io MCP Server started' )
11+ server . sendLoggingMessage ( { level : 'info' , data : 'Coupler.io MCP Server started' } )
12+ } )
13+ . catch ( ( e ) => {
14+ logger . error ( 'Fatal error: ' , e )
15+ process . exit ( 1 )
16+ } )
17+ }
18+ }
19+
20+
You can’t perform that action at this time.
0 commit comments