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

mongodb-js / mongodb-mcp-server / 19925638108

04 Dec 2025 10:23AM UTC coverage: 80.575% (-0.03%) from 80.607%
19925638108

Pull #779

github

web-flow
Merge 1e90969c7 into e12068a03
Pull Request #779: chore: bump mcp SDK, refactor tool arguments

1469 of 1905 branches covered (77.11%)

Branch coverage included in aggregate %.

49 of 66 new or added lines in 12 files covered. (74.24%)

2 existing lines in 2 files now uncovered.

6736 of 8278 relevant lines covered (81.37%)

78.78 hits per line

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

60.4
/src/tools/mongodb/create/insertMany.ts
1
import { z } from "zod";
3✔
2
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
3✔
4
import { type ToolArgs, type OperationType, formatUntrustedData } from "../../tool.js";
3✔
5
import { zEJSON } from "../../args.js";
3✔
6
import { type Document } from "bson";
7
import { zSupportedEmbeddingParameters } from "../mongodbSchemas.js";
3✔
8
import { ErrorCodes, MongoDBError } from "../../../common/errors.js";
3✔
9

10
const zSupportedEmbeddingParametersWithInput = zSupportedEmbeddingParameters.extend({
3✔
11
    input: z
3✔
12
        .array(z.object({}).passthrough())
3✔
13
        .describe(
3✔
14
            "Array of objects with vector search index fields as keys (in dot notation) and the raw text values to generate embeddings for as values. The index of each object corresponds to the index of the document in the documents array."
3✔
15
        ),
3✔
16
});
3✔
17

18
const commonArgs = {
3✔
19
    ...DbOperationArgs,
3✔
20
    documents: z
3✔
21
        .array(zEJSON().describe("An individual MongoDB document"))
3✔
22
        .describe(
3✔
23
            "The array of documents to insert, matching the syntax of the document argument of db.collection.insertMany()."
3✔
24
        ),
3✔
25
} as const;
3✔
26

