Summary
The Java SDK drops MCP permission request fields during deserialization, so applications cannot safely approve a scoped MCP request.
Root cause
java/src/main/java/com/github/copilot/rpc/PermissionRequest.java declares:
@JsonIgnoreProperties(ignoreUnknown = true)
public class PermissionRequest {
@JsonProperty("kind")
private String kind;
// ...
private Map<String, Object> extensionData;
}
There is no @JsonAnySetter (or equivalent custom deserialization) to populate extensionData. Consequently, MCP fields outside the typed properties are discarded.
Reproduction
With copilot-sdk-java 1.0.8 and 1.0.9-preview.3, an MCP permission callback receives kind=mcp, but getExtensionData() is null:
sessionConfig.setOnPermissionRequest(request -> {
System.out.println(request.getKind()); // mcp
System.out.println(request.getExtensionData()); // null
return PermissionResult.deny();
});
The incoming MCP request includes the details needed for a scoped decision:
{
"permissionRequest": {
"kind": "mcp",
"serverName": "playwright",
"toolName": "playwright-browser_navigate",
"args": { "url": "http://127.0.0.1:8106/docs/target-app/" }
}
}
A handler that must enforce an exact server, tool, and URL therefore rejects every request. Approving all MCP requests is not an equivalent security boundary.
Expected behavior
Preserve unknown MCP fields in PermissionRequest.extensionData, including nested args, so permission handlers can enforce exact server/tool/argument allowlists.
Suggested test
Add a Java deserialization test that passes an MCP permission payload through PermissionRequest.fromJsonValue() and verifies extensionData retains serverName, toolName, and args.url.
Affected versions
copilot-sdk-java 1.0.8
copilot-sdk-java 1.0.9-preview.3
Originally filed in github/copilot-sdk-java, but this monorepo owns the affected Java source.
Summary
The Java SDK drops MCP permission request fields during deserialization, so applications cannot safely approve a scoped MCP request.
Root cause
java/src/main/java/com/github/copilot/rpc/PermissionRequest.javadeclares:There is no
@JsonAnySetter(or equivalent custom deserialization) to populateextensionData. Consequently, MCP fields outside the typed properties are discarded.Reproduction
With
copilot-sdk-java1.0.8 and 1.0.9-preview.3, an MCP permission callback receiveskind=mcp, butgetExtensionData()is null:The incoming MCP request includes the details needed for a scoped decision:
{ "permissionRequest": { "kind": "mcp", "serverName": "playwright", "toolName": "playwright-browser_navigate", "args": { "url": "http://127.0.0.1:8106/docs/target-app/" } } }A handler that must enforce an exact server, tool, and URL therefore rejects every request. Approving all MCP requests is not an equivalent security boundary.
Expected behavior
Preserve unknown MCP fields in
PermissionRequest.extensionData, including nestedargs, so permission handlers can enforce exact server/tool/argument allowlists.Suggested test
Add a Java deserialization test that passes an MCP permission payload through
PermissionRequest.fromJsonValue()and verifiesextensionDataretainsserverName,toolName, andargs.url.Affected versions
copilot-sdk-java1.0.8copilot-sdk-java1.0.9-preview.3Originally filed in
github/copilot-sdk-java, but this monorepo owns the affected Java source.