关于 integration-development
面向使用 Membrane 构建集成的开发者,介绍从认证、创建连接到调用外部应用操作的开发流程。涵盖单租户与多租户设计、连接管理及多种操作分发方式。
主要功能
- 01Membrane 五步集成流程
- 02单租户与多租户配置
- 03连接创建与生命周期管理
- 04按意图发现集成和操作
- 05通过 API、代码或操作 ID 分发
适用场景
- 01为团队共享账号创建连接
- 02让用户连接各自的外部应用账号
- 03查找并调用适用的集成操作
MCP 相关
该技能说明 MCP 会话中的认证状态,并列出连接、集成和操作发现等对应的 MCP 工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ membranehq/ agent-skills --skill integration-development安装后在 Claude Code 中输入/integration-development确认已加载。
详细介绍
集成开发
集成如何运作——五步心智模型
每项由 Membrane 提供支持的功能都会沿着同一条线性主线推进。 步骤 0–3 是核心路径;步骤 4 则是能力升级,当你的应用不再绑定到某个特定供应商时,就可以进阶到这一步。
Step 0: Authenticate yourself — you, the developer; via MCP or `membrane` CLI
Step 1: Authenticate your code — sign JWTs in your backend
↳ single-tenant vs multi-tenant decided HERE
Step 2: Create connections — `membrane.ui.connect()` in your app UI
Step 3: Use connections — call actions on the external app
↳ discover via intent search when you don't know what to call
↳ dispatch: inline api/code | catalog id | workspace key
Step 4 (advanced): Universal — app-agnostic code via universal actions + cross-connection logic
在 MCP 会话中,步骤 0 已经完成——membrane status 会对此进行确认。
最重要的选择——你的应用是为一个共享的外部账号(单租户:团队 CRM、内部 Slack)提供服务,还是为许多最终用户提供服务(多租户:每位用户连接自己的 Gmail、Linear 等)——发生在步骤 1。它决定了后端在签发的 JWT 中放入什么信息,而这又会限定后续每个连接和操作的作用范围。步骤 1 之后的所有流程都统一:相同的 membrane.ui.connect() 调用,相同的 /act 分派。
编写代码前——典型的发现流程
四条命令足以覆盖大多数起步场景:
# 1. Populate env with real credentials.
membrane credentials --shell > .env.local
# 2. Find the app you're integrating with (returns externalAppId).
membrane external-app list --search <app-name>
# 3. List catalog actions for that app.
membrane action list --externalAppId <id>
# 4. Check existing connections in the current tenant.
membrane connection list
CLI 快速参考。
- 签发 JWT:
membrane token(按用户区分时添加--tenantKey <key>;用于POST /actions和其他 manager 操作时添加--manager)。membrane --help或membrane <command> --help会列出完整的命令和选项。
创建连接时,如果 connection list 中没有匹配项,首次连接请传入 connectorKey(目录级别,始终可解析),而不是 integrationKey(工作区本地)。
步骤 0:验证你的身份
确认你拥有有效的 Membrane 会话。
membrane status
显示绿色的“Logged in”以及工作区 → 已就绪。显示红色的“Not logged in” → 进行身份验证:
npx @membranehq/cli login
浏览器窗口会打开以供登录。凭据保存在
~/.membrane/credentials.json;之后每条 membrane 命令都会复用这些凭据。会话过期后请重新运行。
步骤 1:验证你的代码
后端向 Membrane 发出的每个请求都会携带一个 Membrane 令牌——一个使用工作区密钥签名、有效期较短的 HS256 JWT。
它的 tenantKey 决定了请求所操作的连接隔离范围。
载荷结构
workspaceKey——请求所针对的 Membrane 工作区。tenantKey——工作区内隔离的连接范围。不同租户无法看到彼此的连接。
此外还需要工作区密钥(用于签名)和 API URL。
如何选择 tenantKey:
| 单租户 | 多租户 | |
|---|---|---|
| 适用场景 | 一个共享的外部应用账号(团队 CRM、Slack) | 每位最终用户都有自己的外部应用账号(Gmail、Linear) |
JWT 中的 tenantKey | 固定值——例如 process.env.MEMBRANE_TENANT_KEY | 已登录用户的稳定 ID |
| 连接密钥形式 | 固定值——例如 hubspot-prod | 根据用户 ID 生成——例如 gmail-${userId} |
| 连接体验(步骤 2) | 管理员页面;每个应用只需点击一次 | 每位用户各自拥有一个按钮;每位用户连接自己的账号 |
获取这些值
membrane credentials --json
# { "apiUri": "...", "workspaceKey": "...", "workspaceSecret": "...", "tenantKey": "..." }
为 .env 文件生成 shell 导出格式:membrane credentials --shell。
签发令牌
使用标准的 HS256 JWT,每次请求都进行签名,并设置较短的 TTL。
import jwt from 'jsonwebtoken'
// tenantKey source:
// single-tenant → process.env.MEMBRANE_TENANT_KEY
// multi-tenant → the signed-in user's stable id
const token = jwt.sign(
{ workspaceKey: process.env.MEMBRANE_WORKSPACE_KEY, tenantKey },
process.env.MEMBRANE_WORKSPACE_SECRET,
{ algorithm: 'HS256', expiresIn: '5m' },
)
// Use as Authorization: Bearer <token>, or hand to
// <MembraneProvider fetchToken={…}> on the frontend.
对于 shell 测试,membrane token 会签发一个限定租户范围的令牌(按用户区分时添加
--tenantKey <key>)。get-membrane-token 是对应的 MCP 方式。
工作区管理器令牌
租户范围的令牌涵盖 act、列表查询以及应用运行时执行的所有操作。以下操作需要管理器令牌(引擎 workspaceAsManager 身份验证层的作用范围):
POST /actions/PATCH /actions/<id>/DELETE /actions/<id>(工作区级可复用操作)PATCH /integrations/<id>/parameters(OAuth 凭据、范围)POST /import/GET /export(工作区配置往返导入导出)
使用 membrane token --manager 创建,或直接签名:
const managerToken = jwt.sign({ workspaceKey, isAdmin: true }, workspaceSecret, { algorithm: 'HS256', expiresIn: '5m' })
步骤 2:创建连接
连接是与一个外部应用建立的已验证身份链接。每次 /act 调用都会通过某个连接进行身份验证。
前端的 membrane.ui.connect(…) 是面向用户的连接流程——它会打开 OAuth 弹出窗口、跟踪状态,并在用户完成操作后返回结果。
连接生命周期
| 操作 | CLI | MCP 工具 |
|---|---|---|
| 列出现有连接 | membrane connection list | list-connections |
| 发现应用 | membrane integration list --search "<q>" | list-integrations |
| 创建 | membrane.ui.connect(…)(生产环境)/ membrane connect …(开发环境) | connect |
| 重新连接 | membrane connect --connectionId <id> | 使用 { connectionId } 调用 connect |
| 删除 | membrane connection delete <id-or-key> | delete-connection |
发现可连接的目标
list-integrations 会搜索工作区的集成,以及目录中的连接器和外部应用。每个结果都包含 connectorId、integrationId、externalAppId——将其中任意一个传给 connect。如果没有匹配项,connect 也接受自由文本 intent,并会即时构建连接器——首次以此方式连接可能需要更长时间(预期会进入 BUILDING 阶段;如果失败,请检查 CONFIGURATION_ERROR / SETUP_FAILED)。
创建连接
向 connect 提供以下其中一项:
connectorKey/connectorId— 目录连接器(即使全新工作区中还没有集成,也可以使用)。integrationKey/integrationId— 已知集成。intent— 自由文本;服务器会选择或构建连接器。
可选:提供自己的 connectionKey,以便稳定查找;否则系统会自动生成。
connect 会返回连接(id、key、state,以及在用户仍在进行身份验证时返回的 clientAction.uiUrl)。CLI 会阻塞,直到 state: READY;在 MCP 中,连接面板会呈现此流程。
重新连接
使用现有的 connectionId 调用 connect,即可重新授权 OAuth,而无需创建新连接。当 act 调用返回连接已断开的错误时,请使用此方法。
删除(归档)
delete-connection / membrane connection delete 会归档记录。该记录将不再显示在 list-connections 中,也无法再用于 act。
自定义集成
默认情况下,集成使用 Membrane 共享的 OAuth 客户端。自定义集成可使用自己的 OAuth 凭据、调整连接表单字段,或更改每个集成的行为。详情请参阅 integration-catalog。
连接 UI — 单租户
一个共享账户,一个管理员连接页面。连接键是固定的。
import { MembraneClient } from '@membranehq/sdk'
// The backend mints a token (step 1) and exposes it at /api/membrane-token
// as { token, apiUri }.
const { token, apiUri } = await (await fetch('/api/membrane-token')).json()
const m = new MembraneClient({ token, apiUri })
await m.ui.connect({ connectorKey: 'hubspot', connectionKey: 'hubspot-prod' })
Connect UI — 多租户
每位已登录用户连接自己的账户。连接密钥根据用户 ID 生成。
使用 @membranehq/react — 用 MembraneProvider 包装一次应用:
import { MembraneProvider, useMembrane } from '@membranehq/react'
;<MembraneProvider
apiUri={process.env.NEXT_PUBLIC_MEMBRANE_API_URI}
fetchToken={async () => (await (await fetch('/api/membrane-token')).json()).token}
>
{children}
</MembraneProvider>
// In any component:
const m = useMembrane()
m.ui.connect({ connectorKey: 'gmail', connectionKey: `gmail-${userId}` })
纯 JS — 使用相同模式和用户级连接密钥:
await m.ui.connect({ connectorKey: 'gmail', connectionKey: `gmail-${userId}` })
关于令牌路由的说明:
- 任何提供
GET /api/membrane-token并返回{ token, apiUri }的服务端框架都适用。fetchToken会按请求调用,因此 令牌的有效期较短。 - 仅用于 Vite 开发环境的应用:添加一个开发中间件,用于签署与步骤 1
相同的 JWT。
loadEnv(mode, …)可让中间件访问MEMBRANE_*环境变量。 - 必须从浏览器调用
m.ui.connect(...)— 它会打开 OAuth 弹窗。服务端重定向或 CLI 命令无法替代。
仪表板目录页面
类似设置的 UI,供用户管理多种集成。使用
@membranehq/react 钩子:
useIntegrations() // → { items: Integration[], loading, loadMore, loadingMore, refresh }
useConnections() // → { items: Connection[], loading, refresh }
useMembrane() // → MembraneClient (.ui.connect(…), .connection(id).archive(), …)
type Connection = {
id: string
name: string
integrationId: string
integration?: { key: string; name: string; logoUri?: string }
disconnected: boolean
state: 'READY' | 'BUILDING' | 'DISCONNECTED' | 'ERROR'
}
type Integration = {
id: string
key: string
name: string
logoUri?: string
}
需要接入的四个独特 Membrane 调用:
// Connect a new integration the user picked from the available list:
m.ui.connect({ integrationKey: i.key })
// Reconnect a disconnected/errored connection:
m.ui.connect({ connectionId: c.id })
// Disconnect (archive):
m.connection(c.id).archive()
state 枚举对 UI 很重要:BUILDING 表示
用户完成身份验证后,Membrane 完成连接器配置前的阶段(首次连接时可能需要
几秒钟)。如果 UI 只显示已连接/未连接,BUILDING 或
ERROR 会被显示为“已连接”——但事实并非如此。
第 3 步:使用连接 — 调用操作
/act 是执行操作的统一端点。提供四种分发方式,
每次调用只能使用其中一种:
api— 通过连接的身份验证层和基础 URL 执行内联 HTTP 请求。 这是默认的基础构建模块。code— 在沙箱中运行 JS 代码片段,其中已预先配置经过身份验证的membrane客户端、connection和integration。适用于多步骤组合操作。id— 指定某个操作(目录操作或工作区本地操作)。通过action list --externalAppId获取的目录操作只有id(key字段为空)。key— 工作区本地操作的稳定句柄。目录操作没有 key;工作区本地操作同时具有两者,任选其一即可。
api 和 code 需要连接(connectionKey 或
connectionId)。key/id 会根据操作自身的作用范围进行路由。
运行操作
使用 membrane act,并指定 --api、--code、--key、--id
之一,以及连接和输入标志。
响应:{ output, actionRunId }。失败时响应中仍会包含 actionRunId —
将其传给运行日志以便调试。
按意图发现操作
知道要做什么,但不知道如何实现时,可按意图排序列出操作。
membrane action list --connectionKey <key> [--intent "<text>"]
分发示例 — 按 id 调用目录操作
典型流程:发现工作流的第 3 步会提供一个目录操作列表,其中包含
id、name、inputSchema、config.request。
按 id 使用匹配项 — Membrane 会处理特定供应商的请求格式、身份验证范围和重试。只有在没有匹配的目录操作时,才回退到内联 api:。
// /act body:
{
id: GMAIL_SEND_MESSAGE_ACTION_ID, // paste from `membrane action list --externalAppId`
connectionKey: `gmail-${userId}`, // or `hubspot-prod` for single-tenant
input: { to, subject, body }, // matches the action's inputSchema
}
// On failure, detect disconnected connection and forward actionRunId:
const needsReconnect = res.status === 401 || payload?.code === 'CONNECTION_DISCONNECTED'
// Return { error: payload, actionRunId: payload?.actionRunId, needsReconnect }
没有匹配目录操作时使用内联 api::
{
connectionKey,
api: {
method: 'POST',
path: '/<vendor-endpoint>',
body: { … },
},
}
升级为可复用的工作区本地操作
当相同的分发形式在多个路由中反复出现时,将其提取为具有稳定
key 的工作区本地操作。使用管理令牌调用一次 POST /actions。
有两种创建方式:
- 按意图 — Membrane Agent 构建并注册操作。
- 按明确规范 — 由你提供
type+config。
# by intent
membrane action create --intent "<text>" --connectionKey <key>
# by explicit spec
membrane action create --key <key> --type <type> --config '<json>' --integrationKey <key>
# update (merge) / replace (whole) / delete
membrane action update <identifier> --data '<json>'
membrane action replace <identifier> --data '<json>'
membrane action delete <identifier>
POST /actions 请求体格式(明确规范):
{
"key": "create-lead",
"name": "Create Lead",
"type": "api-request-to-external-app",
"externalAppId": "<app-id>",
"config": {
"request": { "method": "POST", "path": "/<vendor-endpoint>" }
},
"inputSchema": { "type": "object", "required": ["…"], "properties": { "…": "…" } }
}
返回 { id, key, state: 'READY', inputSchema, outputSchema, … }。
运行时使用 { key: '<your-key>', connectionKey, input } 调用。
操作的作用范围取决于你设置的字段:
- 设置
connectionKey/connectionId→ 连接级(一个连接)。 - 设置
integrationKey/integrationId(且不设置连接) → 集成级(在该集成的每个连接之间共享)。通用操作可以通过这种方式按集成定制 — 使用相同的key,但字段映射和前置/后置钩子各不相同。 - 两者都不设置 → 通用操作(见步骤 4)。
POST /actions 需要管理令牌;租户令牌会收到 403。
调试失败的操作
每个 act 响应都带有 actionRunId。将它传给运行日志
(--details / includeDetails: true 也会获取与外部应用之间的原始 HTTP 交互)。
membrane action-run-log get <actionRunId> --details
步骤 4(高级):通用集成
步骤 0–3 假设你的代码知道正在与哪个外部应用交互。 步骤 4 适用于另一种情况:无论用户连接哪个供应商,你的应用都能提供价值——例如跨 Gmail、Outlook、SendGrid 使用的“发送邮件”功能,或以统一方式处理 Salesforce、HubSpot、Pipedrive 的 CRM 同步层。
这是不同的分发路径。只有当供应商无关的行为是产品的一项核心需求时,才使用这种方式。
通用操作
通用操作的注册不包含 externalAppId 或
integrationKey。它会命名一个意图(“创建联系人”“发送
消息”“列出发票”),并提供由每个实现该操作的集成都共享的输入/输出架构。分发会根据调用方连接所属的集成进行路由。
# Create by intent — Membrane builds a shared schema at workspace scope.
membrane action create --intent "send an email" --key send-email
分发——不指定 externalAppId;操作会根据连接进行适配:
await act({
key: 'send-email',
connectionKey: userPickedConnection, // Gmail, Outlook, SendGrid, etc.
input: { to, subject, body },
})
供应商专属调整(不同的字段名称、某个供应商专用的额外钩子)可在集成层覆盖:使用相同的 key 创建第二个操作,并设置 integrationKey: "gmail"。使用 Gmail 连接时,运行时分发会自动采用该覆盖配置。
跨连接逻辑
Membrane 不会直接对多连接操作建模。当任务涉及多个连接时:
- 从你的后端编排:按顺序调用
/act,每次使用各自的连接。 code:分发:使用预先配置一个连接的简短 JS 代码片段;在片段中通过membrane客户端访问第二个连接。
通用流程的工作区设置
使用管理器令牌通过 PATCH /workspaces/:id 切换:
useMembraneUniverse— 操作发现范围涵盖目录中所有集成的通用操作,而不只限于工作区集成。autoGenerateIntegrationsFromConnectors— 使用新连接器时按需创建集成。通用 UX 需要此设置:用户可以选择任意连接器,并确保存在可供通用操作分发使用的集成。autoGenerateIntegrationsFromExternalApps— 按需从外部应用目录生成集成。
这些设置默认关闭,因为它们会扩大应用用户可见的内容范围。
何时应继续使用步骤 3
- 供应商专属标头或边缘情况 → 使用步骤 3 目录中的
id或内联api:。 - 重复调用同一个应用 → 按
key升级为工作区本地的可复用操作(步骤 3)。 - 赶进度的单一供应商产品 → 通用操作会增加额外的设计工作;之后再考虑。
错误恢复
当 /act 返回连接已断开的错误时,将 connectionId 显示给 UI(或发送到你的运维频道),并让用户重新连接。不要创建新连接——现有连接只需重新授权 OAuth。
if (err.status === 401 || err.payload?.code === 'CONNECTION_DISCONNECTED') {
// Interactive path: return 409 with the connectionId; frontend
// calls m.ui.connect({ connectionId }) and retries after the user
// completes the popup.
//
// Unattended workload (cron, worker, sync): log the connectionId
// and actionRunId, emit an alert, and bail. The next run picks up
// once an admin has reconnected via the Settings page.
}
超出已公开工具的范围——原始 API
Membrane REST API 支持的任何功能,都可以在代码中通过 get-membrane-token 生成令牌并直接调用端点来使用。以下是一些未由一等工具覆盖的重要端点:
- 恢复已归档的操作 / 连接 —
POST /actions/:id/restore、POST /connections/:id/restore。 - 整体替换操作 —
PUT /actions/:id(MCPupdate-action只会合并)。 - 修改连接 —
PATCH /connections/:id。 - 刷新连接凭据 —
POST /connections/:id/refresh。 - 检查 / 自定义集成 —
GET /integrations/:id、PATCH /integrations/:id。参见integration-catalog。
完整 API 参考:
docs.getmembrane.com/reference。
调用端点前,使用 search-docs 查找具体端点。
前端设置
了解如何在浏览器代码中初始化 Membrane — React 应用、其他浏览器框架、嵌入式 UI。凡是会渲染连接对话框或重新连接流程的内容,都属于此处,因为它需要在真实浏览器中运行 OAuth。
**黄金法则:**浏览器永远不会接触你的工作区密钥。在服务器上签发令牌,再通过 fetchToken 这类回调将令牌传给前端。请参阅 backend-setup,了解用于签发令牌的服务器路由。
Next.js / React
安装 @membranehq/react。使用 MembraneProvider 包裹你的应用,并提供一个调用后端的 fetchToken 函数:
// app/layout.tsx
import { MembraneProvider } from '@membranehq/react'
export default function RootLayout({ children }) {
return (
<html>
<body>
<MembraneProvider
fetchToken={async () => {
const res = await fetch('/api/membrane-token')
return (await res.json()).token
}}
>
{children}
</MembraneProvider>
</body>
</html>
)
}
然后,在 Provider 树中的任意位置:
import { useMembrane } from '@membranehq/react'
function ConnectButton() {
const membrane = useMembrane()
return <button onClick={() => membrane.ui.connect({ integrationKey: 'hubspot' })}>Connect HubSpot</button>
}
**Next.js 注意事项:**在 next.config.ts 中添加
transpilePackages: ['@membranehq/react', '@membranehq/sdk']。
非 React 浏览器代码
直接使用 @membranehq/sdk。令牌同样从后端获取 — 将 fetchToken(或静态 token)传给 MembraneClient:
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({
fetchToken: async () => {
const res = await fetch('/api/membrane-token')
return (await res.json()).token
},
})
await membrane.ui.connect({ integrationKey: 'hubspot' })
Vue、Svelte、Angular、纯 JavaScript — 用法相同。提供 fetchToken 后,SDK 会自动刷新令牌。
何时调用前端 SDK
- 需要用户交互的 UI 流程 —
membrane.ui.connect(...)、重新连接对话框、连接管理界面。这些必须在浏览器中运行。 - 与已登录用户关联的只读读取操作 — 列出某个租户自己的连接、读取其自己的操作结果等,都可以从前端执行,因为令牌的作用域已经限定在该租户。
- 其他所有操作 — 代表应用执行写入、后台同步、工作区范围的管理操作 — 应在后端执行。请参阅
backend-setup。
另请参阅
后端设置
了解如何在服务器代码中初始化 Membrane — 后端路由、后台工作进程、定时任务、CLI 和一次性脚本。适用于可以安全存放工作区密钥,且不运行面向用户的 UI 流程的任何场景。
这里也需要实现 frontend-setup 中提到的 /api/membrane-token 路由:前端向后端请求租户范围的 JWT,后端签发令牌并返回。
**黄金法则:**工作区密钥必须保留在服务器上。不要将其嵌入浏览器包、移动应用、用户运行的桌面应用,或任何用户可以检查二进制文件的地方。
两种标准流程
- 基于凭据的客户端 — 将
workspaceKey、workspaceSecret和tenantKey传给MembraneClient;它会为你签发并刷新令牌。最适合一次处理一个租户的长时间运行代码(工作进程、脚本、CLI、单租户后端)。 - 基于令牌的客户端 / 原始 HTTP — 自行签发 JWT,然后将其传给
MembraneClient({ token }),或在原始fetch请求中通过Authorization: Bearer <token>标头传递。最适合需要显式控制的场景 — 多租户请求处理程序、/api/membrane-token路由、非 JavaScript 服务。
两种流程都使用同一个 API。根据你对令牌生命周期的控制需求进行选择。
使用工作区凭据创建 MembraneClient
可直接用于脚本、工作进程和单租户后端。
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({
workspaceKey: process.env.MEMBRANE_WORKSPACE_KEY!,
workspaceSecret: process.env.MEMBRANE_WORKSPACE_SECRET!,
tenantKey: process.env.MEMBRANE_TENANT_KEY!, // or the end-user id
apiUri: process.env.MEMBRANE_API_URL,
})
const connections = await membrane.connections.find()
SDK 会为每次调用签发 HS256 令牌,并在令牌过期前刷新它。在多租户后端中,可按请求更换 tenantKey(通过构造限定作用域的客户端)。
签发令牌并直接调用 API
需要精细控制、运行在非 JavaScript 环境,或正在为前端编写 /api/membrane-token 路由时,请使用此模式。
import jwt from 'jsonwebtoken'
function membraneTokenForTenant(tenantKey: string) {
return jwt.sign(
{
workspaceKey: process.env.MEMBRANE_WORKSPACE_KEY!,
tenantKey,
},
process.env.MEMBRANE_WORKSPACE_SECRET!,
{ algorithm: 'HS256', expiresIn: 3600 },
)
}
// Example: Next.js API route that vends tokens to the browser
export async function GET(req: Request) {
const tenantKey = await resolveTenantForUser(req) // your auth system
return Response.json({ token: membraneTokenForTenant(tenantKey) })
}
// Or: call Membrane directly from the server
async function listConnections(tenantKey: string) {
const token = membraneTokenForTenant(tenantKey)
const res = await fetch(`${process.env.MEMBRANE_API_URL}/connections`, {
headers: { Authorization: `Bearer ${token}` },
})
return res.json()
}
如果你不在 JavaScript 环境中,get-membrane-token 工具提供了完整的载荷参考,以及 Python、Go、Ruby、Java 和 PHP 中的签名示例。
脚本和 CLI
与后端路由采用相同模式:从本地环境文件(或 get-credentials)读取工作区凭据,签发令牌,然后调用 API。单租户脚本可以将与你的控制台会话关联的租户密钥写死 — 这就是 get-credentials 默认返回的租户。
// scripts/sync-hubspot.ts
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({
workspaceKey: process.env.MEMBRANE_WORKSPACE_KEY!,
workspaceSecret: process.env.MEMBRANE_WORKSPACE_SECRET!,
tenantKey: process.env.MEMBRANE_TENANT_KEY!,
})
const contacts = await membrane.connection('hubspot-prod').action('list-contacts').run({})
另请参阅
- 身份验证
- 租户
get-credentials工具 — 返回当前环境的workspaceKey、workspaceSecret、tenantKey和apiUrl。get-membrane-token工具 — 返回一个已签名、可直接使用的 JWT。
集成目录
了解如何设置和配置工作区的集成目录——即产品(或脚本)在运行时通过
integrationKey 引用的集合集成。配置工作在构建时或管理时完成,而非运行时。
运行时 UI 模式
如果要在产品中构建集成页面,标准的运行时流程如下:
- 获取当前租户的
connections - 获取可用的
integrations - 将已连接的账户与用户仍可连接的应用分开展示
- 使用
membrane.ui.connect(...)启动连接或重新连接 - 归档连接以断开连接
import { useConnections, useIntegrations, useMembrane } from '@membranehq/react'
function IntegrationsPage() {
const membrane = useMembrane()
const { items: integrations = [] } = useIntegrations()
const { items: connections = [] } = useConnections()
const connectedIntegrationIds = new Set(connections.map((c) => c.integrationId))
const availableIntegrations = integrations.filter((i) => !connectedIntegrationIds.has(i.id))
return (
<>
{connections.map((connection) => (
<div key={connection.id}>
<span>{connection.name}</span>
{connection.disconnected ? (
<button onClick={() => membrane.ui.connect({ connectionId: connection.id })}>Reconnect</button>
) : (
<button onClick={() => membrane.connection(connection.id).archive()}>Disconnect</button>
)}
</div>
))}
{availableIntegrations.map((integration) => (
<button key={integration.id} onClick={() => membrane.ui.connect({ integrationKey: integration.key })}>
Connect {integration.name}
</button>
))}
</>
)
}
对于非 React 前端应用,遵循相同的流程:从后端获取临时令牌,在 UI 中列出集成和连接,并从前端代码触发相同的连接/重新连接流程。对于该 UI 背后的后端路由、工作进程或 cron 作业,请使用原始 API 调用和短期 Membrane 令牌,而不要使用服务端 SDK。
只有后端脚手架?添加一个最简前端。
如果脚手架是一个没有 UI 的纯 API Express / Fastify / Next 路由处理程序,你仍需要一个用于连接流程的前端界面。
从后端提供一个静态 HTML 页面;该页面会从应用获取每位用户的令牌,并通过浏览器 SDK 调用 membrane.ui.connect:
<!doctype html>
<html>
<body>
<button id="connect-github">Connect GitHub</button>
<script type="module">
import { MembraneClient } from 'https://esm.sh/@membranehq/sdk'
const { token } = await (await fetch('/api/membrane-token')).json()
const m = new MembraneClient({ token, apiUri: 'https://api.getmembrane.com' })
document.getElementById('connect-github').onclick = () =>
m.ui.connect({ connectorKey: 'github', connectionKey: 'github-dev' })
</script>
</body>
</html>
/api/membrane-token 路由是一个轻量的后端端点,用于签发 JWT(参见 kit 中的身份验证)并返回 { token }。
这是唯一正确的终端用户连接模式——不要向终端用户提供 CLI 操作说明,也不要让后端返回 clientAction.uiUrl,再让用户手动粘贴。
React Hook/客户端速查
以下内容均来自 @membranehq/react:
// client — has all the methods you call imperatively
const m = useMembrane()
m.ui.connect({ connectorKey }) // new connection (catalog-level)
m.ui.connect({ integrationKey }) // new connection (workspace-level)
m.ui.connect({ connectionId }) // reconnect an existing connection
m.connection(id).archive() // disconnect
// hooks — SWR-style; re-render on changes
const { items: integrations, loading, error } = useIntegrations({ search?: string })
const { items: connections, loading, error } = useConnections({ integrationKey?: string })
// shape of a Connection
type Connection = {
id: string
key: string
name: string
integrationId: string
disconnected: boolean
state: 'READY' | 'DISCONNECTED' | 'ERROR' | 'BUILDING' | ...
}
// shape of an Integration
type Integration = {
id: string
key: string
name: string
logoUri?: string
}
操作的适用场景
应用连接后,产品功能通常只需使用操作,无需更复杂的机制:
- 在后端、工作进程或 cron 作业中,直接通过
api或code运行内联act调用 - 使用
get-credentials或get-membrane-token为这些后端调用签发令牌;将 SDK 保留在前端层 - 只有在需要稳定的键、架构或可在多个调用位置共享的抽象时,才保存可复用操作
- “同步”通常只需由你自己的作业运行器按计划重复执行操作
如果希望 Membrane 负责更多同步编排、事件处理或可按租户自定义的映射,则可使用数据源、字段映射和流程等更丰富的 Membrane 基元。
从连接器创建集成
每个集成都由一个连接器提供支持(即 Membrane 保存在其目录中的特定供应商适配器)。创建一次集成后,便可始终通过稳定的 integrationKey 引用它。
curl -X POST $API/integrations -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"key":"github","name":"GitHub","connectorKey":"github"}'
生成的集成支持连接(connect --integrationKey github)和可复用操作(create-action --integrationKey github)。
集成参数
参数用于配置集成的行为:OAuth 客户端凭据、默认范围、特定于 API 的设置。参数保存在集成上,可以更新而无需重新创建集成。
# fetch
curl -sG $API/integrations/<id>/parameters -H "Authorization: Bearer $TOKEN"
# set
curl -X PATCH $API/integrations/<id>/parameters -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"clientId":"...","clientSecret":"..."}'
自动生成的集成
设置 connectors=1 / externalApps=1(参见 list-integrations)后,工作区会按需根据目录合成集成——Agent 可以连接尚无专用集成的应用,系统会自动创建一个。只有在需要预先向目录添加自定义名称、参数或连接器版本时,才需要显式调用 POST /integrations。
首次连接可能比普通连接流程耗时更久:Membrane 可能会搜索目录、创建集成记录,或启动 Agent 来构建新的连接器。请预期会进入初始 BUILDING 阶段。如果构建/设置流程失败,通常会看到 CONFIGURATION_ERROR 或 SETUP_FAILED;请完善意图或检查具体失败原因后再重试。
归档和恢复
可以归档集成,而不是删除——默认情况下,DELETE /integrations/<id> 会将其归档。除非设置 includeArchived=1,否则归档的集成会从 list-integrations 中隐藏。使用 POST /integrations/<id>/restore 恢复。
另请参阅
故障排查
在 Membrane 中出现问题时,修复几乎总是需要同时查看两个资源——失败的 act 调用,以及它所经过的连接。本节介绍跨资源的工作流;各工具文档则介绍具体操作(如何重新连接、日志结构是什么样、每种状态代表什么)。
诊断流程
当操作调用失败时,请按照以下流程排查。每一步都为下一步提供依据:
- 阅读响应。 每个
act响应都包含一个actionRunId——无论成功还是返回 4xx 都有。请记下它。 - 获取运行日志。 调用
get-action-run-log并设置includeDetails: true。这是查看 Membrane 映射后的输入、输出、错误以及——最重要的——与外部应用之间原始 HTTP 交互的最快方式。无需查看其他内容,大多数故障都能在此找到答案。 - 判断日志所示的问题类型。 根据情况选择对应的修复方式:
- 身份验证/连接断开 → 重新连接。
- 输入格式错误/缺少字段 → 修正
act输入后重试(内联api/code是最小化的测试方式)。 - 外部应用返回错误 → 查看日志中的响应正文;修正输入或更换端点。
- 缺少连接器配置 → 参见
integration-catalog。
- 使用尽可能简单的调用重试。 先将失败的同步或可复用操作简化为单个内联
act(api或code)。确认可用后,再逐步恢复原有方式。
日志层级——从上往下排查
Membrane 会记录三层证据;请按顺序查看:
- 操作运行日志——每次
act调用对应一条记录。包含 Membrane 对此次调用的记录:输入、输出、错误、状态变更,以及(设置includeDetails: true时的)原始 HTTP 交互。从这里开始。 - 外部 API 日志——发送给供应商的原始请求/响应,可通过
includeDetails查看。当操作运行日志显示“外部错误”且你需要查看供应商的确切响应正文/状态码时使用。 - Webhook 日志——来自供应商的原始传入负载。仅在调试事件驱动流程时使用;与同步
act调用无关。
你很少需要深入到第 2 层以下。
症状 → 工具映射
| 症状 | 首选操作 |
|---|---|
act 返回错误并包含 actionRunId | 使用 includeDetails: true 调用 get-action-run-log |
| 身份验证错误 / “连接已断开” | 使用出错的 connectionId 调用 connect |
连接长时间处于 BUILDING 状态 | 等待,然后调用 list-connections 查看最终状态 |
连接进入 CONFIGURATION_ERROR 状态 | 重新运行 connect;检查返回的错误 |
连接进入 SETUP_FAILED 状态 | 无法构建连接器;尝试使用其他 intent |
| “未找到集成” / “没有匹配的操作” | 重试前调用 list-integrations 或 list-actions |
| 可复用操作产生了错误的输出 | 先使用 act + api / code 内联重建 |
| 问题似乎影响整个平台(多个租户、webhook) | 使用 search-docs 搜索受影响的功能 |
另请参阅
工具
获取凭据
membrane credentials
获取从任何后端与 Membrane 通信所需的凭据。 用于后端路由、工作进程、cron 作业或服务器端脚本。 前端代码应从后端获取临时令牌,然后 使用前端 SDK。
返回内容:
- 工作区密钥 — 指定要访问哪个 Membrane 工作区。
- 工作区密钥 — 用于签署 JWT。仅保留在服务器端。
- 租户密钥 — 将调用限定到某个用户的一组连接。 测试时使用控制台会话租户;在生产环境中,替换为 当前最终用户的唯一标识符。
- API URL — 当前环境的 Membrane 端点。
如果之后遇到 401 错误,工作区密钥可能已轮换 — 再次调用此工具以获取新的密钥。
在代码中
使用返回的值生成 JWT 并验证 API 调用:
# 1. Mint a token (HS256, 1-hour expiry)
TOKEN=$(node -e "
const jwt = require('jsonwebtoken');
console.log(jwt.sign(
{
workspaceKey: '<workspaceKey>',
tenantKey: '<tenantKey>',
name: 'Acme Inc'
},
'<workspaceSecret>',
{ algorithm: 'HS256', expiresIn: 3600 }
))
")
# 2. Use it
curl -sG $API/connections -H "Authorization: Bearer $TOKEN"
任何带有 JWT 库的语言都适用 — 负载为
{ "workspaceKey": "<workspaceKey>", "tenantKey": "<tenantKey>" }
以及可选的显示元数据(如 name),并使用工作区密钥签名。切勿在浏览器/客户端代码中公开此密钥。
获取 Membrane 令牌
membrane token [--tenantKey <key>] [--manager] [--expiresIn <duration>] [--json]
生成 Membrane 令牌——一种短期有效的 JWT,用于对 Membrane API 请求进行身份验证。需要在后端代码的 Authorization: Bearer <token> 标头中使用令牌时,调用此工具。前端代码应向后端请求一个临时令牌,然后使用前端 SDK。
输入
tenantKey(可选)——标识令牌可访问的连接所属的隔离范围。默认为与你当前控制台会话关联的租户。manager(可选,仅 CLI)——签发工作区管理令牌,用于POST /actions、集成参数编辑和导入/导出等工作区级变更。对应引擎的workspaceAsManager身份验证层。设置manager后,租户密钥为可选项。(为兼容引擎现有的身份验证解析逻辑,载荷中会包含isAdmin: true。)expiresIn(可选,仅 CLI)——令牌有效期,例如5m、1h、24h。默认值:1h。
响应
一个 JWT 字符串。在每次 API 调用中,将其作为 Authorization: Bearer <token> 传递。
令牌载荷
| 字段 | 必填 | 描述 |
|---|---|---|
workspaceKey | 是 | 你的工作区密钥。 |
tenantKey | 否 | 租户(用户、团队或组织)的标识符。工作区级操作可省略。 |
name | 否 | 易于阅读的租户名称(有助于排查问题)。 |
fields | 否 | 要存储的租户附加元数据。 |
isAdmin | 否 | 对于工作区管理令牌(不含 tenantKey),设为 true。 |
代码示例
使用任何语言和 JWT 库,只需 3 到 5 行代码。务必在服务器端签名——任何拥有工作区密钥的人都可以为任意租户签发令牌。
import jwt from 'jsonwebtoken'
const token = jwt.sign(
{
workspaceKey: '<WORKSPACE_KEY>',
tenantKey: '<TENANT_ID>',
name: '<TENANT_NAME>',
},
'<WORKSPACE_SECRET>',
{ expiresIn: 7200, algorithm: 'HS256' },
)
import datetime, jwt
token = jwt.encode(
{
"workspaceKey": "<WORKSPACE_KEY>",
"tenantKey": "<TENANT_ID>",
"name": "<TENANT_NAME>",
"exp": datetime.datetime.now() + datetime.timedelta(seconds=7200),
},
"<WORKSPACE_SECRET>",
algorithm="HS256",
)
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
claims := jwt.MapClaims{
"workspaceKey": "<WORKSPACE_KEY>",
"tenantKey": "<TENANT_ID>",
"name": "<TENANT_NAME>",
"exp": time.Now().Add(time.Hour * 2).Unix(),
}
token, _ := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).
SignedString([]byte("<WORKSPACE_SECRET>"))
require 'jwt'
payload = {
workspaceKey: '<WORKSPACE_KEY>',
tenantKey: '<TENANT_ID>',
name: '<TENANT_NAME>',
exp: Time.now.to_i + 7200,
}
token = JWT.encode(payload, '<WORKSPACE_SECRET>', 'HS256')
String token = Jwts.builder()
.claim("workspaceKey", "<WORKSPACE_KEY>")
.claim("tenantKey", "<TENANT_ID>")
.claim("name", "<TENANT_NAME>")
.setExpiration(Date.from(Instant.now().plusSeconds(7200)))
.signWith(
new SecretKeySpec("<WORKSPACE_SECRET>".getBytes(), "HmacSHA256"),
SignatureAlgorithm.HS256)
.compact();
$token = JWT::encode([
'workspaceKey' => '<WORKSPACE_KEY>',
'tenantKey' => '<TENANT_ID>',
'name' => '<TENANT_NAME>',
'exp' => time() + 7200,
], '<WORKSPACE_SECRET>', 'HS256');
# Shell: sign via Node for a one-off curl call
TOKEN=$(node -e "
const jwt = require('jsonwebtoken');
console.log(jwt.sign(
{ workspaceKey: '<WORKSPACE_KEY>', tenantKey: '<TENANT_ID>' },
'<WORKSPACE_SECRET>',
{ algorithm: 'HS256', expiresIn: 3600 }
));
")
curl -sG $API/connections -H "Authorization: Bearer $TOKEN"
获取令牌的其他方式
- 公钥/私钥签名——如需更严格的密钥管理,可使用工作区所有的私钥,通过任意非对称算法(
ES256、RS256、PS256,……)签名,并在工作区设置中注册公钥。可直接替换上述示例。 - 工作区管理令牌——对于跨租户操作(如管理租户、工作区设置和导入/导出),添加
isAdmin: true(并省略tenantKey)。 - 测试令牌——只想快速试用 API 时,可从控制台设置中的「访问」页面获取预先生成的令牌。
- 长期有效令牌——需要一个不会过期的令牌时(例如,无法在运行期间刷新令牌的服务器到服务器任务),可从「访问」页面的「客户端令牌」部分创建。
- 开发者令牌——代表你的 Membrane 帐户在所有工作区中执行操作。在控制台设置中的 API 令牌处签发。
完整参考请参阅身份验证文档。
列出连接
membrane connection list [--integrationKey <key>] [--search "<text>"] [--limit <n>] [--cursor <cursor>]
列出当前租户的活动连接。在要求用户重新进行身份验证之前,可用它检查是否已存在连接。
筛选条件
integrationKey/integrationId——缩小范围,仅列出某个集成。search——按名称 / 密钥进行全文匹配。limit、cursor——标准分页参数。
响应
每条记录都包含 id、key、integrationId、连接名称和连接状态等标识信息。将 connectionId 或 connectionKey 传给 act,即可在该连接上运行操作。
代码示例
# all connections
curl -sG $API/connections -H "Authorization: Bearer $TOKEN"
# filter to one integration
curl -sG $API/connections -H "Authorization: Bearer $TOKEN" \
--data-urlencode 'integrationKey=github'
删除连接
membrane connection delete <identifier> [--json]
按 ID 或密钥归档连接。归档后,该连接不会再显示在
list-connections 中,也无法再通过 act 使用。这是断开连接的操作——Membrane 默认执行软删除;如需恢复或彻底删除,请使用原始
API。
输入
connectionId— 连接的数据库 ID。
使用场景
- 撤销用户的连接(例如,用户在应用的设置中断开 HubSpot)。
- 删除租户或清理账户——归档与该租户关联的所有连接。
- 用新创建的连接替换配置错误的连接。
代码示例
# Shell
curl -s -X DELETE "$API/connections/<id>" -H "Authorization: Bearer $TOKEN"
// SDK
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({ token })
await membrane.connection('<id>').archive()
列出集成
membrane integration list [--search "<text>"] [--connectors 1] [--externalApps 1] [--limit <n>] [--cursor <cursor>]
浏览用户可以连接的内容。返回工作区集成;启用后,还会返回由目录连接器和外部应用生成的合成集成(这些候选项在有人连接后可成为完整集成)。
筛选条件
search— 按名称/密钥/描述进行全文搜索。省略此项可浏览完整目录。connectors— 包含来自 Membrane 目录中连接器的合成集成(1表示启用,0表示禁用;省略时使用工作区默认值)。externalApps— 同上,适用于尚未转为集成的外部应用。limit、cursor— 标准分页参数。
响应
每个条目都包含足够的标识信息(id、key、相关时的 connectorKey、显示名称和徽标),可直接传递给 connect。
如果没有符合用户意图的结果,请跳过此步骤,调用带有 intent: "…" 的
connect——服务端会搜索连接器,并在需要时启动 Agent 即时构建连接器。
代码示例
# free-text search
curl -sG $API/integrations -H "Authorization: Bearer $TOKEN" \
--data-urlencode 'search=crm'
# include catalog candidates that could become integrations
curl -sG $API/integrations -H "Authorization: Bearer $TOKEN" \
--data-urlencode 'connectors=1' --data-urlencode 'externalApps=1'
连接
membrane connect [--integrationKey <key>] [--integrationId <id>] [--connectorKey <key>] [--connectorId <id>] [--connectionId <id>] [--connectionKey <key>] [--intent "<text>"] [--name <name>] [--non-interactive]
连接到外部应用,或重新连接现有应用。返回包含 id、state 的连接;如果用户仍需进行身份验证,还会包含 clientAction.uiUrl。将此 URL 交给用户,以便他们完成 OAuth 流程。
返回的 id 是连接 ID,可用于重新连接、查找和后续调试。
如何指定要连接的对象
integrationKey/integrationId— 工作区中已知的集成。connectorKey/connectorId— 连接器(适用于尚无集成的情况;服务会按需创建集成)。intent— 用自由文本描述用户想要连接的对象。服务会搜索连接器/集成并选择匹配项;如果没有合适的对象,则会启动 Agent 来构建连接器。connectionId— 重新连接现有连接(使用相同的 OAuth 流程和记录)。
从 list-integrations 获取任何具体标识符后,直接将其传入上述参数之一。可以自由组合,例如使用 integrationKey + connectionKey,在稳定的键下创建新连接。
如果 intent 或目录候选项需要生成新内容,首次连接可能会比普通 OAuth 重定向耗时更久。请预期会有一个短暂的 BUILDING 阶段,此时 Membrane 正在搜索目录、创建集成或构建连接器。如果此流程失败,连接将进入 CONFIGURATION_ERROR 或 SETUP_FAILED 状态。
连接键
传入你自己的 connectionKey,以便之后识别该连接(act { connectionKey, ... }、list-connections、重新连接)。如果省略,服务会分配一个。
重新连接
调用 connect,并将 connectionId 指向现有连接(例如,发生过身份验证错误的连接)。使用相同的 OAuth 流程和记录,不会创建新连接。
响应
完整的连接对象:
{
"id": "...",
"key": "...",
"state": "BUILDING" | "CLIENT_ACTION_REQUIRED" | "READY" | "CONFIGURATION_ERROR" | "SETUP_FAILED",
"clientAction": { "type": "connect", "uiUrl": "..." }?,
...
}
交互式 CLI 会一直阻塞,直到 state 为 READY。在 MCP 中,连接面板会渲染 clientAction.uiUrl,并在用户完成后更新连接状态。
在代码中
连接需要用户交互——OAuth / 同意流程必须在真实浏览器中运行——因此它属于前端,并通过 Membrane SDK 的 UI 辅助方法完成。不要自行编写 HTTP 调用;membrane.ui.connect(...) 会以 iframe 覆盖层打开托管的连接界面,处理 OAuth 往返流程以及任何由 Agent 构建的连接器流程,并在完成后返回连接(如果用户关闭对话框,则返回 null)。
import { MembraneClient } from '@membranehq/sdk'
// Mint the token on your backend with get-membrane-token and hand it
// to the browser — never embed workspace secrets in front-end code.
const membrane = new MembraneClient({ token })
// Connect by connector key (catalog-level; resolves in a fresh workspace)
const connection = await membrane.ui.connect({
connectorKey: 'github',
connectionKey: 'github-dev',
})
// Connect by integration key (only once you've confirmed the
// integration exists in the current workspace, e.g. via
// `membrane integration list --search github`)
const existing = await membrane.ui.connect({
integrationKey: 'github',
connectionKey: 'github-dev',
})
// Connect by intent (agent may build a connector if needed)
const built = await membrane.ui.connect({
intent: 'connect my GitHub account',
})
// Reconnect an existing connection (same record, fresh OAuth)
const reconnected = await membrane.ui.connect({
connectionId: existing.id,
})
if (!connection) {
// User closed the dialog before completing the flow
return
}
在 React 中,使用 @membranehq/react 的 useMembrane() hook 获取相同的客户端 — useMembrane().ui.connect({...}) — 这样就不必手动接入 MembraneClient。
列出操作
membrane action list [--connectionId <id>] [--connectionKey <key>] [--intent "<text>"] [--limit <n>]
查找工作区中可复用的操作。先用它通过 key 发现可运行的内容,再考虑使用 act(运行)或 create-action(保存新操作)。
筛选条件
connectionId/connectionKey— 将范围缩小到特定连接的操作集。intent— 自然语言描述。与连接(ID 或键)搭配时,结果会按语义匹配度排序。不指定连接时,intent会被忽略。limit、cursor— 标准分页参数。
响应
每个项目都包含 id、key、name、description、integrationKey、layer、inputSchema 和 outputSchema — 这些信息足以直接传入 act。如果没有匹配项,请转而使用 create-action(intent 路径)来构建操作。
目录操作(通过 --externalAppId 筛选时返回)会带有空的 key 字段 — 使用 act --id <hex> 调用它们。工作区本地操作的 key 非空,可通过任一方式调用。
在代码中
# semantic match on a specific connection
curl -sG $API/actions -H "Authorization: Bearer $TOKEN" \
--data-urlencode 'connectionId=<id>' \
--data-urlencode 'intent=create a contact'
执行
membrane act [--id <id>] [--key <key>] [--integrationKey <key>] [--connectionKey <key>] [--connectionId <id>] [--api <json>] [--code <text>] [--input <json>] [--meta <json>]
执行一项操作。通过 POST /act 进行一次统一调用——可复用操作或内联规范。
内联 api 和 code 执行是构建应用功能、脚本和同步任务的默认方式。需要稳定的键、共享架构,或希望从多个位置调用同一抽象时,请使用可复用操作。
只能指定一个调度字段
id— 可复用操作的数据库 ID。key— 可复用操作的键。如果多个集成中存在相同的键,请与integrationKey/integrationId/connectionId/connectionKey搭配使用。
目录/公开操作(来自 list-actions --externalAppId …)会返回 id,但不返回 key——请通过 id 调度。对于工作区本地操作,id 和 key 可以互换使用。
api— 通过已解析连接的身份验证层和基础 URL 发送的内联 HTTP 请求:{ method, path, body?, headers?, query? }。code— 在沙盒中运行的内联 JavaScript:module.exports = ({ input, membrane, connection, integration }) => …。其返回值即为操作输出。
api 和 code 需要连接。请提供 connectionId / connectionKey / integrationId / integrationKey,或使用工作区默认值。
连接解析
优先级:connectionId → connectionKey → 集成默认值(来自 integrationId 或 integrationKey)→ 工作区默认值。与 POST /actions/:selector/run 使用相同的链路。
响应
{ "output": ..., "actionRunId": "..." }
对于 4xx 响应,仍会携带 actionRunId——请将其与操作运行日志搭配使用以进行调试。
在代码中
# reusable action by key
curl -X POST $API/act -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"key":"create-issue","integrationKey":"github","input":{"title":"Hello"}}'
# inline HTTP through a connection
curl -X POST $API/act -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"api":{"method":"GET","path":"/user/repos"},"connectionKey":"github-dev"}'
# inline JS
curl -X POST $API/act -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"code":"module.exports = ({ input }) => ({ echoed: input })","input":{"hi":1},"connectionKey":"github-dev"}'
创建操作
membrane action create [--intent "<text>"] [--key <key>] [--name <name>] [--type <type>] [--config <json>] [--inputSchema <json>] [--integrationId <id>] [--integrationKey <key>] [--connectionId <id>]
将可复用操作保存到工作区。有两种方式:
按意图创建 — 传入 intent: "…" 和集成或连接上下文。Membrane Agent 会基于供应商的 API 构建操作、对其进行验证并注册。响应会返回处于 BUILDING 状态的操作 id;轮询 list-actions(按 ID 筛选),直到 state 为 READY,然后使用 act 运行。
按明确规范创建 — 传入 type(例如 api-request-to-external-app、run-javascript、list-data-records 等)、config(特定类型的载荷)以及可选的 key / name / inputSchema。当你已知所需结构时使用此方式——例如,你已通过内联 act 调用测试过,现在希望重复使用。
存储位置
- 设置了
connectionId→ 连接级操作实例(限定在一个连接内)。 - 设置了
integrationId/integrationKey(未设置连接)→ 集成级操作(该集成上的所有连接均可使用)。 - 两者均未设置 → 通用操作(所有支持该结构的集成都可使用)。
响应
{ "id": "...", "state": "BUILDING" | "READY" | "ERROR", ...standard action fields }
操作变为 READY 后,可通过 id 或 { integrationKey, key } 使用 act 运行。
在代码中
# intent
curl -X POST $API/actions -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"intent":"open a pull request","integrationKey":"github"}'
# explicit spec
curl -X POST $API/actions -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"key":"list-users","type":"api-request-to-external-app","integrationKey":"github",
"config":{"request":{"method":"GET","path":"/users"}}}'
获取操作
membrane action get <id> [--wait] [--timeout <seconds>] [--json]
通过 ID 获取单个可复用操作。返回完整记录——id、key、name、state、type、config、inputSchema、outputSchema,以及所属的 integrationId / connectionId。
输入
id— 操作的数据库 ID。适用于集成级操作和连接级操作实例。
适用场景
create-action返回state: BUILDING后——轮询此接口,直到state: READY。- 通过
id/key调用act之前——确认操作存在,且符合预期结构。 act调用返回疑似操作配置问题的错误时——检查已保存的config/inputSchema。
在代码中
# Shell
curl -s "$API/actions/<id>" -H "Authorization: Bearer $TOKEN"
// SDK
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({ token })
const action = await membrane.action('<id>').get()
更新操作
membrane action update <selector> [--connectionId <id>] [--integrationId <id>] --data <json> [--json]
按 ID 或键部分更新可重复使用的操作。采用合并语义——只传入要更改的字段。要替换整个记录,请使用原始 API(PUT /actions/:selector)。
输入
id— 操作的数据库 ID(或使用 CLI<selector>,它接受 ID 或键)。data— 要合并的字段。常见字段包括:name、description、config、inputSchema、key。具体结构取决于操作的type。
作用域提示(仅限 CLI)
--connectionId/--integrationId— 当某个键同时存在于连接级实例和集成级操作时,用于区分。传入数据库 ID 时无需使用。
适用场景
- 迭代改进刚创建的可重复使用操作——优化提示词、重命名、调整架构,而无需重新创建。
- 将经过测试的内联
act转换为可重复使用的操作,通常通过create-action完成;之后调整其config时可使用此工具。
代码示例
# Shell — merge update
curl -s -X PATCH "$API/actions/<id>" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name":"Create HubSpot contact"}'
// SDK
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({ token })
const updated = await membrane.action('<id>').patch({ name: 'Create HubSpot contact' })
删除操作
membrane action delete <selector> [--connectionId <id>] [--integrationId <id>] [--json]
按 ID 或键归档可重复使用的操作。归档后的操作不会再显示在 list-actions 中,也无法再通过 act 调用。Membrane 默认执行软删除——使用原始 API 可恢复(POST /actions/:id/restore)或永久清除。
输入
id— 操作的数据库 ID(或 CLI<selector>,它接受 ID 或键)。
作用域提示(仅限 CLI)
--connectionId/--integrationId— 当某个键同时存在于连接级实例和集成级操作时,用于区分。传入数据库 ID 时无需使用。
适用场景
- 清理未成功的实验性操作。
- 移除已被更新键取代的过时集成级操作。
代码示例
# Shell
curl -s -X DELETE "$API/actions/<id>" -H "Authorization: Bearer $TOKEN"
// SDK
import { MembraneClient } from '@membranehq/sdk'
const membrane = new MembraneClient({ token })
await membrane.action('<id>').archive()
获取操作运行日志
membrane action-run-log get <actionRunId> [--details]
获取 Membrane 对单次操作运行的记录。每个 act 响应都会包含一个 actionRunId(成功和 4xx 错误响应中均会提供)——将其传入此处,即可查看实际发生的情况。
输入
actionRunId—act返回的 ID。details(可选)— 为 true 时,还会包含详细的运行内容:与外部应用的原始 HTTP 交互、映射后的输入和输出。
响应
{
"id": "...", "status": "success" | "error",
"action": { ... }, "connection": { ... }, "integration": { ... },
"input": ..., "output": ..., "error": ...,
"details"?: { "request": {...}, "response": {...}, ... }
}
摘要字段会告知你调用的结构。如果操作失败,请查看 details,了解 Membrane 发出的确切 HTTP 请求以及外部应用返回的内容。
代码示例
# summary
curl -sG $API/action-run-logs/<runId> -H "Authorization: Bearer $TOKEN"
# raw HTTP exchange (request/response content)
curl -sG $API/action-run-logs/<runId>/details -H "Authorization: Bearer $TOKEN"