modelcontextprotocol / modelcontextprotocol/typescript-sdk
The MCP client using a tool launched with uvx does not terminate.
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 13.4k
- Forks
- 2.2k
- Avg merge
- 3d 15h
- Merged PRs (30d)
- 4
Description
Describe the bug
As shown in the attached sample, a client that uses a tool launched with uvx does not terminate.
While it is possible to forcefully terminate the process using something like process.exit(0), doing so leaves the uvx cache in a state where it appears to still be in use by the MCP client process.
This issue does not seem to occur when using npx instead.
A similar issue also occurs on Windows Claude Desktop as well.
To Reproduce
Run the attached sample.
Expected behavior
Exit the client process.
==========
import { Anthropic } from "@anthropic-ai/sdk";
import {
MessageParam,
Tool,
ToolUseBlock,
} from "@anthropic-ai/sdk/resources/messages/messages.mjs";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import dotenv from "dotenv";
dotenv.config();
if (!process.env.ANTHROPIC_API_KEY) {
throw new Error("ANTHROPIC_API_KEY is not set");
}
const anthropic = new Anthropic();
const anthropicTools: Tool[] = [];
const mcp = new Client({ name: "test-client", version: "1.0.0" });
const transport = new StdioClientTransport({
command: "uvx",
args: [ "mcp-server-time", "--local-timezone=Asia/Tokyo" ],
});
await mcp.connect(transport);
const toolsResult = await mcp.listTools();
for (const tool of toolsResult.tools) {
anthropicTools.push({
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema,
});
}
console.log("MCP Client Started!");
const messages: MessageParam[] = [
{
role: "user",
content: "What time is it now?",
},
];
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages,
tools: anthropicTools,
});
messages.push({
role: "assistant",
content: response.content,
});
for (const content of response.content) {
if (content.type === "text") {
console.log("<<<" + content.text + ">>>");
} else if (content.type === "tool_use") {
const toolName = content.name;
const toolArgs = content.input as { [x: string]: unknown } | undefined;
console.log(`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`);
const result = await mcp.callTool({
name: toolName,
arguments: toolArgs,
});
console.log(`[Result of tool ${toolName}]: ${JSON.stringify(result.content, null, 2)}`);
messages.push({
role: "user",
content: [{
type: "tool_result",
tool_use_id: content.id,
content: result.content as string,
},
]
});
const response = await anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages,
});
for (const content of response.content) {
if (content.type === "text") {
console.log("<<<" + content.text + ">>>");
}
}
}
}
await mcp.close();
console.log("MCP Client Closed!");
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the attached TypeScript sample with StdioClientTransport and the uvx command. Trace the lifecycle from mcp.connect through mcp.close, comparing the uvx behavior with the npx behavior described in the issue. Done means the client exits normally without process.exit(0), and the uvx cache is not left appearing in use.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100