fix(mcp): stabilize lab search pagination (#578)

This commit is contained in:
Marc-André Bombeck authored and GitHub committed 2026-07-21 16:17:16 +02:00
1 parent b20f1b5c66
commit 0d5d61bc36
3 files changed
+48

No files matched your search

+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
- **MCP search cursors keep lab results stable across pages.** Distinct analyte
names are ordered before offset pagination, preventing repeated or skipped
lab entries when a client follows `nextCursor`.
## [1.31.7] — 2026-07-20
- **Current OpenAI reasoning models use their supported request contract.**
@@ -120,6 +120,49 @@ describe("search", () => {
expect(result.results.map((r) => r.id)).toContain("lab:LDL");
expect(result.results.some((r) => r.id.startsWith("med:"))).toBe(false);
});
it("keeps distinct lab analytes stable across cursor pages", async () => {
vi.mocked(buildCoachDataInventory).mockResolvedValue({
entries: [],
window: "90d",
restMode: false,
cycleEnabled: false,
} as never);
vi.mocked(prisma.medication.findMany).mockResolvedValue([]);
const analytes = Array.from({ length: 60 }, (_, index) => ({
analyte: `Analyte ${String(index).padStart(2, "0")}`,
}));
let callCount = 0;
vi.mocked(prisma.labResult.findMany).mockImplementation((args) => {
const ordered =
(args as { orderBy?: { analyte?: string } }).orderBy?.analyte === "asc";
const rows =
ordered || callCount++ % 2 === 0 ? analytes : [...analytes].reverse();
return Promise.resolve(rows) as ReturnType<
typeof prisma.labResult.findMany
>;
});
const def = tool("search");
const first = (await def.run(CTX, { query: "" })) as {
results: Array<{ id: string }>;
nextCursor?: string;
};
const second = (await def.run(CTX, {
query: "",
cursor: first.nextCursor,
})) as {
results: Array<{ id: string }>;
};
const labIds = [...first.results, ...second.results]
.map((result) => result.id)
.filter((id) => id.startsWith("lab:"));
expect(new Set(labIds)).toHaveLength(60);
expect(prisma.labResult.findMany).toHaveBeenCalledWith(
expect.objectContaining({ orderBy: { analyte: "asc" } }),
);
});
});
describe("fetch", () => {
+1
View File
@@ -385,6 +385,7 @@ function searchAndFetchTools(): McpToolDefinition[] {
where: { userId: ctx.userId, deletedAt: null },
select: { analyte: true },
distinct: ["analyte"],
orderBy: { analyte: "asc" },
take: SEARCH_RESULT_SCAN_CAP,
});
for (const lab of labs) {