mongodb-mcp-server 0.1.2 → 0.2.0

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 (270) hide show
  1. package/.github/pull_request_template.md +5 -0
  2. package/.github/workflows/accuracy-tests.yml +55 -0
  3. package/.github/workflows/check.yml +1 -1
  4. package/.github/workflows/code_health.yaml +4 -4
  5. package/.github/workflows/code_health_fork.yaml +0 -14
  6. package/.github/workflows/dependabot_pr.yaml +26 -0
  7. package/.github/workflows/docker.yaml +1 -1
  8. package/.github/workflows/jira-issue.yml +72 -0
  9. package/.smithery/smithery.yaml +10 -0
  10. package/.vscode/extensions.json +1 -1
  11. package/.vscode/launch.json +11 -1
  12. package/.vscode/settings.json +1 -11
  13. package/Dockerfile +1 -0
  14. package/README.md +132 -31
  15. package/dist/common/atlas/accessListUtils.js +36 -0
  16. package/dist/common/atlas/accessListUtils.js.map +1 -0
  17. package/dist/common/atlas/apiClient.js +25 -6
  18. package/dist/common/atlas/apiClient.js.map +1 -1
  19. package/dist/common/atlas/cluster.js +1 -1
  20. package/dist/common/atlas/cluster.js.map +1 -1
  21. package/dist/{config.js → common/config.js} +8 -1
  22. package/dist/common/config.js.map +1 -0
  23. package/dist/{errors.js → common/errors.js} +1 -0
  24. package/dist/common/errors.js.map +1 -0
  25. package/dist/{logger.js → common/logger.js} +20 -19
  26. package/dist/common/logger.js.map +1 -0
  27. package/dist/common/managedTimeout.js +20 -0
  28. package/dist/common/managedTimeout.js.map +1 -0
  29. package/dist/common/packageInfo.js.map +1 -0
  30. package/dist/{session.js → common/session.js} +20 -21
  31. package/dist/common/session.js.map +1 -0
  32. package/dist/common/sessionStore.js +73 -0
  33. package/dist/common/sessionStore.js.map +1 -0
  34. package/dist/helpers/container.js +28 -0
  35. package/dist/helpers/container.js.map +1 -0
  36. package/dist/helpers/generatePassword.js.map +1 -0
  37. package/dist/helpers/indexCheck.js +63 -0
  38. package/dist/helpers/indexCheck.js.map +1 -0
  39. package/dist/index.js +30 -37
  40. package/dist/index.js.map +1 -1
  41. package/dist/server.js +44 -7
  42. package/dist/server.js.map +1 -1
  43. package/dist/telemetry/constants.js +1 -1
  44. package/dist/telemetry/constants.js.map +1 -1
  45. package/dist/telemetry/telemetry.js +86 -116
  46. package/dist/telemetry/telemetry.js.map +1 -1
  47. package/dist/tools/atlas/atlasTool.js +3 -3
  48. package/dist/tools/atlas/atlasTool.js.map +1 -1
  49. package/dist/tools/atlas/connect/connectCluster.js +198 -0
  50. package/dist/tools/atlas/connect/connectCluster.js.map +1 -0
  51. package/dist/tools/atlas/create/createAccessList.js +9 -10
  52. package/dist/tools/atlas/create/createAccessList.js.map +1 -1
  53. package/dist/tools/atlas/create/createDBUser.js +3 -1
  54. package/dist/tools/atlas/create/createDBUser.js.map +1 -1
  55. package/dist/tools/atlas/create/createFreeCluster.js +2 -0
  56. package/dist/tools/atlas/create/createFreeCluster.js.map +1 -1
  57. package/dist/tools/atlas/create/createProject.js.map +1 -1
  58. package/dist/tools/atlas/read/inspectAccessList.js.map +1 -1
  59. package/dist/tools/atlas/read/inspectCluster.js.map +1 -1
  60. package/dist/tools/atlas/read/listAlerts.js.map +1 -1
  61. package/dist/tools/atlas/read/listClusters.js.map +1 -1
  62. package/dist/tools/atlas/read/listDBUsers.js.map +1 -1
  63. package/dist/tools/atlas/read/listOrgs.js.map +1 -1
  64. package/dist/tools/atlas/read/listProjects.js.map +1 -1
  65. package/dist/tools/atlas/tools.js +1 -1
  66. package/dist/tools/atlas/tools.js.map +1 -1
  67. package/dist/tools/mongodb/{metadata → connect}/connect.js +7 -4
  68. package/dist/tools/mongodb/connect/connect.js.map +1 -0
  69. package/dist/tools/mongodb/create/createCollection.js.map +1 -1
  70. package/dist/tools/mongodb/create/createIndex.js +1 -1
  71. package/dist/tools/mongodb/create/createIndex.js.map +1 -1
  72. package/dist/tools/mongodb/create/insertMany.js +1 -1
  73. package/dist/tools/mongodb/create/insertMany.js.map +1 -1
  74. package/dist/tools/mongodb/delete/deleteMany.js +20 -1
  75. package/dist/tools/mongodb/delete/deleteMany.js.map +1 -1
  76. package/dist/tools/mongodb/delete/dropCollection.js.map +1 -1
  77. package/dist/tools/mongodb/delete/dropDatabase.js.map +1 -1
  78. package/dist/tools/mongodb/metadata/collectionSchema.js.map +1 -1
  79. package/dist/tools/mongodb/metadata/collectionStorageSize.js.map +1 -1
  80. package/dist/tools/mongodb/metadata/dbStats.js.map +1 -1
  81. package/dist/tools/mongodb/metadata/explain.js +2 -2
  82. package/dist/tools/mongodb/metadata/explain.js.map +1 -1
  83. package/dist/tools/mongodb/metadata/listCollections.js.map +1 -1
  84. package/dist/tools/mongodb/metadata/listDatabases.js.map +1 -1
  85. package/dist/tools/mongodb/metadata/logs.js.map +1 -1
  86. package/dist/tools/mongodb/mongodbTool.js +47 -10
  87. package/dist/tools/mongodb/mongodbTool.js.map +1 -1
  88. package/dist/tools/mongodb/read/aggregate.js +10 -1
  89. package/dist/tools/mongodb/read/aggregate.js.map +1 -1
  90. package/dist/tools/mongodb/read/collectionIndexes.js.map +1 -1
  91. package/dist/tools/mongodb/read/count.js +15 -1
  92. package/dist/tools/mongodb/read/count.js.map +1 -1
  93. package/dist/tools/mongodb/read/find.js +14 -4
  94. package/dist/tools/mongodb/read/find.js.map +1 -1
  95. package/dist/tools/mongodb/tools.js +1 -1
  96. package/dist/tools/mongodb/tools.js.map +1 -1
  97. package/dist/tools/mongodb/update/renameCollection.js.map +1 -1
  98. package/dist/tools/mongodb/update/updateMany.js +24 -2
  99. package/dist/tools/mongodb/update/updateMany.js.map +1 -1
  100. package/dist/tools/tool.js +12 -9
  101. package/dist/tools/tool.js.map +1 -1
  102. package/dist/transports/base.js +26 -0
  103. package/dist/transports/base.js.map +1 -0
  104. package/dist/{helpers/EJsonTransport.js → transports/stdio.js} +24 -2
  105. package/dist/transports/stdio.js.map +1 -0
  106. package/dist/transports/streamableHttp.js +140 -0
  107. package/dist/transports/streamableHttp.js.map +1 -0
  108. package/eslint.config.js +13 -4
  109. package/package.json +43 -33
  110. package/resources/test-summary-template.html +415 -0
  111. package/scripts/accuracy/generateTestSummary.ts +335 -0
  112. package/scripts/accuracy/runAccuracyTests.sh +45 -0
  113. package/scripts/accuracy/updateAccuracyRunStatus.ts +21 -0
  114. package/src/common/atlas/accessListUtils.ts +54 -0
  115. package/src/common/atlas/apiClient.ts +25 -6
  116. package/src/common/atlas/cluster.ts +1 -1
  117. package/src/{config.ts → common/config.ts} +16 -2
  118. package/src/{errors.ts → common/errors.ts} +1 -0
  119. package/src/{logger.ts → common/logger.ts} +21 -24
  120. package/src/common/managedTimeout.ts +27 -0
  121. package/src/{session.ts → common/session.ts} +24 -26
  122. package/src/common/sessionStore.ts +111 -0
  123. package/src/helpers/container.ts +35 -0
  124. package/src/helpers/indexCheck.ts +83 -0
  125. package/src/index.ts +30 -40
  126. package/src/server.ts +55 -11
  127. package/src/telemetry/constants.ts +1 -1
  128. package/src/telemetry/telemetry.ts +109 -153
  129. package/src/telemetry/types.ts +2 -1
  130. package/src/tools/atlas/atlasTool.ts +4 -4
  131. package/src/tools/atlas/connect/connectCluster.ts +259 -0
  132. package/src/tools/atlas/create/createAccessList.ts +15 -13
  133. package/src/tools/atlas/create/createDBUser.ts +5 -3
  134. package/src/tools/atlas/create/createFreeCluster.ts +4 -2
  135. package/src/tools/atlas/create/createProject.ts +2 -2
  136. package/src/tools/atlas/read/inspectAccessList.ts +2 -2
  137. package/src/tools/atlas/read/inspectCluster.ts +2 -2
  138. package/src/tools/atlas/read/listAlerts.ts +2 -2
  139. package/src/tools/atlas/read/listClusters.ts +2 -2
  140. package/src/tools/atlas/read/listDBUsers.ts +2 -2
  141. package/src/tools/atlas/read/listOrgs.ts +2 -2
  142. package/src/tools/atlas/read/listProjects.ts +2 -2
  143. package/src/tools/atlas/tools.ts +1 -1
  144. package/src/tools/mongodb/{metadata → connect}/connect.ts +12 -9
  145. package/src/tools/mongodb/create/createCollection.ts +2 -2
  146. package/src/tools/mongodb/create/createIndex.ts +3 -3
  147. package/src/tools/mongodb/create/insertMany.ts +3 -3
  148. package/src/tools/mongodb/delete/deleteMany.ts +24 -3
  149. package/src/tools/mongodb/delete/dropCollection.ts +2 -2
  150. package/src/tools/mongodb/delete/dropDatabase.ts +2 -2
  151. package/src/tools/mongodb/metadata/collectionSchema.ts +2 -2
  152. package/src/tools/mongodb/metadata/collectionStorageSize.ts +2 -2
  153. package/src/tools/mongodb/metadata/dbStats.ts +2 -2
  154. package/src/tools/mongodb/metadata/explain.ts +4 -4
  155. package/src/tools/mongodb/metadata/listCollections.ts +2 -2
  156. package/src/tools/mongodb/metadata/listDatabases.ts +2 -2
  157. package/src/tools/mongodb/metadata/logs.ts +2 -2
  158. package/src/tools/mongodb/mongodbTool.ts +60 -14
  159. package/src/tools/mongodb/read/aggregate.ts +14 -3
  160. package/src/tools/mongodb/read/collectionIndexes.ts +2 -2
  161. package/src/tools/mongodb/read/count.ts +19 -3
  162. package/src/tools/mongodb/read/find.ts +20 -6
  163. package/src/tools/mongodb/tools.ts +1 -1
  164. package/src/tools/mongodb/update/renameCollection.ts +2 -2
  165. package/src/tools/mongodb/update/updateMany.ts +28 -4
  166. package/src/tools/tool.ts +23 -18
  167. package/src/transports/base.ts +34 -0
  168. package/src/{helpers/EJsonTransport.ts → transports/stdio.ts} +30 -1
  169. package/src/transports/streamableHttp.ts +178 -0
  170. package/tests/accuracy/aggregate.test.ts +27 -0
  171. package/tests/accuracy/collectionIndexes.test.ts +40 -0
  172. package/tests/accuracy/collectionSchema.test.ts +28 -0
  173. package/tests/accuracy/collectionStorageSize.test.ts +41 -0
  174. package/tests/accuracy/count.test.ts +44 -0
  175. package/tests/accuracy/createCollection.test.ts +46 -0
  176. package/tests/accuracy/createIndex.test.ts +37 -0
  177. package/tests/accuracy/dbStats.test.ts +15 -0
  178. package/tests/accuracy/deleteMany.test.ts +44 -0
  179. package/tests/accuracy/dropCollection.test.ts +74 -0
  180. package/tests/accuracy/dropDatabase.test.ts +41 -0
  181. package/tests/accuracy/explain.test.ts +73 -0
  182. package/tests/accuracy/find.test.ts +114 -0
  183. package/tests/accuracy/insertMany.test.ts +48 -0
  184. package/tests/accuracy/listCollections.test.ts +60 -0
  185. package/tests/accuracy/listDatabases.test.ts +31 -0
  186. package/tests/accuracy/logs.test.ts +28 -0
  187. package/tests/accuracy/renameCollection.test.ts +31 -0
  188. package/tests/accuracy/sdk/accuracyResultStorage/diskStorage.ts +189 -0
  189. package/tests/accuracy/sdk/accuracyResultStorage/getAccuracyResultStorage.ts +11 -0
  190. package/tests/accuracy/sdk/accuracyResultStorage/mongodbStorage.ts +151 -0
  191. package/tests/accuracy/sdk/accuracyResultStorage/resultStorage.ts +117 -0
  192. package/tests/accuracy/sdk/accuracyScorer.ts +93 -0
  193. package/tests/accuracy/sdk/accuracyTestingClient.ts +94 -0
  194. package/tests/accuracy/sdk/agent.ts +56 -0
  195. package/tests/accuracy/sdk/constants.ts +26 -0
  196. package/tests/accuracy/sdk/describeAccuracyTests.ts +126 -0
  197. package/tests/accuracy/sdk/gitInfo.ts +7 -0
  198. package/tests/accuracy/sdk/matcher.ts +193 -0
  199. package/tests/accuracy/sdk/models.ts +95 -0
  200. package/tests/accuracy/test-data-dumps/comics.books.json +417 -0
  201. package/tests/accuracy/test-data-dumps/comics.characters.json +402 -0
  202. package/tests/accuracy/test-data-dumps/mflix.movies.json +496 -0
  203. package/tests/accuracy/test-data-dumps/mflix.shows.json +572 -0
  204. package/tests/accuracy/updateMany.test.ts +42 -0
  205. package/tests/integration/helpers.ts +9 -9
  206. package/tests/integration/indexCheck.test.ts +464 -0
  207. package/tests/integration/server.test.ts +6 -4
  208. package/tests/integration/telemetry.test.ts +29 -0
  209. package/tests/integration/tools/atlas/accessLists.test.ts +22 -2
  210. package/tests/integration/tools/atlas/alerts.test.ts +3 -2
  211. package/tests/integration/tools/atlas/atlasHelpers.ts +3 -0
  212. package/tests/integration/tools/atlas/clusters.test.ts +68 -16
  213. package/tests/integration/tools/atlas/dbUsers.test.ts +14 -1
  214. package/tests/integration/tools/atlas/orgs.test.ts +2 -1
  215. package/tests/integration/tools/atlas/projects.test.ts +4 -3
  216. package/tests/integration/tools/mongodb/{metadata → connect}/connect.test.ts +34 -3
  217. package/tests/integration/tools/mongodb/create/createCollection.test.ts +1 -0
  218. package/tests/integration/tools/mongodb/create/createIndex.test.ts +1 -0
  219. package/tests/integration/tools/mongodb/create/insertMany.test.ts +1 -0
  220. package/tests/integration/tools/mongodb/delete/deleteMany.test.ts +1 -0
  221. package/tests/integration/tools/mongodb/delete/dropCollection.test.ts +1 -1
  222. package/tests/integration/tools/mongodb/delete/dropDatabase.test.ts +1 -0
  223. package/tests/integration/tools/mongodb/metadata/collectionSchema.test.ts +1 -0
  224. package/tests/integration/tools/mongodb/metadata/collectionStorageSize.test.ts +1 -0
  225. package/tests/integration/tools/mongodb/metadata/dbStats.test.ts +1 -0
  226. package/tests/integration/tools/mongodb/metadata/explain.test.ts +1 -0
  227. package/tests/integration/tools/mongodb/metadata/listCollections.test.ts +1 -0
  228. package/tests/integration/tools/mongodb/metadata/listDatabases.test.ts +3 -2
  229. package/tests/integration/tools/mongodb/metadata/logs.test.ts +1 -0
  230. package/tests/integration/tools/mongodb/mongodbHelpers.ts +67 -2
  231. package/tests/integration/tools/mongodb/read/aggregate.test.ts +2 -1
  232. package/tests/integration/tools/mongodb/read/collectionIndexes.test.ts +1 -0
  233. package/tests/integration/tools/mongodb/read/count.test.ts +1 -0
  234. package/tests/integration/tools/mongodb/read/find.test.ts +2 -1
  235. package/tests/integration/tools/mongodb/update/renameCollection.test.ts +1 -0
  236. package/tests/integration/tools/mongodb/update/updateMany.test.ts +1 -0
  237. package/tests/integration/transports/stdio.test.ts +40 -0
  238. package/tests/integration/transports/streamableHttp.test.ts +56 -0
  239. package/tests/matchers/toIncludeSameMembers.test.ts +59 -0
  240. package/tests/matchers/toIncludeSameMembers.ts +12 -0
  241. package/tests/setup.ts +7 -0
  242. package/tests/unit/accessListUtils.test.ts +39 -0
  243. package/tests/unit/accuracyScorer.test.ts +390 -0
  244. package/tests/unit/{apiClient.test.ts → common/apiClient.test.ts} +15 -15
  245. package/tests/unit/common/managedTimeout.test.ts +67 -0
  246. package/tests/unit/{session.test.ts → common/session.test.ts} +7 -12
  247. package/tests/unit/helpers/indexCheck.test.ts +150 -0
  248. package/tests/unit/telemetry.test.ts +99 -137
  249. package/tests/unit/{EJsonTransport.test.ts → transports/stdio.test.ts} +4 -4
  250. package/tests/vitest.d.ts +11 -0
  251. package/tsconfig.json +0 -1
  252. package/{tsconfig.jest.json → tsconfig.test.json} +1 -2
  253. package/vitest.config.ts +41 -0
  254. package/dist/common/atlas/generatePassword.js.map +0 -1
  255. package/dist/config.js.map +0 -1
  256. package/dist/errors.js.map +0 -1
  257. package/dist/helpers/EJsonTransport.js.map +0 -1
  258. package/dist/helpers/packageInfo.js.map +0 -1
  259. package/dist/logger.js.map +0 -1
  260. package/dist/session.js.map +0 -1
  261. package/dist/tools/atlas/metadata/connectCluster.js +0 -100
  262. package/dist/tools/atlas/metadata/connectCluster.js.map +0 -1
  263. package/dist/tools/mongodb/metadata/connect.js.map +0 -1
  264. package/global.d.ts +0 -1
  265. package/jest.config.cjs +0 -22
  266. package/src/tools/atlas/metadata/connectCluster.ts +0 -121
  267. /package/dist/{helpers → common}/packageInfo.js +0 -0
  268. /package/dist/{common/atlas → helpers}/generatePassword.js +0 -0
  269. /package/src/{helpers → common}/packageInfo.ts +0 -0
  270. /package/src/{common/atlas → helpers}/generatePassword.ts +0 -0
