CRM工具转换服务

一个无状态的Node.js服务,实现模型上下文协议(MCP),将Ontraport CRM功能作为结构化工具暴露给任何兼容MCP的AI代理。

  • by landonray
  • JavaScript
  • 本地部署
  • 更新于
在 GitHub 查看 landonray/Mcp-server

使用说明

Ontraport MCP服务器

一个无状态的Node.js服务,实现了 模型上下文协议(MCP) 将Ontraport CRM功能作为结构化工具公开,可供任何兼容MCP的AI代理使用。

服务器是 翻译层。它接收来自AI代理的工具调用,根据Ontraport API凭据对其进行身份验证,将其转换为适当的Ontraport REST API调用,清除响应,并返回结构化结果。它不包含自己的业务逻辑。


目录


建筑

┌─────────────────┐       ┌──────────────────────────┐       ┌──────────────────┐
│                 │       │   Ontraport MCP Server   │       │                  │
│   AI Agent      │──────▶│                          │──────▶│  Ontraport API   │
│  (any MCP       │  POST │  1. Validate auth        │  HTTP │                  │
│   compatible)   │  /v1  │  2. Route JSON-RPC       │       │  api.ontraport   │
│                 │◀──────│  3. Translate to REST     │◀──────│  .com/1/...      │
│                 │       │  4. Clean response        │       │                  │
└─────────────────┘       └──────────────────────────┘       └──────────────────┘

关键属性:

  • 基于官方MCP SDK构建 --用途 @modelcontextprotocol/sdk 和 StreamableHTTPServerTransport 用于协议兼容的传输和会话管理。
  • 无状态 --没有数据库,没有持久会话存储,没有缓存。整个州都住在昂特拉波特。内存会话仅跟踪MCP传输生命周期。
  • 完整MCP端点 — POST /v1 对于请求, GET /v1 对于SSE通知流, DELETE /v1 用于会话终止。加 GET /v1/health 用于监测。
  • 每会话隔离 --每个代理连接都有自己的 Server + Transport 这对搭档只查看了自己的凭据。无跨会话状态泄漏。
  • 动态清单 --工具列表在每次生成时都是新的 tools/list 通过查询Ontraport帐户的对象元数据来调用。
  • 凭证传递 --服务器转发 Api-Key 和 Api-Appid 头直接发送到Ontraport API。它从不存储、缓存或记录凭据。

入门指南

先决条件

  • Node.js 18+(使用原生 fetch)

安装并运行

npm install
npm start

默认情况下,服务器在端口3000上启动。设置 PORT 环境变量来改变它。

健康检查

curl http://localhost:3000/v1/health
# {"status":"ok"}

此端点不需要身份验证,用于正常运行时间监控。

快速测试--初始化

curl -X POST http://localhost:3000/v1 \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Api-Key: YOUR_API_KEY" \
  -H "Api-Appid: YOUR_APP_ID" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","clientInfo":{"name":"test","version":"1.0"},"capabilities":{}}}'

答复:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "serverInfo": { "name": "ontraport-mcp-server", "version": "1.0.0" },
    "capabilities": { "tools": {} }
  }
}

认证

每一个请求 POST /v1 必须包含两个HTTP标头:

标题 类型 必填 描述
Api-Key string Yes Ontraport帐户的API密钥,作用域为所需权限。
Api-Appid string 是 Ontraport帐户的唯一应用程序ID

如果任一标头丢失,服务器将在进行任何下游调用之前用HTTP 401进行响应。

服务器在每次调用时都会将这些凭据直接传递给Ontraport API。权限范围由Ontraport现有的API密钥范围系统强制执行-如果密钥缺少所需的范围,则Ontraport API会返回错误,MCP服务器会干净地显示它。


运作原理

请求的生命周期

每个请求都遵循相同的路径:

Agent sends JSON-RPC request to POST /v1
  ↓
Express validates Api-Key + Api-Appid headers (401 if missing)
  ↓
Looks up or creates a session (Server + StreamableHTTPServerTransport pair)
  ↓
SDK handles JSON-RPC framing, protocol negotiation, and method routing:
  • initialize     → returns server info + capabilities (handled by SDK)
  • tools/list     → our handler builds dynamic manifest via /objects/meta
  • tools/call     → our handler dispatches to tool implementation
  ↓
