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

mongodb-js / mongodb-mcp-server / 20659002550

02 Jan 2026 01:36PM UTC coverage: 79.432% (+0.03%) from 79.4%
20659002550

Pull #819

github

web-flow
Merge 85f3cdd9a into b5213e680
Pull Request #819: feat: add transport metadata to all tools - MCP-348

1478 of 1936 branches covered (76.34%)

Branch coverage included in aggregate %.

28 of 29 new or added lines in 4 files covered. (96.55%)

56 existing lines in 3 files now uncovered.

6802 of 8488 relevant lines covered (80.14%)

86.27 hits per line

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

60.61
/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
import type { ConnectionMetadata, AutoEmbeddingsUsageMetadata } from "../../../telemetry/types.js";
10

11
const zSupportedEmbeddingParametersWithInput = zSupportedEmbeddingParameters.extend({
3✔
12
    input: z
3✔
13
        .array(z.object({}).passthrough())
3✔
14
        .describe(
3✔
15
            "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✔
16
        ),
3✔
17
});
3✔
18

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

28
export class InsertManyTool extends MongoDBToolBase {
3✔
29
    public name = "insert-many";
118✔
30
    protected description = "Insert an array of documents into a MongoDB collection";
118✔
31
    protected argsShape = this.isFeatureEnabled("search")
118✔
32
        ? {
15✔
33
              ...commonArgs,
15✔
34
              embeddingParameters: zSupportedEmbeddingParametersWithInput
15✔
35
                  .optional()
15✔
36
                  .describe(
15✔
37
                      "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✔
38
                  ),
15✔
39
          }
15✔
40
        : commonArgs;
103✔
41
    static operationType: OperationType = "create";
3✔
42

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
140
        return processedDocuments;
×
141
    }
7✔
142

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

160
    protected resolveTelemetryMetadata(
3✔
161
        args: ToolArgs<typeof this.argsShape>,
3✔
162
        { result }: { result: CallToolResult }
3✔
163
    ): ConnectionMetadata | AutoEmbeddingsUsageMetadata {
3✔
164
        if ("embeddingParameters" in args && this.config.voyageApiKey) {
3!
UNCOV
165
            return {
×
166
                ...super.resolveTelemetryMetadata(args, { result }),
×
167
                embeddingsGeneratedBy: "mcp",
×
168
            };
×
169
        } else {
3✔
170
            return super.resolveTelemetryMetadata(args, { result });
3✔
171
        }
3✔
172
    }
3✔
173
}
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

© 2026 Coveralls, Inc