• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb-js / mongodb-mcp-server / 14705884283

28 Apr 2025 10:45AM UTC coverage: 82.547% (+0.9%) from 81.696%
14705884283

Pull #131

github

fmenezes
fix: make ip changes smooth
Pull Request #131: feat: add atlas-connect-cluster tool

147 of 229 branches covered (64.19%)

Branch coverage included in aggregate %.

26 of 31 new or added lines in 4 files covered. (83.87%)

60 existing lines in 8 files now uncovered.

780 of 894 relevant lines covered (87.25%)

49.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.58
/src/server.ts
1
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
import { Session } from "./session.js";
3
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
4
import { AtlasTools } from "./tools/atlas/tools.js";
31✔
5
import { MongoDbTools } from "./tools/mongodb/tools.js";
31✔
6
import logger, { initializeLogger } from "./logger.js";
31✔
7
import { mongoLogId } from "mongodb-log-writer";
31✔
8
import { ObjectId } from "mongodb";
31✔
9
import { Telemetry } from "./telemetry/telemetry.js";
10
import { UserConfig } from "./config.js";
11
import { type ServerEvent } from "./telemetry/types.js";
12
import { type ServerCommand } from "./telemetry/types.js";
31✔
13
import { CallToolRequestSchema, CallToolResult } from "@modelcontextprotocol/sdk/types.js";
31✔
14
import assert from "assert";
15

16
export interface ServerOptions {
17
    session: Session;
18
    userConfig: UserConfig;
19
    mcpServer: McpServer;
20
}
21

31✔
22
export class Server {
23
    public readonly session: Session;
24
    private readonly mcpServer: McpServer;
25
    private readonly telemetry: Telemetry;
26
    private readonly userConfig: UserConfig;
27
    private readonly startTime: number;
28

29
    constructor({ session, mcpServer, userConfig }: ServerOptions) {
29✔
30
        this.startTime = Date.now();
29✔
31
        this.session = session;
29✔
32
        this.telemetry = new Telemetry(session);
29✔
33
        this.mcpServer = mcpServer;
29✔
34
        this.userConfig = userConfig;
35
    }
36

37
    async connect(transport: Transport) {
29✔
38
        this.mcpServer.server.registerCapabilities({ logging: {} });
39
        this.registerTools();
29✔
40
        this.registerResources();
29✔
41

42
        // This is a workaround for an issue we've seen with some models, where they'll see that everything in the `arguments`
43
        // object is optional, and then not pass it at all. However, the MCP server expects the `arguments` object to be if
44
        // the tool accepts any arguments, even if they're all optional.
45
        //
46
        // see: https://github.com/modelcontextprotocol/typescript-sdk/blob/131776764536b5fdca642df51230a3746fb4ade0/src/server/mcp.ts#L705
47
        // Since paramsSchema here is not undefined, the server will create a non-optional z.object from it.
48
        const existingHandler = (
49
            this.mcpServer.server["_requestHandlers"] as Map<
29✔
50
                string,
51
                (request: unknown, extra: unknown) => Promise<CallToolResult>
52
            >
53
        ).get(CallToolRequestSchema.shape.method.value);
54

55
        assert(existingHandler, "No existing handler found for CallToolRequestSchema");
29✔
56

57
        this.mcpServer.server.setRequestHandler(CallToolRequestSchema, (request, extra): Promise<CallToolResult> => {
29✔
58
            if (!request.params.arguments) {
331✔
59
                request.params.arguments = {};
1✔
60
            }
61

62
            return existingHandler(request, extra);
331✔
63
        });
64

65
        await initializeLogger(this.mcpServer, this.userConfig.logPath);
29✔
66

67
        await this.mcpServer.connect(transport);
29✔
68

69
        this.mcpServer.server.oninitialized = () => {
29✔
70
            this.session.setAgentRunner(this.mcpServer.server.getClientVersion());
29✔
71
            this.session.sessionId = new ObjectId().toString();
29✔
72

73
            logger.info(
29✔
74
                mongoLogId(1_000_004),
75
                "server",
76
                `Server started with transport ${transport.constructor.name} and agent runner ${this.session.agentRunner?.name}`
77
            );
78

79
            this.emitServerEvent("start", Date.now() - this.startTime);
29✔
80
        };
81

82
        this.mcpServer.server.onclose = () => {
29✔
83
            const closeTime = Date.now();
29✔
84
            this.emitServerEvent("stop", Date.now() - closeTime);
29✔
85
        };
86

87
        this.mcpServer.server.onerror = (error: Error) => {
29✔
88
            const closeTime = Date.now();
×
89
            this.emitServerEvent("stop", Date.now() - closeTime, error);
×
90
        };
91
    }
92

93
    async close(): Promise<void> {
94
        await this.session.close();
29✔
95
        await this.mcpServer.close();
29✔
96
    }
97

98
    /**
99
     * Emits a server event
100
     * @param command - The server command (e.g., "start", "stop", "register", "deregister")
101
     * @param additionalProperties - Additional properties specific to the event
102
     */
103
    emitServerEvent(command: ServerCommand, commandDuration: number, error?: Error) {
104
        const event: ServerEvent = {
58✔
105
            timestamp: new Date().toISOString(),
106
            source: "mdbmcp",
107
            properties: {
108
                ...this.telemetry.getCommonProperties(),
109
                result: "success",
110
                duration_ms: commandDuration,
111
                component: "server",
112
                category: "other",
113
                command: command,
114
            },
115
        };
116

117
        if (command === "start") {
58✔
118
            event.properties.startup_time_ms = commandDuration;
29✔
119
        }
29✔
120
        if (command === "stop") {
29!
121
            event.properties.runtime_duration_ms = Date.now() - this.startTime;
122
            if (error) {
58✔
123
                event.properties.result = "failure";
29✔
124
                event.properties.reason = error.message;
29!
UNCOV
125
            }
×
UNCOV
126
        }
×
127

128
        this.telemetry.emitEvents([event]).catch(() => {});
129
    }
130

58✔
131
    private registerTools() {
132
        for (const tool of [...AtlasTools, ...MongoDbTools]) {
133
            new tool(this.session, this.userConfig, this.telemetry).register(this.mcpServer);
134
        }
29✔
135
    }
899✔
136

137
    private registerResources() {
138
        if (this.userConfig.connectionString) {
139
            this.mcpServer.resource(
140
                "connection-string",
29✔
141
                "config://connection-string",
142
                {
143
                    description: "Preconfigured connection string that will be used as a default in the `connect` tool",
144
                },
145
                (uri) => {
146
                    return {
147
                        contents: [
UNCOV
148
                            {
×
149
                                text: `Preconfigured connection string: ${this.userConfig.connectionString}`,
150
                                uri: uri.href,
151
                            },
×
152
                        ],
153
                    };
154
                }
155
            );
UNCOV
156
        }
×
157
    }
158
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc