入门阅读约 2 分钟7 种语言

构建你的第一个 MCP 代码工具:一次调用获取 ERP 订单和 CRM 客户账户

AnythingMCP 代码模式分步教程:启动 code runner,开启代码模式,并保存一个代码工具,在一次工具调用中读取 ERP(weclapp)中的最近订单,以及 CRM(HubSpot)中的客户账户和未结商机。只读,使用调用者的权限,并记录审计日志。

HC作者:HelpCode 团队更新于 2 分钟阅读 在 GitHub 开源

无需信用卡 · 7 天试用 · 提供自托管方案

  • 7 天免费试用
    无需信用卡
  • 符合 GDPR,SOC 2 就绪
    数据驻留欧盟,审计日志
  • 在 GitHub 开源
    开源 · AGPL-3.0
  • 支持 ChatGPT、Claude、Gemini
    任何兼容 MCP 的客户端

摘要

AnythingMCP 代码模式分步教程:启动 code runner,开启代码模式,并保存一个代码工具,在一次工具调用中读取 ERP(weclapp)中的最近订单,以及 CRM(HubSpot)中的客户账户和未结商机。只读,使用调用者的权限,并记录审计日志。

TL;DR: 在客户电话之前,销售代表会让助手给出一份概览:ERP 中的最近订单,以及 CRM 中的客户负责人和未结商机。不使用代码模式时,这需要四五次工具调用,每次的结果都要由模型完整读取。使用已保存的代码工具则只需一次:customer_overview(customer) 会运行一小段 JavaScript 程序,由它发起调用、保留关键信息,并返回一份精简的摘要。本教程在自托管的 AnythingMCP(v0.52.1 或更高版本)上构建这个工具,以 weclapp 作为 ERP、HubSpot 作为 CRM;同样的模式适用于任意两个连接器。

你需要准备什么

  • 自托管的 AnythingMCP v0.52.1 或更高版本。 代码模式即将登陆 AnythingMCP Cloud。
  • 两个带有读取工具的连接器,这里是 weclapp 和 HubSpot,需已安装并能正常工作。
  • 工作区中的管理员权限。

刚接触这个概念?什么是 MCP 代码模式?解释了为什么一个程序胜过多次工具调用。

步骤 1 — 启动 code runner

代码绝不会在 AnythingMCP 自身内部运行,而是在单独的 code-runner 容器中运行;没有它,所有代码运行都会被拒绝。在你的 .env 中添加:

COMPOSE_PROFILES=code-runner
CODE_RUNNER_URL=ws://code-runner:8777

如果你已经在使用 profile,请将它们一并列出,例如 COMPOSE_PROFILES=files,code-runner。然后执行:

docker compose up -d

runner 不保存任何密钥,不发布任何端口,也无法访问互联网;只有后端会通过内部 Docker 网络与它通信。它如何隔离每次运行:AI 智能体的安全代码执行。

步骤 2 — 为 MCP 服务器开启代码模式

代码模式默认对每个 MCP 服务器关闭,在代码模式为 off 的服务器上,已保存的代码工具会被拒绝。请将你的销售团队所使用服务器的代码模式设置为 tools(仅限已保存的代码工具)。inline 还会额外向智能体提供 code_execute 和 code_propose_tool;本教程不需要它。

在控制面板中打开 MCP Servers,再打开该服务器。在顶部的 Server settings 卡片中,将 Code mode 设为 Saved code tools only,然后点击 Save。之后重新连接 AI 客户端。

更喜欢用 API?向 PUT /api/mcp-servers/<id> 发送 {"codeMode": "tools"} 效果相同。该设置从 v0.52.1 开始提供;如果是 v0.52.0,请先升级。

步骤 3 — 记下两个连接器的 id

代码工具需要声明其程序可以调用哪些连接器。在控制面板中打开每个连接器:它的 id 是地址的最后一部分,即 /connectors/<id>。复制 weclapp 和 HubSpot 连接器的 id。

步骤 4 — 创建代码工具

打开 weclapp 连接器,进入 MCP Tools,点击 Add Tool。将 Tool Type 设置为 Code Tool,然后填写:

  • Tool Name: customer_overview
  • Description: "通话前的单个客户概览:ERP 中的最近 10 个订单、CRM 客户账户及其未结商机。传入公司名称或名称的一部分。" 描述是 AI 用来判断何时调用该工具的依据,所以要写明它返回什么。
  • Input Parameters: 一个参数 customer,类型为 string,必填。
anythingmcp.internal/connectors
名为 Accounting 的连接器的 Edit Tool 表单:工具名称 revenue_by_month,Tool Type 为 Code Tool,Program 字段中是调用 amcp.run 的 JavaScript,Uses (connectors) 的 JSON 中包含 connectorId,Run as 为 Invoker(调用者自己的权限),Allow write tools 复选框未勾选,以及 Input Parameters
Tool Type 为 Code Tool 的工具编辑器,这里是演示工作区中的另一个示例工具(revenue_by_month)。Program、Uses、Run as 和 Allow write tools 是本教程要填写的字段。

步骤 5 — 编写程序

Program 是一个异步 JavaScript 函数的函数体。工具的输入在 args 中;amcp.run(name, args) 调用另一个工具,并以解析后的 JSON 返回其结果(如果工具失败则抛出异常)。你 return 的内容就是 AI 收到的内容。

// Input: args.customer, a company name or part of it.
const name = String(args.customer ?? '').trim();
if (!name) return { error: 'Pass a customer name.' };

// ERP (weclapp): the customer, then its latest sales orders.
const parties = await amcp.run('weclapp_list_customers', {
  filter: `company-ilike=%${name}%`,
  pageSize: 5,
});
const customer = (parties.result ?? [])[0];
if (!customer) return { error: `No customer matching "${name}" in the ERP.` };

const orders = await amcp.run('weclapp_list_sales_orders', {
  filter: `customerId-eq=${customer.id}`,
  sort: '-orderDate',
  pageSize: 10,
});

// CRM (HubSpot): the company record and its open deals.
const companies = await amcp.run('hubspot_search_objects', {
  object_type: 'companies',
  query: customer.company,
  properties: ['name', 'domain', 'hubspot_owner_id', 'lifecyclestage'],
  limit: 1,
});
const company = companies.results?.[0];

let deals = [];
if (company) {
  const found = await amcp.run('hubspot_search_objects', {
    object_type: 'deals',
    filter_groups: [{ filters: [
      { propertyName: 'associations.company', operator: 'EQ', value: company.id },
      { propertyName: 'hs_is_closed', operator: 'EQ', value: 'false' },
    ] }],
    properties: ['dealname', 'amount', 'dealstage', 'closedate'],
    limit: 20,
  });
  deals = found.results ?? [];
}

// Only this goes back to the model.
return {
  customer: { number: customer.customerNumber, name: customer.company },
  lastOrders: (orders.result ?? []).map((o) => ({
    number: o.orderNumber, date: o.orderDate, status: o.status, net: o.netAmount,
  })),
  crm: company
    ? { owner: company.properties.hubspot_owner_id, stage: company.properties.lifecyclestage }
    : null,
  openDeals: deals.map((d) => ({
    name: d.properties.dealname, amount: d.properties.amount,
    stage: d.properties.dealstage, close: d.properties.closedate,
  })),
};

字段名是 weclapp 和 HubSpot API 返回的字段名。在依赖某个字段之前,先在其 Test 面板中运行一次底层工具并查看结果;在程序内部,await amcp.describe('weclapp_list_sales_orders') 会返回某个工具的输入 schema。

关于关联匹配的说明。 该程序按名称匹配 CRM 公司,对于会前简报来说已经足够。如果你把 ERP 客户编号存储在了 HubSpot 属性中,请改为按该属性过滤,这样匹配就是精确的。

步骤 6 — 声明程序可以使用什么

Uses (connectors) 列出程序可以调用的连接器,以及(可选的)确切的工具。粘贴步骤 3 中的两个 id:

[
  { "connectorId": "<weclapp connector id>", "tools": ["weclapp_list_customers", "weclapp_list_sales_orders"] },
  { "connectorId": "<hubspot connector id>", "tools": ["hubspot_search_objects"] }
]

指定工具是可选的(不写 "tools" 则允许整个连接器),但列出一份简短的清单能让该工具更易于审查。只接受同一工作区的连接器。即使用户可以直接调用某个工具,只要它不在这份清单中,调用就会失败并报错。

步骤 7 — 以调用者身份运行,只读

  • Run as: Invoker(调用者自己的权限)。 每一次内部调用都会根据使用该工具的人的角色进行检查。没有 HubSpot 访问权限的销售代表,在 HubSpot 部分会收到错误,就像他们直接调用 HubSpot 一样。(Definer 则按作者的授权范围运行,类似存储过程;它面向管理员和 Enterprise 版。)
  • Allow write tools: 关闭。 此时程序只能调用只读工具;weclapp_list_* 和 hubspot_search_objects 都是读取工具。允许写入的代码工具需要 Enterprise 版。

