microsoft / microsoft/copilot-for-eclipse

[Bug] MCP tools silently fail to register when a tool inputSchema uses a nullable type union ("type": ["string","null"])

Open
#325 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Java
Stars
126
Forks
60
Avg merge
2d 6h
Merged PRs (30d)
5

Description

Environment

  • OS: macOS 15 (Apple Silicon / aarch64)
  • Eclipse Version: 2026-06 (4.40.0, build 20260604-0652), JDK 21.0.8 (Temurin)
  • Plugin Version: 0.19.0.202606240339 (GitHub Copilot Language Server 1.502.5)

Describe the bug

Copilot for Eclipse silently fails to register all tools from an MCP server if any tool's inputSchema declares a property with a nullable JSON-Schema type union, i.e. "type": ["string", "null"].

The server connects normally and the Error Log even reports [CopilotMCP] Refreshed N tools for server <name> with the correct count, and [mcpGateway] registered mount … — but in Agent Mode → Configure Tools the server shows as a dead, unexpandable checkbox with no tools, and the agent cannot call any of them. Changing the single union "type": ["string","null"]"type": "string" makes all tools register and work.

This is really two bugs:

  1. Valid schema is rejected. Type-array unions like ["string","null"] are valid JSON Schema (all drafts) and are the exact nullable form [OpenAI's Structured Outputs guidance](https://platform.openai.com/docs/guides/structured-outputs) prescribes for optional fields. Other MCP clients (e.g., Claude Desktop/Code) accept them; Copilot-Eclipse's schema conversion does not.
  2. The failure is silent and server-wide. One offending property in one tool drops the entire server's tool list, with no error in the Error Log or MCP console — Refreshed N tools is logged as if it succeeded. This makes it nearly impossible to diagnose (it took ~12 iterations to bisect).

To Reproduce

  1. Save this minimal MCP server as repro-mcp.js (Node ≥ 18, no dependencies):
// repro-mcp.js — minimal MCP stdio server, no dependencies.
const send = (m) => process.stdout.write(JSON.stringify(m) + "\n");

const TOOL = {
  name: "demo_tool",
  description: "Demo tool with one optional, nullable parameter.",
  inputSchema: {
    type: "object",
    properties: {
      required_arg: { type: "string", description: "A required argument." },
      // 🔴 TRIGGER — valid JSON-Schema / OpenAI nullable union.
      //    With this line present, NO tools from this server register (silently).
      optional_arg: { type: ["string", "null"], description: "Optional, nullable." },
      // ✅ Replace the line above with:
      //    optional_arg: { type: "string", description: "Optional, nullable." }
      //    …and the tool registers and works.
    },
    required: ["required_arg"],
  },
};

let buf = "";
process.stdin.on("data", (chunk) => {
  buf += chunk;
  let nl;
  while ((nl = buf.indexOf("\n")) >= 0) {
    const line = buf.slice(0, nl); buf = buf.slice(nl + 1);
    if (!line.trim()) continue;
    let msg; try { msg = JSON.parse(line); } catch { continue; }
    if (msg.method === "initialize") {
      send({ jsonrpc: "2.0", id: msg.id, result: {
        protocolVersion: "2024-11-05",
        capabilities: { tools: {} },
        serverInfo: { name: "nullable-repro", version: "1.0.0" },
      }});
    } else if (msg.method === "tools/list") {
      send({ jsonrpc: "2.0", id: msg.id, result: { tools: [TOOL] } });
    } else if (msg.method === "ping") {
      send({ jsonrpc: "2.0", id: msg.id, result: {} });
    } else if (msg.id !== undefined) {
      send({ jsonrpc: "2.0", id: msg.id, error: { code: -32601, message: "Method not found" } });
    }
    // notifications (no id, e.g. notifications/initialized) are ignored
  }
});
  1. GitHub Copilot icon → Edit Preferences → Model Context Protocol (MCP) → set:
{
  "servers": {
    "nullable-repro": {
      "type": "stdio",
      "command": "node",
      "args": ["/absolute/path/to/repro-mcp.js"]
    }
  }
}
  1. Apply and Close, restart Eclipse. Open Agent Mode → Configure Tools: the nullable-repro server appears but its tool does not (dead checkbox, can't expand). The Error Log shows [CopilotMCP] Refreshed 1 tools for server nullable-reprono error.
  2. Edit repro-mcp.js: switch optional_arg to { type: "string", … } (the ✅ line). Restart Eclipse.
  3. The tool now registers and is callable. ✅

Expected behavior

Copilot for Eclipse should accept tool input schemas that use nullable type unions ("type": ["string","null"]) — they are valid JSON Schema and the OpenAI-recommended nullable form, and are accepted by other MCP clients. At minimum, if a schema genuinely cannot be converted, Copilot should (a) surface a clear error naming the offending tool/property, and (b) still register the other valid tools — rather than silently dropping the entire server while logging Refreshed N tools.

Screenshots

Configure Tools panel: the MCP server present but its tools missing (dead checkbox).

Image

Error Log: [CopilotMCP] Refreshed N tools for server … with the empty picker.

Image

Additional context

  • Confirmed with the minimal repro-mcp.js above (standalone, no other software): the nullable-repro server registers 0 tools with the union present, and registers/works once it's removed.
  • Originally found while debugging a real MCP server (an SAP/ABAP tool server). All tools loaded in read-only mode but vanished once a write tool with optional, nullable fields was added; bisected to the "type": ["string","null"] unions emitted for optional properties (added for OpenAI strict-mode compatibility).
  • A/B confirmed: identical server, nullable unions on → tools don't register; off → tools register and work; toggling reproduces both ways every time.
  • Not a size/depth/tool-count issue — verified: a tiny schema with the nullable union still fails, and a large schema (~86 KB, 12 tools) without it works.
  • Affected build: GitHub Copilot Language Server 1.502.5. Likely in the MCP-tool → model-function-calling schema conversion.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the minimal repro-mcp.js server with the nullable type union, then repeat with the union removed and compare tool registration in Eclipse. Trace the MCP-tool to model-function-calling schema conversion path; done means nullable schemas register correctly, while an unconvertible schema reports the offending tool or property without suppressing other valid tools.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, javascript
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.