github / github/copilot-cli

MCP tool arguments with array-or-string union schema (anyOf) are stringified before reaching the server

Đang mở
#4,301 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

area:mcp area:tools
Ngôn ngữ chính
Shell
Star
11.2k
Fork
1.9k
Merge trung bình
14 giờ 16 phút
Pull request đã merge (30 ngày)
6

Mô tả

Describe the bug

When an MCP tool parameter's JSON Schema declares a union that includes both array and string (e.g. anyOf: [array, string] or a Zod z.union([z.array(z.string()), z.string(), z.null()])), Copilot CLI's MCP client flattens/stringifies the argument before sending it to the server -- even when a genuine JSON array is supplied. The MCP server (which correctly expects and validates an array) then rejects the call, because it receives a bare string instead.

This reproduces against the Obsidian Local REST API plugin's MCP server (obsidian-mcp), specifically its vault_patch and vault_read tools' target parameter, used for heading-path addressing (e.g. ["Parent Heading", "Child Heading"]).

Affected version

GitHub Copilot CLI 1.0.76 (Windows)

Steps to reproduce the behavior
  1. Register an MCP server exposing a tool whose parameter schema is z.union([z.array(z.string()), z.string(), z.null()]) (or the JSON-Schema equivalent anyOf: [{type: array, items: {type: string}}, {type: string}, {type: null}]).
  2. From Copilot CLI, call that tool with a genuine array value, e.g. target: ["Top", "Child"].
  3. Observe the server rejects the call as if a bare string were sent (e.g. A heading target must be an array of heading texts, not a bare string), even though the client was given a proper array.
  4. Direct/bypass test: calling the identical tool with the identical array directly against the server's /mcp JSON-RPC endpoint (bypassing the Copilot CLI client) succeeds and returns the correct result -- confirming the server is correct and the array is valid.
Root cause (isolated via a controlled A/B test)

We edited the MCP server's own schema for the affected parameter, removing the string option so the union became array | null only (no code changes elsewhere; identical Copilot CLI client, identical server, identical call). With that one change:

  • The exact same array argument (["Top", "Child"]) that previously failed now succeeded and correctly resolved a two-level nested heading.
  • A single-element array (["Top"]) also succeeded.

This isolates the bug precisely: Copilot CLI's MCP client only mis-serializes array arguments when the parameter's declared schema is a union that also includes string. Parameters that are plain/unconstrained JSON (no such union), or presumably schemas of array | null with no string sibling, pass arrays through untouched -- we independently confirmed a plain JSON-typed parameter (no union) on the same server correctly accepted and round-tripped a real array in the same session.

Reproduction table
Channel Argument Parameter schema Result
Copilot CLI MCP tool call target: ["Top","Child"] anyOf: [array, string, null] Fails -- arrives as a stringified value, rejected as "not a bare string"
Copilot CLI MCP tool call target: ["Top"] anyOf: [array, string, null] Fails -- same error
Copilot CLI MCP tool call target: [] (empty array) anyOf: [array, string, null] Fails -- same error
Copilot CLI MCP tool call target: null anyOf: [array, string, null] Fails -- null also arrives stringified
Direct /mcp JSON-RPC call (bypassing Copilot CLI) target: ["Top","Child"] (real array) same schema Succeeds
Copilot CLI MCP tool call, schema patched to remove string target: ["Top","Child"] union([array, null]) Succeeds -- correct nested-heading resolution
Copilot CLI MCP tool call, schema patched to remove string target: ["Top"] union([array, null]) Succeeds
Copilot CLI MCP tool call plain JSON-typed parameter (no union), given ["a","b"] no union constraint Succeeds -- array passed through untouched
Expected behavior

A genuine JSON array argument should be transmitted to the MCP server as an array, regardless of whether the parameter's schema also permits a string (or other) alternative in the same union/anyOf.

Additional context
  • This is likely related to #2634, which reports Copilot CLI's MCP tool-schema handling losing/narrowing fields and unions (including an anyOf mixing array and object) between what an MCP server advertises and what the model/client actually uses. That report is about schema-definition loss at tool-discovery time; this report is about argument-value corruption at call time for a union schema. Both point at the same general area of Copilot CLI's MCP layer mishandling anyOf/union types that include array, so they may share a root cause.
  • This is scoped narrowly: it is not "Copilot CLI can't send array arguments" -- arrays work fine for parameters with a plain array (or non-union) schema. The bug is specific to a schema union that pairs array with string (and possibly other non-array types).

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong đường dẫn máy khách MCP của Copilot CLI chuyển đổi các schema công cụ được quảng bá thành các đối số gọi, sử dụng bản tái hiện /mcp JSON-RPC đã được ghi lại để so sánh các yêu cầu trực tiếp và các yêu cầu qua CLI. Xác minh rằng các giá trị array và null vẫn là các giá trị có kiểu khi anyOf bao gồm array, string và null, đồng thời các trường hợp array thuần túy và không phải union hiện có tiếp tục hoạt động.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
shell
Lĩnh vực
api, cli
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
67/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.