Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
{
Expand Down
10 changes: 10 additions & 0 deletions messages/agent.mcp.asset.replace.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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.
Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions messages/agent.mcp.fetch.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
20 changes: 7 additions & 13 deletions schemas/agent-mcp-fetch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
"items": {
"$ref": "#/definitions/McpFetchedAsset"
}
},
"serverFingerprint": {
"type": "string"
}
},
"required": [
"assets"
],
"required": ["assets"],
"additionalProperties": false
},
"McpFetchedAsset": {
Expand Down Expand Up @@ -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"]
}
}
}
}
7 changes: 7 additions & 0 deletions src/commands/agent/mcp/asset/replace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export default class ApiCatalogMcpServerAssetReplace extends SfCommand<ApiCatalo
exists: true,
exclusive: ['assets'],
}),
'server-fingerprint': Flags.string({
summary: messages.getMessage('flags.server-fingerprint.summary'),
char: 'f',
}),
};

public async run(): Promise<ApiCatalogMcpServerAssetReplaceResult> {
Expand Down Expand Up @@ -81,6 +85,9 @@ export default class ApiCatalogMcpServerAssetReplace extends SfCommand<ApiCatalo
}

const input: McpServerAssetReplaceInput = { assets };
if (flags['server-fingerprint']) {
input.serverFingerprint = flags['server-fingerprint'];
}

let result: McpServerAssetCollection;
try {
Expand Down
3 changes: 3 additions & 0 deletions src/commands/agent/mcp/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export default class ApiCatalogMcpServerFetch extends SfCommand<ApiCatalogMcpSer
{ key: 'securityWarning', name: 'Security Warning' },
],
});
if (result.serverFingerprint) {
this.log(messages.getMessage('output.serverFingerprint', [result.serverFingerprint]));
}
}

return result;
Expand Down