1
>
/*---------------------------------------------------------------------------------------------
claudeClientToolResult.ts
2
>
* Copyright (c) Microsoft Corporation. All rights reserved.
3
>
* Licensed under the MIT License. See License.txt in the project root for license information.
4
>
*--------------------------------------------------------------------------------------------*/
5
>
6
>
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
7
>
import { ToolResultContentType, type ToolCallResult, type ToolResultContent, type ToolResultEmbeddedResourceContent } from '../../../common/state/protocol/channels-chat/state.js';
8
>
9
>
/**
10
>
* Stable URI scheme used when an `EmbeddedResource` content block must be
11
>
* shipped to the MCP server as the `{ type: 'resource', resource: { uri, mimeType, blob } }`
12
>
* shape. The MCP zod schema rejects resource blocks without a URI, and the
13
>
* protocol's `{ data, contentType }` carries no URI of its own — so we mint
14
>
* an ephemeral, per-call URI of the form
15
>
* `claude-client://<toolUseId>/<index>`. This URI is opaque to both sides;
16
>
* the model never dereferences it.
17
>
*/
18
>
const CLAUDE_CLIENT_RESOURCE_SCHEME = 'claude-client';
19
>
20
>
/**
21
>
* Convert a protocol {@link ToolCallResult} into the MCP {@link CallToolResult}
22
>
* shape the Anthropic SDK feeds back to the model. Mostly 1:1 mapping with
23
>
* one shape transform: protocol `EmbeddedResource { data, contentType }` →
24
>
* MCP `{ type: 'image', ... }` for `image/*`, or
25
>
* `{ type: 'resource', resource: { uri, mimeType, blob } }` for everything
26
>
* else (synthesized URI per the scheme above).
27
>
*
28
>
* Unknown content block kinds collapse to a synthesized text block + a
29
>
* console warn — bounded blast radius (one bad call, not a crash).
30
>
*
31
>
* @param toolUseId The SDK `tool_use_id` for this call. Embedded into the
32
>
* synthesized resource URI so the same call's blocks stay disambiguated
33
>
* across parallel tool calls.
34
>
*/
35
>
export function convertToolCallResult(result: ToolCallResult, toolUseId: string): CallToolResult {
36
const blocks = result.content ?? [];
37
const content = blocks.map((block, index) => convertBlock(block, toolUseId, index));