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:
- 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.
- 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
- 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
}
});
- GitHub Copilot icon → Edit Preferences → Model Context Protocol (MCP) → set:
{
"servers": {
"nullable-repro": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/repro-mcp.js"]
}
}
}
- 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-repro — no error.
- Edit
repro-mcp.js: switch optional_arg to { type: "string", … } (the ✅ line). Restart Eclipse.
- 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).
Error Log: [CopilotMCP] Refreshed N tools for server … with the empty picker.
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.
Environment
0.19.0.202606240339(GitHub Copilot Language Server1.502.5)Describe the bug
Copilot for Eclipse silently fails to register all tools from an MCP server if any tool's
inputSchemadeclares 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:
["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.Refreshed N toolsis logged as if it succeeded. This makes it nearly impossible to diagnose (it took ~12 iterations to bisect).To Reproduce
repro-mcp.js(Node ≥ 18, no dependencies):{ "servers": { "nullable-repro": { "type": "stdio", "command": "node", "args": ["/absolute/path/to/repro-mcp.js"] } } }nullable-reproserver appears but its tool does not (dead checkbox, can't expand). The Error Log shows[CopilotMCP] Refreshed 1 tools for server nullable-repro— no error.repro-mcp.js: switchoptional_argto{ type: "string", … }(the ✅ line). Restart Eclipse.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 loggingRefreshed N tools.Screenshots
Configure Tools panel: the MCP server present but its tools missing (dead checkbox).
Error Log:
[CopilotMCP] Refreshed N tools for server …with the empty picker.Additional context
repro-mcp.jsabove (standalone, no other software): thenullable-reproserver registers 0 tools with the union present, and registers/works once it's removed."type": ["string","null"]unions emitted for optional properties (added for OpenAI strict-mode compatibility).1.502.5. Likely in the MCP-tool → model-function-calling schema conversion.