@@ -0,0 +1,73 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+
3
+ /**
4
+ * None of these tests score a parameter match on any of the models, likely
5
+ * because we are using Zod.union, when we probably should've used
6
+ * Zod.discriminatedUnion
7
+ */
8
+ describeAccuracyTests([
9
+ {
10
+ prompt: `Will fetching documents, where release_year is 2020, from 'mflix.movies' namespace perform a collection scan?`,
11
+ expectedToolCalls: [
12
+ {
13
+ toolName: "explain",
14
+ parameters: {
15
+ database: "mflix",
16
+ collection: "movies",
17
+ method: [
18
+ {
19
+ name: "find",
20
+ arguments: {
21
+ filter: { release_year: 2020 },
22
+ },
23
+ },
24
+ ],
25
+ },
26
+ },
27
+ ],
28
+ },
29
+ {
30
+ prompt: `Will aggregating documents, where release_year is 2020, from 'mflix.movies' namespace perform a collection scan?`,
31
+ expectedToolCalls: [
32
+ {
33
+ toolName: "explain",
34
+ parameters: {
35
+ database: "mflix",
36
+ collection: "movies",
37
+ method: [
38
+ {
39
+ name: "aggregate",
40
+ arguments: {
41
+ pipeline: [
42
+ {
43
+ $match: { release_year: 2020 },
44
+ },
45
+ ],
46
+ },
47
+ },
48
+ ],
49
+ },
50
+ },
51
+ ],
52
+ },
53
+ {
54
+ prompt: `Will counting documents, where release_year is 2020, from 'mflix.movies' namespace perform a collection scan?`,
55
+ expectedToolCalls: [
56
+ {
57
+ toolName: "explain",
58
+ parameters: {
59
+ database: "mflix",
60
+ collection: "movies",
61
+ method: [
62
+ {
63
+ name: "count",
64
+ arguments: {
65
+ query: { release_year: 2020 },
66
+ },
67
+ },
68
+ ],
69
+ },
70
+ },
71
+ ],
72
+ },
73
+ ]);
@@ -0,0 +1,114 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+ import { Matcher } from "./sdk/matcher.js";
3
+
4
+ describeAccuracyTests([
5
+ {
6
+ prompt: "List all the movies in 'mflix.movies' namespace.",
7
+ expectedToolCalls: [
8
+ {
9
+ toolName: "find",
10
+ parameters: {
11
+ database: "mflix",
12
+ collection: "movies",
13
+ filter: Matcher.emptyObjectOrUndefined,
14
+ },
15
+ },
16
+ ],
17
+ },
18
+ {
19
+ prompt: "List all the documents in 'comics.books' namespace.",
20
+ expectedToolCalls: [
21
+ {
22
+ toolName: "find",
23
+ parameters: {
24
+ database: "comics",
25
+ collection: "books",
26
+ filter: Matcher.emptyObjectOrUndefined,
27
+ },
28
+ },
29
+ ],
30
+ },
31
+ {
32
+ prompt: "Find all the movies in 'mflix.movies' namespace with runtime less than 100.",
33
+ expectedToolCalls: [
34
+ {
35
+ toolName: "find",
36
+ parameters: {
37
+ database: "mflix",
38
+ collection: "movies",
39
+ filter: {
40
+ runtime: { $lt: 100 },
41
+ },
42
+ },
43
+ },
44
+ ],
45
+ },
46
+ {
47
+ prompt: "Find all movies in 'mflix.movies' collection where director is 'Christina Collins'",
48
+ expectedToolCalls: [
49
+ {
50
+ toolName: "find",
51
+ parameters: {
52
+ database: "mflix",
53
+ collection: "movies",
54
+ filter: {
55
+ director: "Christina Collins",
56
+ },
57
+ },
58
+ },
59
+ ],
60
+ },
61
+ {
62
+ prompt: "Give me all the movie titles available in 'mflix.movies' namespace",
63
+ expectedToolCalls: [
64
+ {
65
+ toolName: "find",
66
+ parameters: {
67
+ database: "mflix",
68
+ collection: "movies",
69
+ projection: {
70
+ title: 1,
71
+ _id: Matcher.anyOf(
72
+ Matcher.undefined,
73
+ Matcher.number((value) => value === 0)
74
+ ),
75
+ },
76
+ filter: Matcher.emptyObjectOrUndefined,
77
+ },
78
+ },
79
+ ],
80
+ },
81
+ {
82
+ prompt: "Use 'mflix.movies' namespace to answer who were casted in the movie 'Certain Fish'",
83
+ expectedToolCalls: [
84
+ {
85
+ toolName: "find",
86
+ parameters: {
87
+ database: "mflix",
88
+ collection: "movies",
89
+ filter: { title: "Certain Fish" },
90
+ projection: {
91
+ cast: 1,
92
+ _id: Matcher.anyOf(Matcher.undefined, Matcher.number()),
93
+ },
94
+ limit: Matcher.number((value) => value > 0),
95
+ },
96
+ },
97
+ ],
98
+ },
99
+ {
100
+ prompt: "From the mflix.movies namespace, give me first 2 movies of Horror genre sorted ascending by their runtime",
101
+ expectedToolCalls: [
102
+ {
103
+ toolName: "find",
104
+ parameters: {
105
+ database: "mflix",
106
+ collection: "movies",
107
+ filter: { genres: "Horror" },
108
+ sort: { runtime: 1 },
109
+ limit: 2,
110
+ },
111
+ },
112
+ ],
113
+ },
114
+ ]);
@@ -0,0 +1,48 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+ import { Matcher } from "./sdk/matcher.js";
3
+
4
+ describeAccuracyTests([
5
+ {
6
+ prompt: [
7
+ "In my namespace 'mflix.movies', insert 3 documents each with the following fields:",
8
+ "- id: an incremental number starting from 1",
9
+ "- name: a string of format 'name<id>'",
10
+ ].join("\n"),
11
+ expectedToolCalls: [
12
+ {
13
+ toolName: "insert-many",
14
+ parameters: {
15
+ database: "mflix",
16
+ collection: "movies",
17
+ documents: [
18
+ {
19
+ id: 1,
20
+ name: "name1",
21
+ },
22
+ {
23
+ id: 2,
24
+ name: "name2",
25
+ },
26
+ {
27
+ id: 3,
28
+ name: "name3",
29
+ },
30
+ ],
31
+ },
32
+ },
33
+ ],
34
+ },
35
+ {
36
+ prompt: "Add three empty documents in collection 'movies' inside database 'mflix'",
37
+ expectedToolCalls: [
38
+ {
39
+ toolName: "insert-many",
40
+ parameters: {
41
+ database: "mflix",
42
+ collection: "movies",
43
+ documents: [{ _id: Matcher.anyValue }, { _id: Matcher.anyValue }, { _id: Matcher.anyValue }],
44
+ },
45
+ },
46
+ ],
47
+ },
48
+ ]);
@@ -0,0 +1,60 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+
3
+ describeAccuracyTests([
4
+ {
5
+ prompt: "How many collections do I have in database mflix?",
6
+ expectedToolCalls: [
7
+ {
8
+ toolName: "list-collections",
9
+ parameters: { database: "mflix" },
10
+ },
11
+ ],
12
+ },
13
+ {
14
+ prompt: "List all the collections in my MongoDB database mflix.",
15
+ expectedToolCalls: [
16
+ {
17
+ toolName: "list-collections",
18
+ parameters: { database: "mflix" },
19
+ },
20
+ ],
21
+ },
22
+ {
23
+ prompt: "Is there a shows collection in my MongoDB database mflix?",
24
+ expectedToolCalls: [
25
+ {
26
+ toolName: "list-collections",
27
+ parameters: { database: "mflix" },
28
+ },
29
+ ],
30
+ },
31
+ {
32
+ prompt: "List all the collections that I have in total on my cluster?",
33
+ expectedToolCalls: [
34
+ {
35
+ toolName: "list-databases",
36
+ parameters: {},
37
+ },
38
+ {
39
+ toolName: "list-collections",
40
+ parameters: { database: "admin" },
41
+ },
42
+ {
43
+ toolName: "list-collections",
44
+ parameters: { database: "comics" },
45
+ },
46
+ {
47
+ toolName: "list-collections",
48
+ parameters: { database: "config" },
49
+ },
50
+ {
51
+ toolName: "list-collections",
52
+ parameters: { database: "local" },
53
+ },
54
+ {
55
+ toolName: "list-collections",
56
+ parameters: { database: "mflix" },
57
+ },
58
+ ],
59
+ },
60
+ ]);
@@ -0,0 +1,31 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+
3
+ describeAccuracyTests([
4
+ {
5
+ prompt: "How many databases do I have?",
6
+ expectedToolCalls: [
7
+ {
8
+ toolName: "list-databases",
9
+ parameters: {},
10
+ },
11
+ ],
12
+ },
13
+ {
14
+ prompt: "List all the databases that I have in my clusters",
15
+ expectedToolCalls: [
16
+ {
17
+ toolName: "list-databases",
18
+ parameters: {},
19
+ },
20
+ ],
21
+ },
22
+ {
23
+ prompt: "Is there a mflix database in my cluster?",
24
+ expectedToolCalls: [
25
+ {
26
+ toolName: "list-databases",
27
+ parameters: {},
28
+ },
29
+ ],
30
+ },
31
+ ]);
@@ -0,0 +1,28 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+ import { Matcher } from "./sdk/matcher.js";
3
+
4
+ describeAccuracyTests([
5
+ {
6
+ prompt: "Were there any startup warnings for my MongoDB server?",
7
+ expectedToolCalls: [
8
+ {
9
+ toolName: "mongodb-logs",
10
+ parameters: {
11
+ type: "startupWarnings",
12
+ },
13
+ },
14
+ ],
15
+ },
16
+ {
17
+ prompt: "Retrieve first 10 logs for my MongoDB server?",
18
+ expectedToolCalls: [
19
+ {
20
+ toolName: "mongodb-logs",
21
+ parameters: {
22
+ type: Matcher.anyOf(Matcher.undefined, Matcher.value("global")),
23
+ limit: 10,
24
+ },
25
+ },
26
+ ],
27
+ },
28
+ ]);
@@ -0,0 +1,31 @@
1
+ import { describeAccuracyTests } from "./sdk/describeAccuracyTests.js";
2
+
3
+ describeAccuracyTests([
4
+ {
5
+ prompt: "Rename my 'mflix.movies' namespace to 'mflix.new_movies'",
6
+ expectedToolCalls: [
7
+ {
8
+ toolName: "rename-collection",
9
+ parameters: {
10
+ database: "mflix",
11
+ collection: "movies",
12
+ newName: "new_movies",
13
+ },
14
+ },
15
+ ],
16
+ },
17
+ {
18
+ prompt: "Rename my 'mflix.movies' namespace to 'mflix.new_movies' while removing the old namespace.",
19
+ expectedToolCalls: [
20
+ {
21
+ toolName: "rename-collection",
22
+ parameters: {
23
+ database: "mflix",
24
+ collection: "movies",
25
+ newName: "new_movies",
26
+ dropTarget: true,
27
+ },
28
+ },
29
+ ],
30
+ },
31
+ ]);
@@ -0,0 +1,189 @@
1
+ import path from "path";
2
+ import fs from "fs/promises";
3
+ import { lock } from "proper-lockfile";
4
+ import { ACCURACY_RESULTS_DIR, LATEST_ACCURACY_RUN_NAME } from "../constants.js";
5
+ import {
6
+ AccuracyResult,
7
+ AccuracyResultStorage,
8
+ AccuracyRunStatus,
9
+ AccuracyRunStatuses,
10
+ ExpectedToolCall,
11
+ ModelResponse,
12
+ } from "./resultStorage.js";
13
+
14
+ export class DiskBasedResultStorage implements AccuracyResultStorage {
15
+ async getAccuracyResult(commitSHA: string, runId?: string): Promise<AccuracyResult | null> {
16
+ const filePath = runId
17
+ ? // If we have both commit and runId then we get the path for
18
+ // specific file. Common case when saving prompt responses during an
19
+ // accuracy run
20
+ this.getAccuracyResultFilePath(commitSHA, runId)
21
+ : // If we only have commit then we grab the latest successful run for the
22
+ // commit. The latest run is a link to the last run that was
23
+ // marked as successful.
24
+ this.getAccuracyResultFilePath(commitSHA, LATEST_ACCURACY_RUN_NAME);
25
+
26
+ return this.withFileLock<AccuracyResult | null>(filePath, () => this.getAccuracyResultWithoutLock(filePath));
27
+ }
28
+
29
+ async updateRunStatus(commitSHA: string, runId: string, status: AccuracyRunStatuses): Promise<void> {
30
+ const resultFilePath = this.getAccuracyResultFilePath(commitSHA, runId);
31
+ await this.withFileLock(resultFilePath, async () => {
32
+ const accuracyResult = await this.getAccuracyResultWithoutLock(resultFilePath);
33
+ if (!accuracyResult) {
34
+ throw new Error("Results not found!");
35
+ }
36
+
37
+ await fs.writeFile(
38
+ resultFilePath,
39
+ JSON.stringify(
40
+ {
41
+ ...accuracyResult,
42
+ runStatus: status,
43
+ },
44
+ null,
45
+ 2
46
+ ),
47
+ { encoding: "utf8" }
48
+ );
49
+ });
50
+
51
+ // This bit is important to mark the current run as the latest run for a
52
+ // commit so that we can use that during baseline comparison.
53
+ if (status === AccuracyRunStatus.Done) {
54
+ const latestResultFilePath = this.getLatestResultFilePath(commitSHA);
55
+ await this.ensureFileWithInitialData(latestResultFilePath, JSON.stringify({}));
56
+ await this.withFileLock(latestResultFilePath, async () => {
57
+ await fs.unlink(latestResultFilePath);
58
+ await fs.link(resultFilePath, latestResultFilePath);
59
+ });
60
+ }
61
+ }
62
+
63
+ async saveModelResponseForPrompt({
64
+ commitSHA,
65
+ runId,
66
+ prompt,
67
+ expectedToolCalls,
68
+ modelResponse,
69
+ }: {
70
+ commitSHA: string;
71
+ runId: string;
72
+ prompt: string;
73
+ expectedToolCalls: ExpectedToolCall[];
74
+ modelResponse: ModelResponse;
75
+ }): Promise<void> {
76
+ const initialData: AccuracyResult = {
77
+ runId,
78
+ runStatus: AccuracyRunStatus.InProgress,
79
+ createdOn: Date.now(),
80
+ commitSHA,
81
+ promptResults: [
82
+ {
83
+ prompt,
84
+ expectedToolCalls,
85
+ modelResponses: [modelResponse],
86
+ },
87
+ ],
88
+ };
89
+ const resultFilePath = this.getAccuracyResultFilePath(commitSHA, runId);
90
+ const { fileCreatedWithInitialData } = await this.ensureFileWithInitialData(
91
+ resultFilePath,
92
+ JSON.stringify(initialData, null, 2)
93
+ );
94
+
95
+ if (fileCreatedWithInitialData) {
96
+ return;
97
+ }
98
+
99
+ await this.withFileLock(resultFilePath, async () => {
100
+ let accuracyResult = await this.getAccuracyResultWithoutLock(resultFilePath);
101
+ if (!accuracyResult) {
102
+ throw new Error("Expected at-least initial accuracy result to be present");
103
+ }
104
+
105
+ const existingPromptIdx = accuracyResult.promptResults.findIndex((result) => result.prompt === prompt);
106
+ const promptResult = accuracyResult.promptResults[existingPromptIdx];
107
+ if (promptResult) {
108
+ accuracyResult.promptResults.splice(existingPromptIdx, 1, {
109
+ prompt: promptResult.prompt,
110
+ expectedToolCalls: promptResult.expectedToolCalls,
111
+ modelResponses: [...promptResult.modelResponses, modelResponse],
112
+ });
113
+ } else {
114
+ accuracyResult = {
115
+ ...accuracyResult,
116
+ promptResults: [
117
+ ...accuracyResult.promptResults,
118
+ {
119
+ prompt,
120
+ expectedToolCalls,
121
+ modelResponses: [modelResponse],
122
+ },
123
+ ],
124
+ };
125
+ }
126
+
127
+ await fs.writeFile(resultFilePath, JSON.stringify(accuracyResult, null, 2));
128
+ });
129
+ }
130
+
131
+ close(): Promise<void> {
132
+ return Promise.resolve();
133
+ }
134
+
135
+ private async getAccuracyResultWithoutLock(filePath: string): Promise<AccuracyResult | null> {
136
+ try {
137
+ const raw = await fs.readFile(filePath, "utf8");
138
+ return JSON.parse(raw) as AccuracyResult;
139
+ } catch (error) {
140
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") {
141
+ return null;
142
+ }
143
+ throw error;
144
+ }
145
+ }
146
+
147
+ private async ensureFileWithInitialData(
148
+ filePath: string,
149
+ initialData: string
150
+ ): Promise<{
151
+ fileCreatedWithInitialData: boolean;
152
+ }> {
153
+ try {
154
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
155
+ await fs.writeFile(filePath, initialData, { flag: "wx" });
156
+ return {
157
+ fileCreatedWithInitialData: true,
158
+ };
159
+ } catch (error) {
160
+ if ((error as NodeJS.ErrnoException).code === "EEXIST") {
161
+ return {
162
+ fileCreatedWithInitialData: false,
163
+ };
164
+ }
165
+ throw error;
166
+ }
167
+ }
168
+
169
+ private async withFileLock<R>(filePath: string, callback: () => Promise<R>): Promise<R> {
170
+ let releaseLock: (() => Promise<void>) | undefined;
171
+ try {
172
+ releaseLock = await lock(filePath, { retries: 10 });
173
+ return await callback();
174
+ } catch (error) {
175
+ console.warn(`Could not acquire lock for file - ${filePath}.`, error);
176
+ throw error;
177
+ } finally {
178
+ await releaseLock?.();
179
+ }
180
+ }
181
+
182
+ private getAccuracyResultFilePath(commitSHA: string, runId: string): string {
183
+ return path.join(ACCURACY_RESULTS_DIR, commitSHA, `${runId}.json`);
184
+ }
185
+
186
+ private getLatestResultFilePath(commitSHA: string): string {
187
+ return path.join(ACCURACY_RESULTS_DIR, commitSHA, `${LATEST_ACCURACY_RUN_NAME}.json`);
188
+ }
189
+ }
@@ -0,0 +1,11 @@
1
+ import { DiskBasedResultStorage } from "./diskStorage.js";
2
+ import { MongoDBBasedResultStorage } from "./mongodbStorage.js";
3
+ import { AccuracyResultStorage } from "./resultStorage.js";
4
+
5
+ export function getAccuracyResultStorage(): AccuracyResultStorage {
6
+ const { MDB_ACCURACY_MDB_URL, MDB_ACCURACY_MDB_DB, MDB_ACCURACY_MDB_COLLECTION } = process.env;
7
+ if (MDB_ACCURACY_MDB_URL && MDB_ACCURACY_MDB_DB && MDB_ACCURACY_MDB_COLLECTION) {
8
+ return new MongoDBBasedResultStorage(MDB_ACCURACY_MDB_URL, MDB_ACCURACY_MDB_DB, MDB_ACCURACY_MDB_COLLECTION);
9
+ }
10
+ return new DiskBasedResultStorage();
11
+ }