数字化技能提升教程,数字化时代生存宝典

首页 / 开发教程 / 如何使用MCP Typescript SDK构建MCP客户端

如何使用MCP Typescript SDK构建MCP客户端

浏览:443

MCP全称为“Model Context Protocol”,是一款可供使用的开源协议;MCP Typescript SDK则是MCP官方的TypeScript实现,主要是为开发者提供一套完整的工具,用于创建符合MCP规范的客户端和服务器应用。接下来将由站长百科为大家详细介绍如何使用MCP Typescript SDK构建MCP Client,用来代理Amazon Bedrock请求。

Amazon Bedrock是AWS推出的完全托管的服务,主要通过单个API提供来自AI21 Labs、Anthropic、Cohere、Meta、Mistral AI、Stability AI和Amazon等人工智能公司的基础模型(FM),以及通过安全性、隐私性和负责任的人工智能构建生成式人工智能应用程序所需的应用。

立即注册AWS账号免费试用演示Amazon Bedrock:点击直达(另享100+国内外免费云产品

话不多数,下面开始演示:

一、设置项目

1、创建并启动项目。

mkdir mcp-bedrock-converse cd mcp-bedrock-converse npm init -y npm install @aws-sdk/client-bedrock-runtime @modelcontextprotocol/sdk @inquirer/prompts npm i --save-dev @types/node mkdir src touch src/index.ts

2、在package.json文件中添加以下内容。

{ "scripts": { "build": "tsc && chmod 755 build/index.js", "converse": "node build/index.js", }, "type": "module", }

3、创建tsconfig.json文件。

{ "compilerOptions": { "target": "ES2022", "module": "Node16", "moduleResolution": "Node16", "outDir": "./build", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true }, "include": [ "src/**/*" ], "exclude": [ "node_modules" ] }

二、MCP Converse Client代码

1、在src/index.ts文件中添加以下内容。

import { BedrockRuntimeClient, ConverseCommand, ConverseCommandInput, Message, Tool, ToolInputSchema } from "@aws-sdk/client-bedrock-runtime"; import { input } from "@inquirer/prompts"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

classConverseMcpClient {
private mcp: Client // from "@modelcontextprotocol/sdk/client/index.js"
private bedrock: BedrockRuntimeClient
private transport: StdioClientTransport | null = null; // from "@modelcontextprotocol/sdk/client/stdio.js"
private tools: Tool[] = []
constructor(modelId: string) {
this.bedrock = new BedrockRuntimeClient({ region: 'us-east-1' })
this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" })
}
async connectToMcpServer(serverScriptPath: string) {
try {
// Determine script type and appropriate command
const isJs = serverScriptPath.endsWith(".js");
const isPy = serverScriptPath.endsWith(".py");
if (!isJs && !isPy) {
thrownew Error("Server script must be a .js or .py file");
}
const command = isPy
? process.platform === "win32"
? "python"
: "python3"
: process.execPath;

// Initialize transport and connect to server
this.transport = new StdioClientTransport({
command,
args: [serverScriptPath],
});
this.mcp.connect(this.transport);

// List available tools
const toolsResult = await this.mcp.listTools();

this.tools = toolsResult.tools.map((tool) => {
const toolInputSchema: ToolInputSchema = {
json: JSON.parse(JSON.stringify(tool.inputSchema))
}
const bedrockTool: Tool = {
toolSpec: {
inputSchema: toolInputSchema,
name: tool.name,
description: tool.description
}
}
return bedrockTool;
});
}
catch (e) {
console.log("Failed to connect to MCP server: ", e);
throw e;
}
}
async converse(conversation: Message[]){
const input: ConverseCommandInput = {
modelId: modelId,
messages: conversation
}
if (this.tools.length > 0) {
input.toolConfig = {
tools: this.tools
}
}
const response = await this.bedrock.send(
new ConverseCommand(input),
);

if (response.stopReason === 'tool_use') {
if (response.output?.message?.content) {
const message = response.output.message
conversation.push(message)
const content = response.output?.message?.content
for (var contentBlock of content) {
if (contentBlock.toolUse?.name) {
const toolName = contentBlock.toolUse.name
const toolArguments = JSON.parse(JSON.stringify(contentBlock.toolUse.input))
const response = await client.mcp.callTool({
name: toolName,
arguments: toolArguments
})
const message: Message = {
role: "user",
content: [{
toolResult: {
toolUseId: contentBlock.toolUse.toolUseId,
content: [{
text: JSON.stringify(response)
}]
}
}]
}
conversation.push(message)
await this.converse(conversation)
}
}

}
}
elseif (response.output?.message) {
const message = response.output.message
console.log(message.content?.[0].text);
conversation.push(message)
}
}

async questionPrompt(message: string, conversation: Message[]): Promise<boolean> {
const answer = await input({ message: message })
if (answer) {
const question: Message = {
role: "user",
content: [{ text: answer }],
}
conversation.push(question)
returntrue
}
else {
returnfalse;
}
}

async chat(){
const conversation: Message[] = []
try {
if (await this.questionPrompt('Whats up?', conversation)) {
while (true) {
await client.converse(conversation)
if (!await this.questionPrompt('', conversation)) { break }
}
}
} catch (error) {
if (error instanceof Error && error.name === 'ExitPromptError') {
// noop; silence this error
} else {
console.error(error)
throw error;
}
}
}
}

const modelId = 'anthropic.claude-3-haiku-20240307-v1:0'
const client = new ConverseMcpClient(modelId)
//await client.connectToMcpServer('/path/to/mcp/index.js')
await client.chat()

2、然后使用以下命令来构建并运行代码。

npm run build npm run converse

以上用于与Amazon Bedrock模型进行交互的基础接口。

3、如果有MCP Server,则可在代码中指定的位置,通过以下代码将其添加进来:

await client.connectToMcpServer

('/path/to/mcp/index.js')

三、检查代码

1、构造函数

private mcp: Client // from "@modelcontextprotocol/sdk/client/index.js" private bedrock: BedrockRuntimeClient constructor(modelId: string){ this.bedrock = new BedrockRuntimeClient({ region: 'us-east-1' }) this.mcp = new Client({ name: "mcp-client-cli", version: "1.0.0" }) }

这将创建Amazon Bedrock Runtime Client,以使用Amazon Bedrock模型,并创建MCP Client,以便与MCP Servers交互。

2、MCP Server连接

private transport: StdioClientTransport | null = null; // from "@modelcontextprotocol/sdk/client/stdio.js" private tools: Tool[] = [] async connectToMcpServer(serverScriptPath: string) { try { // Determine script type and appropriate command const isJs = serverScriptPath.endsWith(".js"); const isPy = serverScriptPath.endsWith(".py"); if (!isJs && !isPy) { thrownew Error("Server script must be a .js or .py file"); } const command = isPy ? process.platform === "win32" ? "python" : "python3" : process.execPath;

// Initialize transport and connect to server
this.transport = new StdioClientTransport({
command,
args: [serverScriptPath],
});
this.mcp.connect(this.transport);

// List available tools
const toolsResult = await this.mcp.listTools();

this.tools = toolsResult.tools.map((tool) => {
const toolInputSchema: ToolInputSchema = {
json: JSON.parse(JSON.stringify(tool.inputSchema))
}
const bedrockTool: Tool = {
toolSpec: {
inputSchema: toolInputSchema,
name: tool.name,
description: tool.description
}
}
return bedrockTool;
});
}
catch (e) {
console.log("Failed to connect to MCP server: ", e);
throw e;
}
}

