Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,44 @@ List of available preview features:

- `mcpUI` - Enables an optional web-based UI for interacting with the MCP server.

#### Monitoring Server (Health Check & Metrics)

When running with `--transport http`, you can expose a separate monitoring HTTP server for health checks and metrics. This server is only started when both `monitoringServerHost` and `monitoringServerPort` are set, and it listens on its own host/port (independent from the main `httpHost`/`httpPort`).

The features exposed are controlled by `monitoringServerFeatures` (default: `health-check`). Available features and their endpoints:

| Feature | Endpoint | Description |
| -------------- | ---------- | ------------------------------------------------------------------------------------------- |
| `health-check` | `/health` | Returns `200 OK` with a JSON body describing the server status. Useful for liveness probes. |
| `metrics` | `/metrics` | Returns server metrics in Prometheus text format. |

The `/health` response is sent with `Cache-Control: no-store` and has the following shape (`status` is always `"ok"` while the process is alive):

```json
{
"status": "ok",
"version": "1.13.0",
"uptimeSeconds": 42,
"timestamp": "2026-06-20T12:00:00.000Z"
}
```

Example: start the server with the monitoring server enabled and call the health-check endpoint:

```shell
npx -y mongodb-mcp-server@latest --transport http --httpHost 0.0.0.0 --httpPort 3000 --monitoringServerHost 0.0.0.0 --monitoringServerPort 8080 &
curl http://0.0.0.0:8080/health
# => {"status":"ok"}
```

To expose both endpoints, pass the features explicitly:

```shell
npx -y mongodb-mcp-server@latest --transport http --monitoringServerHost 0.0.0.0 --monitoringServerPort 8080 --monitoringServerFeatures health-check,metrics
```

> **💡 Note:** `healthCheckHost` / `healthCheckPort` are deprecated aliases for `monitoringServerHost` / `monitoringServerPort` and continue to serve the same `/health` endpoint.

### Atlas API Access

To use the Atlas API tools, you'll need to create a service account in MongoDB Atlas:
Expand Down
10 changes: 9 additions & 1 deletion src/transports/monitoringServer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type express from "express";
import { LogId } from "../common/logging/loggingDefinitions.js";
import { packageInfo } from "../common/packageInfo.js";
import type {
DefaultMetrics,
MonitoringServerFeature,
Expand Down Expand Up @@ -53,7 +54,14 @@ export class MonitoringServer<TMetrics extends DefaultMetrics = DefaultMetrics>
protected override setupRoutes(): Promise<void> {
if (this.features.includes("health-check")) {
this.app.get("/health", (_req: express.Request, res: express.Response) => {
res.json({ status: "ok" });
// Health responses should never be cached by proxies or load balancers.
res.set("Cache-Control", "no-store");
res.json({
status: "ok",
version: packageInfo.version,
uptimeSeconds: Math.floor(process.uptime()),
timestamp: new Date().toISOString(),
});
});
}

Expand Down
17 changes: 14 additions & 3 deletions tests/unit/transports/monitoringServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,20 @@ describe("MonitoringServer", () => {

const response = await fetch(`${server.serverAddress}/health`);
expect(response.status).toBe(200);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const body = await response.json();
expect(body).toEqual({ status: "ok" });
expect(response.headers.get("cache-control")).toBe("no-store");
const body = (await response.json()) as {
status: string;
version: string;
uptimeSeconds: number;
timestamp: string;
};
// status remains "ok" for backward compatibility with existing probes
expect(body.status).toBe("ok");
expect(typeof body.version).toBe("string");
expect(typeof body.uptimeSeconds).toBe("number");
expect(body.uptimeSeconds).toBeGreaterThanOrEqual(0);
// timestamp is a valid ISO date string
expect(Number.isNaN(Date.parse(body.timestamp))).toBe(false);
});

it("does not expose health endpoint when health-check feature is disabled", async () => {
Expand Down