Summary
Using the Rust SDK against an external headless Copilot CLI, MCP tools can connect and be invoked, but the runtime fails during the permission flow with:
Unhandled permission result kind: [object Object]
I can reproduce this with a read-only MCP server tool (readOnlyHint: true) over an external/TCP session.
Environment
- SDK:
github-copilot-sdk = "0.1" (Rust)
- Client OS: Windows
- Transport: external TCP connection to a Linux headless Copilot CLI server
- Model:
gpt-5.4
- MCP server type: local/stdio on the Linux host
Repro shape
Rust session config includes:
with_transport(Transport::External { host, port })
with_mcp_servers(...)
with_env_value_mode("direct")
with_streaming(true)
with_request_permission(false)
The MCP server exposes two tools:
search_markdown
read_markdown_file
Both are advertised with MCP annotations like:
"annotations": {
"title": "Search Markdown",
"readOnlyHint": true
}
The server is healthy:
initialize works
tools/list works
- the SDK reports the server as connected
Observed behavior
The MCP server connects successfully:
[session.mcp_server_status_changed] {"serverName":"search-md","status":"connected"}
[session.mcp_servers_loaded] {"servers":[{"name":"search-md","status":"connected"}]}
The model then invokes the MCP tool:
[tool.execution_start] {"arguments":{"max_matches":10,"query":"IPF"},"mcpServerName":"search-md","mcpToolName":"search_markdown","toolName":"search-md-search_markdown"}
The runtime still requests permission even though the MCP tool is marked read-only:
[permission.requested] {"permissionRequest":{"args":{"max_matches":10,"query":"IPF"},"kind":"mcp","readOnly":true,"serverName":"search-md","toolName":"search-md-search_markdown","toolTitle":"Search Markdown"},"requestId":"50439ba3-35a3-4cb5-8f96-bdba2e229a79"}
Then it reports a reject result and immediately fails with the permission-kind error:
[permission.completed] {"requestId":"50439ba3-35a3-4cb5-8f96-bdba2e229a79","result":{"kind":"reject"}}
[tool.execution_complete] {"error":{"code":"failure","message":"Unhandled permission result kind: [object Object]"},"success":false,"toolName":"search-md-search_markdown"}
The same happens for read_markdown_file:
[permission.requested] {"permissionRequest":{"args":{"end_line":120,"max_lines":120,"path":"685592_IPF_Client_UG_Rev9p0.md","start_line":1},"kind":"mcp","readOnly":true,"serverName":"search-md","toolName":"search-md-read_markdown_file"}}
[permission.completed] {"result":{"kind":"reject"}}
[tool.execution_complete] {"error":{"code":"failure","message":"Unhandled permission result kind: [object Object]"}}
Expected behavior
One of these should happen:
- read-only MCP tools should not go through a broken permission round-trip here, or
- if permission is still required, the runtime should handle the permission result without crashing the tool call.
Notes
If helpful, I can provide a minimal Rust repro plus the tiny Python MCP server used for search_markdown / read_markdown_file.
Summary
Using the Rust SDK against an external headless Copilot CLI, MCP tools can connect and be invoked, but the runtime fails during the permission flow with:
I can reproduce this with a read-only MCP server tool (
readOnlyHint: true) over an external/TCP session.Environment
github-copilot-sdk = "0.1"(Rust)gpt-5.4Repro shape
Rust session config includes:
with_transport(Transport::External { host, port })with_mcp_servers(...)with_env_value_mode("direct")with_streaming(true)with_request_permission(false)The MCP server exposes two tools:
search_markdownread_markdown_fileBoth are advertised with MCP annotations like:
The server is healthy:
initializeworkstools/listworksObserved behavior
The MCP server connects successfully:
The model then invokes the MCP tool:
The runtime still requests permission even though the MCP tool is marked read-only:
Then it reports a reject result and immediately fails with the permission-kind error:
The same happens for
read_markdown_file:Expected behavior
One of these should happen:
Notes
PermissionDecisionpolymorphic base instantiation inExecutePermissionAndRespondAsyncproduces empty JSON, breaks built-in tool permission flow #1194 /PermissionDecisionpolymorphic base instantiation still produces empty JSON forApprovedandUserNotAvailablepaths — follow-up to #1194 #1403, although this repro is from the Rust SDK with MCP tools over an external headless CLI.If helpful, I can provide a minimal Rust repro plus the tiny Python MCP server used for
search_markdown/read_markdown_file.