Skip to content

Commit ff982e0

Browse files
authored
feat: add streamable http [MCP-55] (#359)
1 parent b10990b commit ff982e0

File tree

16 files changed

+357
-69
lines changed

16 files changed

+357
-69
lines changed

.github/workflows/check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,4 @@ jobs:
5555
rm -rf node_modules
5656
npm pkg set scripts.prepare="exit 0"
5757
npm install --omit=dev
58-
- run: npx -y @modelcontextprotocol/inspector --cli --method tools/list -- node dist/index.js --connectionString "mongodb://localhost"
58+
- run: npx -y @modelcontextprotocol/inspector --cli --method tools/list -- node dist/index.js

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ RUN addgroup -S mcp && adduser -S mcp -G mcp
44
RUN npm install -g mongodb-mcp-server@${VERSION}
55
USER mcp
66
WORKDIR /home/mcp
7+
ENV MDB_MCP_LOGGERS=stderr,mcp
78
ENTRYPOINT ["mongodb-mcp-server"]
89
LABEL maintainer="MongoDB Inc <[email protected]>"
910
LABEL description="MongoDB MCP Server"

README.md

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,27 @@ With Atlas API credentials:
225225
}
226226
```
227227

228+
#### Option 6: Running as an HTTP Server
229+
230+
You can run the MongoDB MCP Server as an HTTP server instead of the default stdio transport. This is useful if you want to interact with the server over HTTP, for example from a web client or to expose the server on a specific port.
231+
232+
To start the server with HTTP transport, use the `--transport http` option:
233+
234+
```shell
235+
npx -y mongodb-mcp-server --transport http
236+
```
237+
238+
By default, the server will listen on `http://127.0.0.1:3000`. You can customize the host and port using the `--httpHost` and `--httpPort` options:
239+
240+
```shell
241+
npx -y mongodb-mcp-server --transport http --httpHost=0.0.0.0 --httpPort=8080
242+
```
243+
244+
- `--httpHost` (default: 127.0.0.1): The host to bind the HTTP server.
245+
- `--httpPort` (default: 3000): The port number for the HTTP server.
246+
247+
> **Note:** The default transport is `stdio`, which is suitable for integration with most MCP clients. Use `http` transport if you need to interact with the server over HTTP.
248+
228249
## 🛠️ Supported Tools
229250

230251
### Tool List
@@ -278,23 +299,53 @@ The MongoDB MCP Server can be configured using multiple methods, with the follow
278299

279300
### Configuration Options
280301

281-
| Option | Description |
282-
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
283-
| `apiClientId` | Atlas API client ID for authentication. Required for running Atlas tools. |
284-
| `apiClientSecret` | Atlas API client secret for authentication. Required for running Atlas tools. |
285-
| `connectionString` | MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the `connect` tool before interacting with MongoDB data. |
286-
| `logPath` | Folder to store logs. |
287-
| `disabledTools` | An array of tool names, operation types, and/or categories of tools that will be disabled. |
288-
| `readOnly` | When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations. |
289-
| `indexCheck` | When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan. |
290-
| `telemetry` | When set to disabled, disables telemetry collection. |
302+
| Option | Default | Description |
303+
| ------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
304+
| `apiClientId` | <not set> | Atlas API client ID for authentication. Required for running Atlas tools. |
305+
| `apiClientSecret` | <not set> | Atlas API client secret for authentication. Required for running Atlas tools. |
306+
| `connectionString` | <not set> | MongoDB connection string for direct database connections. Optional, if not set, you'll need to call the `connect` tool before interacting with MongoDB data. |
307+
| `loggers` | disk,mcp | Comma separated values, possible values are `mcp`, `disk` and `stderr`. See [Logger Options](#logger-options) for details. |
308+
| `logPath` | see note\* | Folder to store logs. |
309+
| `disabledTools` | <not set> | An array of tool names, operation types, and/or categories of tools that will be disabled. |
310+
| `readOnly` | false | When set to true, only allows read, connect, and metadata operation types, disabling create/update/delete operations. |
311+
| `indexCheck` | false | When set to true, enforces that query operations must use an index, rejecting queries that perform a collection scan. |
312+
| `telemetry` | enabled | When set to disabled, disables telemetry collection. |
313+
| `transport` | stdio | Either 'stdio' or 'http'. |
314+
| `httpPort` | 3000 | Port number. |
315+
| `httpHost` | 127.0.0.1 | Host to bind the http server. |
316+
317+
#### Logger Options
318+
319+
The `loggers` configuration option controls where logs are sent. You can specify one or more logger types as a comma-separated list. The available options are:
320+
321+
- `mcp`: Sends logs to the MCP client (if supported by the client/transport).
322+
- `disk`: Writes logs to disk files. Log files are stored in the log path (see `logPath` above).
323+
- `stderr`: Outputs logs to standard error (stderr), useful for debugging or when running in containers.
324+
325+
**Default:** `disk,mcp` (logs are written to disk and sent to the MCP client).
326+
327+
You can combine multiple loggers, e.g. `--loggers disk,stderr` or `export MDB_MCP_LOGGERS="mcp,stderr"`.
328+
329+
##### Example: Set logger via environment variable
330+
331+
```shell
332+
export MDB_MCP_LOGGERS="disk,stderr"
333+
```
334+
335+
##### Example: Set logger via command-line argument
336+
337+
```shell
338+
npx -y mongodb-mcp-server --loggers mcp,stderr
339+
```
340+
341+
##### Log File Location
291342

292-
#### Log Path
343+
When using the `disk` logger, log files are stored in:
293344

294-
Default log location is as follows:
345+
- **Windows:** `%LOCALAPPDATA%\mongodb\mongodb-mcp\.app-logs`
346+
- **macOS/Linux:** `~/.mongodb/mongodb-mcp/.app-logs`
295347

296-
- Windows: `%LOCALAPPDATA%\mongodb\mongodb-mcp\.app-logs`
297-
- macOS/Linux: `~/.mongodb/mongodb-mcp/.app-logs`
348+
You can override the log directory with the `logPath` option.
298349

299350
#### Disabled Tools
300351

package-lock.json

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@jest/globals": "^30.0.4",
3838
"@modelcontextprotocol/inspector": "^0.16.0",
3939
"@redocly/cli": "^1.34.4",
40+
"@types/express": "^5.0.1",
4041
"@types/jest": "^30.0.0",
4142
"@types/node": "^24.0.12",
4243
"@types/simple-oauth2": "^5.0.7",
@@ -65,6 +66,7 @@
6566
"@mongodb-js/devtools-connect": "^3.7.2",
6667
"@mongosh/service-provider-node-driver": "^3.6.0",
6768
"bson": "^6.10.4",
69+
"express": "^5.1.0",
6870
"lru-cache": "^11.1.0",
6971
"mongodb": "^6.17.0",
7072
"mongodb-connection-string-url": "^3.0.2",

src/common/config.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ export interface UserConfig {
1717
apiBaseUrl: string;
1818
apiClientId?: string;
1919
apiClientSecret?: string;
20-
telemetry?: "enabled" | "disabled";
20+
telemetry: "enabled" | "disabled";
2121
logPath: string;
2222
connectionString?: string;
2323
connectOptions: ConnectOptions;
2424
disabledTools: Array<string>;
2525
readOnly?: boolean;
2626
indexCheck?: boolean;
27+
transport: "stdio" | "http";
28+
httpPort: number;
29+
httpHost: string;
30+
loggers: Array<"stderr" | "disk" | "mcp">;
2731
}
2832

2933
const defaults: UserConfig = {
@@ -39,6 +43,10 @@ const defaults: UserConfig = {
3943
telemetry: "enabled",
4044
readOnly: false,
4145
indexCheck: false,
46+
transport: "stdio",
47+
httpPort: 3000,
48+
httpHost: "127.0.0.1",
49+
loggers: ["disk", "mcp"],
4250
};
4351

4452
export const config = {

src/common/logger.ts

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const LogId = {
1212
serverCloseRequested: mongoLogId(1_000_003),
1313
serverClosed: mongoLogId(1_000_004),
1414
serverCloseFailure: mongoLogId(1_000_005),
15+
serverDuplicateLoggers: mongoLogId(1_000_006),
1516

1617
atlasCheckCredentials: mongoLogId(1_001_001),
1718
atlasDeleteDatabaseUserFailure: mongoLogId(1_001_002),
@@ -37,9 +38,16 @@ export const LogId = {
3738
mongodbDisconnectFailure: mongoLogId(1_004_002),
3839

3940
toolUpdateFailure: mongoLogId(1_005_001),
41+
42+
streamableHttpTransportStarted: mongoLogId(1_006_001),
43+
streamableHttpTransportSessionInitialized: mongoLogId(1_006_002),
44+
streamableHttpTransportRequestFailure: mongoLogId(1_006_003),
45+
streamableHttpTransportCloseRequested: mongoLogId(1_006_004),
46+
streamableHttpTransportCloseSuccess: mongoLogId(1_006_005),
47+
streamableHttpTransportCloseFailure: mongoLogId(1_006_006),
4048
} as const;
4149

42-
abstract class LoggerBase {
50+
export abstract class LoggerBase {
4351
abstract log(level: LogLevel, id: MongoLogId, context: string, message: string): void;
4452

4553
info(id: MongoLogId, context: string, message: string): void {
@@ -74,14 +82,14 @@ abstract class LoggerBase {
7482
}
7583
}
7684

77-
class ConsoleLogger extends LoggerBase {
85+
export class ConsoleLogger extends LoggerBase {
7886
log(level: LogLevel, id: MongoLogId, context: string, message: string): void {
7987
message = redact(message);
80-
console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message}`);
88+
console.error(`[${level.toUpperCase()}] ${id.__value} - ${context}: ${message} (${process.pid})`);
8189
}
8290
}
8391

84-
class DiskLogger extends LoggerBase {
92+
export class DiskLogger extends LoggerBase {
8593
private constructor(private logWriter: MongoLogWriter) {
8694
super();
8795
}
@@ -133,7 +141,7 @@ class DiskLogger extends LoggerBase {
133141
}
134142
}
135143

136-
class McpLogger extends LoggerBase {
144+
export class McpLogger extends LoggerBase {
137145
constructor(private server: McpServer) {
138146
super();
139147
}
@@ -152,18 +160,12 @@ class McpLogger extends LoggerBase {
152160
}
153161

154162
class CompositeLogger extends LoggerBase {
155-
private loggers: LoggerBase[];
163+
private loggers: LoggerBase[] = [];
156164

157165
constructor(...loggers: LoggerBase[]) {
158166
super();
159167

160-
if (loggers.length === 0) {
161-
// default to ConsoleLogger
162-
this.loggers = [new ConsoleLogger()];
163-
return;
164-
}
165-
166-
this.loggers = [...loggers];
168+
this.setLoggers(...loggers);
167169
}
168170

169171
setLoggers(...loggers: LoggerBase[]): void {
@@ -180,19 +182,5 @@ class CompositeLogger extends LoggerBase {
180182
}
181183
}
182184

183-
const logger = new CompositeLogger();
185+
const logger = new CompositeLogger(new ConsoleLogger());
184186
export default logger;
185-
186-
export async function setStdioPreset(server: McpServer, logPath: string): Promise<void> {
187-
const diskLogger = await DiskLogger.fromPath(logPath);
188-
const mcpLogger = new McpLogger(server);
189-
190-
logger.setLoggers(mcpLogger, diskLogger);
191-
}
192-
193-
export function setContainerPreset(server: McpServer): void {
194-
const mcpLogger = new McpLogger(server);
195-
const consoleLogger = new ConsoleLogger();
196-
197-
logger.setLoggers(mcpLogger, consoleLogger);
198-
}

0 commit comments

Comments
 (0)