一个基于MCP(模型上下文协议)的服务器,通过Twilio API实现代理辅助支付功能,并具有增强的异步回调功能和通过上下文提示引导的工作流程。
你可以通过npx直接使用此服务器:
npx twilio-agent-payments-mcp-server <accountSid> <apiKey> <apiSecret>
或者全局安装:
npm install -g twilio-agent-payments-mcp-server
twilio-agent-payments-mcp-server <accountSid> <apiKey> <apiSecret>
在安装服务器时,需要提供以下参数:
命令行参数(必需):
accountSid:你的Twilio账户SIDapiKey:你的Twilio API密钥apiSecret:你的Twilio API密钥密码环境变量(在运行服务器之前设置):
TOKEN_TYPE:用于支付的令牌类型(例如,'可重复使用的','一次性')CURRENCY:支付货币(例如,'USD','EUR')PAYMENT_CONNECTOR:与Twilio一起使用的支付连接器NGROK_AUTH_TOKEN:你的Ngrok认证令牌(用于回调处理)NGROK_CUSTOM_DOMAIN:Ngrok的可选自定义域名示例环境变量:
TOKEN_TYPE=reusable CURRENCY=USD PAYMENT_CONNECTOR=your_connector NGROK_AUTH_TOKEN=your_token npx twilio-agent-payments-mcp-server <accountSid> <apiKey> <apiSecret>
有关这些参数的详细信息,请参阅下面的配置部分。
服务器需要以下参数:
accountSid:你的Twilio账户SID(必须以'AC'开头,将被验证)apiKey:你的Twilio API密钥(以'SK'开头)apiSecret:你的Twilio API密钥密码以下环境变量用于配置:
TOKEN_TYPE:用于支付的令牌类型(例如,'可重复使用的','一次性')CURRENCY:支付货币(例如,'USD','EUR')PAYMENT_CONNECTOR:与Twilio一起使用的支付连接器NGROK_AUTH_TOKEN:你的Ngrok认证令牌(用于回调处理)NGROK_CUSTOM_DOMAIN:Ngrok的可选自定义域名注意:Twilio凭证(accountSid,apiKey,apiSecret)作为命令行参数提供,而不是环境变量。
此服务器使用API密钥和密码而不是认证令牌来提高安全性。这种方法提供了更好的访问控制,并且可以在需要时撤销凭证。更多信息,请参阅Twilio API密钥文档。
对于本地开发(当包尚未发布到npm时),在你的Claude Desktop配置文件中添加以下内容(macOS上的路径为~/Library/Application Support/Claude/claude_desktop_config.json或Windows上的%APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"twilio-agent-payments": {
"command": "node",
"args": [
"/PATHTONODE/twilio-agent-payments-mcp-server/build/index.js",
"your_account_sid_here",
"your_api_key_here",
"your_api_secret_here"
],
"env": {
"TOKEN_TYPE": "reusable",
"CURRENCY": "USD",
"PAYMENT_CONNECTOR": "your_connector_name",
"NGROK_AUTH_TOKEN": "your_ngrok_auth_token_here",
"NGROK_CUSTOM_DOMAIN": "your_custom_domain_here" // 可选
}
}
}
}
用你的实际Twilio凭证和配置替换值。
一旦包发布到npm,你可以使用以下配置:
{
"mcpServers": {
"twilio-agent-payments": {
"command": "npx",
"args": [
"-y",
"twilio-agent-payments-mcp-server",
"your_account_sid_here",
"your_api_key_here",
"your_api_secret_here"
],
"env": {
...process.env, // 包含现有的环境变量,以便子进程可以访问路径
"TOKEN_TYPE": "reusable",
"CURRENCY": "USD",
"PAYMENT_CONNECTOR": "your_connector_name",
"NGROK_AUTH_TOKEN": "your_ngrok_auth_token_here",
"NGROK_CUSTOM_DOMAIN": "your_custom_domain_here" // 可选
}
}
}
}
MCP(模型上下文协议)的一个关键优势是它消除了对LLM上下文中大量手动配置的需求。MCP服务器会自动向LLM客户端提供所有必要的工具定义、资源模板和能力。
要将此MCP服务器集成到自己的主机应用程序中:
无需在LLM上下文中手动定义工具或资源——MCP协议会自动处理这一发现过程。
这里是一个简化了的例子,展示如何与MCP客户端集成:
// 初始化你的MCP客户端
const mcpClient = new McpClient();
// 连接到Twilio Agent Payments MCP服务器
await mcpClient.connectToServer({
name: "twilio-agent-payments",
// 连接详情取决于你的具体MCP客户端实现
// 这可能是WebSocket URL、stdio连接或其他传输方式
});
// 客户端将自动发现可用的工具和资源
// 当LLM想要使用一个工具时,你的应用程序可以这样处理:
function handleLlmToolRequest(toolRequest) {
// toolRequest包含:
// - server_name: "twilio-agent-payments"
// - tool_name: 例如,"startPaymentCapture"
// - arguments: 例如,{ callSid: "CA1234567890abcdef" }
return mcpClient.callTool(toolRequest);
}
// 同样适用于资源:
function handleLlmResourceRequest(resourceRequest) {
// resourceRequest包含:
// - server_name: "twilio-agent-payments"
// - uri: 例如,"payment://CA1234567890abcdef/PA9876543210abcdef/status"
return mcpClient.accessResource(resourceRequest);
}
LLM只需要知道它可以使用Twilio Agent Payments MCP服务器来处理支付。系统提示中的简单指令就足够了:
你有一个Twilio Agent Payments MCP服务器,可以帮助你在语音通话期间处理安全支付。
当客户想要付款时,你可以使用该服务器提供的工具来安全地捕获支付信息,同时保持PCI合规性。
服务器将在支付流程的每一步通过上下文提示引导你。
MCP服务器本身提供了所有详细的工具定义、输入模式和上下文提示,以引导LLM完成支付流程。
本节解释了MCP服务器实现是如何跨不同组件和文件组织的,重点在于所使用的架构模式。
服务器实现分布在几个目录中:
src/index.ts:主要入口点,负责:
src/tools/:包含单独的工具实现
src/prompts/:包含提示实现
src/resources/:包含资源实现
src/api-servers/:包含Twilio API客户端的实现
src/utils/:包含实用函数
此代码库中的一个重要架构模式是TwilioAgentPaymentServer的单例模式:
class TwilioAgentPaymentServer extends EventEmitter {
// 单例实例
private static instance: TwilioAgentPaymentServer | null = null;
/**
* 获取实例的静态方法
*/
public static getInstance(): TwilioAgentPaymentServer {
if (!TwilioAgentPaymentServer.instance) {
throw new Error('TwilioAgentPaymentServer未初始化。请先调用initialize()。');
}
return TwilioAgentPaymentServer.instance;
}
/**
* 初始化实例的静态方法
*/
public static initialize(accountSid: string, apiKey: string, apiSecret: string): TwilioAgentPaymentServer {
if (!TwilioAgentPaymentServer.instance) {
TwilioAgentPaymentServer.instance = new TwilioAgentPaymentServer(accountSid, apiKey, api_密钥);
}
return TwilioAgentPaymentServer.instance;
}
// 私有构造函数以防止直接实例化
private constructor(accountSid: string, apiKey: string, apiSecret: string) {
// 初始化代码...
}
}
这种方法的好处:
工具、提示和资源使用工厂函数模式实现:
在工具中:
// 来自StartPaymentCaptureTool.ts的示例
export function startPaymentCaptureTool() {
// 获取TwilioAgentPaymentServer实例
const twilioAgentPaymentServer = TwilioAgentPaymentServer.getInstance();
// 创建用于日志记录的事件发射器
const emitter = new EventEmitter();
return {
name: "startPaymentCapture",
description: "开始新的支付捕获会话",
shape: schema.shape,
execute: async function execute(params: z.infer<typeof schema>, extra: any): Promise<ToolResult> {
// 实现调用Twilio API并返回结果
},
emitter // 用于附加事件监听器
}
}
在资源中:
// 来自PaymentStatusResource.ts的示例
export function paymentStatusResource() {
// 获取TwilioAgentPaymentServer实例
const twilioAgentPaymentServer = TwilioAgentPaymentServer.getInstance();
// 创建用于日志记录的事件发射器
const emitter = new EventEmitter();
return {
name: "PaymentStatus",
template: new ResourceTemplate("payment://{callSid}/{paymentSid}/status", { list: undefined }),
description: "获取支付会话的当前状态",
read: async (uri: URL, variables: Record<string, string | string[]>, extra: any): Promise<ResourceReadResult> => {
// 实现检索并格式化支付状态数据
},
emitter // 用于附加事件监听器
};
}
在提示中:
// 来自提示工厂函数的示例
export function startCapturePrompt() {
return {
name: "StartCapture",
description: "启动支付捕获过程的提示",
execute: (args: { callSid: string }, extra: RequestHandlerExtra): GetPromptResult | Promise<GetPromptResult> => {
// 返回提示内容
}
};
}
服务器使用自动发现机制来查找和注册所有组件:
// 在src/utils/autoDiscovery.ts中
export async function discoverComponents(mcpServer: McpServer) {
// 获取当前目录路径
const basePath: string = path.dirname(fileURLToPath(import.meta.url));
await Promise.all([
discoverTools(mcpServer, path.join(basePath, '../tools')),
discoverPrompts(mcpServer, path.join(basePath, '../prompts')),
discoverResources(mcpServer, path.join(basePath, '../resources'))
]);
}
这种方法:
某些提示接受参数,可用于定制提示内容。StartCapturePrompt是一个很好的例子:
参数定义:
// 在提示工厂函数中
return {
name: "StartCapture",
description: "启动支付捕获过程的提示",
schema: { callSid: z.string().describe("Twilio呼叫SID") }, // 参数模式
execute: (args: { callSid: string }, extra: RequestHandlerExtra) => {
// 实现
}
};
callSid参数在提示中使用参数:
execute: (args: { callSid: string }, extra: RequestHandlerExtra): GetPromptResult | Promise<GetPromptResult> => {
const { callSid } = args;
if (!callSid) {
throw new Error("需要提供callSid参数");
}
return {
messages: [
{
role: "assistant",
content: {
type: "text",
text: getStartCapturePromptText(callSid), // 在提示文本中使用参数
}
}
]
};
}
这种模式允许提示动态和上下文化,根据支付流程的当前状态提供量身定制的指导。
启动活动呼叫的支付捕获过程。
参数:
callSid:活动呼叫的Twilio呼叫SID重要:StartCapturePrompt.ts要求用户从MCP客户端侧输入一个呼叫SID。这是一个必需参数,如果未提供,提示将抛出错误。
注意:在处理Twilio呼叫时,你需要了解正在工作的呼叫腿的呼叫SID。Twilio支付需要附着到PSTN侧的呼叫腿。如果应用于Twilio客户端侧,DTMF数字将不会被捕获。因此,这个MCP服务器假设正在使用正确的呼叫腿。通常检查如下:
// 呼叫方向的伪代码
if (event.CallDirection === "toPSTN") {
theCallSid = event.CallSid;
}
if (event.CallDirection == "toSIP") {
theCallSid = event.ParentCallSid;
}
返回:
paymentSid:新支付会话的Twilio支付SID开始捕获支付卡号。
参数:
callSid:活动呼叫的Twilio呼叫SIDpaymentSid:支付会话的Twilio支付SIDcaptureType:设置为'payment-card-number'返回:
开始捕获卡片的安全码。
参数:
callSid:活动呼叫的Twilio呼叫SIDpaymentSid:支付会话的Twilio支付SIDcaptureType:设置为'security-code'返回:
开始捕获卡片的过期日期。
参数:
callSid:活动呼叫的Twilio呼叫SIDpaymentSid:支付会话的Twilio支付SIDcaptureType:设置为'expiration-date'返回:
完成支付捕获会话。
参数:
callSid:活动呼叫的Twilio呼叫SIDpaymentSid:支付会话的Twilio支付SID返回:
以JSON对象形式获取支付会话的当前状态。此资源提供了关于支付捕获过程当前状态的详细信息,包括: