mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Emit Trusted MCP App Identity on Tool-Call Items (#27132)
## Summary
- Add optional `appContext` to app-server MCP tool-call items with
trusted `connectorId`, `linkId`, and `mcpAppResourceUri` metadata.
- Preserve that context across tool-call events, persisted history,
reconnects, and thread resume.
- Keep the deprecated top-level `mcpAppResourceUri` temporarily for
client migration.
The consumer contract is `{ appContext: { connectorId, linkId,
mcpAppResourceUri }, tool }`.
## Validation
- Full GitHub Actions suite passes, including CLA, Bazel tests, clippy,
release builds, and argument-comment lint.
---------
Co-authored-by: martinauyeung-oai <280153141+martinauyeung-oai@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
9bcc09f9f7
commit
765309d5a6
@@ -4121,6 +4121,7 @@ async fn turn_event_counts_completed_tool_items() {
|
||||
tool: "search".to_string(),
|
||||
status,
|
||||
arguments: json!({}),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
result: None,
|
||||
|
||||
@@ -2396,6 +2396,29 @@
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -4066,6 +4089,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -4089,6 +4122,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
+34
@@ -12119,6 +12119,29 @@
|
||||
"title": "McpServerToolCallResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -17511,6 +17534,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/v2/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -17534,6 +17567,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
+34
@@ -8543,6 +8543,29 @@
|
||||
"title": "McpServerToolCallResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -15290,6 +15313,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -15313,6 +15346,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -297,6 +297,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -784,6 +807,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -807,6 +840,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -297,6 +297,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -784,6 +807,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -807,6 +840,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -434,6 +434,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -928,6 +951,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -951,6 +984,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -539,6 +539,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1420,6 +1443,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1443,6 +1476,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -460,6 +460,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1235,6 +1258,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1258,6 +1291,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
+34
@@ -460,6 +460,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1235,6 +1258,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1258,6 +1291,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -460,6 +460,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1235,6 +1258,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1258,6 +1291,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -539,6 +539,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1420,6 +1443,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1443,6 +1476,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -460,6 +460,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1235,6 +1258,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1258,6 +1291,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -539,6 +539,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1420,6 +1443,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1443,6 +1476,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -460,6 +460,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1235,6 +1258,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1258,6 +1291,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -460,6 +460,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -1235,6 +1258,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -1258,6 +1291,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -434,6 +434,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -928,6 +951,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -951,6 +984,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -434,6 +434,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -928,6 +951,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -951,6 +984,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -434,6 +434,29 @@
|
||||
"LegacyAppPathString": {
|
||||
"type": "string"
|
||||
},
|
||||
"McpToolCallAppContext": {
|
||||
"properties": {
|
||||
"connectorId": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkId": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"resourceUri": {
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"connectorId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"McpToolCallError": {
|
||||
"properties": {
|
||||
"message": {
|
||||
@@ -928,6 +951,16 @@
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"appContext": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/McpToolCallAppContext"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arguments": true,
|
||||
"durationMs": {
|
||||
"description": "The duration of the MCP tool call in milliseconds.",
|
||||
@@ -951,6 +984,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mcpAppResourceUri": {
|
||||
"description": "Deprecated: use `appContext.resourceUri` instead.",
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type McpToolCallAppContext = { connectorId: string, linkId: string | null, resourceUri: string | null, };
|
||||
@@ -16,6 +16,7 @@ import type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputCo
|
||||
import type { DynamicToolCallStatus } from "./DynamicToolCallStatus";
|
||||
import type { FileUpdateChange } from "./FileUpdateChange";
|
||||
import type { HookPromptFragment } from "./HookPromptFragment";
|
||||
import type { McpToolCallAppContext } from "./McpToolCallAppContext";
|
||||
import type { McpToolCallError } from "./McpToolCallError";
|
||||
import type { McpToolCallResult } from "./McpToolCallResult";
|
||||
import type { McpToolCallStatus } from "./McpToolCallStatus";
|
||||
@@ -55,7 +56,11 @@ exitCode: number | null,
|
||||
/**
|
||||
* The duration of the command execution in milliseconds.
|
||||
*/
|
||||
durationMs: number | null, } | { "type": "fileChange", id: string, changes: Array<FileUpdateChange>, status: PatchApplyStatus, } | { "type": "mcpToolCall", id: string, server: string, tool: string, status: McpToolCallStatus, arguments: JsonValue, mcpAppResourceUri?: string, pluginId: string | null, result: McpToolCallResult | null, error: McpToolCallError | null,
|
||||
durationMs: number | null, } | { "type": "fileChange", id: string, changes: Array<FileUpdateChange>, status: PatchApplyStatus, } | { "type": "mcpToolCall", id: string, server: string, tool: string, status: McpToolCallStatus, arguments: JsonValue, appContext: McpToolCallAppContext | null,
|
||||
/**
|
||||
* Deprecated: use `appContext.resourceUri` instead.
|
||||
*/
|
||||
mcpAppResourceUri?: string, pluginId: string | null, result: McpToolCallResult | null, error: McpToolCallError | null,
|
||||
/**
|
||||
* The duration of the MCP tool call in milliseconds.
|
||||
*/
|
||||
|
||||
@@ -243,6 +243,7 @@ export type { McpServerStatusDetail } from "./McpServerStatusDetail";
|
||||
export type { McpServerStatusUpdatedNotification } from "./McpServerStatusUpdatedNotification";
|
||||
export type { McpServerToolCallParams } from "./McpServerToolCallParams";
|
||||
export type { McpServerToolCallResponse } from "./McpServerToolCallResponse";
|
||||
export type { McpToolCallAppContext } from "./McpToolCallAppContext";
|
||||
export type { McpToolCallError } from "./McpToolCallError";
|
||||
export type { McpToolCallProgressNotification } from "./McpToolCallProgressNotification";
|
||||
export type { McpToolCallResult } from "./McpToolCallResult";
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::protocol::v2::CollabAgentToolCallStatus;
|
||||
use crate::protocol::v2::CommandExecutionStatus;
|
||||
use crate::protocol::v2::DynamicToolCallOutputContentItem;
|
||||
use crate::protocol::v2::DynamicToolCallStatus;
|
||||
use crate::protocol::v2::McpToolCallAppContext;
|
||||
use crate::protocol::v2::McpToolCallError;
|
||||
use crate::protocol::v2::McpToolCallResult;
|
||||
use crate::protocol::v2::McpToolCallStatus;
|
||||
@@ -765,6 +766,14 @@ impl ThreadHistoryBuilder {
|
||||
.arguments
|
||||
.clone()
|
||||
.unwrap_or(serde_json::Value::Null),
|
||||
app_context: payload
|
||||
.connector_id
|
||||
.clone()
|
||||
.map(|connector_id| McpToolCallAppContext {
|
||||
connector_id,
|
||||
link_id: payload.link_id.clone(),
|
||||
resource_uri: payload.mcp_app_resource_uri.clone(),
|
||||
}),
|
||||
mcp_app_resource_uri: payload.mcp_app_resource_uri.clone(),
|
||||
plugin_id: payload.plugin_id.clone(),
|
||||
result: None,
|
||||
@@ -807,6 +816,14 @@ impl ThreadHistoryBuilder {
|
||||
.arguments
|
||||
.clone()
|
||||
.unwrap_or(serde_json::Value::Null),
|
||||
app_context: payload
|
||||
.connector_id
|
||||
.clone()
|
||||
.map(|connector_id| McpToolCallAppContext {
|
||||
connector_id,
|
||||
link_id: payload.link_id.clone(),
|
||||
resource_uri: payload.mcp_app_resource_uri.clone(),
|
||||
}),
|
||||
mcp_app_resource_uri: payload.mcp_app_resource_uri.clone(),
|
||||
plugin_id: payload.plugin_id.clone(),
|
||||
result,
|
||||
@@ -1567,7 +1584,6 @@ mod tests {
|
||||
use codex_protocol::protocol::DynamicToolCallResponseEvent;
|
||||
use codex_protocol::protocol::ExecCommandEndEvent;
|
||||
use codex_protocol::protocol::ExecCommandSource;
|
||||
use codex_protocol::protocol::ItemCompletedEvent;
|
||||
use codex_protocol::protocol::ItemStartedEvent;
|
||||
use codex_protocol::protocol::McpInvocation;
|
||||
use codex_protocol::protocol::McpToolCallEndEvent;
|
||||
@@ -2397,7 +2413,9 @@ mod tests {
|
||||
tool: "lookup".into(),
|
||||
arguments: Some(serde_json::json!({"id":"123"})),
|
||||
},
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
duration: Duration::from_millis(8),
|
||||
result: Err("boom".into()),
|
||||
@@ -2447,6 +2465,7 @@ mod tests {
|
||||
tool: "lookup".into(),
|
||||
status: McpToolCallStatus::Failed,
|
||||
arguments: serde_json::json!({"id":"123"}),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
@@ -2475,7 +2494,9 @@ mod tests {
|
||||
tool: "lookup".into(),
|
||||
arguments: Some(serde_json::json!({"id":"123"})),
|
||||
},
|
||||
connector_id: Some("calendar".into()),
|
||||
mcp_app_resource_uri: Some("ui://widget/lookup.html".into()),
|
||||
link_id: Some("link_calendar".into()),
|
||||
plugin_id: Some("sample@test".into()),
|
||||
duration: Duration::from_millis(8),
|
||||
result: Ok(CallToolResult {
|
||||
@@ -2506,6 +2527,11 @@ mod tests {
|
||||
tool: "lookup".into(),
|
||||
status: McpToolCallStatus::Completed,
|
||||
arguments: serde_json::json!({"id":"123"}),
|
||||
app_context: Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".into(),
|
||||
link_id: Some("link_calendar".into()),
|
||||
resource_uri: Some("ui://widget/lookup.html".into()),
|
||||
}),
|
||||
mcp_app_resource_uri: Some("ui://widget/lookup.html".into()),
|
||||
plugin_id: Some("sample@test".into()),
|
||||
result: Some(Box::new(McpToolCallResult {
|
||||
|
||||
@@ -290,8 +290,10 @@ pub enum ThreadItem {
|
||||
tool: String,
|
||||
status: McpToolCallStatus,
|
||||
arguments: JsonValue,
|
||||
app_context: Option<McpToolCallAppContext>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
/// Deprecated: use `appContext.resourceUri` instead.
|
||||
mcp_app_resource_uri: Option<String>,
|
||||
plugin_id: Option<String>,
|
||||
result: Option<Box<McpToolCallResult>>,
|
||||
@@ -384,6 +386,15 @@ pub enum ThreadItem {
|
||||
ContextCompaction { id: String },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
||||
pub struct McpToolCallAppContext {
|
||||
pub connector_id: String,
|
||||
pub link_id: Option<String>,
|
||||
pub resource_uri: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(rename_all = "camelCase", export_to = "v2/")]
|
||||
@@ -877,6 +888,11 @@ impl From<CoreTurnItem> for ThreadItem {
|
||||
tool: mcp.tool,
|
||||
status: McpToolCallStatus::from(mcp.status),
|
||||
arguments: mcp.arguments,
|
||||
app_context: mcp.connector_id.map(|connector_id| McpToolCallAppContext {
|
||||
connector_id,
|
||||
link_id: mcp.link_id,
|
||||
resource_uri: mcp.mcp_app_resource_uri.clone(),
|
||||
}),
|
||||
mcp_app_resource_uri: mcp.mcp_app_resource_uri,
|
||||
plugin_id: mcp.plugin_id,
|
||||
result: mcp.result.map(McpToolCallResult::from).map(Box::new),
|
||||
|
||||
@@ -2615,7 +2615,9 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
server: "server".to_string(),
|
||||
tool: "tool".to_string(),
|
||||
arguments: json!({"arg": "value"}),
|
||||
connector_id: Some("calendar".to_string()),
|
||||
mcp_app_resource_uri: Some("app://connector".to_string()),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
status: CoreMcpToolCallStatus::InProgress,
|
||||
result: None,
|
||||
@@ -2631,6 +2633,11 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
tool: "tool".to_string(),
|
||||
status: McpToolCallStatus::InProgress,
|
||||
arguments: json!({"arg": "value"}),
|
||||
app_context: Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".to_string(),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
resource_uri: Some("app://connector".to_string()),
|
||||
}),
|
||||
mcp_app_resource_uri: Some("app://connector".to_string()),
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
result: None,
|
||||
@@ -2644,7 +2651,9 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
server: "server".to_string(),
|
||||
tool: "tool".to_string(),
|
||||
arguments: JsonValue::Null,
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
status: CoreMcpToolCallStatus::Completed,
|
||||
result: Some(CallToolResult {
|
||||
@@ -2665,6 +2674,7 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
tool: "tool".to_string(),
|
||||
status: McpToolCallStatus::Completed,
|
||||
arguments: JsonValue::Null,
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: Some(Box::new(McpToolCallResult {
|
||||
@@ -2678,6 +2688,49 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mcp_tool_call_app_context_serializes_connector_id() {
|
||||
let item = ThreadItem::McpToolCall {
|
||||
id: "mcp-1".to_string(),
|
||||
server: "codex_apps".to_string(),
|
||||
tool: "calendar.create_event".to_string(),
|
||||
status: McpToolCallStatus::InProgress,
|
||||
arguments: json!({}),
|
||||
app_context: Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".to_string(),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
resource_uri: Some("app://connector".to_string()),
|
||||
}),
|
||||
mcp_app_resource_uri: Some("app://connector".to_string()),
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
error: None,
|
||||
duration_ms: None,
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
serde_json::to_value(item).expect("MCP tool call should serialize"),
|
||||
json!({
|
||||
"type": "mcpToolCall",
|
||||
"id": "mcp-1",
|
||||
"server": "codex_apps",
|
||||
"tool": "calendar.create_event",
|
||||
"status": "inProgress",
|
||||
"arguments": {},
|
||||
"appContext": {
|
||||
"connectorId": "calendar",
|
||||
"linkId": "link_calendar",
|
||||
"resourceUri": "app://connector",
|
||||
},
|
||||
"mcpAppResourceUri": "app://connector",
|
||||
"pluginId": null,
|
||||
"result": null,
|
||||
"error": null,
|
||||
"durationMs": null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_input_into_core_preserves_image_detail() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -1365,7 +1365,7 @@ Today both notifications carry an empty `items` array even when item events were
|
||||
- `reasoning` — `{id, summary, content}` where `summary` holds streamed reasoning summaries (applicable for most OpenAI models) and `content` holds raw reasoning blocks (applicable for e.g. open source models).
|
||||
- `commandExecution` — `{id, command, cwd, status, commandActions, aggregatedOutput?, exitCode?, durationMs?}` for sandboxed commands; `status` is `inProgress`, `completed`, `failed`, or `declined`.
|
||||
- `fileChange` — `{id, changes, status}` describing proposed edits; `changes` list `{path, kind, diff}` and `status` is `inProgress`, `completed`, `failed`, or `declined`.
|
||||
- `mcpToolCall` — `{id, server, tool, status, arguments, mcpAppResourceUri?, pluginId, result?, error?}` describing MCP calls; `status` is `inProgress`, `completed`, or `failed`.
|
||||
- `mcpToolCall` — `{id, server, tool, status, arguments, appContext, mcpAppResourceUri?, pluginId, result?, error?}` describing MCP calls; `appContext` is `{connectorId, linkId, resourceUri}` for calls through a trusted MCP app, where `connectorId` identifies the connector that owns the tool, `linkId` identifies the app link, and `resourceUri` points to the widget template. The top-level `mcpAppResourceUri` is deprecated and temporarily duplicated for client migration. `tool` identifies the invoked action. `status` is `inProgress`, `completed`, or `failed`.
|
||||
- `collabToolCall` — `{id, tool, status, senderThreadId, receiverThreadId?, newThreadId?, prompt?, agentStatus?}` describing collab tool calls (`spawn_agent`, `send_input`, `resume_agent`, `wait`, `close_agent`); `status` is `inProgress`, `completed`, or `failed`.
|
||||
- `webSearch` — `{id, query, action?}` for a web search request issued by the agent; `action` mirrors the Responses API web_search action payload (`search`, `open_page`, `find_in_page`) and may be omitted until completion.
|
||||
- `imageView` — `{id, path}` emitted when the agent invokes the image viewer tool.
|
||||
|
||||
@@ -52,6 +52,7 @@ fn redacted_mcp_tool_call_result() -> McpToolCallResult {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use codex_app_server_protocol::McpToolCallAppContext;
|
||||
use codex_app_server_protocol::McpToolCallError;
|
||||
use codex_app_server_protocol::McpToolCallStatus;
|
||||
use codex_app_server_protocol::SessionSource;
|
||||
@@ -78,6 +79,11 @@ mod tests {
|
||||
tool: "lookup".to_string(),
|
||||
status: McpToolCallStatus::Completed,
|
||||
arguments: serde_json::json!({"secret":"argument"}),
|
||||
app_context: Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".to_string(),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
}),
|
||||
mcp_app_resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
result: Some(Box::new(McpToolCallResult {
|
||||
@@ -120,6 +126,11 @@ mod tests {
|
||||
tool: "lookup".to_string(),
|
||||
status: McpToolCallStatus::Completed,
|
||||
arguments: JsonValue::String(REDACTED_PAYLOAD.to_string()),
|
||||
app_context: Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".to_string(),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
}),
|
||||
mcp_app_resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
result: Some(Box::new(redacted_mcp_tool_call_result())),
|
||||
@@ -137,6 +148,7 @@ mod tests {
|
||||
tool: "lookup".to_string(),
|
||||
status: McpToolCallStatus::Failed,
|
||||
arguments: serde_json::json!({"secret":"argument"}),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
@@ -156,6 +168,7 @@ mod tests {
|
||||
tool: "lookup".to_string(),
|
||||
status: McpToolCallStatus::Failed,
|
||||
arguments: JsonValue::String(REDACTED_PAYLOAD.to_string()),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
|
||||
@@ -513,6 +513,7 @@ url = "{mcp_server_url}/mcp"
|
||||
tool,
|
||||
status,
|
||||
arguments: json!({ "message": LARGE_RESPONSE_MESSAGE }),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: Some(result),
|
||||
|
||||
@@ -23,6 +23,7 @@ use codex_app_server_protocol::FileChangeRequestApprovalResponse;
|
||||
use codex_app_server_protocol::ItemStartedNotification;
|
||||
use codex_app_server_protocol::JSONRPCError;
|
||||
use codex_app_server_protocol::JSONRPCResponse;
|
||||
use codex_app_server_protocol::McpToolCallAppContext;
|
||||
use codex_app_server_protocol::PatchApplyStatus;
|
||||
use codex_app_server_protocol::PatchChangeKind;
|
||||
use codex_app_server_protocol::RequestId;
|
||||
@@ -729,6 +730,7 @@ async fn thread_resume_redacts_payloads_for_chatgpt_remote_clients() -> Result<(
|
||||
.expect("remote resume should include redacted MCP item");
|
||||
let ThreadItem::McpToolCall {
|
||||
arguments,
|
||||
app_context,
|
||||
result,
|
||||
error,
|
||||
..
|
||||
@@ -737,6 +739,14 @@ async fn thread_resume_redacts_payloads_for_chatgpt_remote_clients() -> Result<(
|
||||
unreachable!("matched MCP item");
|
||||
};
|
||||
assert_eq!(arguments, &json!("[redacted]"));
|
||||
assert_eq!(
|
||||
app_context,
|
||||
&Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".to_string(),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
})
|
||||
);
|
||||
let result = result.as_ref().expect("redacted MCP result");
|
||||
assert_eq!(
|
||||
result.content,
|
||||
@@ -770,12 +780,23 @@ async fn thread_resume_redacts_payloads_for_chatgpt_remote_clients() -> Result<(
|
||||
.find(|item| matches!(item, ThreadItem::McpToolCall { .. }))
|
||||
.expect("normal resume should include MCP item");
|
||||
let ThreadItem::McpToolCall {
|
||||
arguments, result, ..
|
||||
arguments,
|
||||
app_context,
|
||||
result,
|
||||
..
|
||||
} = normal_mcp_item
|
||||
else {
|
||||
unreachable!("matched MCP item");
|
||||
};
|
||||
assert_eq!(arguments, &json!({"secret":"argument"}));
|
||||
assert_eq!(
|
||||
app_context,
|
||||
&Some(McpToolCallAppContext {
|
||||
connector_id: "calendar".to_string(),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
})
|
||||
);
|
||||
let result = result.as_ref().expect("normal MCP result");
|
||||
assert_eq!(
|
||||
result.content,
|
||||
@@ -877,7 +898,9 @@ fn append_resume_redaction_history(
|
||||
tool: "lookup".to_string(),
|
||||
arguments: Some(json!({"secret":"argument"})),
|
||||
},
|
||||
connector_id: Some("calendar".to_string()),
|
||||
mcp_app_resource_uri: Some("ui://widget/lookup.html".to_string()),
|
||||
link_id: Some("link_calendar".to_string()),
|
||||
plugin_id: None,
|
||||
duration: Duration::from_millis(8),
|
||||
result: Ok(CallToolResult {
|
||||
|
||||
@@ -143,14 +143,7 @@ pub(crate) async fn handle_mcp_tool_call(
|
||||
|
||||
let metadata =
|
||||
lookup_mcp_tool_metadata(sess.as_ref(), turn_context.as_ref(), &server, &tool_name).await;
|
||||
let item_metadata = McpToolCallItemMetadata {
|
||||
mcp_app_resource_uri: metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.mcp_app_resource_uri.clone()),
|
||||
plugin_id: metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.plugin_id.clone()),
|
||||
};
|
||||
let item_metadata = McpToolCallItemMetadata::from_tool_metadata(&server, metadata.as_ref());
|
||||
let app_tool_policy = if server == CODEX_APPS_MCP_SERVER_NAME {
|
||||
let annotations = metadata
|
||||
.as_ref()
|
||||
@@ -312,12 +305,32 @@ pub(crate) struct HandledMcpToolCall {
|
||||
pub(crate) tool_input: JsonValue,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct McpToolCallItemMetadata {
|
||||
connector_id: Option<String>,
|
||||
link_id: Option<String>,
|
||||
mcp_app_resource_uri: Option<String>,
|
||||
plugin_id: Option<String>,
|
||||
}
|
||||
|
||||
impl McpToolCallItemMetadata {
|
||||
fn from_tool_metadata(server: &str, metadata: Option<&McpToolApprovalMetadata>) -> Self {
|
||||
let trusted_mcp_app_metadata = if server == CODEX_APPS_MCP_SERVER_NAME {
|
||||
metadata
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self {
|
||||
connector_id: trusted_mcp_app_metadata
|
||||
.and_then(|metadata| metadata.connector_id.clone()),
|
||||
link_id: trusted_mcp_app_metadata.and_then(|metadata| metadata.link_id.clone()),
|
||||
mcp_app_resource_uri: metadata
|
||||
.and_then(|metadata| metadata.mcp_app_resource_uri.clone()),
|
||||
plugin_id: metadata.and_then(|metadata| metadata.plugin_id.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_approved_mcp_tool_call(
|
||||
sess: &Session,
|
||||
turn_context: &TurnContext,
|
||||
@@ -892,7 +905,9 @@ async fn notify_mcp_tool_call_started(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(JsonValue::Null),
|
||||
connector_id: item_metadata.connector_id,
|
||||
mcp_app_resource_uri: item_metadata.mcp_app_resource_uri,
|
||||
link_id: item_metadata.link_id,
|
||||
plugin_id: item_metadata.plugin_id,
|
||||
status: McpToolCallStatus::InProgress,
|
||||
result: None,
|
||||
@@ -932,7 +947,9 @@ async fn notify_mcp_tool_call_completed(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(JsonValue::Null),
|
||||
connector_id: item_metadata.connector_id,
|
||||
mcp_app_resource_uri: item_metadata.mcp_app_resource_uri,
|
||||
link_id: item_metadata.link_id,
|
||||
plugin_id: item_metadata.plugin_id,
|
||||
status,
|
||||
result,
|
||||
@@ -998,6 +1015,7 @@ enum McpToolApprovalDecision {
|
||||
pub(crate) struct McpToolApprovalMetadata {
|
||||
annotations: Option<ToolAnnotations>,
|
||||
connector_id: Option<String>,
|
||||
link_id: Option<String>,
|
||||
connector_name: Option<String>,
|
||||
connector_description: Option<String>,
|
||||
plugin_id: Option<String>,
|
||||
@@ -1010,6 +1028,7 @@ pub(crate) struct McpToolApprovalMetadata {
|
||||
|
||||
const MCP_TOOL_OPENAI_OUTPUT_TEMPLATE_META_KEY: &str = "openai/outputTemplate";
|
||||
const MCP_TOOL_UI_RESOURCE_URI_META_KEY: &str = "ui/resourceUri";
|
||||
const MCP_TOOL_LINK_ID_META_KEY: &str = "link_id";
|
||||
const MCP_TOOL_PLUGIN_ID_META_KEY: &str = "plugin_id";
|
||||
const MCP_TOOL_THREAD_ID_META_KEY: &str = "threadId";
|
||||
|
||||
@@ -1493,6 +1512,13 @@ pub(crate) async fn lookup_mcp_tool_metadata(
|
||||
Some(McpToolApprovalMetadata {
|
||||
annotations: tool_info.tool.annotations,
|
||||
connector_id: tool_info.connector_id,
|
||||
link_id: tool_info
|
||||
.tool
|
||||
.meta
|
||||
.as_ref()
|
||||
.and_then(|meta| meta.get(MCP_TOOL_LINK_ID_META_KEY))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::to_string),
|
||||
connector_name: tool_info.connector_name,
|
||||
connector_description,
|
||||
plugin_id,
|
||||
|
||||
@@ -78,6 +78,7 @@ fn approval_metadata(
|
||||
McpToolApprovalMetadata {
|
||||
annotations: None,
|
||||
connector_id: connector_id.map(str::to_string),
|
||||
link_id: None,
|
||||
connector_name: connector_name.map(str::to_string),
|
||||
connector_description: connector_description.map(str::to_string),
|
||||
plugin_id: None,
|
||||
@@ -1149,8 +1150,39 @@ async fn plugin_mcp_tool_call_request_meta_includes_plugin_id() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mcp_tool_call_item_metadata_only_trusts_codex_apps_identity() {
|
||||
let mut metadata = approval_metadata(
|
||||
Some("asdk_app_0123456789abcdef0123456789abcdef"),
|
||||
/*connector_name*/ None,
|
||||
/*connector_description*/ None,
|
||||
/*tool_title*/ None,
|
||||
/*tool_description*/ None,
|
||||
);
|
||||
metadata.link_id = Some("link_fedcba9876543210fedcba9876543210".to_string());
|
||||
|
||||
assert_eq!(
|
||||
McpToolCallItemMetadata::from_tool_metadata(CODEX_APPS_MCP_SERVER_NAME, Some(&metadata),),
|
||||
McpToolCallItemMetadata {
|
||||
connector_id: Some("asdk_app_0123456789abcdef0123456789abcdef".to_string()),
|
||||
link_id: Some("link_fedcba9876543210fedcba9876543210".to_string()),
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
McpToolCallItemMetadata::from_tool_metadata("custom_server", Some(&metadata)),
|
||||
McpToolCallItemMetadata {
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mcp_tool_call_item_includes_plugin_id() {
|
||||
async fn mcp_tool_call_item_includes_app_identity() {
|
||||
let (session, turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
|
||||
notify_mcp_tool_call_started(
|
||||
@@ -1158,11 +1190,13 @@ async fn mcp_tool_call_item_includes_plugin_id() {
|
||||
&turn_context,
|
||||
"call-plugin",
|
||||
McpInvocation {
|
||||
server: "sample".to_string(),
|
||||
server: CODEX_APPS_MCP_SERVER_NAME.to_string(),
|
||||
tool: "echo".to_string(),
|
||||
arguments: None,
|
||||
},
|
||||
McpToolCallItemMetadata {
|
||||
connector_id: Some("asdk_app_0123456789abcdef0123456789abcdef".to_string()),
|
||||
link_id: Some("link_fedcba9876543210fedcba9876543210".to_string()),
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
},
|
||||
@@ -1180,6 +1214,14 @@ async fn mcp_tool_call_item_includes_plugin_id() {
|
||||
panic!("expected MCP tool call item");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
item.connector_id.as_deref(),
|
||||
Some("asdk_app_0123456789abcdef0123456789abcdef")
|
||||
);
|
||||
assert_eq!(
|
||||
item.link_id.as_deref(),
|
||||
Some("link_fedcba9876543210fedcba9876543210")
|
||||
);
|
||||
assert_eq!(item.plugin_id.as_deref(), Some("sample@test"));
|
||||
}
|
||||
|
||||
@@ -1193,6 +1235,7 @@ async fn codex_apps_tool_call_request_meta_includes_turn_metadata_and_codex_apps
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: None,
|
||||
connector_id: Some("calendar".to_string()),
|
||||
link_id: None,
|
||||
connector_name: Some("Calendar".to_string()),
|
||||
connector_description: Some("Manage events".to_string()),
|
||||
plugin_id: None,
|
||||
@@ -1661,6 +1704,7 @@ fn guardian_mcp_review_request_includes_annotations_when_present() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2326,6 +2370,7 @@ async fn approve_mode_skips_when_annotations_do_not_require_approval() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2400,6 +2445,7 @@ async fn guardian_mode_skips_auto_when_annotations_do_not_require_approval() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2457,6 +2503,7 @@ async fn permission_request_hook_allows_mcp_tool_call() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2593,6 +2640,7 @@ async fn permission_request_hook_runs_after_remembered_mcp_approval() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2680,6 +2728,7 @@ async fn guardian_mode_mcp_denial_returns_rationale_message() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2734,6 +2783,7 @@ async fn prompt_mode_waits_for_approval_when_annotations_do_not_require_approval
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2789,6 +2839,7 @@ async fn full_access_mode_skips_mcp_tool_approval_for_all_approval_modes() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: Some("calendar".to_string()),
|
||||
link_id: None,
|
||||
connector_name: Some("Calendar".to_string()),
|
||||
connector_description: Some("Manage events".to_string()),
|
||||
plugin_id: None,
|
||||
@@ -2842,6 +2893,7 @@ async fn approve_mode_skips_guardian_in_every_permission_mode() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: Some("calendar".to_string()),
|
||||
link_id: None,
|
||||
connector_name: Some("Calendar".to_string()),
|
||||
connector_description: Some("Manage events".to_string()),
|
||||
plugin_id: None,
|
||||
|
||||
@@ -203,7 +203,9 @@ async fn emit_tool_call_begin(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(Value::Null),
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
status: McpToolCallStatus::InProgress,
|
||||
result: None,
|
||||
@@ -242,7 +244,9 @@ async fn emit_tool_call_end(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(Value::Null),
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
status,
|
||||
result,
|
||||
|
||||
@@ -17,6 +17,7 @@ use wiremock::matchers::path;
|
||||
use wiremock::matchers::path_regex;
|
||||
|
||||
const CONNECTOR_ID: &str = "calendar";
|
||||
pub const LINK_ID: &str = "link_calendar";
|
||||
const CONNECTOR_NAME: &str = "Calendar";
|
||||
const DISCOVERABLE_CALENDAR_ID: &str = "connector_2128aebfecb84f64a069897515042a44";
|
||||
const DISCOVERABLE_GMAIL_ID: &str = "connector_68df038e0ba48191908c8434991bbac2";
|
||||
@@ -352,6 +353,7 @@ impl Respond for CodexAppsJsonRpcResponder {
|
||||
},
|
||||
"_meta": {
|
||||
"connector_id": CONNECTOR_ID,
|
||||
"link_id": LINK_ID,
|
||||
"connector_name": self.connector_name.clone(),
|
||||
"connector_description": self.connector_description.clone(),
|
||||
"openai/outputTemplate": CALENDAR_CREATE_EVENT_MCP_APP_RESOURCE_URI,
|
||||
@@ -378,6 +380,7 @@ impl Respond for CodexAppsJsonRpcResponder {
|
||||
},
|
||||
"_meta": {
|
||||
"connector_id": CONNECTOR_ID,
|
||||
"link_id": LINK_ID,
|
||||
"connector_name": self.connector_name.clone(),
|
||||
"connector_description": self.connector_description.clone(),
|
||||
"_codex_apps": {
|
||||
@@ -410,6 +413,7 @@ impl Respond for CodexAppsJsonRpcResponder {
|
||||
},
|
||||
"_meta": {
|
||||
"connector_id": CONNECTOR_ID,
|
||||
"link_id": LINK_ID,
|
||||
"connector_name": self.connector_name.clone(),
|
||||
"connector_description": self.connector_description.clone(),
|
||||
"openai/fileParams": ["file"],
|
||||
|
||||
@@ -1337,7 +1337,9 @@ async fn stdio_image_responses_round_trip() -> anyhow::Result<()> {
|
||||
tool: "image".to_string(),
|
||||
arguments: Some(json!({})),
|
||||
},
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -25,6 +25,7 @@ use core_test_support::apps_test_server::CALENDAR_CREATE_EVENT_MCP_APP_RESOURCE_
|
||||
use core_test_support::apps_test_server::CALENDAR_CREATE_EVENT_RESOURCE_URI;
|
||||
use core_test_support::apps_test_server::DIRECT_CALENDAR_CREATE_EVENT_TOOL as CALENDAR_CREATE_TOOL;
|
||||
use core_test_support::apps_test_server::DIRECT_CALENDAR_LIST_EVENTS_TOOL as CALENDAR_LIST_TOOL;
|
||||
use core_test_support::apps_test_server::LINK_ID;
|
||||
use core_test_support::apps_test_server::SEARCH_CALENDAR_APP_ONLY_TOOL;
|
||||
use core_test_support::apps_test_server::SEARCH_CALENDAR_CREATE_TOOL;
|
||||
use core_test_support::apps_test_server::SEARCH_CALENDAR_LIST_TOOL;
|
||||
@@ -559,10 +560,12 @@ async fn tool_search_returns_deferred_tools_without_follow_up_tool_injection() -
|
||||
unreachable!("event guard guarantees McpToolCallEnd");
|
||||
};
|
||||
assert_eq!(end.call_id, "calendar-call-1");
|
||||
assert_eq!(end.connector_id.as_deref(), Some("calendar"));
|
||||
assert_eq!(
|
||||
end.mcp_app_resource_uri.as_deref(),
|
||||
Some(CALENDAR_CREATE_EVENT_MCP_APP_RESOURCE_URI)
|
||||
);
|
||||
assert_eq!(end.link_id.as_deref(), Some(LINK_ID));
|
||||
assert_eq!(
|
||||
end.invocation,
|
||||
McpInvocation {
|
||||
|
||||
@@ -98,6 +98,7 @@ fn mcp_tool_call_result_preserves_meta_in_jsonl_event() {
|
||||
tool: "web_run".to_string(),
|
||||
status: McpToolCallStatus::Completed,
|
||||
arguments: json!({"search_query": [{"q": "OpenAI Codex CLI documentation"}]}),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: Some(Box::new(codex_app_server_protocol::McpToolCallResult {
|
||||
|
||||
@@ -478,6 +478,7 @@ fn mcp_tool_call_begin_and_end_emit_item_events() {
|
||||
tool: "tool_x".to_string(),
|
||||
status: ApiMcpToolCallStatus::InProgress,
|
||||
arguments: json!({ "key": "value" }),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
@@ -496,6 +497,7 @@ fn mcp_tool_call_begin_and_end_emit_item_events() {
|
||||
tool: "tool_x".to_string(),
|
||||
status: ApiMcpToolCallStatus::Completed,
|
||||
arguments: json!({ "key": "value" }),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: Some(Box::new(McpToolCallResult {
|
||||
@@ -568,6 +570,7 @@ fn mcp_tool_call_failure_sets_failed_status() {
|
||||
tool: "tool_y".to_string(),
|
||||
status: ApiMcpToolCallStatus::Failed,
|
||||
arguments: json!({ "param": 42 }),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
@@ -617,6 +620,7 @@ fn mcp_tool_call_defaults_arguments_and_preserves_structured_content() {
|
||||
tool: "tool_z".to_string(),
|
||||
status: ApiMcpToolCallStatus::InProgress,
|
||||
arguments: serde_json::Value::Null,
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
@@ -635,6 +639,7 @@ fn mcp_tool_call_defaults_arguments_and_preserves_structured_content() {
|
||||
tool: "tool_z".to_string(),
|
||||
status: ApiMcpToolCallStatus::Completed,
|
||||
arguments: serde_json::Value::Null,
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: Some(Box::new(McpToolCallResult {
|
||||
|
||||
@@ -188,9 +188,15 @@ pub struct McpToolCallItem {
|
||||
pub arguments: serde_json::Value,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub connector_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub mcp_app_resource_uri: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub link_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub plugin_id: Option<String>,
|
||||
pub status: McpToolCallStatus,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
@@ -546,7 +552,9 @@ impl McpToolCallItem {
|
||||
tool: self.tool.clone(),
|
||||
arguments: (!self.arguments.is_null()).then(|| self.arguments.clone()),
|
||||
},
|
||||
connector_id: self.connector_id.clone(),
|
||||
mcp_app_resource_uri: self.mcp_app_resource_uri.clone(),
|
||||
link_id: self.link_id.clone(),
|
||||
plugin_id: self.plugin_id.clone(),
|
||||
})
|
||||
}
|
||||
@@ -566,6 +574,8 @@ impl McpToolCallItem {
|
||||
arguments: (!self.arguments.is_null()).then(|| self.arguments.clone()),
|
||||
},
|
||||
mcp_app_resource_uri: self.mcp_app_resource_uri.clone(),
|
||||
connector_id: self.connector_id.clone(),
|
||||
link_id: self.link_id.clone(),
|
||||
plugin_id: self.plugin_id.clone(),
|
||||
duration: self.duration?,
|
||||
result,
|
||||
|
||||
@@ -2324,9 +2324,15 @@ pub struct McpToolCallBeginEvent {
|
||||
pub invocation: McpInvocation,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub connector_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub mcp_app_resource_uri: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub link_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub plugin_id: Option<String>,
|
||||
}
|
||||
|
||||
@@ -2337,9 +2343,15 @@ pub struct McpToolCallEndEvent {
|
||||
pub invocation: McpInvocation,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub connector_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub mcp_app_resource_uri: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub link_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub plugin_id: Option<String>,
|
||||
#[ts(type = "string")]
|
||||
pub duration: Duration,
|
||||
@@ -4940,7 +4952,9 @@ mod tests {
|
||||
server: "server".into(),
|
||||
tool: "tool".into(),
|
||||
arguments: json!({"arg": "value"}),
|
||||
connector_id: Some("connector".into()),
|
||||
mcp_app_resource_uri: Some("app://connector".into()),
|
||||
link_id: Some("link_123".into()),
|
||||
plugin_id: Some("sample@test".into()),
|
||||
status: McpToolCallStatus::InProgress,
|
||||
result: None,
|
||||
@@ -4956,10 +4970,12 @@ mod tests {
|
||||
assert_eq!(event.call_id, "mcp-1");
|
||||
assert_eq!(event.invocation.server, "server");
|
||||
assert_eq!(event.invocation.tool, "tool");
|
||||
assert_eq!(event.connector_id.as_deref(), Some("connector"));
|
||||
assert_eq!(
|
||||
event.mcp_app_resource_uri.as_deref(),
|
||||
Some("app://connector")
|
||||
);
|
||||
assert_eq!(event.link_id.as_deref(), Some("link_123"));
|
||||
assert_eq!(event.plugin_id.as_deref(), Some("sample@test"));
|
||||
}
|
||||
_ => panic!("expected McpToolCallBegin event"),
|
||||
@@ -5047,7 +5063,9 @@ mod tests {
|
||||
server: "server".into(),
|
||||
tool: "tool".into(),
|
||||
arguments: json!({"arg": "value"}),
|
||||
connector_id: Some("connector".into()),
|
||||
mcp_app_resource_uri: Some("app://connector".into()),
|
||||
link_id: Some("link_123".into()),
|
||||
plugin_id: Some("sample@test".into()),
|
||||
status: McpToolCallStatus::Completed,
|
||||
result: Some(CallToolResult {
|
||||
@@ -5068,10 +5086,12 @@ mod tests {
|
||||
assert_eq!(event.call_id, "mcp-1");
|
||||
assert_eq!(event.invocation.server, "server");
|
||||
assert_eq!(event.invocation.tool, "tool");
|
||||
assert_eq!(event.connector_id.as_deref(), Some("connector"));
|
||||
assert_eq!(
|
||||
event.mcp_app_resource_uri.as_deref(),
|
||||
Some("app://connector")
|
||||
);
|
||||
assert_eq!(event.link_id.as_deref(), Some("link_123"));
|
||||
assert_eq!(event.plugin_id.as_deref(), Some("sample@test"));
|
||||
assert_eq!(event.duration, Duration::from_millis(42));
|
||||
assert!(event.is_success());
|
||||
|
||||
@@ -973,6 +973,7 @@ async fn replayed_in_progress_mcp_tool_call_stays_active() {
|
||||
tool: "copilot".to_string(),
|
||||
status: codex_app_server_protocol::McpToolCallStatus::InProgress,
|
||||
arguments: json!({"action": "wait"}),
|
||||
app_context: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
result: None,
|
||||
|
||||
Reference in New Issue
Block a user