Repository navigation
fix(discovery): inventory centrally managed MCP servers - #128
Conversation
Claude Code and Claude Desktop inventory only read user-level config files, so servers pushed through the `managedMcpServers` managed setting (including the ones Agentdesktop itself writes) were reported as 0 MCP. - Claude Code: also read `managedMcpServers` from managed-settings.json and managed-settings.d/*.json (object keyed by server name). - Claude Desktop: also read `managedMcpServers` from the system-managed settings (property list on macOS, JSON elsewhere). Desktop uses an array of named entries, encoded as a JSON string in MDM payloads. - Claude Desktop: scan the third-party deployment directory (~/Library/Application Support/Claude-3p) on macOS. - Accept `transport` as well as `type` for the transport field. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Discovery ignores configured path overrides and can report duplicate managed servers instead of effective settings.
Review effort: Balanced
Findings: 3
Open (3)
What changed in this PR
Adds centrally managed MCP servers to Claude Code and Claude Desktop inventory.
Changes:
- Parses managed settings and supported MCP server shapes.
- Scans Claude Code drop-ins and macOS Claude-3p configuration.
| File | Description |
|---|---|
claude_code/discovery.rs |
Discovers managed MCP configurations. |
claude_desktop/discovery.rs |
Reads system-managed and Claude-3p settings. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if let Some(root) = managed_root() { | ||
| servers.extend(mcp_servers_from_json(&root.join("managed-mcp.json"))); | ||
| // Servers pushed through the `managedMcpServers` managed setting — including the | ||
| // ones Agentdesktop itself writes to `managed-settings.d/50-agentdesktop.json`. | ||
| for path in managed_settings_files(&root) { | ||
| servers.extend(managed_mcp_servers_from_json(&path)); |
There was a problem hiding this comment.
Fixed in b699852. ClaudeCode::discover now passes self.settings_path into discovery, and managed_settings_sources appends the configured file (merged last) when it is not already one of the files under the managed root, so a daemon.claudeCode.config override is inventoried. Covered by configured_settings_path_outside_the_managed_root_is_inventoried_last.
| for path in managed_settings_files(&root) { | ||
| servers.extend(managed_mcp_servers_from_json(&path)); |
There was a problem hiding this comment.
Fixed in b699852. merged_managed_mcp_servers now merges managedMcpServers across managed-settings.json and the lexically sorted drop-ins by server name, with later files overriding earlier ones, so each effective server is reported once with the source of the file that won. Covered by later_managed_settings_files_override_servers_by_name.
| let managed = default_claude_desktop_managed_settings_path(); | ||
| let mut servers = managed_settings(&managed) |
There was a problem hiding this comment.
Fixed in b699852. ClaudeDesktop::discover now passes self.managed_settings_path into discovery, which reads it in the platform-native format (plist on macOS, JSON elsewhere). Covered by inventories_managed_servers_from_the_configured_settings_path.
peterj
left a comment
There was a problem hiding this comment.
thanks for the PR! could you address the comments?
Scan the Claude Code and Claude Desktop settings files the reconciler is configured to write, so daemon config path overrides are inventoried from the same place. Merge Claude Code managedMcpServers across the base file and drop-ins by server name with later files winning, so each effective server is reported once. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
fixed it can you check once @peterj |

Fixes #127
Problem
Discovery only reads user-level
mcpServers, so servers distributed via themanagedMcpServersmanaged setting — including the ones Agentdesktop's own reconciler writes fromdaemonConfig— never show up in inventory. On a device with 15 managed Claude Desktop connectors, Tools reports0 MCP.Changes
Claude Code (
provider/claude_code/discovery.rs)managedMcpServersfrommanaged-settings.jsonand eachmanaged-settings.d/*.json(sorted, matching Claude Code's drop-in order), in addition to the existingmanaged-mcp.json.managed_mcp_servers_from_valueaccepts all three shapes seen in practice:namefield (Claude Desktop),mcp_server_from_entry;transportis accepted as a fallback fortype.Claude Desktop (
provider/claude_desktop/discovery.rs)managedMcpServersfrom the system managed settings (default_claude_desktop_managed_settings_path) — plist on macOS, JSON elsewhere.~/Library/Application Support/Claude-3p/claude_desktop_config.jsonon macOS (only~/.config/Claude-3pwas checked before).Testing
cargo fmt --check,cargo clippy --all-targetsclean.cargo test -p agentunit tests pass, including three new ones:reads_claude_code_managed_servers_keyed_by_namereads_claude_desktop_managed_servers_encoded_as_a_json_stringignores_malformed_managed_serversintegration/managed_gateway_lifecycletests need a Linux-built daemon binary and fail on macOS both with and without this change, so they weren't run locally.agentdesktop-headless discoveron a managed device with this build.🤖 Generated with Claude Code