27
export class InsertManyTool extends MongoDBToolBase {
3✔
28
    public name = "insert-many";
118✔
29
    protected description = "Insert an array of documents into a MongoDB collection";
118✔
30
    protected argsShape = this.isFeatureEnabled("search")
118✔
31
        ? {
15✔
32
              ...commonArgs,
15✔
33
              embeddingParameters: zSupportedEmbeddingParametersWithInput
15✔
34
                  .optional()
15✔
35
                  .describe(
15✔
36
                      "The embedding model and its parameters to use to generate embeddings for fields with vector search indexes. Note to LLM: If unsure which embedding model to use, ask the user before providing one."
15✔
37
                  ),
15✔
38
          }
15✔
39
        : commonArgs;
103✔
40
    static operationType: OperationType = "create";
3✔
41

42
    protected async execute({
3✔
43
        database,
7✔
44
        collection,
7✔
45
        documents,
7✔
46
        ...conditionalArgs
7✔
47
    }: ToolArgs<typeof this.argsShape>): Promise<CallToolResult> {
7✔
48
        const provider = await this.ensureConnected();
7✔
49

50
        let embeddingParameters: z.infer<typeof zSupportedEmbeddingParametersWithInput> | undefined;
6✔
51
        if ("embeddingParameters" in conditionalArgs) {
7!
NEW
52
            embeddingParameters = conditionalArgs.embeddingParameters;
×
NEW
53
        }
✔
54

55
        // Process documents to replace raw string values with generated embeddings
56
        documents = await this.replaceRawValuesWithEmbeddingsIfNecessary({
6✔
57
            database,
6✔
58
            collection,
6✔
59
            documents,
6✔
60
            embeddingParameters,
6✔
61
        });
6✔
62

63
        await this.session.vectorSearchEmbeddingsManager.assertFieldsHaveCorrectEmbeddings(
6✔
64
            { database, collection },
6✔
65
            documents
6✔
66
        );
6✔
67

68
        const result = await provider.insertMany(database, collection, documents);
5✔
69
        const content = formatUntrustedData(
4✔
70
            "Documents were inserted successfully.",
4✔
71
            `Inserted \`${result.insertedCount}\` document(s) into ${database}.${collection}.`,
4✔
72
            `Inserted IDs: ${Object.values(result.insertedIds).join(", ")}`
4✔
73
        );
4✔
74
        return {
4✔
75
            content,
4✔
76
        };
4✔
77
    }
7✔
78

79
    private async replaceRawValuesWithEmbeddingsIfNecessary({
3✔
80
        database,
6✔
81
        collection,
6✔
82
        documents,
6✔
83
        embeddingParameters,
6✔
84
    }: {
6✔
85
        database: string;
86
        collection: string;
87
        documents: Document[];
88
        embeddingParameters?: z.infer<typeof zSupportedEmbeddingParametersWithInput>;
89
    }): Promise<Document[]> {
6✔
90
        // If no embedding parameters or no input specified, return documents as-is
91
        if (!embeddingParameters?.input || embeddingParameters.input.length === 0) {
6!
92
            return documents;
6✔
93
        }
6!
94

95
        // Get vector search indexes for the collection
96
        const vectorIndexes = await this.session.vectorSearchEmbeddingsManager.embeddingsForNamespace({
×
97
            database,
×
98
            collection,
×
99
        });
×
100

101
        // Ensure for inputted fields, the vector search index exists.
102
        for (const input of embeddingParameters.input) {
×
103
            for (const fieldPath of Object.keys(input)) {
×
104
                if (!vectorIndexes.some((index) => index.path === fieldPath)) {
×
105
                    throw new MongoDBError(
×
106
                        ErrorCodes.AtlasVectorSearchInvalidQuery,
×
107
                        `Field '${fieldPath}' does not have a vector search index in collection ${database}.${collection}. Only fields with vector search indexes can have embeddings generated.`
×
108
                    );
×
109
                }
×
110
            }
×
111
        }
×
112

113
        // We make one call to generate embeddings for all documents at once to avoid making too many API calls.
114
        const flattenedEmbeddingsInput = embeddingParameters.input.flatMap((documentInput, index) =>
×
115
            Object.entries(documentInput).map(([fieldPath, rawTextValue]) => ({
×
116
                fieldPath,
×
117
                rawTextValue,
×
118
                documentIndex: index,
×
119
            }))
×
120
        );
×
121

122
        const generatedEmbeddings = await this.session.vectorSearchEmbeddingsManager.generateEmbeddings({
×
123
            rawValues: flattenedEmbeddingsInput.map(({ rawTextValue }) => rawTextValue) as string[],
×
124
            embeddingParameters,
×
125
            inputType: "document",
×
126
        });
×
127

128
        const processedDocuments: Document[] = [...documents];
×
129

130
        for (const [index, { fieldPath, documentIndex }] of flattenedEmbeddingsInput.entries()) {
×
131
            if (!processedDocuments[documentIndex]) {
×
132
                throw new MongoDBError(ErrorCodes.Unexpected, `Document at index ${documentIndex} does not exist.`);
×
133
            }
×
134
            // Ensure no nested fields are present in the field path.
135
            this.deleteFieldPath(processedDocuments[documentIndex], fieldPath);
×
136
            processedDocuments[documentIndex][fieldPath] = generatedEmbeddings[index];
×
137
        }
×
138

139
        return processedDocuments;
×
140
    }
6✔
141

142
    // Delete a specified field path from a document using dot notation.
143
    private deleteFieldPath(document: Record<string, unknown>, fieldPath: string): void {
3✔
144
        const parts = fieldPath.split(".");
×
145
        let current: Record<string, unknown> = document;
×
146
        for (let i = 0; i < parts.length; i++) {
×
147
            const part = parts[i];
×
148
            const key = part as keyof typeof current;
×
149
            if (!current[key]) {
×
150
                return;
×
151
            } else if (i === parts.length - 1) {
×
152
                delete current[key];
×
153
            } else {
×
154
                current = current[key] as Record<string, unknown>;
×
155
            }
×
156
        }
×
157
    }
×
158
}
3✔
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