Expose MCP read-only hints in tool call items (#36055)

## What changed

- Propagate MCP tool `readOnlyHint` annotations through tool-call start and
  completion events.
- Include the optional hint in persisted thread history and app-server
  `mcpToolCall` items, preserving compatibility when the annotation is absent.
- Document that the hint describes tool capability, not the outcome of a
  particular invocation.

## Testing

- Cover read-only and write-capable tools in live events and persisted rollout
  data.
- Verify the hint survives thread reads and resumes for both in-progress and
  completed MCP calls.

GitOrigin-RevId: dddfe905146075e5137a1094da485b86b99807f0
This commit is contained in:
bear-oai authored and copyberry committed 2026-07-30 01:37:41 +00:00
1 parent 1c5f336c40
commit 406dc92394
38 files changed
+406 -2

No files matched your search

@@ -787,6 +787,7 @@ impl ThreadHistoryBuilder {
}),
mcp_app_resource_uri: payload.mcp_app_resource_uri.clone(),
plugin_id: payload.plugin_id.clone(),
read_only_hint: payload.read_only_hint,
result: None,
error: None,
duration_ms: None,
@@ -839,6 +840,7 @@ impl ThreadHistoryBuilder {
}),
mcp_app_resource_uri: payload.mcp_app_resource_uri.clone(),
plugin_id: payload.plugin_id.clone(),
read_only_hint: payload.read_only_hint,
result,
error,
duration_ms,
@@ -2782,6 +2784,7 @@ mod tests {
app_name: None,
action_name: None,
plugin_id: None,
read_only_hint: None,
duration: Duration::from_millis(8),
result: Err("boom".into()),
}),
@@ -2840,6 +2843,7 @@ mod tests {
app_context: None,
mcp_app_resource_uri: None,
plugin_id: None,
read_only_hint: None,
result: None,
error: Some(McpToolCallError {
message: "boom".into(),
@@ -2872,6 +2876,7 @@ mod tests {
app_name: Some("Calendar".into()),
action_name: Some("lookup".into()),
plugin_id: Some("sample@test".into()),
read_only_hint: Some(false),
duration: Duration::from_millis(8),
result: Ok(CallToolResult {
content: vec![serde_json::json!({
@@ -2910,6 +2915,7 @@ mod tests {
}),
mcp_app_resource_uri: Some("ui://widget/lookup.html".into()),
plugin_id: Some("sample@test".into()),
read_only_hint: Some(false),
result: Some(Box::new(McpToolCallResult {
content: vec![serde_json::json!({
"type": "text",