news 2026/7/9 2:08:13

绕过 Claude Desktop!Affinity MCP 直连 WorkBuddy/Cursor 完整配置指南(Windows)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
绕过 Claude Desktop!Affinity MCP 直连 WorkBuddy/Cursor 完整配置指南(Windows)

绕过 Claude Desktop!Affinity MCP 直连 WorkBuddy/Cursor 完整配置指南(Windows)

适用人群:Affinity Designer / Photo / Publisher 用户,想用自然语言操控设计软件、批量处理图层、自动化设计工作流的开发者。

Windows 本地配置记录:把 Affinity by Canva 的 MCP 连接到 Codex

楔子:Affinity 终于有脚本接口了——只是藏得有点深

2026 年 4 月,Canva 在 Affinity 的「April '26」版本中悄悄内置了MCP(Model Context Protocol)服务器。官方文档只说"配合 Claude Desktop 使用",而且宣称中国区不可用

经过一整天的逆向分析和踩坑,我成功绕过了所有限制:

  • 中国区 Windows 版本可用(设置里直接有 MCP 开关)
  • 不需要 Claude Desktop(直连 SSE 端点即可)
  • 支持 WorkBuddy、Cursor、Codex 等任意 MCP 客户端
  • 暴露 11 个 MCP 工具 + 完整 JavaScript SDK(文档、文档节点、图层、文字、颜色、填充、导出…全部 API)

这篇文章记录完整的发现过程和配置方法。


一、前置条件

条件要求
Affinity 版本April '26 或更新(我用的 Designer 2.6.x,Photo/Publisher 同理)
操作系统Windows 10/11(macOS 同理,端口绑定行为可能不同)
MCP 客户端WorkBuddy / Cursor / Codex / Claude Desktop(任选)

打开 Affinity MCP

  1. 打开 Affinity
  2. Edit → Settings → Model Context Protocol
  3. 勾选Enable MCP server
  4. 把下面这些权限也全部打开(后面要用):
    • 访问桌面上的文件
    • 访问网络
    • 使用已保存的脚本
    • 将脚本保存到脚本面板
    • 保存任务提示到设备本地内存
  5. 重启 Affinity


二、架构剖析:官方方案的"套娃结构"

先搞清楚官方是怎么连的,才能谈"怎么绕"。

官方连接链路

Claude Desktop(AI 客户端) │ │ stdio(标准输入输出) ▼ Affinity Connector(Node.js 代理,npm 包) │ ant.dir.gh.canva.affinity v1.0.8 │ 安装位置:%APPDATA%/Claude/Claude Extensions/ant.dir.gh.canva.affinity/ │ 入口:server/index.js │ │ SSE Client Transport → http://localhost:6767/sse ▼ Affinity 应用(内置 MCP Server) │ 进程名:Affinity.exe │ 监听:[::1]:6767(IPv6)

关键发现:Claude Desktop 的 Affinity Connector 本质上就是个stdio ↔ SSE 转发代理。它没有自己的业务逻辑,所有工具调用直接透传给 Affinity。

代理源码印证

server/index.js核心代码(简化后):

const SSE_URL = process.env.SSE_URL || "http://localhost:6767/sse"; // 作为 MCP Server 暴露给 Claude Desktop(stdio 传输) const stdioTransport = new StdioServerTransport(); await server.connect(stdioTransport); // 同时作为 MCP Client 连接到 Affinity(SSE 传输) async function freshConnect() { const transport = new SSEClientTransport(new URL(SSE_URL)); const client = new Client({ name: "Claude Desktop", version: "1.0.8" }); await client.connect(transport); upstream = client; } // 工具调用直接转发 server.setRequestHandler(CallToolRequestSchema, async (request) => { return await withUpstream(() => upstream.callTool(request.params)); });

既然代理只是个透明转发层,我们当然可以直连 Affinity 的 SSE 端点,完全跳过 Claude Desktop。


三、配置任意 MCP 客户端

Schema:11 个可用工具

