Skip to content

The MCP client using a tool launched with uvx does not terminate. #320

@ynaoto

Description

@ynaoto

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!");

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions