Skip to content

Commit a27489c

Browse files
committed
fix: Use CallToolResult type from MCP SDK to properly parse tool results
1 parent bf44cc7 commit a27489c

File tree

2 files changed

+60
-41
lines changed
  • e2e_tests/typescript/src/server_clients
  • examples/chatbots/typescript/src/server_clients

2 files changed

+60
-41
lines changed

e2e_tests/typescript/src/server_clients/server.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2+
import {
3+
CallToolResult,
4+
TextContent,
5+
} from "@modelcontextprotocol/sdk/types.js";
26
import { Tool } from "./tool.js";
37
import logger from "../logger.js";
4-
import { ToolResultBlock } from "@aws-sdk/client-bedrock-runtime";
5-
8+
import {
9+
ToolResultBlock,
10+
ToolResultContentBlock,
11+
} from "@aws-sdk/client-bedrock-runtime";
612
/**
713
* Abstract base class for communicating with an MCP server.
814
*/
@@ -79,27 +85,36 @@ export abstract class Server {
7985
while (attempt < retries) {
8086
try {
8187
logger.info(`Executing ${toolName}...`);
82-
const result = await this.client.callTool({
88+
const result: CallToolResult = (await this.client.callTool({
8389
name: toolName,
8490
arguments: args,
85-
});
91+
})) as CallToolResult;
8692
logger.info(`Finished executing ${toolName}`);
8793

88-
if (result && typeof result === "object" && "progress" in result) {
89-
const progress = result.progress as number;
90-
const total = result.total as number;
91-
const percentage = (progress / total) * 100;
92-
logger.info(
93-
`Progress: ${progress}/${total} (${percentage.toFixed(1)}%)`
94-
);
95-
throw new Error(
96-
"Does not support progress notifications from tools yet"
97-
);
94+
if (result.isError) {
95+
throw new Error(`Error executing tool: ${JSON.stringify(result)}`);
96+
}
97+
98+
if (result.structuredContent) {
99+
return {
100+
toolUseId: toolUseId,
101+
content: [{ text: JSON.stringify(result.structuredContent) }],
102+
status: "success",
103+
};
104+
}
105+
106+
const content: ToolResultContentBlock[] = [];
107+
for (const block of result.content) {
108+
if (block.type === "text") {
109+
content.push({ text: (block as TextContent).text });
110+
} else {
111+
throw new Error(`Unexpected content type: ${block.type}`);
112+
}
98113
}
99114

100115
return {
101116
toolUseId: toolUseId,
102-
content: [{ text: String(result) }],
117+
content,
103118
status: "success",
104119
};
105120
} catch (e) {

examples/chatbots/typescript/src/server_clients/server.ts

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2+
import {
3+
CallToolResult,
4+
TextContent,
5+
} from "@modelcontextprotocol/sdk/types.js";
26
import { Tool } from "./tool.js";
37
import logger from "../logger.js";
4-
import { ToolResultBlock } from "@aws-sdk/client-bedrock-runtime";
8+
import {
9+
ToolResultBlock,
10+
ToolResultContentBlock,
11+
} from "@aws-sdk/client-bedrock-runtime";
512

613
/**
714
* Abstract base class for communicating with an MCP server.
@@ -79,27 +86,36 @@ export abstract class Server {
7986
while (attempt < retries) {
8087
try {
8188
logger.info(`Executing ${toolName}...`);
82-
const result = await this.client.callTool({
89+
const result: CallToolResult = (await this.client.callTool({
8390
name: toolName,
8491
arguments: args,
85-
});
92+
})) as CallToolResult;
8693
logger.info(`Finished executing ${toolName}`);
8794

88-
if (result && typeof result === "object" && "progress" in result) {
89-
const progress = result.progress as number;
90-
const total = result.total as number;
91-
const percentage = (progress / total) * 100;
92-
logger.info(
93-
`Progress: ${progress}/${total} (${percentage.toFixed(1)}%)`
94-
);
95-
throw new Error(
96-
"Does not support progress notifications from tools yet"
97-
);
95+
if (result.isError) {
96+
throw new Error(`Error executing tool: ${JSON.stringify(result)}`);
97+
}
98+
99+
if (result.structuredContent) {
100+
return {
101+
toolUseId: toolUseId,
102+
content: [{ text: JSON.stringify(result.structuredContent) }],
103+
status: "success",
104+
};
105+
}
106+
107+
const content: ToolResultContentBlock[] = [];
108+
for (const block of result.content) {
109+
if (block.type === "text") {
110+
content.push({ text: (block as TextContent).text });
111+
} else {
112+
throw new Error(`Unexpected content type: ${block.type}`);
113+
}
98114
}
99115

100116
return {
101117
toolUseId: toolUseId,
102-
content: [{ text: this.formatText(result) }],
118+
content,
103119
status: "success",
104120
};
105121
} catch (e) {
@@ -124,16 +140,4 @@ export abstract class Server {
124140
// This should never be reached due to the loop above
125141
throw new Error("Unexpected error in executeTool");
126142
}
127-
128-
formatText(text: unknown): string {
129-
if (typeof text === "string") {
130-
return text;
131-
} else if (Array.isArray(text)) {
132-
return text.map((item) => this.formatText(item)).join("\n");
133-
} else if (typeof text === "object" && text !== null) {
134-
return JSON.stringify(text);
135-
} else {
136-
return String(text);
137-
}
138-
}
139143
}

0 commit comments

Comments
 (0)