基于MCP协议的大语言模型能力调用实践——以动态修改网页背景为例

技术背景

MCP(Model Context Protocol)是由Anthropic于2024年提出的开放协议,其核心价值在于:

  1. 标准化接口:建立大语言模型与外部资源间的"USB式"通信规范
  2. 安全沙箱:通过权限控制确保模型操作的边界安全
  3. 语义理解:将自然语言转化为结构化指令的中间层协议

核心实现原理

系统架构

触发工具
用户输入
本地语义分析
调用LLM解析
JSON解析
执行工具函数

关键技术点

  • 双阶段验证机制:本地语义触发 + LLM精准解析
  • 动态权限管理:基于声明式权限的沙箱控制
  • 语义泛化能力:支持隐喻式表达(如"雨天"→#87CEEB)
关键要点
  • 研究表明,MCP(模型上下文协议)是一种开放协议,可通过提示词让大语言模型(LLM)输出符合要求的JSON代码,然后由本地解释器解析并执行功能。
  • 证据倾向于,调用LLM的能力主要用于解析用户自然语言,确定函数名和参数,例如从“喜欢雨天的颜色”解析为“犹豫的蓝色”并提供RGB颜色码。
  • 看起来可能在用户输入包含语义触发词(如“颜色”、“背景”)时调用LLM,结合本地策略分析是否需要调用。
  • 对于几十上百种工具函数,建议先通过本地分析语义匹配触发词,再由LLM进一步解析细节。

如何调用LLM修改网页背景

实现步骤

  1. 定义MCP服务:首先,定义工具函数,例如“set_background_color”,包括描述、参数(如颜色字符串)、语义触发词(如“颜色”、“背景”)和所需权限。
  2. 本地分析用户输入:通过检查用户输入是否包含触发词,确定是否需要调用LLM。例如,用户说“我喜欢雨天”,可能触发“颜色”相关工具。
  3. 调用LLM解析:将用户输入和工具信息发送给LLM,LLM输出JSON格式的函数调用代码,例如解析“我喜欢雨天”为“犹豫的蓝色”并提供RGB颜色码。
  4. 解析并执行:本地解释器解析JSON,执行对应函数,例如修改网页背景颜色。

一个意外的细节:即使不严格遵循MCP标准,自定义程序也能通过类似方式利用LLM能力,灵活性较高,但可能缺乏MCP的通用性和安全性。


详细调研报告

引言

模型上下文协议(MCP)是AI领域近年来的重要技术协议,尤其在提升大语言模型(LLM)与外部环境交互能力方面具有革新意义。Anthropic于2024年11月提出MCP,旨在建立LLM与外部数据源/工具之间的标准化接口,类似于AI领域的“USB协议”。它通过定义统一的通信规则,使大模型能安全调用本地或云端资源,例如读取文件、执行API调用、访问数据库等,从而突破传统LLM的“信息孤岛”局限。

本文将详细探讨如何利用MCP设计思路,在自己的程序中借助LLM能力修改网页背景,并分析调用时机和工具函数匹配策略。我们以AI心理咨询助理为例,展示一个实际案例。

MCP的核心机制

根据Anthropic的MCP公告官方文档,MCP采用客户端-服务器架构:

  • MCP主机:如聊天界面或IDE,需要访问外部数据或工具。
  • MCP服务器:轻量级程序,暴露特定功能,通过MCP标准与主机通信。
  • MCP客户端:主机内的组件,负责与服务器交互。

MCP的核心在于通过标准格式(如JSON)定义工具调用规则,LLM通过提示词输出符合格式的代码,本地解释器解析并执行。例如,LLM可从用户输入“喜欢雨天的颜色”解析为“犹豫的蓝色”,并生成RGB颜色码。

协议本质解析

与传统的大模型微调技术不同,MCP技术不需要修改大模型,仅通过调整提示词就可以达到控制本地程序行为的能力。

  • 传统微调方案:修改模型参数 → 适配特定任务
  • MCP方案:结构化Prompt → JSON指令 → 本地执行
案例分析:AI心理咨询助理修改聊天背景

假设我们设计一个AI心理咨询助理,功能包括根据用户需求修改聊天背景。交互场景如下:

  • AI助理:”在开始之前,你希望今天的对话空间是什么颜色的?暖黄色像咖啡馆的下午,还是薄荷绿像清晨的阳台?”
  • 用户回答:”我喜欢雨天。”
第一步:定义MCP服务

我们定义一个MCP服务,包含工具“set_background_color”:

let mcp_tools = {
  "mcp_protocol": "v1.2",
  "reverse_tools": [
    {
      "name": "set_background_color",
      "description": "设置界面背景颜色,支持CSS颜色名称或HEX值",
      "parameters": {
        "color": {
          "type": "string",
          "examples": ["blue", "#0000FF"]
        }
      },
      "semantic_triggers": [
        "颜色",
        "背景",
        "主题"
      ],
      "required_permissions": [
        "ui:modify_theme"
      ]
    }
  ],
  "context": {
    "user_preferences": {
      "favorite_colors": ["蓝色"]
    },
    "recent_actions": [
      {
        "action": "search",
        "query": "咖啡馆UI设计"
      }
    ]
  },
  "permissions": [
    "ui:modify_theme"
  ]
};

这里,工具定义了名称、描述、参数、触发词和权限,上下文包含用户偏好和近期动作,供LLM参考。

第二步:本地语义分析

通过本地策略分析用户输入,确定是否需要调用LLM。我们实现analyzematchTool函数:

analyze: function(userMessage) {
  const result = {
    isMatched: false,
    toolName: '',
    params: null,
    confidence: 0
  };
  
  for (const tool of mcp_tools.reverse_tools) {
    const matchResult = this.matchTool(tool, userMessage);
    if (matchResult.isMatched && matchResult.confidence > result.confidence) {
      result.isMatched = true;
      result.toolName = tool.name;
      result.params = matchResult.params;
      result.confidence = matchResult.confidence;
    }
  }
  
  return result;
},
matchTool: function(tool, userMessage) {
  const result = {
    isMatched: false,
    params: null,
    confidence: 0
  };

  const triggerMatches = tool.semantic_triggers.filter(trigger => 
    userMessage.includes(trigger)
  );

  if (triggerMatches.length > 0) {
    result.isMatched = true;
    result.confidence = triggerMatches.length / tool.semantic_triggers.length;
  }

  return result;
},

本地分析检查用户输入是否包含触发词(如“颜色”),计算置信度,决定是否调用LLM。

第三步:调用LLM解析参数

如果匹配成功,调用LLM进一步解析用户意图。例如,用户说“我喜欢雨天”,LLM可能输出JSON:

{
  "tool": "set_background_color",
  "parameters": {
    "color": "#87CEEB" // 解析为天蓝色
  }
}

实现如下:

queryMCP: function(toolName, userMessage) {
  var url = "/webapi/chat.aspx?user=MCP&client=" + code;
  var tool = mcp_tools.reverse_tools.find(t => t.name === toolName);
  if(null == tool) {
    console.log("工具不存在:", toolName);
    return;
  }
  var json = {
    "reverse_tools": [
      tool
    ],
    "messages": [
      {
        "role": "user",
        "content": userMessage
      }
    ]
  }
  var formData = new FormData();
  formData.append("text", JSON.stringify(json));
  $.ajax({
    url: url,
    type: "POST",
    data: formData,
    contentType: false,
    processData: false,
    dataType: "text",
    success: function(response) {
      console.log("response", response);
      MCPIntentAnalyzer.parseAndExecuteMCPResponse(response);
    },
    error: function(xhr, status, error) {
      console.error("发送MCP请求失败:", error);
    }
  });
},

这里通过HTTP POST请求发送数据,LLM返回JSON响应。

第四步:解析并执行

最后,解析LLM返回的JSON,执行对应函数:

parseAndExecuteMCPResponse: function (response) {
  try {
    const jsonMatch = response.match(/```json\n([\s\S]*?)\n```/);
    if (!jsonMatch) {
      console.log("没有找到JSON代码块");
      return false;
    }
    
    const toolCall = JSON.parse(jsonMatch[1]);
    
    if (!toolCall.tool || !toolCall.parameters) {
      console.log('工具调用格式无效');
      return false;
    }
    
    return this.executeTool(toolCall.tool, toolCall.parameters);
    
  } catch (error) {
    console.error('解析或执行工具调用时出错:', error);
    return false;
  }
},

executeTool: function(toolName, params) {
  const tool = mcp_tools.reverse_tools.find(t => t.name === toolName);
  if (!tool) return false;

  const hasPermission = tool.required_permissions.every(permission => 
    mcp_tools.permissions.includes(permission)
  );

  if (!hasPermission) {
    console.log('缺少所需权限:', tool.required_permissions);
    return false;
  }

  switch (toolName) {
    case 'set_background_color':
      if (params && params.color) {
        console.log("修改.myBox3的背景颜色", params.color);
        $('.myBox3').css('background-color', params.color);
        return true;
      }
      break;
  }

  return false;
}

这里提取JSON,验证格式后执行,例如修改.myBox3的背景颜色。

调用LLM的能力与时机

LLM能力:研究表明,LLM主要用于自然语言解析,输出函数调用名和参数。例如,从“我喜欢雨天”解析为“set_background_color”并提供颜色值(如RGB码)。这依赖LLM的语义理解和上下文推理能力。

调用时机:证据倾向于在以下两种情况下调用:

  1. 本地触发:用户输入包含语义触发词(如“颜色”),通过本地策略初步匹配。
  2. 复杂解析:本地无法直接确定参数时,调用LLM进一步分析。例如,“雨天的颜色”需LLM解析为具体颜色值。

对于几十上百种工具函数,建议策略如下:

  • 本地分析:先检查触发词,快速筛选可能工具。
  • LLM辅助:再由LLM分析语义,确定具体函数和参数。
不严格遵循MCP的灵活性

即使不严格遵循MCP标准,自定义程序也能利用LLM能力。这是因为MCP的核心机制(提示词+JSON解析)可独立实现。例如,上述案例中,我们仅需确保LLM输出格式正确,本地解释器能执行即可。但不遵循MCP可能失去通用性和安全性,建议在复杂场景下参考MCP标准。

讨论与挑战

MCP的潜在好处包括提高AI应用灵活性和用户体验,但也面临挑战:

  • 安全性:确保LLM访问外部资源时数据隐私,MCP通过权限检查解决,但需开发者正确实现。
  • 采用率:MCP的成功依赖社区接受度,当前GitHub仓库显示活跃开发,但行业广泛采用尚需时间。
结论

通过上述案例,我们看到MCP如何在AI应用中实现功能扩展,如修改网页背景。调用LLM的能力主要用于自然语言解析,时机可结合本地触发和复杂需求,工具函数匹配需本地筛选加LLM辅助。不严格遵循MCP虽灵活,但可能牺牲通用性,建议在复杂场景下参考标准。

实例代码
  // 定义MCP
  let mcp_tools = {
    "mcp_protocol": "v1.2",
    "reverse_tools": [
      {
        "name": "set_background_color",
        "description": "设置界面背景颜色,支持CSS颜色名称或HEX值",
        "parameters": {
          "color": {
            "type": "string",
            "examples": ["blue", "#0000FF"]
          }
        },
        "semantic_triggers": [
          "颜色",
          "背景",
          "主题"
        ],
        "required_permissions": [
          "ui:modify_theme"
        ]
      }
    ],
    "context": {
      "user_preferences": {
        "favorite_colors": [
          "蓝色"
        ]
      },
      "recent_actions": [
        {
          "action": "search",
          "query": "咖啡馆UI设计"
        }
      ]
    },
    "permissions": [
      "ui:modify_theme"
    ]
  }
  // 添加MCP语义识别相关函数
  const MCPIntentAnalyzer = {
    // 分析用户输入,返回意图和参数
    analyze: function(userMessage) {
      const result = {
        isMatched: false,
        toolName: '',
        params: null,
        confidence: 0
      };
      
      // 遍历所有工具检查是否匹配
      for (const tool of mcp_tools.reverse_tools) {
        const matchResult = this.matchTool(tool, userMessage);
        if (matchResult.isMatched && matchResult.confidence > result.confidence) {
          result.isMatched = true;
          result.toolName = tool.name;
          result.params = matchResult.params;
          result.confidence = matchResult.confidence;
        }
      }
      
      return result;
    },

    // 匹配具体工具
    matchTool: function(tool, userMessage) {
      const result = {
        isMatched: false,
        params: null, // 总是为空,我们不在本地分析参数,稍后调用LLM大模型进行分析
        confidence: 0
      };

      // 检查语义触发词
      const triggerMatches = tool.semantic_triggers.filter(trigger => 
        userMessage.includes(trigger) // 使用简单的关键词匹配
      );

      if (triggerMatches.length > 0) {
        result.isMatched = true;
        result.confidence = triggerMatches.length / tool.semantic_triggers.length;
      }

      return result;
    },

    // 调用MCP大模型
    queryMCP: function(toolName, userMessage) {
      // 调用大模型
      var url = "/webapi/chat.aspx?user=MCP&client=" + code;
      var tool = mcp_tools.reverse_tools.find(t => t.name === toolName);
      if(null == tool) {
        console.log("工具不存在:", toolName);
        return;
      }
      var json = {
        "reverse_tools": [
          tool
        ],
        "messages": [
          {
            "role": "user",
            "content": userMessage
          }
        ]
      }
      var formData = new FormData();
      formData.append("text", JSON.stringify(json));
      $.ajax({
        url: url,
        type: "POST",
        data: formData,
        contentType: false,
        processData: false,
        dataType: "text",
        success: function(response) {
          console.log("response", response);
          MCPIntentAnalyzer.parseAndExecuteMCPResponse(response);
        },
        error: function(xhr, status, error) {
          console.error("发送MCP请求失败:", error);
        }
      });
    },
      // 添加工具调用解析和执行函数
    parseAndExecuteMCPResponse: function (response) {
      try {
        // 提取JSON代码块
        const jsonMatch = response.match(/```json\n([\s\S]*?)\n```/);
        if (!jsonMatch) 
        {
          console.log("没有找到JSON代码块");
          return false;
        }
        
        // 解析JSON
        const toolCall = JSON.parse(jsonMatch[1]);
        
        // 验证工具调用格式
        if (!toolCall.tool || !toolCall.parameters) {
          console.log('工具调用格式无效');
          return false;
        }
        
        // 执行工具调用
        return this.executeTool(toolCall.tool, toolCall.parameters);
        
      } catch (error) {
        console.error('解析或执行工具调用时出错:', error);
        return false;
      }
    },

    // 执行工具
    executeTool: function(toolName, params) {
      // 检查权限
      const tool = mcp_tools.reverse_tools.find(t => t.name === toolName);
      if (!tool) return false;

      const hasPermission = tool.required_permissions.every(permission => 
        mcp_tools.permissions.includes(permission)
      );

      if (!hasPermission) {
        console.log('缺少所需权限:', tool.required_permissions);
        return false;
      }

      // 执行具体工具
      switch (toolName) {
        case 'set_background_color':
          if (params && params.color) {
            // 修改.myBox3的背景颜色
            console.log("修改.myBox2的背景颜色", params.color);
            $('.myBox3').css('background-color', params.color);
            return true;
          }
          break;
      }

      return false;
    }
  };
  // 用户对话时调用
  function sendUserMessage(message) {
    var lastText = "";
    if(messageList.length > 0) {
      lastText = messageList[messageList.length - 1].message;
      // 上下文结合分析语义
      const intentResult = MCPIntentAnalyzer.analyze(lastText + "\n" + message);
      console.log("intentResult", intentResult);
      if (intentResult.isMatched) {
        // 调用MCP大模型分析调用参数
        MCPIntentAnalyzer.queryMCP(intentResult.toolName, message);
      }
    }
    // 添加到消息列表
    messageList.push({
      message: message,
      type: "user"
    });
    // 正常调用对话大模型
   if (ws && ws.readyState === WebSocket.OPEN) {
     ws.send(message);
   }
  }

MCP大模型设置系统提示词

你是一个JavaScript环境下的MCP智能代理,请严格遵循以下规则:

# 可用工具
**dom_set_background**
- 功能:修改网页背景色
- 参数:{ color: "hex/css颜色值" }
- 示例:`dom_set_background({color: 'darkblue'})`
- 权限:dom:modify

# 操作规范
1. 所有DOM操作必须通过工具调用完成
2. 修改颜色时需考虑当前色彩模式({{viewport.colorScheme}}3. 超过5/分钟的操作需添加防抖处理

# 安全限制
- 禁止修改<header><footer>区域
- 颜色值必须通过正则校验:/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$|^[a-zA-Z]+$/

# 错误处理
- 网络超时:自动重试最多3- 权限不足:返回用户友好的提示语
- 参数错误:列出具体校验失败项

当前用户权限:[dom:read, dom:modify]
浏览器状态:1280x720 暗色模式 内存使用145MB

请根据用户请求选择合适工具并生成合规调用。
案例效果

上下文分析调用MCP
调用MCP大模型返回JSON代码

response 根据您的描述,您提到喜欢雨天,这让我联想到宁静的蓝色调。考虑到您的偏好和最近的搜索记录(咖啡馆UI设计),我建议将背景颜色设置为柔和的蓝色,以营造舒适的氛围。

我将使用 `set_background_color` 工具来执行此操作。

### 工具调用
json
{
  "tool": "set_background_color",
  "parameters": {
    "color": "#ADD8E6"
  }
}


这个颜色是浅蓝色,适合营造宁静的环境,并且符合您对雨天的喜好。如果您有任何其他偏好或需要调整,请告诉我!

执行本地代码修改背景颜色

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