Tool handler:
  1. Validates input parameters
  2. Constructs Ontraport API request
  3. Executes via OntraportClient with provided credentials
  4. Cleans response (strips noise fields)
  5. Returns structured result

SDK的 StreamableHTTPServerTransport 处理完整的MCP流式HTTP规范,包括会话管理(Mcp-Session-Id header),服务器通知的SSE流(GET /v1),以及会话终止(DELETE /v1).

动态清单生成

并非所有Ontraport帐户都有相同的对象。客户可以创建自定义对象,每个对象都有自己的API端点和唯一的对象类型ID。因此,工具清单不能是静态的。

当代理人来电时 tools/list,服务器:

  1. 呼叫 GET /objects/meta 在Ontraport API上使用代理的凭据
  2. 标识自定义对象(不在内置对象类型ID列表中的任何对象)
  3. 为每个自定义对象生成4个工具定义(get_, create_, update_, search_)
  4. 将48个静态工具与动态生成的自定义对象工具合并
  5. 强制执行100个工具清单上限(请参见 舱单尺寸保护)
  6. 返回完整的工具列表

清单是 从未缓存.每一个 tools/list 通话引发新的 /objects/meta 请求,以便清单始终反映帐户的当前状态。

如果 /objects/meta 调用失败(凭据错误、Ontraport中断),服务器返回MCP错误——它从不返回部分清单。

工具执行

当代理人来电时 tools/call,服务器:

  1. 在静态处理程序注册表中查找工具名称
  2. 如果未找到,则检查名称是否与自定义对象模式匹配(get_X, create_X, update_X, search_X)
  3. 对于自定义对象工具,调用 /objects/meta 动态解析对象的类型ID——这意味着 tools/call 独立于任何先前的作品 tools/list 呼叫
  4. 执行处理程序,该处理程序将工具参数转换为适当的Ontraport REST API调用
  5. 清除响应并以MCP内容格式返回

这个设计完全 无状态 --没有全局可变状态,两者之间没有依赖关系 tools/list 和 tools/call,并且来自不同帐户的并发请求是安全的。

响应清洁

在将Ontraport API响应返回给代理之前,服务器将删除添加无值噪声的字段:

  • system_source
  • source_location
  • import_id
  • bindex
  • ip_addy (已弃用)
  • ip_addy_display
  • contact_cat (已弃用)
  • updateSequence (已弃用)
  • updateCampaign (已弃用)
  • account_id (代理已经知道它连接到哪个帐户)

对嵌套对象和数组进行递归清理。


项目结构

src/
├── index.js                        # Express app: auth, session management, HTTP routing
├── errors.js                       # Structured error builders (400–500 taxonomy)
├── mcp/
│   └── server.js                   # MCP Server factory: creates per-session Server instances
│                                   #   with tools/list and tools/call handlers registered
├── manifest/
│   ├── static-tools.js             # All 42 static tool definitions (single source of truth)
│   ├── custom-object-tools.js      # Generates 4 tools per custom object
│   ├── builder.js                  # Merges static + dynamic tools, enforces 100-tool cap
│   └── builder-constants.js        # Built-in object type IDs (shared constant)
├── ontraport/
│   ├── client.js                   # HTTP client for the Ontraport REST API
│   └── response-cleaner.js         # Strips noise fields from API responses
└── tools/
    ├── registry.js                 # Tool name → handler dispatch (static + dynamic resolution)
    ├── contacts.js                 # 7 contact tools
    ├── tags.js                     # 6 tag tools
    ├── sequences.js                # 4 sequence/campaign tools
    ├── tasks.js                    # 5 task tools
    ├── notes.js                    # 2 note tools
    ├── messages.js                 # 2 message tools
    ├── purchases.js                # 5 purchase/order read tools
    ├── transactions.js             # 13 transaction write tools
    ├── products.js                 # 2 product tools
    ├── custom-objects.js           # Generic CRUD handlers for custom objects
    └── metadata.js                 # 2 metadata/discovery tools

test/
├── health.test.js                  # Health endpoint
├── auth.test.js                    # Authentication validation (SDK transport)
├── mcp-server.test.js              # MCP Server factory
├── error-handling.test.js          # Error taxonomy
├── response-cleaner.test.js        # Response cleaning
├── manifest.test.js                # Manifest generation, cap, truncation
└── tools/
    ├── contacts.test.js
    ├── tags.test.js
    ├── sequences.test.js
    ├── tasks.test.js
    ├── notes.test.js
    ├── messages.test.js
    ├── purchases.test.js
    ├── transactions.test.js
    ├── products.test.js
    ├── custom-objects.test.js
    └── metadata.test.js

设计原则

  • 单一真相来源 --所有工具定义(名称、描述、输入模式)都存在于 static-tools.js。清单、输入验证和处理程序调度都来自这个文件。
  • 一种模式 -每个工具处理程序都遵循相同的形状:验证输入,构造Ontraport API调用,执行它,返回结果。错误处理由客户端和传输层处理。
  • 没有重复就没有抽象 --每个工具模块都是一组导出的异步函数。没有基类,没有中间件链,除了Express和MCP SDK之外没有框架。

工具参考

联系人(7个工具)

工具 描述 API端点
get_contact 通过ID或电子邮件检索单个联系人。 GET /Contact 或 GET /object/getByEmail
search_contacts 按条件、标签或自由文本搜索联系人。分页(最多50个)。 GET /Contacts
create_contact 创建新联系人。允许重复的电子邮件。 POST /Contacts
merge_or_create_contact 通过电子邮件查找并更新,如果找不到,则创建。使用代理最安全。 POST /Contacts/saveorupdate
update_contact 按ID更新现有联系人的字段 PUT /Contacts
delete_contact 永久删除联系人。无法撤消。 DELETE /Contact
get_contact_count 获取匹配的联系人总数,而不返回记录。 GET /Contacts/getInfo

标签(6工具)

工具 描述 API端点
add_tag_by_name 按名称应用标签。自动创建不存在的标签。 PUT /objects/tagByName
remove_tag_by_name 按名称删除标签。默默地忽略不存在的标签。 DELETE /objects/tagByName
add_tag_by_id 按ID应用标签 PUT /objects/tag
remove_tag_by_id 按ID删除标签 DELETE /objects/tag
get_contacts_by_tag 获取具有特定标签的联系人(按姓名或ID)。 GET /objects/tag
list_tags 列出帐户中的所有标签。 GET /Tags

序列和活动(4个工具)

工具 描述 API端点
subscribe_to_sequence 在序列或活动中注册联系人。 PUT /objects/subscribe
unsubscribe_from_sequence 从序列或活动中删除联系人。 DELETE /objects/subscribe
pause_rules_and_sequences 暂停联系人的所有自动化操作。 POST /objects/pause
unpause_rules_and_sequences 恢复暂停的自动化。 POST /objects/unpause

任务(5个工具)

工具 描述 API端点
assign_task 从消息模板创建和分配任务。 POST /task/assign
complete_task 将任务标记为已完成,并带有可选结果。 POST /task/complete
cancel_task 取消任务(状态2,不再可操作)。 POST /task/cancel
update_task 更新受让人、到期日或状态。 PUT /Tasks
get_tasks 使用可选筛选检索任务 GET /Tasks

注释(2个工具)

工具 描述 API端点
create_note 创建一个附加到联系人记录的注释。 POST /objects (对象ID=12)
get_notes 检索笔记,可选择按联系人筛选。 GET /objects (对象ID=12)

消息(2个工具)

工具 描述 API端点
get_messages 列出可用的电子邮件、短信和任务消息。 GET /Messages
get_message 获取一条内容完整的消息。 GET /Message

采购和订单(5个工具)

工具 描述 API端点
get_purchases 检索购买记录。 GET /Purchases
get_purchase_logs 检索购买生命周期日志。 GET /PurchaseHistoryLogs
get_transactions 检索交易/发票记录。 GET /Transactions
get_orders 检索订单记录(订阅、付款计划)。 GET /Orders
get_open_orders 检索活动订阅记录。 GET /OpenOrders

交易记录写入(13个工具)

这些工具可以修改财务记录。代理在执行之前应与用户确认。