工具描述毁坏性
execute_script执行 JavaScript 脚本(核心工具,万物皆可操作)🔴 毁坏性
render_spread渲染整个画布/页面 → base64 JPEG🟢 只读
render_selection渲染当前选中对象 → base64 JPEG🟢 只读
list_sdk_documentation列出 Affinity JavaScript SDK 全部文档主题🟢 只读
read_sdk_documentation_topic读取指定 SDK 文档内容🟢 只读
search_sdk_hints从百万级全局 hints 中搜索参考方案🟢 只读
list_library_scripts列出脚本库中所有已保存脚本🟢 只读
read_library_script读取脚本库中指定脚本源码🟢 只读
save_script_to_library将脚本保存到脚本库(可复用)🔴 毁坏性
add_sdk_hint贡献 hint 到全局池🔴 毁坏性
report_sdk_issue向 Serif 报告 SDK 问题🔴 毁坏性

WorkBuddy 配置

编辑~/.workbuddy/mcp.json,添加:

{ "mcpServers": { "affinity": { "url": "http://[::1]:6767/sse", "transport": "sse", "disabled": false } } }

然后去 WorkBuddy 连接器管理页面点「重连」或重启 WorkBuddy。

Cursor / Codex / 其他 MCP 客户端

同样的配置,把urltransport写入对应的mcp.json即可:

{ "mcpServers": { "affinity": { "url": "http://[::1]:6767/sse", "transport": "sse" } } }

⚠️ 关键注意事项:IPv6 绑定

Affinity 的 MCP Server只绑定 IPv6,不绑定 IPv4!

地址结果
http://127.0.0.1:6767/sseECONNREFUSED(IPv4 没人在家)
http://[::1]:6767/sse✅ 正常返回 SSE endpoint
http://localhost:6767/sse⚠️ 取决于系统 IPv4/IPv6 优先级,不稳定

必须使用[::1]格式!

可以用 curl 验证:

# 验证 IPv4(应该失败) curl http://127.0.0.1:6767/sse # 验证 IPv6(应该返回 SSE endpoint) curl http://[::1]:6767/sse # 预期输出: # event: endpoint # data: /message?session_id=xxxxxxxxxxxxxxxxxxxxx


四、验证连接 & 初探 SDK

连接成功后,先让 AI 执行list_sdk_documentation查看全部可用的 SDK 文档。会返回一个庞大的清单,包含:

Affinity JavaScript SDK 全览

# 文档核心模块 document.js — 文档对象 API nodes.js — 图层/节点操作 layereffects.js — 图层效果(阴影、发光等) curvesinterface.js — 贝塞尔曲线路径 shapeinterface.js — 形状操作 textframeinterface.js — 文字框 story.js — 文字排版引擎(段落、字符属性、样式) selections.js — 选区管理 rasterinterface.js — 光栅/位图操作 vectorbrush.js — 矢量画笔 artboardinterface.js — 画板操作 exportconfig.js — 导出配置 colours.js — 颜色管理 fills.js — 填充(渐变/图案/位图) blendmodeinterface.js — 混合模式 geometry.js — 几何变换 fonts.js — 字体管理 # 示例脚本 examples/artboardGrid.js — 创建画板网格 examples/addGuides.js — 添加参考线 examples/alignToPage.js — 对齐到页面 examples/tableFromJson.js — 从 JSON 生成表格 examples/flexibleLayout.js — 弹性布局 # 单元测试(学习 API 的最佳参考) tests/documentTests.js tests/storyTests.js tests/curveTests.js ...(20+ 个测试文件,覆盖所有核心 API)

五、API 核心模式:从猜到对

⚠️ 这一节很重要——Affinity SDK 的 API 不是"直觉型"的,踩了很多坑才跑通。

5.1 必须显式require()导入

Affinity 的 JS 引擎不暴露全局变量。所有模块(DocumentShapeNodeDefinitionRGBA8…)必须用require()导入才能使用:

