Resolve imported connectors by MCP server name (#35856)

## Why

Imported session attribution can identify an MCP server by its configured name
instead of the UUID stored in the session manifest.

## What changed

Match attributed MCP servers against normalized manifest names without regard to
case, while retaining UUID matching.

## Testing

Add focused coverage for both name- and UUID-based attribution.

GitOrigin-RevId: 827443f9e7f14028e17b5c5775ca372bfe2e217e
This commit is contained in:
charlesgong-openai authored and copyberry committed 2026-07-29 00:51:17 +00:00
1 parent 07490c7523
commit fcd2273de7
3 files changed
+91 -7

No files matched your search

@@ -1563,7 +1563,7 @@ async fn external_agent_config_import_creates_session_rollouts() -> Result<()> {
"type": "assistant", "type": "assistant",
"cwd": &project_root, "cwd": &project_root,
"timestamp": source_updated_at_text, "timestamp": source_updated_at_text,
"attributionMcpServer": "gmail-server", "attributionMcpServer": "gmail",
"message": { "content": "first answer" }, "message": { "content": "first answer" },
}) })
.to_string(), .to_string(),
@@ -65,17 +65,23 @@ pub fn detect_imported_cla_session_connectors(
let connector_names = connector_names_by_session.entry(session_id).or_default(); let connector_names = connector_names_by_session.entry(session_id).or_default();
for server in manifest.remote_mcp_servers_config { for server in manifest.remote_mcp_servers_config {
let Some(uuid) = server.uuid else {
continue;
};
if !attributed_server_ids.contains(&uuid) {
continue;
}
let Some(name) = let Some(name) =
crate::sessions::normalized_connector_display_name(server.name.as_deref()) crate::sessions::normalized_connector_display_name(server.name.as_deref())
else { else {
continue; continue;
}; };
// Depending on the source client, attributionMcpServer contains either the
// manifest UUID or its configured server name.
let matches_uuid = server
.uuid
.as_deref()
.is_some_and(|uuid| attributed_server_ids.contains(uuid));
let matches_name = attributed_server_ids
.iter()
.any(|server_id| server_id.eq_ignore_ascii_case(&name));
if !matches_uuid && !matches_name {
continue;
}
connector_names.entry(name.to_lowercase()).or_insert(name); connector_names.entry(name.to_lowercase()).or_insert(name);
} }
} }
@@ -114,3 +120,7 @@ fn json_files_recursively(root: &Path) -> Vec<PathBuf> {
} }
files files
} }
#[cfg(test)]
#[path = "connectors_cla_tests.rs"]
mod tests;
@@ -0,0 +1,74 @@
use super::*;
use pretty_assertions::assert_eq;
use std::collections::BTreeSet;
use tempfile::TempDir;
#[test]
fn resolves_attributed_server_name_from_session_manifest() {
let metadata_root = TempDir::new().expect("tempdir");
let manifests_root = metadata_root.path().join(SESSION_MANIFESTS_DIR);
std::fs::create_dir_all(&manifests_root).expect("manifest directory");
std::fs::write(
manifests_root.join("session.json"),
serde_json::json!({
"cliSessionId": "session-1",
"remoteMcpServersConfig": [
{
"uuid": "c58ac595-58b5-48f8-ac77-d8d01523dede",
"name": "Figma",
},
],
})
.to_string(),
)
.expect("manifest");
let attributions = vec![ImportedSessionConnectorAttribution {
session_id: "session-1".to_string(),
server_ids: BTreeSet::from(["figma".to_string()]),
}];
let connector_names = detect_imported_cla_session_connectors(
&attributions,
&[metadata_root.path().to_path_buf()],
);
assert_eq!(
connector_names,
BTreeMap::from([("session-1".to_string(), vec!["Figma".to_string()])])
);
}
#[test]
fn still_resolves_attributed_server_uuid_from_session_manifest() {
let metadata_root = TempDir::new().expect("tempdir");
let manifests_root = metadata_root.path().join(SESSION_MANIFESTS_DIR);
std::fs::create_dir_all(&manifests_root).expect("manifest directory");
std::fs::write(
manifests_root.join("session.json"),
serde_json::json!({
"cliSessionId": "session-1",
"remoteMcpServersConfig": [
{
"uuid": "c58ac595-58b5-48f8-ac77-d8d01523dede",
"name": "Figma",
},
],
})
.to_string(),
)
.expect("manifest");
let attributions = vec![ImportedSessionConnectorAttribution {
session_id: "session-1".to_string(),
server_ids: BTreeSet::from(["c58ac595-58b5-48f8-ac77-d8d01523dede".to_string()]),
}];
let connector_names = detect_imported_cla_session_connectors(
&attributions,
&[metadata_root.path().to_path_buf()],
);
assert_eq!(
connector_names,
BTreeMap::from([("session-1".to_string(), vec!["Figma".to_string()])])
);
}