mcpField
P
pipefy-portal-setup

pipefy-portal-setup

github.com/pipefy生产力51687 次安装2 天前更新
代码仓库

关于 pipefy-portal-setup

pipefy-portal-setup 是用于配置组织 Pipefy 门户的技能,涵盖页面、组件、布局和子门户。它说明主门户的搭建流程,以及关联和发布子门户的步骤。

主要功能

  1. 01列出并创建组织门户
  2. 02创建和编辑页面及元素
  3. 03调整页面布局与元素位置
  4. 04创建、关联和发布子门户
  5. 05检查门户权限与发布状态

适用场景

  1. 01初始化组织的主门户
  2. 02添加页面、表单、链接或组件
  3. 03在主门户发布子门户
  4. 04调整门户页面元素布局

MCP 相关

面向 MCP 客户端,技能提供 MCP 参考,并说明用于读取和修改门户结构、页面、元素及子门户的工具。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pipefy/ai-toolkit --skill pipefy-portal-setup

安装后在 Claude Code 中输入/pipefy-portal-setup确认已加载。

附带文件references/cli.mdreferences/mcp.md

详细介绍

门户设置

MCP 客户端:请阅读 references/mcp.md。CLI 用户:请阅读 references/cli.md。以下示例介绍通用操作参数。

配置组织的 Pipefy 门户:初始化主门户,添加页面和小组件,连接并发布子门户(子门户连接使用 Interfaces GraphQL + internal_api)。

详细参考:docs/mcp/tools/portal.md。功能对照表:docs/parity.md。环境变量:docs/config.md。


适用场景

  • “创建我们的公司门户”“列出组织 X 的门户”“发布子门户”。
  • 添加或更改门户页面、布局或页面元素(forms、link 等)。
  • 在主门户上附加、发布、取消发布或删除子门户。

不要用于:

  • Pipe、阶段、卡片或自动化——请参阅 pipefy-pipes-and-cards、pipefy-automations。
  • HTML 界面(作为单个 HTML 文档编写、存放在 customCode 元素中的独立页面)——请参阅 pipefy-html-interfaces。以下元素工具接受 customCode 元素;切勿将它们用于此类元素。
  • 存在门户工具时使用原始 GraphQL——请优先使用以下工具。
  • 通过未公开的 createInterface GraphQL 初始化门户——始终使用 create_portal。

前提条件

  • 组织 ID: 可使用 UUID 或来自组织查询或 Pipefy URL 的数字组织 ID(以下示例使用 fixture_ids.py 中的虚构 ID 123456789)。SDK 会在调用 Interfaces 前解析数字 ID。传递给 list_portals / create_portal 的组织必须与令牌有权写入的组织相同。
  • 门户写入权限: 令牌需要在该组织上具有 create_portal 和/或 manage_portals 权限。许多服务账号仅在其默认组织上拥有 Pipe/卡片范围的权限,因此即使在其他组织上读取成功,门户变更操作仍会返回 PERMISSION_DENIED。
  • 每个组织只能有一个主门户——create_portal 是幂等的(第二次调用会返回相同的门户 UUID)。
写入前确认访问权限

在错误的组织上读取可能成功,但 Interfaces 写入会失败。在更改页面、元素或子门户之前:

  1. 使用预期的 organization_uuid 调用 list_portals。
  2. 确认令牌适用于该组织(服务账号邮箱与属于其他组织的人类用户不匹配,是常见问题)。
  3. 优先选择账号拥有 manage_portals 权限且在 Pipefy 中具有门户管理员权限的组织(而非仅在来自其他组织的读取查询中拥有 canManagePortals)。

如果 update_portal 或 delete_portal 返回 PERMISSION_DENIED,但用户坚持认为组织角色正确:Pipefy 可能要求服务账号对该门户界面执行 joinAsAdmin(Interfaces 变更操作,MCP/CLI 尚未提供)。服务账号写入成功前,用户必须先在 UI(或通过 GraphQL)中针对每个门户 UUID 以门户管理员身份加入一次。


门户的组织方式

概念预期情况
主门户每个组织最多 一个(subType: portal)。使用 create_portal(findOrCreateInterfaceByTemplate)创建。
list_portals通常只有 一行——仅主门户(筛选条件为 portal)。子门户不会显示在此处。
子门户独立实体(create_sub_portal)。列在 get_portal → subPortals[] 下。
主枢纽上的 UI创建子门户不会在主页上添加磁贴。必须通过 publish_sub_portal / update_sub_portal_element 在 forms 元素上发布(或附加)。
终端用户可见性published: false 的子门户会存在于 API 中,但在发布前对门户访客不可见。
公开主枢纽在 get_portal 中,主门户的 published 始终为 true。公开访问 = update_portal(visibility="public"),而不是 published 标志。
主门户生命周期
  • 对于会重复用于测试的组织,优先对现有主门户使用 update_portal,而不是删除后再使用 create_portal。
  • 对主门户调用 delete_portal 会移除一个接口 UUID;除非先删除孤立子门户,否则它们可能会保留。
  • 删除主门户后,create_portal 可能会失败并提示 Menu already created(当 mainPortal 为 null 时,组织菜单状态仍会保留)。恢复方法:删除孤立子门户、联系 Pipefy 管理员/支持团队,或在保留的 UUID 上初始化内容——不要改用原始 createInterface,因为这会留下一个骨架主页面("Page",0 个元素)和一个损坏的构建器;幂等的 create_portal 会持续返回该 UUID。
空主页面

如果 get_portal 显示主页面没有任何元素,请仅使用 title 调用 create_portal_page(请求中不要包含 elements)。API 通常会返回一个包含 约 14 个模板小组件(文本、表单、链接等)的页面。将该页面用于发布槽位和元素测试。请勿在 create_portal_page 中传入 type: subPortal——这会导致创建时验证失败。

架构说明

主题规则
列表中的 publishedlist_portals 不会返回 published——请调用 get_portal。
布局中的子门户即使顶层 subPortals[] 为空,磁贴也可能出现在 pages[].elements[] 下,且类型为 subPortal。
发布流程对现有的 forms 元素使用 publish_sub_portal / update_sub_portal_element(在 internal_api 上使用 updateSubPortalElement)。create_portal_element 且类型为 subPortal 不能替代发布操作。
元素元数据update_portal_element 会整体替换元数据——每次都要发送完整的 metadata JSON。
元素数据源每次调用 update_portal_element 都必须传入 data_sources 或 portal_uuid,与元素类型无关;两者都省略会被拒绝。data_sources 会整体替换:[] 会取消元素与其管道或表格的关联;对于没有绑定的元素(link、text),应使用单次调用并传入 []。要保留绑定,请省略 data_sources 并传入 portal_uuid(即你传给 get_portal 的 uuid,其 pages[] 中包含 page_id);元素的 dataSources 和 editable 标志会一并传回。
元数据键forms → name(不是 formId);link → linkName / linkUrl(不是 url / label)。
布局 JSONupdate_portal_page_layout 需要一个行对象数组。每一行都必须有非空的 id、type: "row",且 children 中必须是非空字符串。请从 get_portal 复制目标 pages[].layout。metadata.gridMap 提供的是元素尺寸,而非位置。API 会原样存储这里的任何 JSON,因此包装对象或不完整的行都会替换网格。工具包会在本地拒绝非数组及任何不完整的行,但仍接受表示空页面的 [];切勿使用原始 GraphQL 绕过校验。
页面网格与元素create_portal_element 不会改动布局网格,除非你传入 element_id + layout(现有行加上列出新 ID 的一行);duplicate_portal_element 会追加布局行;delete_portal_element 会保留布局引用,除非你传入 layout(现有行中移除该元素后的布局);孤立的引用可能导致门户查看器出错(HTTP 500)。

所需工具

操作只读
list_portals是
get_portal是
create_portal否
update_portal否
delete_portal否
create_portal_page否
update_portal_page否
delete_portal_page否
sort_portal_pages否
update_portal_page_layout否
create_portal_element否
update_portal_element否
delete_portal_element否
duplicate_portal_element否
create_sub_portal否
update_sub_portal_element否
publish_sub_portal否
unpublish_sub_portal否
delete_sub_portal_element否
delete_sub_portal否

元素 type 值(15 种):text、table、field、embedLink、embedVideo、embedImage、button、divider、link、forms、pages、subPortal、automationButton、contentBlock、document。


步骤 — 顺利流程(主门户 + 子门户发布)

  1. 列出或初始化主门户

    操作参数:

    list_portals(organization_uuid="123456789")
    

    主门户行最多只能有一条。如果没有:

    操作参数:

    create_portal(organization_uuid="123456789")
    

    记录 subType 为主门户的 uuid。

  2. 检查结构

    操作参数:

    get_portal(portal_uuid="<MAIN_PORTAL_UUID>")
    

    记录 pages[]、elements[] 和 forms 元素 ID。如果主页面没有任何元素,请先在该门户上运行 create_portal_page(仅设置标题),然后再添加小组件。

  3. 可选 — 添加 forms 元素(如果不存在模板化的 forms 插槽)

    操作参数:

    create_portal_element(page_id="<PAGE_ID>", type="forms", metadata={"name": "Request access", "gridMap": {"height": 66, "columns": 4, "minColumns": 4}})
    

    如果 create_portal_element 从 Interfaces 返回不透明错误或 INTERNAL_SERVER_ERROR,请改为从同一 portal_uuid 和 page_id 上已有的链接运行 duplicate_portal_element,不要盲目重试创建。

  4. 创建子门户

    操作参数:

    create_sub_portal(main_portal_uuid="<MAIN_PORTAL_UUID>", name="Partner hub")
    

    记录子门户的 uuid。get_portal 会在 subPortals[] 中列出该门户,且 published: false — 在第 5 步之前,主门户中心 UI 不会发生变化。

  5. 在 forms 元素上发布

    操作参数:

    publish_sub_portal(portal_uuid="<MAIN_PORTAL_UUID>", element_id="<FORMS_ELEMENT_ID>", sub_portal_uuid="<SUB_PORTAL_UUID>")
    
  6. 验证发布状态

    操作参数:

    get_portal(portal_uuid="<MAIN_PORTAL_UUID>")
    

    成功条件:目标 subPortals[].published 为 true。只有在此步骤之后(且符合门户中心可见性规则),最终用户才能看到子门户。

  7. 可选 — 将主门户中心设为公开

    通过 update_portal 将 <MAIN_PORTAL_UUID> 的 visibility 更新为 "public"(SDK 参数:interface_uuid;MCP 参数:portal_uuid)。


步骤 — 页面、布局和安全编辑

在共享组织的主门户上进行元素/布局实验时,请使用临时页面:

  1. 使用唯一标题运行 create_portal_page(例如 Agent smoke 2026-06-01)。
  2. 仅在该页面上运行 create_portal_element、update_portal_element、duplicate_portal_element、update_portal_page_layout。
  3. 检查并批准删除临时页面,然后使用 delete_portal_page。

duplicate_portal_element: element_id、portal_uuid 和 page_id 必须指向已包含源元素的同一页面(在同一页面上复制,不要跨页面)。

update_portal_page_layout: 从 get_portal 读取目标 pages[].layout,并保留其行 ID、子元素 UUID 以及未受影响的行。发送完整数组,只修改预期的顺序/分组;然后重新读取并比较。elements[].metadata.gridMap(height、columns、minColumns)描述的是尺寸,因此无法还原行顺序或分组。调整元素大小时,请保留完整元数据。如果布局不可用,请停止位置编辑,不要猜测。切勿将数组包装在 { "rows": [ ... ] } 中。

MCP:

get_portal portal_uuid="<portal_uuid>"
update_portal_page_layout page_id="<page_uuid>" layout=[<complete edited rows from that page>]
get_portal portal_uuid="<portal_uuid>"

CLI:

pipefy portal get <portal_uuid> --json
pipefy portal page layout update --page-id <page_uuid> --layout '[<complete edited rows from that page>]' --json
pipefy portal get <portal_uuid> --json

带位置设置的 create_portal_element: 读取 pages[].layout,为 element_id 生成 UUID,追加或插入一行 { "id": "<new row uuid>", "type": "row", "children": ["<element_id>"] },并同时传入 element_id 和完整的 layout。如果不提供 layout,元素会被创建,但不会出现在网格中。重新读取并比较。

MCP:

