mongodb-mcp-server 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/.dockerignore +11 -0
  2. package/.github/CODEOWNERS +0 -2
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +8 -0
  4. package/.github/workflows/check-pr-title.yml +29 -0
  5. package/.github/workflows/{lint.yml → check.yml} +22 -1
  6. package/.github/workflows/code_health.yaml +0 -22
  7. package/.github/workflows/code_health_fork.yaml +7 -63
  8. package/.github/workflows/docker.yaml +57 -0
  9. package/.github/workflows/stale.yml +32 -0
  10. package/.smithery/Dockerfile +30 -0
  11. package/.smithery/smithery.yaml +63 -0
  12. package/.vscode/extensions.json +9 -0
  13. package/.vscode/settings.json +11 -0
  14. package/CONTRIBUTING.md +1 -1
  15. package/Dockerfile +10 -0
  16. package/README.md +173 -35
  17. package/dist/common/atlas/apiClient.js +151 -35
  18. package/dist/common/atlas/apiClient.js.map +1 -1
  19. package/dist/common/atlas/apiClientError.js +38 -5
  20. package/dist/common/atlas/apiClientError.js.map +1 -1
  21. package/dist/common/atlas/cluster.js +66 -0
  22. package/dist/common/atlas/cluster.js.map +1 -0
  23. package/dist/common/atlas/generatePassword.js +9 -0
  24. package/dist/common/atlas/generatePassword.js.map +1 -0
  25. package/dist/helpers/EJsonTransport.js +38 -0
  26. package/dist/helpers/EJsonTransport.js.map +1 -0
  27. package/dist/helpers/connectionOptions.js +10 -0
  28. package/dist/helpers/connectionOptions.js.map +1 -0
  29. package/dist/{packageInfo.js → helpers/packageInfo.js} +1 -1
  30. package/dist/helpers/packageInfo.js.map +1 -0
  31. package/dist/index.js +23 -3
  32. package/dist/index.js.map +1 -1
  33. package/dist/logger.js +7 -0
  34. package/dist/logger.js.map +1 -1
  35. package/dist/server.js +16 -12
  36. package/dist/server.js.map +1 -1
  37. package/dist/session.js +8 -3
  38. package/dist/session.js.map +1 -1
  39. package/dist/telemetry/constants.js +1 -3
  40. package/dist/telemetry/constants.js.map +1 -1
  41. package/dist/telemetry/eventCache.js.map +1 -1
  42. package/dist/telemetry/telemetry.js +126 -47
  43. package/dist/telemetry/telemetry.js.map +1 -1
  44. package/dist/tools/atlas/atlasTool.js +38 -0
  45. package/dist/tools/atlas/atlasTool.js.map +1 -1
  46. package/dist/tools/atlas/create/createDBUser.js +19 -2
  47. package/dist/tools/atlas/create/createDBUser.js.map +1 -1
  48. package/dist/tools/atlas/create/createProject.js +5 -1
  49. package/dist/tools/atlas/create/createProject.js.map +1 -1
  50. package/dist/tools/atlas/metadata/connectCluster.js +5 -22
  51. package/dist/tools/atlas/metadata/connectCluster.js.map +1 -1
  52. package/dist/tools/atlas/read/inspectCluster.js +4 -24
  53. package/dist/tools/atlas/read/inspectCluster.js.map +1 -1
  54. package/dist/tools/atlas/read/listAlerts.js +41 -0
  55. package/dist/tools/atlas/read/listAlerts.js.map +1 -0
  56. package/dist/tools/atlas/read/listClusters.js +9 -18
  57. package/dist/tools/atlas/read/listClusters.js.map +1 -1
  58. package/dist/tools/atlas/read/listProjects.js +3 -1
  59. package/dist/tools/atlas/read/listProjects.js.map +1 -1
  60. package/dist/tools/atlas/tools.js +2 -0
  61. package/dist/tools/atlas/tools.js.map +1 -1
  62. package/dist/tools/mongodb/metadata/listDatabases.js.map +1 -1
  63. package/dist/tools/mongodb/read/count.js +2 -2
  64. package/dist/tools/mongodb/read/count.js.map +1 -1
  65. package/dist/tools/mongodb/tools.js +2 -4
  66. package/dist/tools/mongodb/tools.js.map +1 -1
  67. package/dist/tools/tool.js +38 -6
  68. package/dist/tools/tool.js.map +1 -1
  69. package/eslint.config.js +2 -1
  70. package/{jest.config.ts → jest.config.cjs} +1 -1
  71. package/package.json +11 -9
  72. package/scripts/apply.ts +8 -5
  73. package/scripts/filter.ts +5 -0
  74. package/src/common/atlas/apiClient.ts +190 -38
  75. package/src/common/atlas/apiClientError.ts +58 -7
  76. package/src/common/atlas/cluster.ts +94 -0
  77. package/src/common/atlas/generatePassword.ts +10 -0
  78. package/src/common/atlas/openapi.d.ts +1876 -239
  79. package/src/helpers/EJsonTransport.ts +47 -0
  80. package/src/helpers/connectionOptions.ts +20 -0
  81. package/src/{packageInfo.ts → helpers/packageInfo.ts} +1 -1
  82. package/src/index.ts +27 -3
  83. package/src/logger.ts +8 -0
  84. package/src/server.ts +23 -15
  85. package/src/session.ts +8 -4
  86. package/src/telemetry/constants.ts +2 -3
  87. package/src/telemetry/eventCache.ts +1 -1
  88. package/src/telemetry/telemetry.ts +182 -64
  89. package/src/telemetry/types.ts +1 -1
  90. package/src/tools/atlas/atlasTool.ts +47 -1
  91. package/src/tools/atlas/create/createDBUser.ts +22 -2
  92. package/src/tools/atlas/create/createProject.ts +7 -1
  93. package/src/tools/atlas/metadata/connectCluster.ts +5 -27
  94. package/src/tools/atlas/read/inspectCluster.ts +4 -40
  95. package/src/tools/atlas/read/listAlerts.ts +45 -0
  96. package/src/tools/atlas/read/listClusters.ts +19 -36
  97. package/src/tools/atlas/read/listProjects.ts +4 -2
  98. package/src/tools/atlas/tools.ts +2 -0
  99. package/src/tools/mongodb/metadata/listDatabases.ts +0 -1
  100. package/src/tools/mongodb/read/count.ts +3 -2
  101. package/src/tools/mongodb/tools.ts +2 -4
  102. package/src/tools/tool.ts +45 -8
  103. package/src/types/mongodb-connection-string-url.d.ts +69 -0
  104. package/tests/integration/helpers.ts +41 -2
  105. package/tests/integration/tools/atlas/accessLists.test.ts +2 -2
  106. package/tests/integration/tools/atlas/alerts.test.ts +42 -0
  107. package/tests/integration/tools/atlas/atlasHelpers.ts +5 -3
  108. package/tests/integration/tools/atlas/clusters.test.ts +4 -4
  109. package/tests/integration/tools/atlas/dbUsers.test.ts +58 -33
  110. package/tests/integration/tools/atlas/orgs.test.ts +2 -2
  111. package/tests/integration/tools/atlas/projects.test.ts +3 -3
  112. package/tests/integration/tools/mongodb/create/createCollection.test.ts +2 -2
  113. package/tests/integration/tools/mongodb/create/createIndex.test.ts +2 -2
  114. package/tests/integration/tools/mongodb/create/insertMany.test.ts +1 -1
  115. package/tests/integration/tools/mongodb/delete/dropCollection.test.ts +1 -1
  116. package/tests/integration/tools/mongodb/metadata/collectionSchema.test.ts +2 -2
  117. package/tests/integration/tools/mongodb/metadata/connect.test.ts +2 -6
  118. package/tests/integration/tools/mongodb/metadata/dbStats.test.ts +4 -4
  119. package/tests/integration/tools/mongodb/metadata/explain.test.ts +10 -10
  120. package/tests/integration/tools/mongodb/metadata/listCollections.test.ts +1 -1
  121. package/tests/integration/tools/mongodb/metadata/listDatabases.test.ts +9 -5
  122. package/tests/integration/tools/mongodb/metadata/logs.test.ts +4 -4
  123. package/tests/integration/tools/mongodb/mongodbHelpers.ts +15 -24
  124. package/tests/integration/tools/mongodb/read/aggregate.test.ts +22 -7
  125. package/tests/integration/tools/mongodb/read/collectionIndexes.test.ts +5 -5
  126. package/tests/integration/tools/mongodb/read/count.test.ts +15 -10
  127. package/tests/integration/tools/mongodb/read/find.test.ts +32 -4
  128. package/tests/integration/tools/mongodb/update/renameCollection.test.ts +4 -4
  129. package/tests/unit/EJsonTransport.test.ts +71 -0
  130. package/tests/unit/apiClient.test.ts +193 -0
  131. package/tests/unit/session.test.ts +65 -0
  132. package/tests/unit/telemetry.test.ts +222 -80
  133. package/tsconfig.build.json +2 -1
  134. package/dist/packageInfo.js.map +0 -1
  135. package/dist/telemetry/device-id.js +0 -20
  136. package/dist/telemetry/device-id.js.map +0 -1
  137. package/src/telemetry/device-id.ts +0 -21
package/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Server-0098FF?logo=data:image/svg%2bxml;base64,PHN2ZyBmaWxsPSIjRkZGRkZGIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciICB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiPjxwYXRoIGQ9Ik00NC45OTkgMTAuODd2MjYuMjFjMCAxLjAzLS41OSAxLjk3LTEuNTEgMi40Mi0yLjY4IDEuMjktOCAzLjg1LTguMzUgNC4wMS0uMTMuMDctLjM4LjItLjY3LjMxLjM1LS42LjUzLTEuMy41My0yLjAyVjYuMmMwLS43NS0uMi0xLjQ1LS41Ni0yLjA2LjA5LjA0LjE3LjA4LjI0LjExLjIuMSA1Ljk4IDIuODYgOC44IDQuMkM0NC40MDkgOC45IDQ0Ljk5OSA5Ljg0IDQ0Ljk5OSAxMC44N3pNNy40OTkgMjYuMDNjMS42IDEuNDYgMy40MyAzLjEzIDUuMzQgNC44NmwtNC42IDMuNWMtLjc3LjU3LTEuNzguNS0yLjU2LS4wNS0uNS0uMzYtMS44OS0xLjY1LTEuODktMS42NS0xLjAxLS44MS0xLjA2LTIuMzItLjExLTMuMTlDMy42NzkgMjkuNSA1LjE3OSAyOC4xMyA3LjQ5OSAyNi4wM3pNMzEuOTk5IDYuMnYxMC4xMWwtNy42MyA1LjgtNi44NS01LjIxYzQuOTgtNC41MyAxMC4wMS05LjExIDEyLjY1LTExLjUyQzMwLjg2OSA0Ljc0IDMxLjk5OSA1LjI1IDMxLjk5OSA2LjJ6TTMyIDQxLjc5OFYzMS42OUw4LjI0IDEzLjYxYy0uNzctLjU3LTEuNzgtLjUtMi41Ni4wNS0uNS4zNi0xLjg5IDEuNjUtMS44OSAxLjY1LTEuMDEuODEtMS4wNiAyLjMyLS4xMSAzLjE5IDAgMCAyMC4xNDUgMTguMzM4IDI2LjQ4NSAyNC4xMTZDMzAuODcxIDQzLjI2IDMyIDQyLjc1MyAzMiA0MS43OTh6Ii8+PC9zdmc+)](https://insiders.vscode.dev/redirect/mcp/install?name=mongodb&inputs=%5B%7B%22id%22%3A%22connection_string%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22MongoDB%20connection%20string%22%7D%5D&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mongodb-mcp-server%22%5D%2C%22env%22%3A%7B%22MDB_MCP_CONNECTION_STRING%22%3A%22%24%7Binput%3Aconnection_string%7D%22%7D%7D)
2
+ [![Install in Cursor](https://img.shields.io/badge/Cursor-Install_Server-1e1e1e?logo=data:image/svg%2bxml;base64,PHN2ZyBoZWlnaHQ9IjFlbSIgc3R5bGU9ImZsZXg6bm9uZTtsaW5lLWhlaWdodDoxIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxZW0iCiAgICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogICAgPHRpdGxlPkN1cnNvcjwvdGl0bGU+CiAgICA8cGF0aCBkPSJNMTEuOTI1IDI0bDEwLjQyNS02LTEwLjQyNS02TDEuNSAxOGwxMC40MjUgNnoiCiAgICAgICAgZmlsbD0idXJsKCNsb2JlLWljb25zLWN1cnNvcnVuZGVmaW5lZC1maWxsLTApIj48L3BhdGg+CiAgICA8cGF0aCBkPSJNMjIuMzUgMThWNkwxMS45MjUgMHYxMmwxMC40MjUgNnoiIGZpbGw9InVybCgjbG9iZS1pY29ucy1jdXJzb3J1bmRlZmluZWQtZmlsbC0xKSI+PC9wYXRoPgogICAgPHBhdGggZD0iTTExLjkyNSAwTDEuNSA2djEybDEwLjQyNS02VjB6IiBmaWxsPSJ1cmwoI2xvYmUtaWNvbnMtY3Vyc29ydW5kZWZpbmVkLWZpbGwtMikiPjwvcGF0aD4KICAgIDxwYXRoIGQ9Ik0yMi4zNSA2TDExLjkyNSAyNFYxMkwyMi4zNSA2eiIgZmlsbD0iIzU1NSI+PC9wYXRoPgogICAgPHBhdGggZD0iTTIyLjM1IDZsLTEwLjQyNSA2TDEuNSA2aDIwLjg1eiIgZmlsbD0iI2ZmZiI+PC9wYXRoPgogICAgPGRlZnM+CiAgICAgICAgPGxpbmVhckdyYWRpZW50IGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBpZD0ibG9iZS1pY29ucy1jdXJzb3J1bmRlZmluZWQtZmlsbC0wIgogICAgICAgICAgICB4MT0iMTEuOTI1IiB4Mj0iMTEuOTI1IiB5MT0iMTIiIHkyPSIyNCI+CiAgICAgICAgICAgIDxzdG9wIG9mZnNldD0iLjE2IiBzdG9wLWNvbG9yPSIjZmZmIiBzdG9wLW9wYWNpdHk9Ii4zOSI+PC9zdG9wPgogICAgICAgICAgICA8c3RvcCBvZmZzZXQ9Ii42NTgiIHN0b3AtY29sb3I9IiNmZmYiIHN0b3Atb3BhY2l0eT0iLjgiPjwvc3RvcD4KICAgICAgICA8L2xpbmVhckdyYWRpZW50PgogICAgICAgIDxsaW5lYXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9ImxvYmUtaWNvbnMtY3Vyc29ydW5kZWZpbmVkLWZpbGwtMSIKICAgICAgICAgICAgeDE9IjIyLjM1IiB4Mj0iMTEuOTI1IiB5MT0iNi4wMzciIHkyPSIxMi4xNSI+CiAgICAgICAgICAgIDxzdG9wIG9mZnNldD0iLjE4MiIgc3RvcC1jb2xvcj0iI2ZmZiIgc3RvcC1vcGFjaXR5PSIuMzEiPjwvc3RvcD4KICAgICAgICAgICAgPHN0b3Agb2Zmc2V0PSIuNzE1IiBzdG9wLWNvbG9yPSIjZmZmIiBzdG9wLW9wYWNpdHk9IjAiPjwvc3RvcD4KICAgICAgICA8L2xpbmVhckdyYWRpZW50PgogICAgICAgIDxsaW5lYXJHcmFkaWVudCBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgaWQ9ImxvYmUtaWNvbnMtY3Vyc29ydW5kZWZpbmVkLWZpbGwtMiIKICAgICAgICAgICAgeDE9IjExLjkyNSIgeDI9IjEuNSIgeTE9IjAiIHkyPSIxOCI+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNmZmYiIHN0b3Atb3BhY2l0eT0iLjYiPjwvc3RvcD4KICAgICAgICAgICAgPHN0b3Agb2Zmc2V0PSIuNjY3IiBzdG9wLWNvbG9yPSIjZmZmIiBzdG9wLW9wYWNpdHk9Ii4yMiI+PC9zdG9wPgogICAgICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8L2RlZnM+Cjwvc3ZnPgo=)](https://cursor.com/install-mcp?name=MongoDB&config=eyJjb21tYW5kIjoibnB4IC15IG1vbmdvZGItbWNwLXNlcnZlciJ9)
3
+ [![View on Smithery](https://smithery.ai/badge/@mongodb-js/mongodb-mcp-server)](https://smithery.ai/server/@mongodb-js/mongodb-mcp-server)
4
+
1
5
  # MongoDB MCP Server
2
6
 
3
7
  A Model Context Protocol server for interacting with MongoDB Databases and MongoDB Atlas.
@@ -22,24 +26,28 @@ A Model Context Protocol server for interacting with MongoDB Databases and Mongo
22
26
 
23
27
  ## Prerequisites
24
28
 
25
- - Node.js (v20 or later)
29
+ - Node.js (v20.10.0 or later)
26
30
 
27
31
  ```shell
28
32
  node -v
29
33
  ```
30
34
 
31
35
  - A MongoDB connection string or Atlas API credentials, **_the Server will not start unless configured_**.
32
- - **_Atlas API credentials_** are required to use the Atlas tools. You can create a service account in MongoDB Atlas and use its credentials for authentication. See [Atlas API Access](#atlas-api-access) for more details.
36
+ - **_Service Accounts Atlas API credentials_** are required to use the Atlas tools. You can create a service account in MongoDB Atlas and use its credentials for authentication. See [Atlas API Access](#atlas-api-access) for more details.
33
37
  - If you have a MongoDB connection string, you can use it directly to connect to your MongoDB instance.
34
38
 
35
39
  ## Setup
36
40
 
37
41
  ### Quick Start
38
42
 
43
+ > **Note:** When using Atlas API credentials, be sure to assign only the minimum required permissions to your service account. See [Atlas API Permissions](#atlas-api-permissions) for details.
44
+
39
45
  Most MCP clients require a configuration file to be created or modified to add the MCP server.
40
46
 
47
+ Note: The configuration file syntax can be different across clients. Please refer to the following links for the latest expected syntax:
48
+
41
49
  - **Windsurf**:https://docs.windsurf.com/windsurf/mcp
42
- - **VSCode**: https://docs.codeium.com/docs/mcp
50
+ - **VSCode**: https://code.visualstudio.com/docs/copilot/chat/mcp-servers
43
51
  - **Claude Desktop**: https://modelcontextprotocol.io/quickstart/user
44
52
  - **Cursor**: https://docs.cursor.com/context/model-context-protocol
45
53
 
@@ -49,49 +57,155 @@ You can pass your connection string via args, make sure to use a valid username
49
57
 
50
58
  ```json
51
59
  {
52
- "servers": {
60
+ "mcpServers": {
53
61
  "MongoDB": {
54
62
  "command": "npx",
55
63
  "args": [
56
64
  "-y",
57
65
  "mongodb-mcp-server",
58
66
  "--connectionString",
59
- "mongodb+srv://username:password@cluster.mongodb.net/myDatabase"
67
+ "mongodb://localhost:27017/myDatabase"
60
68
  ]
61
69
  }
62
70
  }
63
71
  }
64
72
  ```
65
73
 
74
+ NOTE: The connection string can be configured to connect to any MongoDB cluster, whether it's a local instance or an Atlas cluster.
75
+
66
76
  #### Option 2: Atlas API credentials args
67
77
 
68
- Use your Atlas API Service Account credentials. More details in the [Atlas API Access](#atlas-api-access) section.
78
+ Use your Atlas API Service Accounts credentials. Must follow all the steps in [Atlas API Access](#atlas-api-access) section.
69
79
 
70
80
  ```json
71
81
  {
72
- "servers": {
82
+ "mcpServers": {
73
83
  "MongoDB": {
74
84
  "command": "npx",
75
85
  "args": [
76
86
  "-y",
77
87
  "mongodb-mcp-server",
78
88
  "--apiClientId",
79
- "your-atlas-client-id",
89
+ "your-atlas-service-accounts-client-id",
80
90
  "--apiClientSecret",
81
- "your-atlas-client-secret"
91
+ "your-atlas-service-accounts-client-secret"
82
92
  ]
83
93
  }
84
94
  }
85
95
  }
86
96
  ```
87
97
 
88
- #### Other options
98
+ #### Option 3: Standalone Service using command arguments
99
+
100
+ Start Server using npx command:
101
+
102
+ ```shell
103
+ npx -y mongodb-mcp-server --apiClientId="your-atlas-service-accounts-client-id" --apiClientSecret="your-atlas-service-accounts-client-secret"
104
+ ```
105
+
106
+ - For a complete list of arguments see [Configuration Options](#configuration-options)
107
+ - To configure your Atlas Service Accounts credentials please refer to [Atlas API Access](#atlas-api-access)
108
+
109
+ #### Option 4: Standalone Service using environment variables
110
+
111
+ ```shell
112
+ npx -y mongodb-mcp-server
113
+ ```
89
114
 
90
- Alternatively you can use environment variables in the config file or set them and run the server via npx.
115
+ You can use environment variables in the config file or set them and run the server via npx.
91
116
 
92
117
  - Connection String via environment variables in the MCP file [example](#connection-string-with-environment-variables)
93
118
  - Atlas API credentials via environment variables in the MCP file [example](#atlas-api-credentials-with-environment-variables)
94
119
 
120
+ #### Option 5: Using Docker
121
+
122
+ You can run the MongoDB MCP Server in a Docker container, which provides isolation and doesn't require a local Node.js installation.
123
+
124
+ #### Run with Environment Variables
125
+
126
+ You may provide either a MongoDB connection string OR Atlas API credentials:
127
+
128
+ ##### Option A: No configuration
129
+
130
+ ```shell
131
+ docker run --rm -i \
132
+ mongodb/mongodb-mcp-server:latest
133
+ ```
134
+
135
+ ##### Option B: With MongoDB connection string
136
+
137
+ ```shell
138
+ docker run --rm -i \
139
+ -e MDB_MCP_CONNECTION_STRING="mongodb+srv://username:password@cluster.mongodb.net/myDatabase" \
140
+ mongodb/mongodb-mcp-server:latest
141
+ ```
142
+
143
+ ##### Option C: With Atlas API credentials
144
+
145
+ ```shell
146
+ docker run --rm -i \
147
+ -e MDB_MCP_API_CLIENT_ID="your-atlas-service-accounts-client-id" \
148
+ -e MDB_MCP_API_CLIENT_SECRET="your-atlas-service-accounts-client-secret" \
149
+ mongodb/mongodb-mcp-server:latest
150
+ ```
151
+
152
+ ##### Docker in MCP Configuration File
153
+
154
+ Without options:
155
+
156
+ ```json
157
+ {
158
+ "mcpServers": {
159
+ "MongoDB": {
160
+ "command": "docker",
161
+ "args": ["run", "--rm", "-i", "mongodb/mongodb-mcp-server:latest"]
162
+ }
163
+ }
164
+ }
165
+ ```
166
+
167
+ With connection string:
168
+
169
+ ```json
170
+ {
171
+ "mcpServers": {
172
+ "MongoDB": {
173
+ "command": "docker",
174
+ "args": [
175
+ "run",
176
+ "--rm",
177
+ "-i",
178
+ "-e",
179
+ "MDB_MCP_CONNECTION_STRING=mongodb+srv://username:password@cluster.mongodb.net/myDatabase",
180
+ "mongodb/mongodb-mcp-server:latest"
181
+ ]
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ With Atlas API credentials:
188
+
189
+ ```json
190
+ {
191
+ "mcpServers": {
192
+ "MongoDB": {
193
+ "command": "docker",
194
+ "args": [
195
+ "run",
196
+ "--rm",
197
+ "-i",
198
+ "-e",
199
+ "MDB_MCP_API_CLIENT_ID=your-atlas-service-accounts-client-id",
200
+ "-e",
201
+ "MDB_MCP_API_CLIENT_SECRET=your-atlas-service-accounts-client-secret",
202
+ "mongodb/mongodb-mcp-server:latest"
203
+ ]
204
+ }
205
+ }
206
+ }
207
+ ```
208
+
95
209
  ## 🛠️ Supported Tools
96
210
 
97
211
  ### Tool List
@@ -108,7 +222,8 @@ Alternatively you can use environment variables in the config file or set them a
108
222
  - `atlas-inspect-access-list` - Inspect IP/CIDR ranges with access to MongoDB Atlas clusters
109
223
  - `atlas-create-access-list` - Configure IP/CIDR access list for MongoDB Atlas clusters
110
224
  - `atlas-list-db-users` - List MongoDB Atlas database users
111
- - `atlas-create-db-user` - List MongoDB Atlas database users
225
+ - `atlas-create-db-user` - Creates a MongoDB Atlas database user
226
+ - `atlas-list-alerts` - List MongoDB Atlas Alerts for a Project
112
227
 
113
228
  NOTE: atlas tools are only available when you set credentials on [configuration](#configuration) section.
114
229
 
@@ -144,15 +259,15 @@ The MongoDB MCP Server can be configured using multiple methods, with the follow
144
259
 
145
260
  ### Configuration Options
146
261
 
147
- | Option | Description |
148
- | ------------------ | --------------------------------------------------------------------------------------------------------------------- |
149
- | `apiClientId` | Atlas API client ID for authentication |
150
- | `apiClientSecret` | Atlas API client secret for authentication |
151
- | `connectionString` | MongoDB connection string for direct database connections (optional users may choose to inform it on every tool call) |
152
- | `logPath` | Folder to store logs |
153
- | `disabledTools` | An array of tool names, operation types, and/or categories of tools that will be disabled |
154
- | `readOnly` | When set to true, only allows read and metadata operation types, disabling create/update/delete operations |
155
- | `telemetry` | When set to disabled, disables telemetry collection |
262
+ | Option | Description |
263
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
264
+ | `apiClientId` | Atlas API client ID for authentication. Required for running Atlas tools. |
265
+ | `apiClientSecret` | Atlas API client secret for authentication. Required for running Atlas tools. |
266
+ | `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. |
267
+ | `logPath` | Folder to store logs. |
268
+ | `disabledTools` | An array of tool names, operation types, and/or categories of tools that will be disabled. |
269
+ | `readOnly` | When set to true, only allows read and metadata operation types, disabling create/update/delete operations. |
270
+ | `telemetry` | When set to disabled, disables telemetry collection. |
156
271
 
157
272
  #### Log Path
158
273
 
@@ -211,13 +326,16 @@ You can disable telemetry using:
211
326
 
212
327
  To use the Atlas API tools, you'll need to create a service account in MongoDB Atlas:
213
328
 
329
+ > **ℹ️ Note:** For a detailed breakdown of the minimum required permissions for each Atlas operation, see the [Atlas API Permissions](#atlas-api-permissions) section below.
330
+
214
331
  1. **Create a Service Account:**
215
332
 
216
333
  - Log in to MongoDB Atlas at [cloud.mongodb.com](https://cloud.mongodb.com)
217
334
  - Navigate to Access Manager > Organization Access
218
335
  - Click Add New > Applications > Service Accounts
219
336
  - Enter name, description and expiration for your service account (e.g., "MCP, MCP Server Access, 7 days")
220
- - Select appropriate permissions (for full access, use Organization Owner)
337
+ - **Assign only the minimum permissions needed for your use case.**
338
+ - See [Atlas API Permissions](#atlas-api-permissions) for details.
221
339
  - Click "Create"
222
340
 
223
341
  To learn more about Service Accounts, check the [MongoDB Atlas documentation](https://www.mongodb.com/docs/atlas/api/service-accounts-overview/).
@@ -227,13 +345,33 @@ To learn more about Service Accounts, check the [MongoDB Atlas documentation](ht
227
345
  - After creation, you'll be shown the Client ID and Client Secret
228
346
  - **Important:** Copy and save the Client Secret immediately as it won't be displayed again
229
347
 
230
- 3. **Add Access List Entry (Optional but recommended):**
348
+ 3. **Add Access List Entry:**
231
349
 
232
350
  - Add your IP address to the API access list
233
351
 
234
352
  4. **Configure the MCP Server:**
235
353
  - Use one of the configuration methods below to set your `apiClientId` and `apiClientSecret`
236
354
 
355
+ ### Atlas API Permissions
356
+
357
+ > **Security Warning:** Granting the Organization Owner role is rarely necessary and can be a security risk. Assign only the minimum permissions needed for your use case.
358
+
359
+ #### Quick Reference: Required roles per operation
360
+
361
+ | What you want to do | Safest Role to Assign (where) |
362
+ | ------------------------------------ | --------------------------------------- |
363
+ | List orgs/projects | Org Member or Org Read Only (Org) |
364
+ | Create new projects | Org Project Creator (Org) |
365
+ | View clusters/databases in a project | Project Read Only (Project) |
366
+ | Create/manage clusters in a project | Project Cluster Manager (Project) |
367
+ | Manage project access lists | Project IP Access List Admin (Project) |
368
+ | Manage database users | Project Database Access Admin (Project) |
369
+
370
+ - **Prefer project-level roles** for most operations. Assign only to the specific projects you need to manage or view.
371
+ - **Avoid Organization Owner** unless you require full administrative control over all projects and settings in the organization.
372
+
373
+ For a full list of roles and their privileges, see the [Atlas User Roles documentation](https://www.mongodb.com/docs/atlas/reference/user-roles/#service-user-roles).
374
+
237
375
  ### Configuration Methods
238
376
 
239
377
  #### Environment Variables
@@ -241,9 +379,9 @@ To learn more about Service Accounts, check the [MongoDB Atlas documentation](ht
241
379
  Set environment variables with the prefix `MDB_MCP_` followed by the option name in uppercase with underscores:
242
380
 
243
381
  ```shell
244
- # Set Atlas API credentials
245
- export MDB_MCP_API_CLIENT_ID="your-atlas-client-id"
246
- export MDB_MCP_API_CLIENT_SECRET="your-atlas-client-secret"
382
+ # Set Atlas API credentials (via Service Accounts)
383
+ export MDB_MCP_API_CLIENT_ID="your-atlas-service-accounts-client-id"
384
+ export MDB_MCP_API_CLIENT_SECRET="your-atlas-service-accounts-client-secret"
247
385
 
248
386
  # Set a custom MongoDB connection string
249
387
  export MDB_MCP_CONNECTION_STRING="mongodb+srv://username:password@cluster.mongodb.net/myDatabase"
@@ -258,7 +396,7 @@ export MDB_MCP_LOG_PATH="/path/to/logs"
258
396
 
259
397
  ```json
260
398
  {
261
- "servers": {
399
+ "mcpServers": {
262
400
  "MongoDB": {
263
401
  "command": "npx",
264
402
  "args": ["-y", "mongodb-mcp-server"],
@@ -274,13 +412,13 @@ export MDB_MCP_LOG_PATH="/path/to/logs"
274
412
 
275
413
  ```json
276
414
  {
277
- "servers": {
415
+ "mcpServers": {
278
416
  "MongoDB": {
279
417
  "command": "npx",
280
418
  "args": ["-y", "mongodb-mcp-server"],
281
419
  "env": {
282
- "MDB_MCP_API_CLIENT_ID": "your-atlas-client-id",
283
- "MDB_MCP_API_CLIENT_SECRET": "your-atlas-client-secret"
420
+ "MDB_MCP_API_CLIENT_ID": "your-atlas-service-accounts-client-id",
421
+ "MDB_MCP_API_CLIENT_SECRET": "your-atlas-service-accounts-client-secret"
284
422
  }
285
423
  }
286
424
  }
@@ -292,7 +430,7 @@ export MDB_MCP_LOG_PATH="/path/to/logs"
292
430
  Pass configuration options as command-line arguments when starting the server:
293
431
 
294
432
  ```shell
295
- npx -y mongodb-mcp-server --apiClientId="your-atlas-client-id" --apiClientSecret="your-atlas-client-secret" --connectionString="mongodb+srv://username:password@cluster.mongodb.net/myDatabase" --logPath=/path/to/logs
433
+ npx -y mongodb-mcp-server --apiClientId="your-atlas-service-accounts-client-id" --apiClientSecret="your-atlas-service-accounts-client-secret" --connectionString="mongodb+srv://username:password@cluster.mongodb.net/myDatabase" --logPath=/path/to/logs
296
434
  ```
297
435
 
298
436
  #### MCP configuration file examples
@@ -301,7 +439,7 @@ npx -y mongodb-mcp-server --apiClientId="your-atlas-client-id" --apiClientSecret
301
439
 
302
440
  ```json
303
441
  {
304
- "servers": {
442
+ "mcpServers": {
305
443
  "MongoDB": {
306
444
  "command": "npx",
307
445
  "args": [
@@ -319,16 +457,16 @@ npx -y mongodb-mcp-server --apiClientId="your-atlas-client-id" --apiClientSecret
319
457
 
320
458
  ```json
321
459
  {
322
- "servers": {
460
+ "mcpServers": {
323
461
  "MongoDB": {
324
462
  "command": "npx",
325
463
  "args": [
326
464
  "-y",
327
465
  "mongodb-mcp-server",
328
466
  "--apiClientId",
329
- "your-atlas-client-id",
467
+ "your-atlas-service-accounts-client-id",
330
468
  "--apiClientSecret",
331
- "your-atlas-client-secret"
469
+ "your-atlas-service-accounts-client-secret"
332
470
  ]
333
471
  }
334
472
  }
@@ -1,13 +1,15 @@
1
1
  import createClient from "openapi-fetch";
2
2
  import { ClientCredentials } from "simple-oauth2";
3
3
  import { ApiClientError } from "./apiClientError.js";
4
- import { packageInfo } from "../../packageInfo.js";
4
+ import { packageInfo } from "../../helpers/packageInfo.js";
5
5
  const ATLAS_API_VERSION = "2025-03-12";
6
6
  export class ApiClient {
7
7
  constructor(options) {
8
8
  this.getAccessToken = async () => {
9
9
  if (this.oauth2Client && (!this.accessToken || this.accessToken.expired())) {
10
- this.accessToken = await this.oauth2Client.getToken({});
10
+ this.accessToken = await this.oauth2Client.getToken({
11
+ agent: this.options.userAgent,
12
+ });
11
13
  }
12
14
  return this.accessToken?.token.access_token;
13
15
  };
@@ -26,13 +28,6 @@ export class ApiClient {
26
28
  }
27
29
  },
28
30
  };
29
- this.errorMiddleware = {
30
- async onResponse({ response }) {
31
- if (!response.ok) {
32
- throw await ApiClientError.fromResponse(response);
33
- }
34
- },
35
- };
36
31
  this.options = {
37
32
  ...options,
38
33
  userAgent: options.userAgent ||
@@ -58,11 +53,13 @@ export class ApiClient {
58
53
  });
59
54
  this.client.use(this.authMiddleware);
60
55
  }
61
- this.client.use(this.errorMiddleware);
62
56
  }
63
57
  hasCredentials() {
64
58
  return !!(this.oauth2Client && this.accessToken);
65
59
  }
60
+ async validateAccessToken() {
61
+ await this.getAccessToken();
62
+ }
66
63
  async getIpInfo() {
67
64
  const accessToken = await this.getAccessToken();
68
65
  const endpoint = "api/private/ipinfo";
@@ -81,19 +78,53 @@ export class ApiClient {
81
78
  return (await response.json());
82
79
  }
83
80
  async sendEvents(events) {
84
- let endpoint = "api/private/unauth/telemetry/events";
81
+ if (!this.options.credentials) {
82
+ await this.sendUnauthEvents(events);
83
+ return;
84
+ }
85
+ try {
86
+ await this.sendAuthEvents(events);
87
+ }
88
+ catch (error) {
89
+ if (error instanceof ApiClientError) {
90
+ if (error.response.status !== 401) {
91
+ throw error;
92
+ }
93
+ }
94
+ // send unauth events if any of the following are true:
95
+ // 1: the token is not valid (not ApiClientError)
96
+ // 2: if the api responded with 401 (ApiClientError with status 401)
97
+ await this.sendUnauthEvents(events);
98
+ }
99
+ }
100
+ async sendAuthEvents(events) {
101
+ const accessToken = await this.getAccessToken();
102
+ if (!accessToken) {
103
+ throw new Error("No access token available");
104
+ }
105
+ const authUrl = new URL("api/private/v1.0/telemetry/events", this.options.baseUrl);
106
+ const response = await fetch(authUrl, {
107
+ method: "POST",
108
+ headers: {
109
+ Accept: "application/json",
110
+ "Content-Type": "application/json",
111
+ "User-Agent": this.options.userAgent,
112
+ Authorization: `Bearer ${accessToken}`,
113
+ },
114
+ body: JSON.stringify(events),
115
+ });
116
+ if (!response.ok) {
117
+ throw await ApiClientError.fromResponse(response);
118
+ }
119
+ }
120
+ async sendUnauthEvents(events) {
85
121
  const headers = {
86
122
  Accept: "application/json",
87
123
  "Content-Type": "application/json",
88
124
  "User-Agent": this.options.userAgent,
89
125
  };
90
- const accessToken = await this.getAccessToken();
91
- if (accessToken) {
92
- endpoint = "api/private/v1.0/telemetry/events";
93
- headers["Authorization"] = `Bearer ${accessToken}`;
94
- }
95
- const url = new URL(endpoint, this.options.baseUrl);
96
- const response = await fetch(url, {
126
+ const unauthUrl = new URL("api/private/unauth/telemetry/events", this.options.baseUrl);
127
+ const response = await fetch(unauthUrl, {
97
128
  method: "POST",
98
129
  headers,
99
130
  body: JSON.stringify(events),
@@ -104,67 +135,152 @@ export class ApiClient {
104
135
  }
105
136
  // DO NOT EDIT. This is auto-generated code.
106
137
  async listClustersForAllProjects(options) {
107
- const { data } = await this.client.GET("/api/atlas/v2/clusters", options);
138
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/clusters", options);
139
+ if (error) {
140
+ throw ApiClientError.fromError(response, error);
141
+ }
108
142
  return data;
109
143
  }
110
144
  async listProjects(options) {
111
- const { data } = await this.client.GET("/api/atlas/v2/groups", options);
145
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups", options);
146
+ if (error) {
147
+ throw ApiClientError.fromError(response, error);
148
+ }
112
149
  return data;
113
150
  }
114
151
  async createProject(options) {
115
- const { data } = await this.client.POST("/api/atlas/v2/groups", options);
152
+ const { data, error, response } = await this.client.POST("/api/atlas/v2/groups", options);
153
+ if (error) {
154
+ throw ApiClientError.fromError(response, error);
155
+ }
116
156
  return data;
117
157
  }
118
158
  async deleteProject(options) {
119
- await this.client.DELETE("/api/atlas/v2/groups/{groupId}", options);
159
+ const { error, response } = await this.client.DELETE("/api/atlas/v2/groups/{groupId}", options);
160
+ if (error) {
161
+ throw ApiClientError.fromError(response, error);
162
+ }
120
163
  }
121
164
  async getProject(options) {
122
- const { data } = await this.client.GET("/api/atlas/v2/groups/{groupId}", options);
165
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}", options);
166
+ if (error) {
167
+ throw ApiClientError.fromError(response, error);
168
+ }
123
169
  return data;
124
170
  }
125
171
  async listProjectIpAccessLists(options) {
126
- const { data } = await this.client.GET("/api/atlas/v2/groups/{groupId}/accessList", options);
172
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/accessList", options);
173
+ if (error) {
174
+ throw ApiClientError.fromError(response, error);
175
+ }
127
176
  return data;
128
177
  }
129
178
  async createProjectIpAccessList(options) {
130
- const { data } = await this.client.POST("/api/atlas/v2/groups/{groupId}/accessList", options);
179
+ const { data, error, response } = await this.client.POST("/api/atlas/v2/groups/{groupId}/accessList", options);
180
+ if (error) {
181
+ throw ApiClientError.fromError(response, error);
182
+ }
131
183
  return data;
132
184
  }
133
185
  async deleteProjectIpAccessList(options) {
134
- await this.client.DELETE("/api/atlas/v2/groups/{groupId}/accessList/{entryValue}", options);
186
+ const { error, response } = await this.client.DELETE("/api/atlas/v2/groups/{groupId}/accessList/{entryValue}", options);
187
+ if (error) {
188
+ throw ApiClientError.fromError(response, error);
189
+ }
190
+ }
191
+ async listAlerts(options) {
192
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/alerts", options);
193
+ if (error) {
194
+ throw ApiClientError.fromError(response, error);
195
+ }
196
+ return data;
135
197
  }
136
198
  async listClusters(options) {
137
- const { data } = await this.client.GET("/api/atlas/v2/groups/{groupId}/clusters", options);
199
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/clusters", options);
200
+ if (error) {
201
+ throw ApiClientError.fromError(response, error);
202
+ }
138
203
  return data;
139
204
  }
140
205
  async createCluster(options) {
141
- const { data } = await this.client.POST("/api/atlas/v2/groups/{groupId}/clusters", options);
206
+ const { data, error, response } = await this.client.POST("/api/atlas/v2/groups/{groupId}/clusters", options);
207
+ if (error) {
208
+ throw ApiClientError.fromError(response, error);
209
+ }
142
210
  return data;
143
211
  }
144
212
  async deleteCluster(options) {
145
- await this.client.DELETE("/api/atlas/v2/groups/{groupId}/clusters/{clusterName}", options);
213
+ const { error, response } = await this.client.DELETE("/api/atlas/v2/groups/{groupId}/clusters/{clusterName}", options);
214
+ if (error) {
215
+ throw ApiClientError.fromError(response, error);
216
+ }
146
217
  }
147
218
  async getCluster(options) {
148
- const { data } = await this.client.GET("/api/atlas/v2/groups/{groupId}/clusters/{clusterName}", options);
219
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/clusters/{clusterName}", options);
220
+ if (error) {
221
+ throw ApiClientError.fromError(response, error);
222
+ }
149
223
  return data;
150
224
  }
151
225
  async listDatabaseUsers(options) {
152
- const { data } = await this.client.GET("/api/atlas/v2/groups/{groupId}/databaseUsers", options);
226
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/databaseUsers", options);
227
+ if (error) {
228
+ throw ApiClientError.fromError(response, error);
229
+ }
153
230
  return data;
154
231
  }
155
232
  async createDatabaseUser(options) {
156
- const { data } = await this.client.POST("/api/atlas/v2/groups/{groupId}/databaseUsers", options);
233
+ const { data, error, response } = await this.client.POST("/api/atlas/v2/groups/{groupId}/databaseUsers", options);
234
+ if (error) {
235
+ throw ApiClientError.fromError(response, error);
236
+ }
157
237
  return data;
158
238
  }
159
239
  async deleteDatabaseUser(options) {
160
- await this.client.DELETE("/api/atlas/v2/groups/{groupId}/databaseUsers/{databaseName}/{username}", options);
240
+ const { error, response } = await this.client.DELETE("/api/atlas/v2/groups/{groupId}/databaseUsers/{databaseName}/{username}", options);
241
+ if (error) {
242
+ throw ApiClientError.fromError(response, error);
243
+ }
244
+ }
245
+ async listFlexClusters(options) {
246
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/flexClusters", options);
247
+ if (error) {
248
+ throw ApiClientError.fromError(response, error);
249
+ }
250
+ return data;
251
+ }
252
+ async createFlexCluster(options) {
253
+ const { data, error, response } = await this.client.POST("/api/atlas/v2/groups/{groupId}/flexClusters", options);
254
+ if (error) {
255
+ throw ApiClientError.fromError(response, error);
256
+ }
257
+ return data;
258
+ }
259
+ async deleteFlexCluster(options) {
260
+ const { error, response } = await this.client.DELETE("/api/atlas/v2/groups/{groupId}/flexClusters/{name}", options);
261
+ if (error) {
262
+ throw ApiClientError.fromError(response, error);
263
+ }
264
+ }
265
+ async getFlexCluster(options) {
266
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/flexClusters/{name}", options);
267
+ if (error) {
268
+ throw ApiClientError.fromError(response, error);
269
+ }
270
+ return data;
161
271
  }
162
272
  async listOrganizations(options) {
163
- const { data } = await this.client.GET("/api/atlas/v2/orgs", options);
273
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/orgs", options);
274
+ if (error) {
275
+ throw ApiClientError.fromError(response, error);
276
+ }
164
277
  return data;
165
278
  }
166
279
  async listOrganizationProjects(options) {
167
- const { data } = await this.client.GET("/api/atlas/v2/orgs/{orgId}/groups", options);
280
+ const { data, error, response } = await this.client.GET("/api/atlas/v2/orgs/{orgId}/groups", options);
281
+ if (error) {
282
+ throw ApiClientError.fromError(response, error);
283
+ }
168
284
  return data;
169
285
  }
170
286
  }