client.ts•3.56 kB
import readline from "readline/promises"
import { Anthropic } from "@anthropic-ai/sdk"
import {
MessageParam,
Tool
} 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()
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY
if (!ANTHROPIC_API_KEY) {
throw new Error("ANTHROPIC_API_KEY is not set")
}
export class MCPClient {
private mcp: Client
private anthropic: Anthropic
private transport: StdioClientTransport | null = null
private tools: Tool[] = []
constructor() {
this.anthropic = new Anthropic({
apiKey: ANTHROPIC_API_KEY
})
this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" })
}
async connectToServer() {
try {
this.transport = new StdioClientTransport({
command: "npx",
args: ["-y", "@bnb-chain/mcp@latest"],
env: {
PRIVATE_KEY: process.env.PRIVATE_KEY || ""
}
})
this.mcp.connect(this.transport)
const toolsResult = await this.mcp.listTools()
this.tools = toolsResult.tools.map((tool) => {
return {
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema
}
})
console.log(
"Connected to server with tools:",
this.tools.map(({ name }) => name)
)
} catch (e) {
console.log("Failed to connect to MCP server: ", e)
throw e
}
}
async processQuery(query: string) {
const messages: MessageParam[] = [
{
role: "user",
content: query
}
]
const response = await this.anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages,
tools: this.tools
})
const finalText: string[] = []
const toolResults: any[] = []
for (const content of response.content) {
if (content.type === "text") {
finalText.push(content.text)
} else if (content.type === "tool_use") {
const toolName = content.name
const toolArgs = content.input as { [x: string]: unknown } | undefined
const result = await this.mcp.callTool({
name: toolName,
arguments: toolArgs
})
toolResults.push(result)
finalText.push(
`[Calling tool ${toolName} with args ${JSON.stringify(toolArgs)}]`
)
messages.push({
role: "user",
content: result.content as string
})
const response = await this.anthropic.messages.create({
model: "claude-3-5-sonnet-20241022",
max_tokens: 1000,
messages
})
finalText.push(
response.content[0].type === "text" ? response.content[0].text : ""
)
}
}
return finalText.join("\n")
}
async chatLoop() {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
try {
console.log("\nMCP Client Started!")
console.log("Type your queries or 'quit' to exit.")
while (true) {
const message = await rl.question("\nQuery: ")
if (message.toLowerCase() === "quit") {
break
}
const response = await this.processQuery(message)
console.log("\n" + response)
}
} finally {
rl.close()
}
}
async cleanup() {
await this.mcp.close()
}
}