这将采用MCP Server脚本路径,并通过Stdio使用MCP Client连接到该服务器。然后,它会将该MCP Server添加到Amazon Bedrock可用的工具列表中,并在您与Amazon Bedrock交互时提供这些工具。

3、交互

async converse(conversation: Message[]){ const input: ConverseCommandInput = { modelId: modelId, messages: conversation } if (this.tools.length > 0) { input.toolConfig = { tools: this.tools } } const response = await this.bedrock.send( new ConverseCommand(input), );

if (response.stopReason === 'tool_use') {
if (response.output?.message?.content) {
const message = response.output.message
conversation.push(message)
const content = response.output?.message?.content
for (var contentBlock of content) {
if (contentBlock.toolUse?.name) {
const toolName = contentBlock.toolUse.name
const toolArguments = JSON.parse(JSON.stringify(contentBlock.toolUse.input))
const response = await client.mcp.callTool({
name: toolName,
arguments: toolArguments
})
const message: Message = {
role: "user",
content: [{
toolResult: {
toolUseId: contentBlock.toolUse.toolUseId,
content: [{
text: JSON.stringify(response)
}]
}
}]
}
conversation.push(message)
await this.converse(conversation)
}
}

}
}
elseif (response.output?.message) {
const message = response.output.message
console.log(message.content?.[0].text);
conversation.push(message)
}
}

使用Converse时,您需要提供包含用户与助手之间所有消息的对话记录。

因此会获取一组Amazon Bedrock Message构成的对话内容,并发送ConverseCommand,同时附上当前可用的工具,即MCP Servers(如果有的话)。

4、Lo-fi聊天界面

由于还需要一个界面,因此本例以基础方式使用了Inquirer.js来实现。如下代码会接收输入,并保持对话循环,直至用户退出(输入空白消息)。

async questionPrompt(message: string, conversation: Message[]): Promise<boolean> { const answer = await input({ message: message }) if (answer) { const question: Message = { role: "user", content: [{ text: answer }], } conversation.push(question) returntrue } else { returnfalse; } }

async chat(){
const conversation: Message[] = []
try {
if (await this.questionPrompt('Whats up?', conversation)) {
while (true) {
await client.converse(conversation)
if (!await this.questionPrompt('', conversation)) { break }
}
}
} catch (error) {
if (error instanceof Error && error.name === 'ExitPromptError') {
// noop; silence this error
} else {
console.error(error)
throw error;
}
}
}

相关文章

猜你喜欢