点击 Create Tool。

步骤 8 — 在 Claude 或 ChatGPT 中试用

先在控制面板中用该工具的 Test 按钮检查程序:它会在 code runner 中运行代码,规则与真实调用相同。然后再从连接到该 MCP 服务器的 AI 客户端进行测试。该工具在每个带有 weclapp 连接器且已开启代码模式的服务器上都可用。在你的 AI 客户端中重新连接或刷新工具,然后提问:

"我十分钟后要给 Lindenhof Bau 打电话。他们最近订了什么,谁负责这个客户账户,有没有未结商机?"

助手只调用一次 customer_overview,并根据精简的结果撰写简报,而不是去读取完整的订单列表和 CRM 记录。如果出了问题,工具结果会说明原因:调用了 Uses 之外的工具('hubspot_search_objects' is not a tool this code tool can use)、API 返回了错误,或者超时。修复程序、保存,然后再问一次。

每次调用时会发生什么

  • 一次运行,一条记录。 工具的每次调用都会记录为一次代码运行,程序发起的每个工具调用也都会像其他调用一样,连同用户一起记入审计日志。
  • 限制。 一次运行最长 10 秒,最多发起 500 次工具调用(同时最多 16 个),最多返回 1 MB。超出限制的程序会以清晰的错误停止,且不影响其他任何内容。
  • 不可嵌套。 代码工具不能调用另一个代码工具。
  • 仅限你自己的服务器。 代码工具只在工作区自己的 MCP 服务器上提供,绝不会出现在共享的 /mcp 端点上。

套餐

各版本可保存的代码工具数量,以 v0.52 发布时公布的为准:Community 3 个,Starter 5 个,Team 20 个,Enterprise 不限。允许写入的代码工具和"以 definer 身份运行"属于 Enterprise 版。比较套餐。

FAQ

我需要懂 JavaScript 吗? 掌握基础的 JavaScript 就够了:await、对象、map 和 filter。你也可以让智能体起草程序,并将其作为工具提议,交由你审查。

程序可以直接调用外部 API 吗? 不可以。它没有网络访问权限,只能调用 Uses 中列出的 MCP 工具;要访问其他 API,请先将其添加为连接器。

代码工具应该放在哪个连接器上? 放在它所用到的任意一个连接器上都可以;该连接器被分配到哪里,工具就会出现在哪里。请选择其受众应该获得该工具的那个连接器。

相关内容

这份指南对你有帮助吗?

60 秒内把 MCP 接入你的技术栈。

在托管云上启动 AnythingMCP,或在你自己的基础设施上自托管。免费试用 7 天,无需信用卡。

相关指南

GS
入门

代码模式:通过一步运行工具削减 AI 智能体的 token 用量

代码模式让 AI 智能体运行一段简短程序,在一次调用中编排多个 MCP 工具,而不必对每个工具都往返一次。筛选和关联都在锁定的沙箱中完成,因此只返回最终结果——在数据密集型工作流中可将 token 用量最多降低 90–99%。

GS
入门

MCP 代码模式实战:一次调用完成月度营收统计、发票对账和 100 次价格查询

AnythingMCP 的三个实用代码模式程序:汇总网店(Shopify)与财务系统(Lexware Office)的月度营收、将订单与发票对账,以及一次工具调用完成 100 次客户价格查询,而不是调用 100 次。包含代码、需要注意的关键限制,以及何时把程序保存为工具。

GS
入门

什么是 MCP 代码模式?为 AI 智能体减少 token 消耗与往返次数

代码模式让 AI 智能体运行一段调用多个 MCP 工具的简短程序,而不是通过模型逐个调用这些工具。本文介绍为什么这样可以节省 token 和往返次数、何时有用、何时没用,以及 AnythingMCP 如何在隔离的运行器中提供三种形式:已保存的代码工具、内联代码和智能体提案。

GS
入门

MCP 知识图谱:一个会学习你的系统如何关联的连接器

AnythingMCP 不只是 MCP 代理——它会为你的工具构建一张知识图谱,让 AI 智能体知道如何把 CRM 里的客户串联到 ERP 里的订单。下面看看这个智能连接器如何工作。

GS
入门

模型上下文协议 (MCP) 是什么?

全面了解模型上下文协议的指南 — 它是如何工作的,为什么重要,以及如何开始使用。

GS
入门

开始使用 AnythingMCP

在几分钟内安装和配置 AnythingMCP。克隆代码库,运行交互式设置脚本,并开始将你的 API 连接到 AI 代理。