mirror of
https://github.com/aljazceru/mcp-gateway.git
synced 2025-12-17 05:04:24 +01:00
🔑 Authentication and Logging 📝
- Added optional debug configuration to `config.yaml` for logging levels. - Implemented Basic and Bearer token authentication methods in the gateway. - Updated `README.md` to include new authentication features and examples. - Integrated Winston for structured logging with customizable log levels. - Modified server command execution for Puppeteer and added YouTube server configuration. - Updated `package.json` and `package-lock.json` to include Winston as a dependency.
This commit is contained in:
94
README.md
94
README.md
@@ -10,14 +10,52 @@ A flexible gateway server that bridges Model Context Protocol (MCP) STDIO server
|
|||||||
- Clean separation between server instances using session IDs
|
- Clean separation between server instances using session IDs
|
||||||
- Automatic cleanup of server resources on connection close
|
- Automatic cleanup of server resources on connection close
|
||||||
- YAML-based configuration
|
- YAML-based configuration
|
||||||
|
- Optional Basic and Bearer token authentication
|
||||||
|
- Configurable debug logging levels
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
At the moment, most MCP servers are designed for local execution. MCP Gateway enables HTTP+SSE capable clients to interact with MCP servers running on remote machines. This addresses common deployment scenarios, such as running [LibreChat](https://github.com/LibreChat/LibreChat) in a containerized environment where certain MCP servers, like the Puppeteer server, may have limited functionality. MCP Gateway provides a robust solution for distributing MCP servers across multiple machines while maintaining seamless connectivity.
|
At the moment, most MCP servers are designed for local execution. MCP Gateway enables HTTP+SSE capable clients to interact with MCP servers running on remote machines. This addresses common deployment scenarios, such as running [LibreChat](https://github.com/LibreChat/LibreChat) in a containerized environment where certain MCP servers, like the Puppeteer server, may have limited functionality. MCP Gateway provides a robust solution for distributing MCP servers across multiple machines while maintaining seamless connectivity.
|
||||||
|
|
||||||
## Security Warning
|
## Security Features
|
||||||
|
|
||||||
MCP Gateway does not yet provide any authentication or authorization. Run MCP Gateway only on a trusted network!
|
MCP Gateway supports two authentication methods that can be enabled independently:
|
||||||
|
|
||||||
|
1. Basic Authentication: Username/password pairs
|
||||||
|
2. Bearer Token Authentication: Token-based authentication
|
||||||
|
|
||||||
|
Both methods can be enabled simultaneously, and any valid authentication will grant access.
|
||||||
|
|
||||||
|
### Authentication Configuration
|
||||||
|
|
||||||
|
Add authentication settings to your `config.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
auth:
|
||||||
|
basic:
|
||||||
|
enabled: true
|
||||||
|
credentials:
|
||||||
|
- username: "admin"
|
||||||
|
password: "your-secure-password"
|
||||||
|
# Add more username/password pairs as needed
|
||||||
|
bearer:
|
||||||
|
enabled: true
|
||||||
|
tokens:
|
||||||
|
- "your-secure-token"
|
||||||
|
# Add more tokens as needed
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Authentication
|
||||||
|
|
||||||
|
#### Basic Authentication
|
||||||
|
```bash
|
||||||
|
curl -u username:password http://localhost:3000/serverName
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Bearer Token Authentication
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: Bearer your-secure-token" http://localhost:3000/serverName
|
||||||
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -29,6 +67,31 @@ npm install
|
|||||||
|
|
||||||
The gateway is configured using a YAML file. By default, it looks for `config.yaml` in the current directory, but you can specify a different path using the `CONFIG_PATH` environment variable.
|
The gateway is configured using a YAML file. By default, it looks for `config.yaml` in the current directory, but you can specify a different path using the `CONFIG_PATH` environment variable.
|
||||||
|
|
||||||
|
### Debug Configuration
|
||||||
|
|
||||||
|
The gateway uses [Winston](https://github.com/winstonjs/winston) for logging, providing rich formatting and multiple log levels:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
debug:
|
||||||
|
level: "info" # Possible values: "error", "warn", "info", "debug", "verbose"
|
||||||
|
```
|
||||||
|
|
||||||
|
Log levels, from least to most verbose:
|
||||||
|
- `error`: Only show errors
|
||||||
|
- `warn`: Show warnings and errors
|
||||||
|
- `info`: Show general information, warnings, and errors (default)
|
||||||
|
- `debug`: Show debug information and all above
|
||||||
|
- `verbose`: Show all possible logging information
|
||||||
|
|
||||||
|
The logs include timestamps and are color-coded by level when viewing in a terminal. Additional metadata is included as JSON when relevant.
|
||||||
|
|
||||||
|
Example log output:
|
||||||
|
```
|
||||||
|
2024-01-20T10:15:30.123Z [INFO]: New SSE connection for filesystem
|
||||||
|
2024-01-20T10:15:30.124Z [DEBUG]: Server instance created with sessionId: /filesystem?sessionId=abc123
|
||||||
|
2024-01-20T10:15:30.125Z [VERBOSE]: STDIO message received: {"type":"ready"}
|
||||||
|
```
|
||||||
|
|
||||||
### Basic Configuration Example
|
### Basic Configuration Example
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -89,6 +152,33 @@ servers:
|
|||||||
- "--some-option"
|
- "--some-option"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Complete Configuration Example
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
hostname: "0.0.0.0"
|
||||||
|
port: 3000
|
||||||
|
|
||||||
|
# Authentication configuration (optional)
|
||||||
|
auth:
|
||||||
|
basic:
|
||||||
|
enabled: true
|
||||||
|
credentials:
|
||||||
|
- username: "admin"
|
||||||
|
password: "your-secure-password"
|
||||||
|
bearer:
|
||||||
|
enabled: true
|
||||||
|
tokens:
|
||||||
|
- "your-secure-token"
|
||||||
|
|
||||||
|
servers:
|
||||||
|
filesystem:
|
||||||
|
command: npx
|
||||||
|
args:
|
||||||
|
- -y
|
||||||
|
- "@modelcontextprotocol/server-filesystem"
|
||||||
|
- "/path/to/root"
|
||||||
|
```
|
||||||
|
|
||||||
## Running the Gateway
|
## Running the Gateway
|
||||||
|
|
||||||
Standard start:
|
Standard start:
|
||||||
|
|||||||
34
config.yaml
34
config.yaml
@@ -1,7 +1,24 @@
|
|||||||
hostname: "0.0.0.0" # Listen on all interfaces by default
|
hostname: "0.0.0.0" # Listen on all interfaces by default
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|
||||||
|
# Debug configuration (optional)
|
||||||
|
debug:
|
||||||
|
level: "info" # Possible values: "error", "warn", "info", "debug", "verbose"
|
||||||
|
|
||||||
|
# Authentication configuration (optional)
|
||||||
|
# auth:
|
||||||
|
# basic:
|
||||||
|
# enabled: true
|
||||||
|
# credentials:
|
||||||
|
# - username: "admin"
|
||||||
|
# password: "your-secure-password"
|
||||||
|
# bearer:
|
||||||
|
# enabled: true
|
||||||
|
# tokens:
|
||||||
|
# - "your-secure-token"
|
||||||
|
|
||||||
servers:
|
servers:
|
||||||
|
# run an MCP server with npx
|
||||||
filesystem:
|
filesystem:
|
||||||
command: npx
|
command: npx
|
||||||
args:
|
args:
|
||||||
@@ -9,14 +26,13 @@ servers:
|
|||||||
- "@modelcontextprotocol/server-filesystem"
|
- "@modelcontextprotocol/server-filesystem"
|
||||||
- "/home/aaron"
|
- "/home/aaron"
|
||||||
|
|
||||||
git:
|
# run a an MCP server from local source
|
||||||
command: npx
|
|
||||||
args:
|
|
||||||
- -y
|
|
||||||
- "@modelcontextprotocol/server-git"
|
|
||||||
|
|
||||||
puppeteer:
|
puppeteer:
|
||||||
command: npx
|
command: tsx
|
||||||
args:
|
args:
|
||||||
- -y
|
- "/home/aaron/AI/MCP-Servers/src/puppeteer/index.ts"
|
||||||
- "@modelcontextprotocol/server-puppeteer"
|
|
||||||
|
youtube:
|
||||||
|
command: tsx
|
||||||
|
args:
|
||||||
|
- "/home/aaron/AI/mcp-server-youtube-transcript/src/index.ts"
|
||||||
279
package-lock.json
generated
279
package-lock.json
generated
@@ -13,12 +13,22 @@
|
|||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.2",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
|
"winston": "^3.17.0",
|
||||||
"yaml": "^2.6.1"
|
"yaml": "^2.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tsx": "^4.19.2"
|
"tsx": "^4.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@colors/colors": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.1.90"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@cspotcode/source-map-support": {
|
"node_modules/@cspotcode/source-map-support": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
@@ -31,6 +41,17 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dabh/diagnostics": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"colorspace": "1.1.x",
|
||||||
|
"enabled": "2.0.x",
|
||||||
|
"kuler": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.23.1",
|
"version": "0.23.1",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
|
||||||
@@ -508,6 +529,12 @@
|
|||||||
"undici-types": "~6.20.0"
|
"undici-types": "~6.20.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/triple-beam": {
|
||||||
|
"version": "1.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
|
||||||
|
"integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.14.0",
|
"version": "8.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||||
@@ -538,6 +565,12 @@
|
|||||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/async": {
|
||||||
|
"version": "3.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
|
||||||
|
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/bytes": {
|
"node_modules/bytes": {
|
||||||
"version": "3.1.2",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||||
@@ -547,6 +580,51 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/color": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-convert": "^1.9.3",
|
||||||
|
"color-string": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-convert": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "1.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/color-name": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/color-string": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color-name": "^1.0.0",
|
||||||
|
"simple-swizzle": "^0.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/colorspace": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"color": "^3.1.3",
|
||||||
|
"text-hex": "1.0.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/content-type": {
|
"node_modules/content-type": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||||
@@ -580,6 +658,12 @@
|
|||||||
"node": ">=0.3.1"
|
"node": ">=0.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/enabled": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/esbuild": {
|
"node_modules/esbuild": {
|
||||||
"version": "0.23.1",
|
"version": "0.23.1",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
|
||||||
@@ -620,6 +704,18 @@
|
|||||||
"@esbuild/win32-x64": "0.23.1"
|
"@esbuild/win32-x64": "0.23.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fecha": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/fn.name": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/fsevents": {
|
"node_modules/fsevents": {
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
@@ -682,12 +778,68 @@
|
|||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/is-arrayish": {
|
||||||
|
"version": "0.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||||
|
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/is-stream": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/kuler": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/logform": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@colors/colors": "1.6.0",
|
||||||
|
"@types/triple-beam": "^1.3.2",
|
||||||
|
"fecha": "^4.2.0",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"safe-stable-stringify": "^2.3.1",
|
||||||
|
"triple-beam": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/make-error": {
|
"node_modules/make-error": {
|
||||||
"version": "1.3.6",
|
"version": "1.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/one-time": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fn.name": "1.x.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/raw-body": {
|
"node_modules/raw-body": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
|
||||||
@@ -703,6 +855,20 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/readable-stream": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve-pkg-maps": {
|
"node_modules/resolve-pkg-maps": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||||
@@ -713,6 +879,35 @@
|
|||||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/safe-stable-stringify": {
|
||||||
|
"version": "2.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz",
|
||||||
|
"integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/safer-buffer": {
|
"node_modules/safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
@@ -725,6 +920,24 @@
|
|||||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/simple-swizzle": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||||
|
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-arrayish": "^0.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/stack-trace": {
|
||||||
|
"version": "0.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
||||||
|
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
@@ -734,6 +947,21 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/text-hex": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/toidentifier": {
|
"node_modules/toidentifier": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||||
@@ -743,6 +971,15 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/triple-beam": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ts-node": {
|
"node_modules/ts-node": {
|
||||||
"version": "10.9.2",
|
"version": "10.9.2",
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
|
||||||
@@ -834,12 +1071,54 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/v8-compile-cache-lib": {
|
"node_modules/v8-compile-cache-lib": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/winston": {
|
||||||
|
"version": "3.17.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz",
|
||||||
|
"integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@colors/colors": "^1.6.0",
|
||||||
|
"@dabh/diagnostics": "^2.0.2",
|
||||||
|
"async": "^3.2.3",
|
||||||
|
"is-stream": "^2.0.0",
|
||||||
|
"logform": "^2.7.0",
|
||||||
|
"one-time": "^1.0.0",
|
||||||
|
"readable-stream": "^3.4.0",
|
||||||
|
"safe-stable-stringify": "^2.3.1",
|
||||||
|
"stack-trace": "0.0.x",
|
||||||
|
"triple-beam": "^1.3.0",
|
||||||
|
"winston-transport": "^4.9.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/winston-transport": {
|
||||||
|
"version": "4.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz",
|
||||||
|
"integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"logform": "^2.7.0",
|
||||||
|
"readable-stream": "^3.6.2",
|
||||||
|
"triple-beam": "^1.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
"@types/node": "^22.10.2",
|
"@types/node": "^22.10.2",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
|
"winston": "^3.17.0",
|
||||||
"yaml": "^2.6.1"
|
"yaml": "^2.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
110
src/gateway.ts
110
src/gateway.ts
@@ -1,9 +1,30 @@
|
|||||||
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
||||||
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
||||||
|
import { createLogger, format, transports } from 'winston';
|
||||||
import { parse } from 'yaml';
|
import { parse } from 'yaml';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import http from "http";
|
import http from "http";
|
||||||
|
|
||||||
|
type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'verbose';
|
||||||
|
|
||||||
|
interface DebugConfig {
|
||||||
|
level: LogLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AuthConfig {
|
||||||
|
basic?: {
|
||||||
|
enabled: boolean;
|
||||||
|
credentials: Array<{
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
bearer?: {
|
||||||
|
enabled: boolean;
|
||||||
|
tokens: string[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface ServerConfig {
|
interface ServerConfig {
|
||||||
command: string;
|
command: string;
|
||||||
args: string[];
|
args: string[];
|
||||||
@@ -13,6 +34,8 @@ interface ServerConfig {
|
|||||||
interface GatewayConfig {
|
interface GatewayConfig {
|
||||||
hostname: string;
|
hostname: string;
|
||||||
port: number;
|
port: number;
|
||||||
|
debug?: DebugConfig;
|
||||||
|
auth?: AuthConfig;
|
||||||
servers: Record<string, ServerConfig>;
|
servers: Record<string, ServerConfig>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,13 +48,81 @@ class MCPServer {
|
|||||||
|
|
||||||
class MCPGateway {
|
class MCPGateway {
|
||||||
private servers: Map<string, MCPServer> = new Map();
|
private servers: Map<string, MCPServer> = new Map();
|
||||||
|
private logger: ReturnType<typeof createLogger>;
|
||||||
|
|
||||||
constructor(private config: GatewayConfig) { }
|
constructor(private config: GatewayConfig) {
|
||||||
|
this.logger = createLogger({
|
||||||
|
level: config.debug?.level || 'info',
|
||||||
|
format: format.combine(
|
||||||
|
format.timestamp(),
|
||||||
|
format.colorize(),
|
||||||
|
format.printf(({ level, message, timestamp, ...metadata }) => {
|
||||||
|
let msg = `${timestamp} [${level}]: ${message}`;
|
||||||
|
if (Object.keys(metadata).length > 0) {
|
||||||
|
msg += ` ${JSON.stringify(metadata)}`;
|
||||||
|
}
|
||||||
|
return msg;
|
||||||
|
})
|
||||||
|
),
|
||||||
|
transports: [
|
||||||
|
new transports.Console()
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private authenticateRequest(req: http.IncomingMessage): boolean {
|
||||||
|
// If no auth config is present, allow all requests
|
||||||
|
if (!this.config.auth) {
|
||||||
|
this.logger.debug('No authentication configured, allowing request');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authHeader = req.headers.authorization;
|
||||||
|
this.logger.verbose('Processing authentication header:', { header: authHeader });
|
||||||
|
|
||||||
|
// Check Bearer token authentication
|
||||||
|
if (this.config.auth.bearer?.enabled) {
|
||||||
|
if (authHeader?.startsWith('Bearer ')) {
|
||||||
|
const token = authHeader.substring(7);
|
||||||
|
const isValid = this.config.auth.bearer.tokens.includes(token);
|
||||||
|
this.logger.debug('Bearer token authentication result:', { isValid });
|
||||||
|
if (isValid) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Basic authentication
|
||||||
|
if (this.config.auth.basic?.enabled) {
|
||||||
|
if (authHeader?.startsWith('Basic ')) {
|
||||||
|
const base64Credentials = authHeader.substring(6);
|
||||||
|
const credentials = Buffer.from(base64Credentials, 'base64').toString('utf-8');
|
||||||
|
const [username, password] = credentials.split(':');
|
||||||
|
|
||||||
|
const validCredentials = this.config.auth.basic.credentials.some(
|
||||||
|
cred => cred.username === username && cred.password === password
|
||||||
|
);
|
||||||
|
|
||||||
|
this.logger.debug('Basic authentication result:', { validCredentials });
|
||||||
|
if (validCredentials) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.warn('Authentication failed for request');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
const httpServer = http.createServer(async (req, res) => {
|
const httpServer = http.createServer(async (req, res) => {
|
||||||
|
// Check authentication first
|
||||||
|
if (!this.authenticateRequest(req)) {
|
||||||
|
this.logger.warn('Unauthorized request rejected');
|
||||||
|
res.writeHead(401, {
|
||||||
|
'WWW-Authenticate': 'Basic realm="MCP Gateway", Bearer'
|
||||||
|
}).end('Unauthorized');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const serverName = req.url?.split('/')[1].split('?')[0] || "";
|
const serverName = req.url?.split('/')[1].split('?')[0] || "";
|
||||||
console.debug({
|
this.logger.debug('Incoming request:', {
|
||||||
fullUrl: req.url,
|
fullUrl: req.url,
|
||||||
method: req.method,
|
method: req.method,
|
||||||
serverName,
|
serverName,
|
||||||
@@ -40,14 +131,14 @@ class MCPGateway {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!serverName || !this.config.servers[serverName] || !req.url) {
|
if (!serverName || !this.config.servers[serverName] || !req.url) {
|
||||||
console.log('404: Server not found or invalid URL path');
|
this.logger.warn('404: Server not found or invalid URL path');
|
||||||
res.writeHead(404).end();
|
res.writeHead(404).end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle root server path - establish SSE connection
|
// Handle root server path - establish SSE connection
|
||||||
if (req.method === "GET") {
|
if (req.method === "GET") {
|
||||||
console.log(`New SSE connection for ${serverName}`);
|
this.logger.info(`New SSE connection for ${serverName}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const serverConfig = this.config.servers[serverName];
|
const serverConfig = this.config.servers[serverName];
|
||||||
@@ -64,25 +155,27 @@ class MCPGateway {
|
|||||||
|
|
||||||
// Store server info
|
// Store server info
|
||||||
this.servers.set(sessionId, server);
|
this.servers.set(sessionId, server);
|
||||||
|
this.logger.debug(`Server instance created with sessionId: ${sessionId}`);
|
||||||
|
|
||||||
// Bridge messages from STDIO to SSE
|
// Bridge messages from STDIO to SSE
|
||||||
server.stdioTransport.onmessage = (msg) => {
|
server.stdioTransport.onmessage = (msg) => {
|
||||||
|
this.logger.verbose('STDIO -> SSE:', msg);
|
||||||
sseTransport.send(msg);
|
sseTransport.send(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
res.on('close', () => {
|
res.on('close', () => {
|
||||||
console.log(`SSE connection closed for ${sessionId}`);
|
this.logger.info(`SSE connection closed for ${sessionId}`);
|
||||||
server.sseTransport.close();
|
server.sseTransport.close();
|
||||||
server.stdioTransport.close();
|
server.stdioTransport.close();
|
||||||
this.servers.delete(sessionId);
|
this.servers.delete(sessionId);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Starting transports for ${sessionId}`);
|
this.logger.info(`Starting transports for ${sessionId}`);
|
||||||
await server.stdioTransport.start();
|
await server.stdioTransport.start();
|
||||||
await server.sseTransport.start();
|
await server.sseTransport.start();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error setting up SSE connection:', error);
|
this.logger.error('Error setting up SSE connection:', error);
|
||||||
res.writeHead(500).end(String(error));
|
res.writeHead(500).end(String(error));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -107,6 +200,9 @@ class MCPGateway {
|
|||||||
try {
|
try {
|
||||||
// Parse and forward message to STDIO server
|
// Parse and forward message to STDIO server
|
||||||
const message = JSON.parse(body);
|
const message = JSON.parse(body);
|
||||||
|
|
||||||
|
this.logger.verbose('SSE -> STDIO:', message);
|
||||||
|
|
||||||
await server.stdioTransport.send(message);
|
await server.stdioTransport.send(message);
|
||||||
|
|
||||||
// Send success response
|
// Send success response
|
||||||
|
|||||||
Reference in New Issue
Block a user