Skip to content

Commit 8206acc

Browse files
committed
chore: use memory limits and support custom sample size
1 parent 4219bd5 commit 8206acc

File tree

2 files changed

+39
-8
lines changed

2 files changed

+39
-8
lines changed

src/tools/mongodb/metadata/collectionSchema.ts

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,35 @@
11
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
22
import { DbOperationArgs, MongoDBToolBase } from "../mongodbTool.js";
3-
import type { ToolArgs, OperationType } from "../../tool.js";
3+
import type { ToolArgs, OperationType, ToolExecutionContext } from "../../tool.js";
44
import { formatUntrustedData } from "../../tool.js";
55
import { getSimplifiedSchema } from "mongodb-schema";
6+
import z from "zod";
7+
import { ONE_MB } from "../../../helpers/constants.js";
8+
import { collectCursorUntilMaxBytesLimit } from "../../../helpers/collectCursorUntilMaxBytes.js";
69

710
export class CollectionSchemaTool extends MongoDBToolBase {
811
public name = "collection-schema";
912
protected description = "Describe the schema for a collection";
10-
protected argsShape = DbOperationArgs;
13+
protected argsShape = {
14+
...DbOperationArgs,
15+
sampleSize: z.number().optional().default(50).describe("Number of documents to sample for schema inference"),
16+
responseBytesLimit: z.number().optional().default(ONE_MB).describe(`The maximum number of bytes to return in the response. This value is capped by the server’s configured maxBytesPerQuery and cannot be exceeded.`),
17+
};
1118

1219
public operationType: OperationType = "metadata";
1320

14-
protected async execute({ database, collection }: ToolArgs<typeof DbOperationArgs>): Promise<CallToolResult> {
21+
protected async execute(
22+
{ database, collection, sampleSize, responseBytesLimit }: ToolArgs<typeof DbOperationArgs>,
23+
{ signal }: ToolExecutionContext
24+
): Promise<CallToolResult> {
1525
const provider = await this.ensureConnected();
16-
const documents = await provider.aggregate(database, collection, [
17-
{ $sample: { size: 50 } },
18-
]).toArray();
26+
const cursor = provider.aggregate(database, collection, [{ $sample: { size: Math.min(sampleSize, this.config.maxDocumentsPerQuery) } }]);
27+
const { cappedBy, documents } = await collectCursorUntilMaxBytesLimit({
28+
cursor,
29+
configuredMaxBytesPerQuery: this.config.maxBytesPerQuery,
30+
toolResponseBytesLimit: responseBytesLimit,
31+
abortSignal: signal,
32+
});
1933
const schema = await getSimplifiedSchema(documents);
2034

2135
const fieldsCount = Object.entries(schema).length;
@@ -30,9 +44,12 @@ export class CollectionSchemaTool extends MongoDBToolBase {
3044
};
3145
}
3246

47+
const header = `Found ${fieldsCount} fields in the schema for "${database}.${collection}"`;
48+
const cappedWarning = cappedBy !== undefined ? `\nThe schema was inferred from a subset of documents due to the response size limit. (${cappedBy})` : "";
49+
3350
return {
3451
content: formatUntrustedData(
35-
`Found ${fieldsCount} fields in the schema for "${database}.${collection}"`,
52+
`${header}${cappedWarning}`,
3653
JSON.stringify(schema)
3754
),
3855
};

tests/integration/tools/mongodb/metadata/collectionSchema.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,21 @@ describeWithMongoDB("collectionSchema tool", (integration) => {
1919
integration,
2020
"collection-schema",
2121
"Describe the schema for a collection",
22-
databaseCollectionParameters
22+
[
23+
...databaseCollectionParameters,
24+
{
25+
name: "sampleSize",
26+
type: "number",
27+
description: "Number of documents to sample for schema inference",
28+
required: false,
29+
},
30+
{
31+
name: "responseBytesLimit",
32+
type: "number",
33+
description: `The maximum number of bytes to return in the response. This value is capped by the server’s configured maxBytesPerQuery and cannot be exceeded.`,
34+
required: false,
35+
}
36+
]
2337
);
2438

2539
validateThrowsForInvalidArguments(integration, "collection-schema", databaseCollectionInvalidArgs);

0 commit comments

Comments
 (0)