自托管 Macro 容易撞的几类坑:端口窗口、OAuth 回调端口与本地 MCP 服务边界

2026-08-17

Macro 的自托管入口其实很短:装好 Nix 和 Docker,nix develop 进壳,然后 just run_local --no-doppler,剩下的编译、起基础设施、起后端、起代理和前端由这一条命令包办。真正会卡住人的不是这条命令本身,而是它跑完之后的那些「起来了但不对劲」——前端能打开,登录却转不回来;API 请求返回的是 HTML 不是 JSON;MCP 客户端连不上,不知道该指向哪个地址。

这篇把自托管阶段最容易撞的几类问题拉出来单说。需要先讲清楚本文的取材口径,因为它决定了每一条你能指望到什么程度:

  • 有官方处理办法的,来自仓库里的 docs/RUNNING_LOCALLY.md,我会把命令和标志原样给出;
  • 只是「有人报过」的,来自 macro-inc/macro 仓库的 issue 标题(截至 2026-08-17)。issue 标题只能说明有人在这个地方遇到了麻烦,不能当成结论,更不是解决方案。凡是官方文档里没写处理办法的,我会明写「官方尚未给出解决方案」,不去替官方编一个。

我们没有部署运行过这套栈,下面所有内容都来自文档和仓库公开信息,不含任何实测数据或界面描述。完整的本地启动步骤在自托管 Macro 的完整本地启动步骤那篇里,本文只讲踩坑面。

端口:默认实例绑一组固定端口,macOS 会跟你抢

这是文档花篇幅最多的一类问题,也说明它足够常见。

默认实例(不带 --instance)绑定的是一组固定的宿主机端口。文档点名了两个在 Mac 上最常撞的:

端口谁在占撞上之后的表现
8080macOS 自带的 WebDriver 服务 com.apple.WebDriver.HTTPService,开启远程自动化时会监听它认证服务绑不上这个端口
8090别的项目的开发服务器,文档举的例子是带 --port 8090 的 Expo本地代理绑不上这个端口

撞上之后的症状很有欺骗性:前端照常加载,你以为起来了,但登录和 API 调用打到了另一个进程上,于是你看到的是 HTML 或者控制台报错,而不是预期的 JSON。如果你的第一反应是去查后端日志,很可能什么都查不到,因为请求压根没进 Macro 的服务。

文档给的处理办法是先体检再动手,而且不需要去杀掉占端口的那个进程

just doctor-local                                     # 看默认端口哪些被占了
just doctor-local --instance test --port-base 31000   # 确认新窗口是空的
just run_local --no-doppler --instance test --port-base 31000

just doctor-local 是文档建议在第一次启动前就跑一遍的预检,它会检查 Docker 守护进程、工具链和所需端口,报告问题并给出建议。启动失败之后也可以再跑一次。

原理是:命名实例会把每个服务绑到 port-base + 偏移量 上,挑一个空闲的基准值(文档举例 31000)就能把整套栈平移到一段连续且空闲的窗口里。同一个实例名每次运行拿到的端口是确定的,所以后续保持相同的 --instance--port-base 就不会漂。

端口一改,后面每条命令都得跟着改

这是紧跟着上一条的连带坑,文档专门警告过。

--instance--port-base 这两个标志必须在每一条命令上保持一致——起栈、灌种子数据、看状态,全都要带:

just run_local --no-doppler --instance test --port-base 31000
just seed-scenario --instance test --port-base 31000 apply --file seed/scenarios/team-perms.json
just seed-scenario --instance test --port-base 31000 status --file seed/scenarios/team-perms.json
just status_local --instance test --port-base 31000

漏掉 --port-base 不会报「参数缺失」这种明显错误:命名实例会退回到由实例名推导出的那个确定性端口窗口,而那个窗口跟你手动指定的并不是同一个。文档的原话是,用显式 --port-base 启动的栈,也必须用同样显式的 --port-base 去灌种子,否则种子 CLI 会去看错误的那个数据库。这种错法不会崩,只会让你对着一个空空的界面怀疑人生。

