Add explicit app and account targets to MCP resource reads (#47248)

## What changed

Allow `mcpServer/resource/read` to specify `target: {connectorId, linkId}` for direct hosted app reads without tool discovery, when supported by the backend. Require an explicit `linkId`: a string selects an account, while `null` requests no-auth access subject to backend policy.

Restrict direct targets to `codex_apps` and reject empty connector IDs, empty link IDs, and synthetic link IDs. Preserve originating app/account scope when `originCallId` and `threadId` are supplied, and retain discovery when `target` is omitted.

Update protocol schemas and TypeScript and Python models, preserving required-but-nullable `linkId` semantics in Python code generation.

## Testing

Extend resource-read tests to check target metadata with and without a thread, including explicit no-auth targets and omitted targets. Add Python model tests for string and null `linkId` values and rejection of a missing `linkId`.

GitOrigin-RevId: 8cf5595fbdd937193aeb529901fc95299f6e18ad
This commit is contained in:
victor-openai
2026-09-22 10:42:50 +00:00
committed by copyberry
parent c46aa58a7b
commit 3b50349e1a
19 changed files with 324 additions and 60 deletions
@@ -2469,6 +2469,7 @@ mod tests {
server: "server-a".to_string(),
uri: "file:///tmp/resource".to_string(),
connector_id: None,
target: None,
},
};
assert_eq!(
@@ -2658,6 +2659,7 @@ mod tests {
server: "server-a".to_string(),
uri: "file:///tmp/resource".to_string(),
connector_id: None,
target: None,
},
};
assert_eq!(mcp_resource_read.serialization_scope(), None);
@@ -116,6 +116,24 @@ pub struct McpResourceReadParams {
pub uri: String,
#[ts(optional = nullable)]
pub connector_id: Option<String>,
/// Explicit hosted app/account. Omit to retain legacy resource discovery.
#[ts(optional = nullable)]
pub target: Option<McpResourceReadTarget>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct McpResourceReadTarget {
pub connector_id: String,
/// Null explicitly requests no-auth access, subject to the app's resource policy.
#[serde(deserialize_with = "Option::deserialize")]
#[schemars(
required,
schema_with = "crate::protocol::serde_helpers::nullable_string_schema"
)]
#[ts(type = "string | null")]
pub link_id: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]