fix: convert MCP tool schemas from JSON Schema to Zod for SDK v1.29.0
The MCP SDK v1.29.0 changed server.tool() to require Zod schemas (raw shapes) instead of plain JSON Schema objects. The old format triggered "expected a Zod schema or ToolAnnotations" errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { z } from "zod";
|
||||
import type { db as prodDb } from "../../../db/index.ts";
|
||||
import {
|
||||
createCandidate,
|
||||
@@ -31,14 +32,12 @@ export const threadToolDefinitions = [
|
||||
description:
|
||||
"List research threads. Threads are the recommended way to evaluate gear purchases — each thread tracks multiple candidates for a single gear slot, making it easy to compare options before committing.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
includeResolved: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Include resolved threads (default: false, only active threads)",
|
||||
},
|
||||
},
|
||||
includeResolved: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe(
|
||||
"Include resolved threads (default: false, only active threads)",
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -46,11 +45,7 @@ export const threadToolDefinitions = [
|
||||
description:
|
||||
"Get a thread with all its candidates for detailed comparison.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
id: { type: "number", description: "Thread ID" },
|
||||
},
|
||||
required: ["id"],
|
||||
id: z.number().describe("Thread ID"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -58,15 +53,8 @@ export const threadToolDefinitions = [
|
||||
description:
|
||||
"Start a new research thread for a gear slot. This is the preferred workflow: create a thread, add candidates with pros/cons/prices, compare them, then resolve the thread to add the winner to your collection.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
name: {
|
||||
type: "string",
|
||||
description: "Thread name (e.g. 'Handlebar bag')",
|
||||
},
|
||||
categoryId: { type: "number", description: "Category ID" },
|
||||
},
|
||||
required: ["name", "categoryId"],
|
||||
name: z.string().describe("Thread name (e.g. 'Handlebar bag')"),
|
||||
categoryId: z.number().describe("Category ID"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -74,35 +62,24 @@ export const threadToolDefinitions = [
|
||||
description:
|
||||
"Resolve a research thread by picking the winning candidate. The winner is automatically added to the gear collection as a new item, and the thread is marked as resolved.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
threadId: { type: "number", description: "Thread ID" },
|
||||
candidateId: {
|
||||
type: "number",
|
||||
description: "ID of the winning candidate",
|
||||
},
|
||||
},
|
||||
required: ["threadId", "candidateId"],
|
||||
threadId: z.number().describe("Thread ID"),
|
||||
candidateId: z.number().describe("ID of the winning candidate"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "add_candidate",
|
||||
description: "Add a candidate option to a research thread for comparison.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
threadId: { type: "number", description: "Thread ID" },
|
||||
name: { type: "string", description: "Candidate name" },
|
||||
categoryId: { type: "number", description: "Category ID" },
|
||||
weightGrams: { type: "number", description: "Weight in grams" },
|
||||
priceCents: { type: "number", description: "Price in cents" },
|
||||
notes: { type: "string", description: "Notes" },
|
||||
productUrl: { type: "string", description: "Product URL" },
|
||||
imageFilename: { type: "string", description: "Image filename" },
|
||||
pros: { type: "string", description: "Pros of this candidate" },
|
||||
cons: { type: "string", description: "Cons of this candidate" },
|
||||
},
|
||||
required: ["threadId", "name", "categoryId"],
|
||||
threadId: z.number().describe("Thread ID"),
|
||||
name: z.string().describe("Candidate name"),
|
||||
categoryId: z.number().describe("Category ID"),
|
||||
weightGrams: z.number().optional().describe("Weight in grams"),
|
||||
priceCents: z.number().optional().describe("Price in cents"),
|
||||
notes: z.string().optional().describe("Notes"),
|
||||
productUrl: z.string().optional().describe("Product URL"),
|
||||
imageFilename: z.string().optional().describe("Image filename"),
|
||||
pros: z.string().optional().describe("Pros of this candidate"),
|
||||
cons: z.string().optional().describe("Cons of this candidate"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -110,36 +87,28 @@ export const threadToolDefinitions = [
|
||||
description:
|
||||
"Update a candidate's details (name, price, pros, cons, etc.).",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
id: { type: "number", description: "Candidate ID" },
|
||||
name: { type: "string", description: "Candidate name" },
|
||||
weightGrams: { type: "number", description: "Weight in grams" },
|
||||
priceCents: { type: "number", description: "Price in cents" },
|
||||
categoryId: { type: "number", description: "Category ID" },
|
||||
notes: { type: "string", description: "Notes" },
|
||||
productUrl: { type: "string", description: "Product URL" },
|
||||
imageFilename: { type: "string", description: "Image filename" },
|
||||
imageSourceUrl: { type: "string", description: "Image source URL" },
|
||||
status: {
|
||||
type: "string",
|
||||
description: "Status: researching, ordered, or arrived",
|
||||
},
|
||||
pros: { type: "string", description: "Pros" },
|
||||
cons: { type: "string", description: "Cons" },
|
||||
},
|
||||
required: ["id"],
|
||||
id: z.number().describe("Candidate ID"),
|
||||
name: z.string().optional().describe("Candidate name"),
|
||||
weightGrams: z.number().optional().describe("Weight in grams"),
|
||||
priceCents: z.number().optional().describe("Price in cents"),
|
||||
categoryId: z.number().optional().describe("Category ID"),
|
||||
notes: z.string().optional().describe("Notes"),
|
||||
productUrl: z.string().optional().describe("Product URL"),
|
||||
imageFilename: z.string().optional().describe("Image filename"),
|
||||
imageSourceUrl: z.string().optional().describe("Image source URL"),
|
||||
status: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Status: researching, ordered, or arrived"),
|
||||
pros: z.string().optional().describe("Pros"),
|
||||
cons: z.string().optional().describe("Cons"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remove_candidate",
|
||||
description: "Remove a candidate from a research thread.",
|
||||
inputSchema: {
|
||||
type: "object" as const,
|
||||
properties: {
|
||||
id: { type: "number", description: "Candidate ID to remove" },
|
||||
},
|
||||
required: ["id"],
|
||||
id: z.number().describe("Candidate ID to remove"),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user