create_portal_element page_id="<page_uuid>" type="link" metadata={...} element_id="<element_id>" layout=[<existing rows>, {"id": "<row uuid>", "type": "row", "children": ["<element_id>"]}]

CLI:

pipefy portal element create --page-id <page_uuid> --type link --metadata '{...}' --element-id <element_id> --layout '[<existing rows>, {"id": "<row uuid>", "type": "row", "children": ["<element_id>"]}]' --json

带清理操作的 delete_portal_element: 读取 pages[].layout,从每一行的 children 中移除 element_id,并将完整数组作为 layout 传入。网格和元素会在一次调用中一起更改,因此不会有行继续指向已删除的元素。如果布局仍列出 element_id,请求会被拒绝。重新读取并比较。MCP 和 CLI 参考资料中的删除调用都包含 layout。

sort_portal_pages: 传入非空的 page_ids 列表,且列表中不得有重复项。如果响应中出现嵌套的 success: false,则视为操作失败。

链接元素元数据(创建/更新,完整替换):

{
  "gridMap": { "height": 64, "columns": 4, "minColumns": 4 },
  "linkUrl": "https://example.com",
  "linkName": "Example link"
}

link 没有绑定,因此更新时也要传入 data_sources: [](CLI --data-sources '[]')。


步骤 — 取消发布或移除子门户

取消发布(保留子门户实体;访客将无法访问):

操作参数:

unpublish_sub_portal(portal_uuid="<MAIN_PORTAL_UUID>", element_id="<FORMS_ELEMENT_ID>")

解除元素连线:检查影响并获得批准后,使用 delete_sub_portal_element。

使用 delete_sub_portal 删除子门户界面(不可撤销);删除前请检查并获得批准。


成功标准

  • list_portals 返回组织的主门户(通常为一行);重复调用 create_portal 会返回相同的 UUID。
  • 写入后,get_portal 会显示预期的 pages / elements。
  • 调用 create_sub_portal 后,子门户会存在于 API 中,但在发布前 published: false。
  • 发布后:subPortals[].published 为 true,且主页面会显示已连线的 forms 插槽。
  • 取消发布后:published 为 false,但不会删除子门户实体(除非调用了 delete_sub_portal)。
  • 在临时页面上编辑布局/元素后,生产环境中使用的主门户页面仍可在构建器中打开(不会出现 HTTP 500)。

故障模式

症状可能原因恢复方法
写入时出现 PERMISSION_DENIED组织错误、缺少 manage_portals,或 SA 未加入该界面使用与 list_portals 相同的组织;让用户加入门户管理员;尝试使用人工管理员令牌
读取正常,但在 admin 组织中写入失败令牌属于组织 A 中的用户,但数字 ID 属于组织 B使 organization_uuid 与令牌所属组织一致
create_portal 出现 Menu already created主门户已删除,但组织菜单状态仍然存在删除孤立的子门户;避免直接调用 createInterface;在现有 UUID 上使用 create_portal_page 进行初始化
构建器中的主页面为空门户是在 create_portal 模板路径之外创建的使用 create_portal_page(仅标题)创建模板化元素
列表中缺少 published符合预期使用 get_portal
get_portal 中有许多子门户,但主界面为空子门户尚未发布到 forms 插槽对每个子门户调用 publish_sub_portal + forms element_id
发布无效元素类型错误,或跳过了 internal_api 连线get_portal → forms 元素 → publish_sub_portal
subPortals[] 为空,但界面显示了磁贴链接位于 pages[].elements 下检查 elements[] 中的 type: subPortal
create_portal_element 结果不明或出现 500某些组织的 Interfaces 不稳定从同一页面上的现有组件使用 duplicate_portal_element
门户查看器出现 HTTP 500存在孤立的 layout 子项,或布局结构错误从 get_portal 复制/修复布局;删除临时测试页面
嵌套的 success: falseAPI 拒绝了变更读取 error.message;不要仅凭顶层成功状态作判断
元素验证失败元数据键错误或部分更新提供完整的元数据内容;根据类型使用 linkName / name

另请参阅

  • docs/mcp/tools/portal.md — 端点、连线命名、维护者内省
  • pipefy-introspection — 在更改工具前验证 Interfaces / internal_api 变更

评论

支持 Markdown