工具 描述 API端点
process_transaction 将联系人的卡记入档案。需要提供产品和已保存的卡ID。不接受新卡详细信息。 POST /transaction/processManual
log_transaction 不收费记录交易(线下销售、现金、支票)。 POST /transaction/processManual (chargeNow=0)
get_order 检索交易的订单详细信息(订阅计划、下一次收费日期)。 GET /transaction/order
update_order 更新订单的下一个收费日期、金额或其他字段。 PUT /transaction/order
cancel_subscription 通过删除订单记录来取消活动订阅。停止所有未来的收费。 DELETE /order
delete_order 删除单个订单记录(订阅或付款计划时间表)。 DELETE /order
convert_to_collections 将逾期交易升级到收款状态。 PUT /transaction/convertToCollections
refund_transaction 通过原始支付网关退款。无法撤消。 PUT /transaction/refund
void_transaction 撤销未结算的交易。 PUT /transaction/void
write_off_transaction 核销未付交易(坏账)。 PUT /transaction/writeOff
mark_transaction_paid 标记为手动支付(支票、现金、电汇等)。 PUT /transaction/markPaid
rerun_transaction 重试被拒绝/失败的事务。 POST /transaction/rerun
resend_invoice 重新发送发票电子邮件。 POST /transaction/resendInvoice

产品(2个工具)

工具 描述 API端点
list_products 列出帐户中的所有产品。 GET /Products
get_product 按ID获取单个产品 GET /Product

自定义对象(每个对象4个工具)

这些工具是 动态生成 对于通过以下方式在帐户中发现的每个自定义对象 /objects/meta。工具名称包括对象的名称和 object_type_id 自动注射。

模式 描述 API端点
get_[ObjectName] 按ID检索记录 GET /object
create_[ObjectName] 创建新记录。 owner 是必需的。 POST /objects
update_[ObjectName] 更新现有记录上的字段。 PUT /objects
search_[ObjectName] 按条件、文本或标签搜索。分页。 GET /objects

元数据和发现(2个工具)

工具 描述 API端点
get_object_meta 获取任何对象类型的字段定义。 GET /objects/meta
get_collection_count 使用可选筛选获取任何对象的记录计数 GET /objects/getInfo

输入参考

条件参数

这 condition 参数用于所有搜索和列表工具。它是一个JSON编码的字符串,包含一组条件对象。

单一条件:

[{"field":{"field":"lastname"},"op":"=","value":{"value":"Smith"}}]

支持的操作员:

操作员 描述
= 等于。适用于文本、数字和时间戳字段。
> 大于。数字和时间戳字段。
< 小于。数字和时间戳字段。
>= 大于或等于
<= 小于或等于
IN 值在列表中。值格式: {"list":[{"value":1},{"value":2}]}
CONTAINS 用于列表类型字段。检查是否分配了选项。
DOES NOT CONTAIN 用于列表类型字段。检查是否未分配选项。

复合条件:

插入 "AND" 或 "OR" 条件对象之间的字符串:

[{"field":{"field":"lastname"},"op":"=","value":{"value":"Smith"}}, "AND", {"field":{"field":"city"},"op":"=","value":{"value":"Austin"}}]

分页

所有列表/搜索工具都支持分页:

参数 类型 默认值 说明
start integer 0 从零开始的偏移量。
range integer 50 要返回的记录数。最多50。
sort string -- 要排序的字段名
sortDir string -- "asc" 或 "desc"。必须与 sort.

时间戳

所有日期/时间字段都使用 Unix时间戳 (自1970年1月1日00:00:00 UTC以来的秒数)。在将人类可读的日期传递给任何工具之前,代理必须将其转换为Unix时间戳。

列出选择字段

列表选择类型的自定义字段需要用 */* 分隔符:

"f1500": "*/*1*/*2*/*"

使用 get_object_meta 以发现列表字段的选项ID。


错误处理

服务器将Ontraport API错误转换为结构化响应,为代理提供足够的信息来决定是否重试、修复输入或向用户报告。

HTTP代码 类别 代理指南
200 成功 解析 data 字段从响应。
400 错误请求 不要重试。修复格式错误的输入参数。
401 未经授权 凭据无效或丢失。在没有新凭据的情况下不要重试。
403 禁止 API密钥缺少所需的范围。向用户报告。
404 找不到 对象ID不存在。请在重试之前验证ID。
422 无法处理 字段验证失败(例如,电子邮件格式无效)。请修复并重试。
429 速率受限 后退并重试。检查 Retry-After 头球限额:180需求/分钟/账户。
500 服务器错误 使用指数回退重试(最多3次尝试)。

错误响应格式:

{
  "code": 400,
  "error": "bad_request",
  "message": "id is required for update_contact."
}

舱单尺寸保护