还有一个细节:种子生成的人格登录链接里嵌了前端端口(形如 http://alice.localhost:3000/app/login?email=alice@seed.macro.local)。换过端口之后,旧链接就失效了,得重新跑一次 just seed-scenario apply 拿新链接。想看当前实际端点,just status_local 带上同样两个标志会打印出来。

默认实例(不带 --instance)用的一直是那组固定端口,不需要任何额外标志。

OAuth 回调端口:有人报过写死的问题,官方文档没覆盖

上面那条延伸出来的问题,在仓库里有人提过。截至 2026-08-17,macro-inc/macro 有一条开放状态的 issue,标题是「OAuth redirect URI hardcoded to localhost:8085, doesn’t account for --instance/--port-base」(#5682)——意思是 OAuth 回调地址被写死成了 localhost:8085,没有把 --instance--port-base 造成的端口平移考虑进去。

必须强调:这只说明有人在这个位置遇到了问题。我没有复现过,也不会替它编一套复现步骤或修法。

那官方文档怎么说?docs/RUNNING_LOCALLY.md 里关于端口的段落,只讲了实例端口窗口和 macOS 端口冲突,没有任何一段涉及 OAuth 回调地址如何跟着实例端口走。文档里跟第三方登录相关的内容只有集成密钥那张表:Google 登录/Gmail 要 GOOGLE_CLIENT_IDGOOGLE_CLIENT_SECRET_KEY,GitHub 登录要 GITHUB_CLIENT_IDGITHUB_CLIENT_SECRETGITHUB_IDP_ID,配法是把真实值写进一个 local.env 再传进去:

just run_local --no-doppler --env-file ./local.env

回调地址怎么随端口变,文档没提。所以这条的结论只能是:官方尚未在公开文档里给出解决方案。如果你正好要在非默认端口窗口上调 OAuth 登录,把这条当成已知风险点看待,而不是当成一个有现成解法的配置项。

顺带说一个能绕开它的路径:本地栈不依赖任何外部登录也能创建用户。无密码登录是按需建号的,用任意邮箱注册,FusionAuth 会发一次性验证码,而这封信落在 Mailpit(http://localhost:8025,不会进真实邮箱。只是想把界面点起来的话,走这条路比配 OAuth 省事得多。

集成默认全是桩值,「不工作」是预期行为

很多人第一次跑完 --no-doppler 会以为自己配错了,其实文档写得很直白:这套栈用代码里定义的本地配置启动,带着假的 AWS 凭据和固定的测试密钥,所有第三方集成都是确定性的桩值——足够让服务起得来,但背后的集成不通

文档把每个桩的具体表现列成了表,这张表比「不工作」三个字有用得多:

集成桩值下的实际表现
Google 登录 / GmailGoogle SSO 和 Gmail 收件箱绑定不可用;本地注册照常工作;邮件服务会报告没有 Gmail 授权并跳过收件箱同步
GitHub 登录用 GitHub 登录不可用
Stripe 计费结账和订阅相关端点会失败;注册仍然可用——建用户的 webhook 检测到是桩密钥就跳过真实 Stripe 调用,存一个占位的 customer id
CloudFront 签名 URL文档下载 URL 不签名(对本地 S3 而言没问题)

除这四个之外的桩值(REDIS_HOSTMACRO_DB_URLINTERNAL_API_KEYAUTHENTICATION_SERVICE_SECRET_KEYOPENSEARCH_USERNAMEOPENSEARCH_PASSWORD)文档明说是内部管线,本地值本来就是对的,不需要你去覆盖。有人排查问题时习惯把所有环境变量都改一遍,这里属于改了只会更乱。

文档同时给了一句定心话:认证、文档、邮件、搜索这几块在桩值下是完整可用的。所以自托管跑不通 Gmail 不等于你的栈坏了。

本地 MCP 服务的边界:这条目前是开放问题

Macro 的 MCP 面在托管版上是明确的,README 里直接给了接入命令:

claude mcp add --transport http macro https://mcp-server.macro.com/mcp

自托管这边则要谨慎得多。docs/RUNNING_LOCALLY.md 列了 run_local 会做的四件事——编译 Rust 后端服务、起本地基础设施(Postgres、Redis、LocalStack、OpenSearch、Kafka、FusionAuth)、起后端服务、起本地代理和前端——这份清单里没有单独点名 mcp_service,文档里也没有一节讲自托管栈上 MCP 端点在哪、怎么连。

仓库里有人问的正是这件事。截至 2026-08-17 有两条开放 issue 用了同一个标题:「Does mcp_service run under run_local, or is MCP local-workspace access not yet supported for self-hosted?」(#5673、#5664)——即 mcp_service 是否随 run_local 启动,或者说自托管下的 MCP 本地工作区访问是不是还不支持。同一个问题被问两次,本身就说明文档在这里留了空白。

结论同样只能停在事实上:官方文档尚未说明自托管栈下的 MCP 服务边界,也未给出解决方案。 在拿到官方口径之前,不要在方案里默认「自托管 = MCP 也能本地用」。想先了解 MCP 面本身能做什么,可以看 Macro 的 MCP 服务能做什么

MCP 服务端注册与鉴权:几条被报过的口子

这一类问题不限于自托管,但自托管的人会更早撞上,因为托管版帮你挡掉的东西自托管都要自己面对。截至 2026-08-17,macro-inc/macro 的开放 issue 里有这么几条:

issue标题说的是什么官方文档是否给出处理办法
#5598没有动态客户端注册(Dynamic Client Registration)的 MCP 服务端连不上,举的例子是 HubSpotRUNNING_LOCALLY.md / README 均未涉及,本文所据文档未给出解决方案
#5519受保护资源的元数据缺少 RFC 9728 要求的 resource 字段同上,未给出解决方案
#5465功能请求:MCP 连接器的鉴权 token / 请求头。该 issue 在仓库里被打了 planned 标签标签只表示仓库把它列入计划,本文所据文档未提供可用配置
#5669ListEntities 的 AST 过滤参数没有发出类型信息,导致按 schema 驱动的 MCP 客户端把它们当字符串发送同上,未给出解决方案
#5606功能请求:让远程 / 自托管 agent 成为可被调度的 ActionKind属于计划性请求,尚未提供

这几条放在一起看有个共同点:都发生在 Macro 作为 MCP 客户端去连别人,或者别的客户端按标准来连 Macro 的接缝上。标准化的鉴权和注册流程一旦有缺口,表现出来就是「连不上」,但根因分散在协议细节里。具体到连接失败该怎么排查,MCP 连不上:动态客户端注册与鉴权头那篇按官方 MCP 文档展开。

另外提醒一句红线:README 提到 MCP 面「没有速率限制」,那是针对托管服务说的,别把这句话搬到自托管环境上当结论。

三个不算 bug 但很浪费时间的地方

辅助服务的镜像不会自动重建。 Rust 服务是在宿主机上用 cargo zigbuild 编的,二进制挂进共享运行时镜像,按 r 只重建改动过的服务。但有三个服务是 Docker 构建出镜像的——sync_servicelexical_servicewebsocket_service——默认不重建。你改了它们,运行中的栈可能还在用旧镜像,症状是改了代码没反应。处理办法是带上标志启动:

just run_local --build-aux-services

带上这个标志之后,按 r 才会重建这些镜像并重建容器。文档也提醒这样更慢,不动这三个服务就别开。如果已经没带标志起来了又怀疑镜像陈旧,先按 q 停掉,再带标志重启。

退出要按 q,不要直接关终端窗口。 q 会一次性停掉并移除容器,下次启动不必先清理残留的栈。关窗口留下的是脏状态。

nix develop 失败先想实验性特性。 这不是环境坏了,Nix 需要开启对应的实验性特性:

nix develop --extra-experimental-features nix-command --extra-experimental-features flakes

这条只对当次生效。想永久开启,在 ~/.config/nix/nix.conf 里写 experimental-features = nix-command flakes。另外默认的 shell 不含 Tauri 平台依赖,它们体积大,被拆进了单独的 shell:Linux 桌面开发用 nix develop .#tauri-linux,x86_64 Linux 上做 Android 开发用 nix develop .#tauri-android

什么情况下这篇帮不上你

你想要的是生产级自托管。 上面所有内容都基于 RUNNING_LOCALLY.md,这份文档讲的是在自己机器上把 Macro 跑起来,不是生产部署指南。自托管在授权层面的边界另说,README 写明 Macro 以 AGPLv3 开源,可以在 AGPLv3 条款下自托管,商业与托管相关事宜要走官方联系方式;这块见 AGPL 协议与 Macro 自托管的边界

你撞的是本文没覆盖的 issue。 仓库开放 issue 里还有几条跟自托管取舍相关但方向不同的,例如「Add support for local and custom OpenAI-compatible models」(#4795,带 planned 标签)、「Feature: Add support for IMAP/SMTP」(#5652)、「Outlook / Microsoft Graph mail provider: status and can we help?」(#5670)。这些都是尚未提供的能力,不要按已有功能去规划。

你需要的是「这条 issue 怎么修」。 这篇给不了。凡是文档没写处理办法的,我只写到「官方尚未给出解决方案」为止,因为再往前一步就是编造,而部署文里编造出来的一条命令,代价通常由读者来付。

真要动手,最稳的顺序是:先 just doctor-local 看端口,选一个空闲的 --port-base 定下来,之后每条命令都带着相同的 --instance--port-base;先用 Mailpit 的无密码登录把界面跑通,再决定要不要碰 OAuth 和 MCP 这两块目前还有开放问题的区域。

延伸阅读


本文依据 Macro 官方仓库(github.com/macro-inc/macro,AGPL-3.0 协议)的 apps/docs/ 产品文档、 MCP 工具参考与自托管说明整理,核对日 2026-08-17。 我们没有注册或运行过 Macro,因此不涉及界面外观与操作手感; 官方标注为计划中的能力文中已如实标明,不代表当前可用。 价格与额度以官网 macro.com 最新页面为准;许可证相关问题请咨询专业人士并以官方许可证原文为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。