MCP全稱為“Model Context Protocol”,是一款可供使用的開源協(xié)議;MCP Typescript SDK則是MCP官方的TypeScript實(shí)現(xiàn),主要是為開發(fā)者提供一套完整的工具,用于創(chuàng)建符合MCP規(guī)范的客戶端和服務(wù)器應(yīng)用。接下來將由站長百科為大家詳細(xì)介紹如何使用MCP Typescript SDK構(gòu)建MCP Client,用來代理Amazon Bedrock請求。
Amazon Bedrock是AWS推出的完全托管的服務(wù),主要通過單個(gè)API提供來自AI21 Labs、Anthropic、Cohere、Meta、Mistral AI、Stability AI和Amazon等人工智能公司的基礎(chǔ)模型(FM),以及通過安全性、隱私性和負(fù)責(zé)任的人工智能構(gòu)建生成式人工智能應(yīng)用程序所需的應(yīng)用。
立即注冊AWS賬號免費(fèi)試用演示Amazon Bedrock:點(diǎn)擊直達(dá)(另享100+國內(nèi)外免費(fèi)云產(chǎn)品)
話不多數(shù),下面開始演示:
一、設(shè)置項(xiàng)目
1、創(chuàng)建并啟動項(xiàng)目。
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文件中添加以下內(nèi)容。
{
“scripts”: {
“build”: “tsc && chmod 755 build/index.js”,
“converse”: “node build/index.js”,
},
“type”: “module”,
}
3、創(chuàng)建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文件中添加以下內(nèi)容。
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、然后使用以下命令來構(gòu)建并運(yùn)行代碼。
npm run build
npm run converse
以上用于與Amazon Bedrock模型進(jìn)行交互的基礎(chǔ)接口。
3、如果有MCP Server,則可在代碼中指定的位置,通過以下代碼將其添加進(jìn)來:
await client.connectToMcpServer
(‘/path/to/mcp/index.js’)
三、檢查代碼
1、構(gòu)造函數(shù)
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” })
}
這將創(chuàng)建Amazon Bedrock Runtime Client,以使用Amazon Bedrock模型,并創(chuàng)建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連接到該服務(wù)器。然后,它會將該MCP Server添加到Amazon Bedrock可用的工具列表中,并在您與Amazon Bedrock交互時(shí)提供這些工具。
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時(shí),您需要提供包含用戶與助手之間所有消息的對話記錄。
因此會獲取一組Amazon Bedrock Message構(gòu)成的對話內(nèi)容,并發(fā)送ConverseCommand,同時(shí)附上當(dāng)前可用的工具,即MCP Servers(如果有的話)。
4、Lo-fi聊天界面
由于還需要一個(gè)界面,因此本例以基礎(chǔ)方式使用了Inquirer.js來實(shí)現(xiàn)。如下代碼會接收輸入,并保持對話循環(huán),直至用戶退出(輸入空白消息)。
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;
}
}
}
-
廣告合作
-
QQ群號:4114653