var Document = require('/document').Document; var NewDocumentOptions = require('/document').NewDocumentOptions; var UnitType = require('/units').UnitType; var RasterFormat = require('/rasterobject').RasterFormat; var ShapeNodeDefinition = require('/nodes').ShapeNodeDefinition; var Shape = require('/shapes').Shape; var ShapeType = require('/shapes').ShapeType; var FillDescriptor = require('/fills').FillDescriptor; var RGBA8 = require('/colours').RGBA8; var BlendMode = require('affinity:common').BlendMode; var Rectangle = require('/geometry').Rectangle;

直接写Document.create(...)不导入?→ReferenceError: Document is not defined

5.2 创建文档

var opts = NewDocumentOptions.createDefault(); opts.width = 600; opts.height = 240; opts.units = UnitType.Pixel; opts.rasterFormat = RasterFormat.RGBA8; opts.dpi = 150; var doc = Document.create(opts); var dpi = doc.dpi; // 后面文字样式要用 var fmt = doc.rasterFormat;

5.3 创建形状:三个坑

坑 1:边界框必须用new Rectangle(),不能用{x,y,w,h}字面量

// ❌ 报错:expected RectangleHandle ShapeNodeDefinition.create(shape, {x:0, y:0, w:600, h:240}, fill, null, null, null); // ✅ 正确 ShapeNodeDefinition.create(shape, new Rectangle(0, 0, 600, 240), fill, null, null, null);

坑 2:create()第一个参数是Shape对象,不是ShapeType枚举

// ❌ 直接传枚举 ShapeNodeDefinition.create(ShapeType.Rectangle, ...); // ✅ 先用 Shape.create() 包装 var shape = Shape.create(ShapeType.Rectangle); ShapeNodeDefinition.create(shape, new Rectangle(0,0,600,240), fill, null, null, null);

坑 3:形状必须用addShapeNode(),文字才用addNode()

var def = ShapeNodeDefinition.create(shape, rect, fill, null, null, null); var builder = AddChildNodesCommandBuilder.create(); // ❌ 形状用 addNode 会静默失败(图层不出现) builder.addNode(def); // ✅ 形状用 addShapeNode builder.addShapeNode(def); doc.executeCommand(builder.createCommand(false, NodeChildType.Main));

5.4 创建文字:最大的坑

文字节点用ArtTextNodeDefinition+StoryBuilder创建。直接addText()后文字存在但不可见——因为缺少默认文本样式。

关键:必须调用setToArtisticTextDefaultStyle(dpi, format)

var StoryBuilder = require('/storybuilder').StoryBuilder; var GlyphAtts = require('/glyphatts').GlyphAtts; var GlyphAttDoubleType = require('/glyphatts').GlyphAttDoubleType; var StoryDelta = require('/storydelta').StoryDelta; var ArtTextNodeDefinition = require('/nodes').ArtTextNodeDefinition; var sb = StoryBuilder.create(); // ⚠️ 这一行是文字可见的关键!不调文字就隐形 sb.setToArtisticTextDefaultStyle(dpi, fmt); // 设置字号(用 applyGlyphDelta,不是 ga.height) sb.applyGlyphDelta( StoryDelta.createGlyphDouble(GlyphAttDoubleType.Height, 34) ); // 设置文字颜色 var ga = GlyphAtts.create(); ga.brushFill = FillDescriptor.createSolid(RGBA8(255, 255, 255, 255), BlendMode.Normal); sb.setGlyphAtts(ga); // ⚠️ setGlyphAtts 会重置字号,必须重新 apply sb.applyGlyphDelta( StoryDelta.createGlyphDouble(GlyphAttDoubleType.Height, 34) ); // 添加文字内容 sb.addText('Hello World'); // 创建节点 var def = ArtTextNodeDefinition.createFromStoryBuilder({x: 50, y: 100}, sb); var builder = AddChildNodesCommandBuilder.create(); builder.addNode(def); // 文字用 addNode,不是 addShapeNode doc.executeCommand(builder.createCommand(false, NodeChildType.Main));

5.5 渲染验证

// 获取文档 UUID console.log('UUID:', doc.sessionUuid); // 输出类似:UUID: 92F6B057-2CDD-4691-8599-222B4C350AF5

然后用render_spread工具,传入document_session_uuidspread_index: 0,得到 base64 JPEG 预览。

注意render_spread的视口约为700×525px固定大小。画布尺寸超过此范围的,右侧内容会被裁切。建议设计稿宽度控制在 650px 以内,或使用较小画布多次渲染。


六、实战:程序化生成店招海报

把上面的 API 组合起来,用一段脚本在 Affinity 中生成完整的店招海报。

效果预览

深蓝底 + 金色装饰条 + 菱形装饰 + 中英文文字,全部通过代码生成:

元素说明
背景深海军蓝RGBA8(15, 23, 42, 255)
顶/底装饰条金色矩形RGBA8(212, 175, 55, 255)
左右菱形各 3 个递减大小金色菱形
主标题AICSF Studio — 白色 34pt
副标题AI Commercial Svc Framework — 金色 13pt
中文标语让 AI 成为每个人的超级能力 — 白色 12pt
角标by AICSF — 金色 9pt

完整代码

// === 导入所有模块(必须显式 require) === var Document = require('/document').Document; var NewDocumentOptions = require('/document').NewDocumentOptions; var UnitType = require('/units').UnitType; var RasterFormat = require('/rasterobject').RasterFormat; var ShapeNodeDefinition = require('/nodes').ShapeNodeDefinition; var ArtTextNodeDefinition = require('/nodes').ArtTextNodeDefinition; var AddChildNodesCommandBuilder = require('/commands').AddChildNodesCommandBuilder; var NodeChildType = require('/nodes').NodeChildType; var StoryBuilder = require('/storybuilder').StoryBuilder; var GlyphAtts = require('/glyphatts').GlyphAtts; var GlyphAttDoubleType = require('/glyphatts').GlyphAttDoubleType; var FillDescriptor = require('/fills').FillDescriptor; var RGBA8 = require('/colours').RGBA8; var BlendMode = require('affinity:common').BlendMode; var Shape = require('/shapes').Shape; var ShapeType = require('/shapes').ShapeType; var StoryDelta = require('/storydelta').StoryDelta; var Rectangle = require('/geometry').Rectangle; // === 创建文档 === var opts = NewDocumentOptions.createDefault(); opts.width = 600; opts.height = 240; opts.units = UnitType.Pixel; opts.rasterFormat = RasterFormat.RGBA8; opts.dpi = 150; var doc = Document.create(opts); var dpi = doc.dpi, fmt = doc.rasterFormat; // === 工具函数 === function addShape(shapeType, x, y, w, h, fill) { var s = Shape.create(shapeType); var d = ShapeNodeDefinition.create(s, new Rectangle(x, y, w, h), fill, null, null, null); var b = AddChildNodesCommandBuilder.create(); b.addShapeNode(d); doc.executeCommand(b.createCommand(false, NodeChildType.Main)); } function addText(text, x, y, height, fillColor) { var sb = StoryBuilder.create(); sb.setToArtisticTextDefaultStyle(dpi, fmt); // 关键! sb.applyGlyphDelta(StoryDelta.createGlyphDouble(GlyphAttDoubleType.Height, height)); if (fillColor) { var ga = GlyphAtts.create(); ga.brushFill = fillColor; sb.setGlyphAtts(ga); sb.applyGlyphDelta(StoryDelta.createGlyphDouble(GlyphAttDoubleType.Height, height)); } sb.addText(text); var def = ArtTextNodeDefinition.createFromStoryBuilder({x: x, y: y}, sb); var b = AddChildNodesCommandBuilder.create(); b.addNode(def); doc.executeCommand(b.createCommand(false, NodeChildType.Main)); } // === 颜色定义 === var navyFill = FillDescriptor.createSolid(RGBA8(15, 23, 42, 255), BlendMode.Normal); var goldFill = FillDescriptor.createSolid(RGBA8(212, 175, 55, 255), BlendMode.Normal); var whiteFill = FillDescriptor.createSolid(RGBA8(255, 255, 255, 255), BlendMode.Normal); var goldDimFill = FillDescriptor.createSolid(RGBA8(160, 135, 30, 255), BlendMode.Normal); // === 1. 深蓝背景 === addShape(ShapeType.Rectangle, 0, 0, 600, 240, navyFill); // === 2. 顶/底金色装饰条 === addShape(ShapeType.Rectangle, 0, 0, 600, 3, goldFill); addShape(ShapeType.Rectangle, 0, 237, 600, 3, goldFill); // === 3. 左侧菱形装饰(3个递减) === addShape(ShapeType.Diamond, 12, 88, 14, 14, goldFill); addShape(ShapeType.Diamond, 12, 108, 9, 9, goldFill); addShape(ShapeType.Diamond, 12, 124, 5, 5, goldFill); // === 4. 右侧菱形装饰 === addShape(ShapeType.Diamond, 574, 88, 14, 14, goldFill); addShape(ShapeType.Diamond, 579, 108, 9, 9, goldFill); addShape(ShapeType.Diamond, 582, 124, 5, 5, goldFill); // === 5. 文字 === addText('AICSF Studio', 32, 72, 34, whiteFill); addText('AI Commercial Svc Framework', 34, 115, 13, goldFill); addText('让 AI 成为每个人的超级能力', 34, 140, 12, whiteFill); addText('by AICSF', 490, 220, 9, goldDimFill); console.log('UUID:', doc.sessionUuid);

执行后用render_spread渲染即可看到完整海报。整个过程零 UI 操作,完全代码驱动。

踩坑总结表

问题原因解决方案
Document is not defined未 require 导入每个 API 都要显式require()
形状图层不出现用了addNode()形状用addShapeNode(),文字用addNode()
expected RectangleHandle传了{x,y,w,h}字面量必须用new Rectangle(x, y, w, h)
文字创建成功但不可见缺少默认文本样式调用sb.setToArtisticTextDefaultStyle(dpi, fmt)
setGlyphAtts后字号消失setGlyphAtts 重置了所有属性之后重新applyGlyphDelta设字号
渲染右侧被裁切render_spread 视口 ~700px画布控制在 650px 宽以内

七、常见问题

Q1:中国区能用吗?

能。官方文档说 “MCP is not available in Affinity China”,但我用的就是中国区购买的版本(Windows),设置里 MCP 开关可用、端口正常监听。这个限制可能只是针对某些特定渠道,或者未严格执行。

Q2:一定要 Claude Desktop 吗?

不。这篇文章的核心结论就是:Affinity MCP Server 是独立的 SSE 服务,任何支持 SSE 传输的 MCP 客户端都可以直连。

Q3:端口会变吗?

不会。端口固定6767,变的是每次连接的session_id(SSE 协议标准行为)。

Q4:为什么我的连接失败?

  1. 检查 Affinity 是否正在运行
  2. 检查Edit → Settings → Model Context Protocol → Enable MCP server是否勾选
  3. 检查端口:netstat -ano | findstr 6767
  4. 确认使用 IPv6 地址http://[::1]:6767/sse

Q5:支持哪些 Affinity 产品?

Designer、Photo、Publisher 均支持。MCP Server 是 Affinity 框架层功能,不是某个具体产品的独有功能。

Q6:文字创建成功但渲染不可见?

检查是否调用了sb.setToArtisticTextDefaultStyle(dpi, fmt)。不调用这行,StoryBuilder不会设置默认填充色,文字虽然存在于图层列表中(doc.layers可查到plainText),但渲染时完全透明。详见第五节 5.4。

Q7:渲染出来的画面右边被截断?

render_spread工具的视口约为 700×525px 固定大小,超过部分被裁切。如果画布是 1200px 宽,只有左侧约 650px 可见。解决方案:设计稿控制在 650px 宽以内,或分区域多次渲染。


八、后续方向

打通 MCP 并验证实战之后,这些方向已经具备可行性:

  1. 批量设计自动化— “把文件夹里 100 张图全部加上水印,导出 PNG”(已验证形状+文字+渲染链路)
  2. 模板引擎— 从数据库/CSV 读取数据,自动填充到 Affinity 模板生成海报(本文店招海报即为原型验证)
  3. 图层 AI 管理— “按内容自动分组和命名所有图层”(doc.layers可迭代,isArtTextNode/isShapeNode可判断类型)
  4. 设计审查机器人— 检查颜色一致性、边距违规、字体缺失
  5. 跨工具联动— ComfyUI 出图 → Affinity 排版 → 一键发布
  6. 脚本库复用save_script_to_library保存常用生成脚本,后续run_saved_workflow一键调用

总结

阶段认知事实
之前「Affinity 没有脚本接口,无法自动化」错的
探索「只有 Claude Desktop 能用 MCP」不完全
破解后「任何 MCP 客户端都能直连 Affinity 的 SSE 端点」

从"完全没有脚本能力"到"11 个 MCP 工具 + 完整 JS SDK 直接可用",再到实际跑通程序化海报生成——Affinity 的自动化潜力比想象中大得多。希望这篇文章能帮到同样在 Windows 上用 Affinity 的开发者。


作者:WorkBuddy × 用户联合探索
日期:2026-07-08(初版)/ 2026-07-09(更新:补充真实 API 模式 + 店招海报实战案例)
技术栈:Affinity April '26 · MCP · SSE · WorkBuddy · JavaScript
更新记录

  • 2026-07-09:第五节重写为真实验证过的 API 模式(替换猜测 API),新增第六节店招海报完整实战代码,补充踩坑总结表
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/9 2:05:52

javaweb结课设计

一、项目概述 电视节目管理系统是一个面向广播电台和电视节目制作单位的Web应用,实现节目信息管理、主持人管理、观众留言管理等核心功能,解决传统Excel管理方式中信息分散、查询不便、留言处理不及时等问题。 - - - 技术栈 后端采用 Spring Boot 3.5.…

作者头像 李华
网站建设 2026/7/9 2:05:32

标书撰写基本逻辑

真正能提高中标率的,不是把参数写死成“只有我们能中”,而是把产品的真实优势转化成“标准依据、检测报告、平台接入、运行案例、验收闭环、售后能力”这套证据链。 这样能合规地把低价拼装厂家、无检测厂家、无平台厂家、无现场经验厂家筛出去。 不写“…

作者头像 李华
网站建设 2026/7/9 2:05:00

Tokio io_uring 支持:异步 I/O 在 Linux 上的新路径

Tokio io_uring 支持:异步 I/O 在 Linux 上的新路径 一、epoll 挺好,但还不够 Tokio 是目前 Rust 异步生态的绝对核心。它的 TcpListener、File、定时器这些组件,让异步 I/O 在 Rust 里变得和同步 I/O 一样顺手。但如果你把它的底层引擎拆开…

作者头像 李华
网站建设 2026/7/9 2:04:40

ISC DHCP完全指南:网络自动配置的终极解决方案

ISC DHCP完全指南:网络自动配置的终极解决方案 【免费下载链接】dhcp ISC DHCP is a collection of software that implements all aspects of the DHCP (Dynamic Host Configuration Protocol). 项目地址: https://gitcode.com/openeuler/dhcp 前往项目官网…

作者头像 李华
网站建设 2026/7/9 2:00:52

AI Agent频繁执行失败?5个工作流配置问题必须检查

摘要AI Agent执行失败,不一定是模型能力不足,更常见的原因是工具参数、任务边界、上下文状态、终止条件和日志追踪没有配置完整。本文整理5个常见工作流问题,帮助快速定位Agent调用失败、重复执行和任务卡住的原因。很多人在搭建AI Agent后&a…

作者头像 李华