You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MCP SDK自定义工具Zod参数验证兼容问题:Cursor正常Flowise报“Expected object, received string”错误

MCP SDK自定义工具Zod参数验证兼容问题:Cursor正常Flowise报“Expected object, received string”错误

我最近基于Model Context Protocol (MCP) SDK开发了带Zod参数验证的自定义工具,在Cursor AI里调用完全正常,但在Flowise中遇到了参数格式的矛盾错误——有时候提示“Expected object, received string”,手动转成对象后又提示“Expected string, received object”,折腾了好一阵子都没解决。

报错信息

McpError: MCP error -32602: Invalid arguments for tool getUserData: [ { "code": "invalid_type", "expected": "object", "received": "string", "path": ["parameters"], "message": "Expected object, received string" }]

我的工具代码

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";

// Zod schema definition
const UserFilterSchema = z.object({
  userId: z.string().describe("User ID to filter by"),
  page: z.number().int().positive().optional().default(1),
  limit: z.number().int().positive().optional().default(10),
  includeDetails: z.boolean().optional().default(false)
});

type UserFilterInput = z.infer<typeof UserFilterSchema>;

// Tool registration
server.tool(
  "getUserData",
  {
    parameters: UserFilterSchema,
    token: z.string().describe("Authentication token"),
  },
  async (args: { parameters: UserFilterInput, token: string }) => {
    const { userId, page = 1, limit = 10, includeDetails = false } = args.parameters;
    try {
      // Mock data processing logic
      const mockData = {
        userId,
        userData: `Sample data for user ${userId}`,
        page,
        limit,
        includeDetails
      };
      return {
        content: [{ type: "text", text: JSON.stringify({ success: true, data: mockData }) }]
      };
    } catch (error) {
      return {
        content: [{ type: "text", text: JSON.stringify({ success: false, error: error.message }) }],
        isError: true
      };
    }
  }
);

环境差异与尝试

环境状态说明
Cursor AI✅ 正常工作参数验证和解析完全正常
Flowise❌ 报错参数格式矛盾验证失败

我已经试过两种参数传递方式,但都触发相反的错误:

  • 传入对象格式:{ userId: "user123", page: 1, limit: 10 } → 提示“Expected string, received object”
  • 传入字符串格式:"user123" → 提示“Expected object, received string”

可能的解决方案

1. 用Zod Union兼容两种参数格式

修改Schema,让它同时支持对象和字符串输入,自动转换为统一结构:

// 兼容对象和字符串的UserFilterSchema
const UserFilterSchema = z.union([
  // 原始对象格式
  z.object({
    userId: z.string().describe("User ID to filter by"),
    page: z.number().int().positive().optional(),
    limit: z.number().int().positive().optional(),
    includeDetails: z.boolean().optional()
  }),
  // 直接传入userId字符串,自动转为对象
  z.string().transform(userId => ({ userId }))
]).pipe(
  // 统一应用默认值
  z.object({
    userId: z.string(),
    page: z.number().int().positive().default(1),
    limit: z.number().int().positive().default(10),
    includeDetails: z.boolean().default(false)
  })
);

2. 在工具函数中显式处理参数格式

如果不想修改Schema,可以在工具逻辑里先做格式兼容:

async (args: { parameters: unknown, token: string }) => {
  let parsedParams: UserFilterInput;

  // 处理字符串格式的参数
  if (typeof args.parameters === 'string') {
    try {
      // 尝试解析为JSON对象
      parsedParams = UserFilterSchema.parse(JSON.parse(args.parameters));
    } catch {
      // 解析失败则用字符串作为userId
      parsedParams = UserFilterSchema.parse({ userId: args.parameters });
    }
  } else {
    // 处理对象格式的参数
    parsedParams = UserFilterSchema.parse(args.parameters);
  }

  const { userId, page = 1, limit = 10, includeDetails = false } = parsedParams;
  // 后续业务逻辑...
}

3. 检查Flowise的参数配置

有些低代码平台会自动序列化参数,检查Flowise中调用MCP工具的设置:

  • 确认是否开启了“自动JSON序列化”选项,尝试关闭它
  • 在Flowise中用表达式手动处理参数,比如{{ JSON.stringify(参数对象) }}或{{ 参数对象.userId }}

这种问题本质是不同MCP客户端对协议细节的实现差异,通过兼容输入格式或者显式转换,就能解决跨平台的调用问题。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 07:35:32