如果一个帐户有许多自定义对象,则清单可能会超过LLM上下文窗口中的容量。服务器强制执行的最大值为 100工具:

  1. 始终包括所有48个静态工具
  2. 自定义对象按最近修改的内容排序
  3. 自定义对象工具以4个为一组(一次一个完整对象),直到达到限制
  4. 如果被截断,a _manifest_note 添加了一个工具,告诉代理存在其他对象,可以通过以下方式发现 get_object_meta

速率限制

服务器不添加自己的速率限制。它继承了Ontraport的极限 每个账户每分钟180个API请求 透明。当超过限制时,服务器返回HTTP 429 Retry-After 来自Ontraport的标头,以便代理可以适当地回退。


安全

  • 凭证传递 — Api-Key 和 Api-Appid 在每次呼叫时转发到Ontraport,从不存储。
  • 会话凭据绑定 --会话通过SHA-256哈希绑定到凭据。返回的请求必须呈现相同的内容 Api-Key/Api-Appid 这创建了会话。防止跨帐户的会话劫持。
  • 在所有端点上进行身份验证 — Api-Key 和 Api-Appid 每个请求(POST、GET(SSE)和DELETE)都会验证标头,而不仅仅是会话创建。
  • 每会话隔离 --每个代理连接都有自己的 Server 实例的作用域为其凭据。会话之间没有共享的可变状态。
  • 会话TTL --被放弃的会话在30分钟不活动后会自动清理。背景扫描每5分钟运行一次,以防止内存泄漏。
  • 不记录凭据 --仅错误处理程序日志 err.message,永远不要在堆栈跟踪中包含可能包含凭据的完整错误对象。
  • 没有毅力 --服务器没有数据库,没有文件存储。内存会话仅跟踪MCP传输生命周期。
  • 范围执行 -权限由Ontraport现有的API密钥范围系统强制执行。如果键缺少作用域,API调用将失败,服务器将显示错误。

测试

npm test

测试套件包括 17个套件中的106个测试:

套房 保险范围
health.test.js 健康端点返回200,无需身份验证
auth.test.js 缺少标题→ 401,有效的身份验证+SDK初始化→ 200
mcp-server.test.js 服务器工厂创建隔离的每个凭据实例
error-handling.test.js 所有错误类型,转换为JSON格式,来自HttpStatus映射
response-cleaner.test.js 剥离所有10个噪声场,递归清理,空处理
manifest.test.js 静态工具、自定义对象、内置ID排除、100工具上限、对象边界截断、无内部字段泄漏、故障传播
tools/contacts.test.js 所有7个联系工具——正确的端点、参数、验证
tools/tags.test.js 所有6个标签工具——正确的有效载荷、对象ID注入
tools/sequences.test.js 所有4个序列工具——sub_type默认值,正确的方法
tools/tasks.test.js 所有5个任务工具——正确的车身结构
tools/notes.test.js 两个笔记工具——objectID=12注入
tools/messages.test.js 所有2个消息工具——正确的端点
tools/purchases.test.js 所有5个采购/订单工具——正确的端点
tools/transactions.test.js 所有13个事务写入工具——正确的方法和路径
tools/products.test.js 两种产品工具——正确的端点
tools/custom-objects.test.js 所有4个自定义对象操作——对象ID注入、验证
tools/metadata.test.js 两种元数据工具——参数传递

配置

环境变量 默认值 描述
PORT 3000 服务器监听的端口

什么被排除在v1之外

以下内容被有意排除在外,可能会被考虑用于未来的版本:

特性 原因
活动生成器 复杂性高,存在帐户配置错误的风险
表单 对代理用例的需求低
Webhooks 基于推送的模式,独立架构
散装作业 需要对药剂爆炸半径进行安全审查
日历事件 保持清单专注于CRM和商务
收件箱/对话 需要消息传递基础架构上下文
信用卡管理 安全敏感,需要确认流程
流程手册(新交易) 财务风险、复杂报价/产品构建

对象类型ID引用

对象 类型ID
联系人 0
任务 1
组 3
序列 5
规则 6
消息 7
注释 12
标签 14
产品 16
购买 17
购买历史记录日志 30
未结订单 44
交易 46
订单 52
标签订阅者 138
活动/自动化 140

自定义对象具有动态分配的ID,并通过以下方式发现 /objects/meta.