From f7166787d2e696091f6acbad07ca3b75317e2d5a Mon Sep 17 00:00:00 2001 From: cvallejos Date: Wed, 29 Jul 2026 20:26:41 +0200 Subject: [PATCH] feat: surface serverFingerprint on agent mcp fetch/asset replace @W-23608280 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire the MCP tool-drift fingerprint through the CLI: - `agent mcp fetch` now prints the `serverFingerprint` returned by POST /fetch (an opaque hash of the server's current tool definitions). - `agent mcp asset replace` gains `--server-fingerprint` (`-f`): round-trip the value from a prior fetch so the server can confirm the reviewed definitions haven't drifted. Without it, keeping an already-active OUT_OF_SYNC tool active is rejected with a 409 conflict — re-fetch, review, then resend with the new fingerprint. Bumps @salesforce/agents for the McpServerFetchOutput/McpServerAssetReplaceInput serverFingerprint field. Regenerated command-snapshot.json and the fetch schema. Co-Authored-By: Claude Opus 4.8 (1M context) --- command-snapshot.json | 13 +++++++++++-- messages/agent.mcp.asset.replace.md | 10 ++++++++++ messages/agent.mcp.fetch.md | 6 ++++++ schemas/agent-mcp-fetch.json | 20 +++++++------------- src/commands/agent/mcp/asset/replace.ts | 7 +++++++ src/commands/agent/mcp/fetch.ts | 3 +++ 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/command-snapshot.json b/command-snapshot.json index 39455470..a2398239 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -207,8 +207,17 @@ "alias": [], "command": "agent:mcp:asset:replace", "flagAliases": [], - "flagChars": ["i", "o"], - "flags": ["api-version", "assets", "assets-file", "flags-dir", "json", "mcp-server-id", "target-org"], + "flagChars": ["f", "i", "o"], + "flags": [ + "api-version", + "assets", + "assets-file", + "flags-dir", + "json", + "mcp-server-id", + "server-fingerprint", + "target-org" + ], "plugin": "@salesforce/plugin-agent" }, { diff --git a/messages/agent.mcp.asset.replace.md b/messages/agent.mcp.asset.replace.md index 49a4d478..ecf0a8b6 100644 --- a/messages/agent.mcp.asset.replace.md +++ b/messages/agent.mcp.asset.replace.md @@ -6,6 +6,8 @@ Replace the asset set of an MCP server in the API Catalog. Replaces the full set of assets (tools, prompts, resources) for an MCP server with the asset items you supply. Provide the assets either inline with `--assets` (a JSON string, or `-` to read from stdin) or from a file with `--assets-file`. The JSON must be either an array of asset items or an object of the form `{ "assets": [...] }`. Each asset item may include `id`, `name`, `label`, `description`, `active`, and `kind`. This is a full replacement: existing assets not present in the supplied set are removed, so provide the complete desired asset set (read the current set first with `agent mcp asset list` or `agent mcp fetch`). +Pass `--server-fingerprint` with the value returned by `agent mcp fetch` to confirm the tool definitions you reviewed are still current. Without it, keeping an already-active tool active after its definition drifted on the MCP server (status OUT_OF_SYNC) is rejected with an HTTP 409 conflict — re-run `agent mcp fetch`, review the new definitions, then resend with the returned fingerprint. + # examples - Replace the assets inline with a JSON string: @@ -20,6 +22,10 @@ Replaces the full set of assets (tools, prompts, resources) for an MCP server wi cat assets.json | <%= config.bin %> <%= command.id %> --mcp-server-id 0XSxx0000000001 --assets - --target-org myOrg +- Confirm the definitions are current by round-tripping the fingerprint from a prior fetch: + + <%= config.bin %> <%= command.id %> --mcp-server-id 0XSxx0000000001 --assets-file ./assets.json --server-fingerprint 7053fc245a1cebe5994b5d4e24d02bac8773a85fb96f721b081dbadc9bf5c434 --target-org myOrg + # flags.mcp-server-id.summary ID of the MCP server whose assets you want to replace. @@ -32,6 +38,10 @@ The desired asset allowlist as a JSON string (or "-" to read from stdin). Mutual Path to a JSON file containing the desired asset allowlist. Mutually exclusive with --assets. +# flags.server-fingerprint.summary + +Fingerprint from a prior "agent mcp fetch" (serverFingerprint), round-tripped to confirm the tool definitions haven't drifted. Required to keep an OUT_OF_SYNC tool active; otherwise the save is rejected with a 409 conflict. + # error.failed Failed to replace MCP server assets: %s diff --git a/messages/agent.mcp.fetch.md b/messages/agent.mcp.fetch.md index e8105392..8eb49b6c 100644 --- a/messages/agent.mcp.fetch.md +++ b/messages/agent.mcp.fetch.md @@ -6,6 +6,8 @@ Fetch the live assets (tools, prompts, resources) advertised by an MCP server. Performs a live fetch against the configured MCP server identified by its ID, returning the assets (MCP tools, prompts, and resources) it currently advertises along with their status and activation state. Use this to refresh the view of what an MCP server exposes before activating its assets as agent actions. +The response also includes a `serverFingerprint` — an opaque hash of the server's current tool definitions. Pass it to `agent mcp asset replace --server-fingerprint` to confirm the definitions you reviewed are still current when you save the allowlist. + # examples - Fetch the assets advertised by an MCP server in the default target org: @@ -20,6 +22,10 @@ Performs a live fetch against the configured MCP server identified by its ID, re ID of the MCP server to fetch assets from. +# output.serverFingerprint + +Server fingerprint: %s + # error.failed Failed to fetch MCP server assets: %s diff --git a/schemas/agent-mcp-fetch.json b/schemas/agent-mcp-fetch.json index d45e364f..c61e8014 100644 --- a/schemas/agent-mcp-fetch.json +++ b/schemas/agent-mcp-fetch.json @@ -13,11 +13,12 @@ "items": { "$ref": "#/definitions/McpFetchedAsset" } + }, + "serverFingerprint": { + "type": "string" } }, - "required": [ - "assets" - ], + "required": ["assets"], "additionalProperties": false }, "McpFetchedAsset": { @@ -51,19 +52,12 @@ "type": "string" } }, - "required": [ - "name", - "kind" - ], + "required": ["name", "kind"], "additionalProperties": false }, "McpAssetKind": { "type": "string", - "enum": [ - "MCP_TOOL", - "MCP_PROMPT", - "MCP_RESOURCE" - ] + "enum": ["MCP_TOOL", "MCP_PROMPT", "MCP_RESOURCE"] } } -} \ No newline at end of file +} diff --git a/src/commands/agent/mcp/asset/replace.ts b/src/commands/agent/mcp/asset/replace.ts index 9dc036a0..e3243f2a 100644 --- a/src/commands/agent/mcp/asset/replace.ts +++ b/src/commands/agent/mcp/asset/replace.ts @@ -53,6 +53,10 @@ export default class ApiCatalogMcpServerAssetReplace extends SfCommand { @@ -81,6 +85,9 @@ export default class ApiCatalogMcpServerAssetReplace extends SfCommand