一篇关于「把 MCP 用好」而不是「把 MCP 装好」的实践记录。
我在一个车企超级 APP 项目的 iOS 迭代里,用蓝湖(Lanhu)MCP + Lookin MCP 搭了一套项目无关的工具层(harness),把 AI 写代码从「看着截图猜」变成了「读着需求写、对着真机验」。这篇文章讲清楚两件事:MCP 和 harness 到底差在哪一层,以及这套东西是怎么一步步落地的。

一、先分清两件事:MCP 是协议,Harness 是交付形态

这两年 MCP(Model Context Protocol)很火,但很多人把它当成万能药:装个 MCP server,AI 就能用了。实际用下来你会发现,MCP 只解决「连接」,不解决「复用」

我的理解是两层:

  • MCP 层:一种开放协议,让 AI 应用(Claude Code、Cursor、ZCode……)以统一方式调用外部工具。它回答的问题是「AI 怎么连上某个能力」。
  • Harness 层:在能力之上做一层项目无关的封装——命令行入口、接入模板、提示词模板、产出目录约定。它回答的问题是「这个能力怎么被任何项目、任何 AI 工具顺手用起来」。

用一个比喻:MCP 是「通了电的插座」,harness 是「把插座装成你能顺手插拔的接线板,还贴好了每个插口的标签」。插座本身很有价值,但真正让工作流跑起来的是那套组织方式。

我们实际搭了两套 harness,分别包着两个 MCP:

蓝湖 MCP(lanhu-mcp) Lookin MCP
管什么 设计源头:需求文档(Axure)、设计稿识别 运行端:真机/模拟器上 App 的实时视图层级
解决什么 AI 读得懂需求、看得见设计 AI 验得了实现、对得上真机
Harness lanhu-harness(CLI + 模板 + 产出分目录) lookin-harness(stdio 桥 + 自检 + 多 IDE 安装)

二、痛点:AI 写 iOS 代码的两个断层

AI 写 iOS 代码这件事,真正卡人的不是「写不出来」,而是两个断层:

断层一:设计源头读不到。 需求在蓝湖的 Axure 原型里,设计稿在蓝湖的切图里。让 AI「打开网页看看」不现实——登录墙、动态渲染、截图信息密度太低。没有结构化输入,AI 只能靠人肉翻译需求,等于没省事。

断层二:运行端验不了。 代码写完了,对不对?光编译通过不够——UI 是不是按设计稿还原的?文案、字号、颜色、约束对不对?传统做法是人眼对着模拟器截图比对,一轮一轮改。AI 自己看不见运行中的 App,就没法自证。

一个管「源头」,一个管「运行端」,两个 MCP 正好补上这两个断层,形成闭环:

1
蓝湖(需求/设计稿)→ AI 理解 → 写代码 → 真机跑起来 → Lookin(实时视图树)→ AI 比对 → 通过/差异

三、落地一:lanhu-harness(设计源头)

蓝湖社区有一个很火的 MCP:dsphper/lanhu-mcp(2k+ star),把蓝湖的文档分析、设计稿识别暴露成 13 个 lanhu_* 工具。它解决了「连上」的问题,但直接用有几个不爽:

  • 依赖 IDE 的 MCP 集成,换工具就要重新配;
  • 没有统一的提示词模板,每次识别结果结构都不一样;
  • 产出散落各处,没法按迭代回溯。

于是我们做了 lanhu-harness,四个东西:

1
2
3
4
5
6
lanhu-harness/
├── bin/lanhu-mcp # 独立 CLI:tools / pages / doc / call 四个子命令
├── .mcp.json # 项目接入模板(拷进任意项目即可直连)
├── prompts/ # 识别任务提示词模板(保证每次产出结构一致)
├── docs/ # 工具参数速查(CLI 自动生成)
└── output/ # 识别产出,按「迭代-端」分目录

关键设计是 bin/lanhu-mcp:一个不依赖任何 IDE 的 stdio MCP 客户端——按需拉起 server、调用工具、把结构化结果和页面截图落盘。终端能跑、脚本能调、任何 AI Agent 都能用。doc 子命令一条命令拉完一个 Axure 文档的指定页面(文本 + 截图 + 样式参考),之后把「截图 + 原文」交给 AI 按 prompts/ 模板做内容识别。

实战效果:在车企 APP 的 0931 迭代里,用它从蓝湖 Axure 里识别了 APP 端 6 页需求——需求跟踪表 7 条、变更类型逐项定性、UI 要点带截图锚点,直接作为迭代计划的需求输入。整个过程从「人肉扒原型」变成「一条命令 + AI 整理」。

四、落地二:lookin-harness(运行端)

Lookin(hughkli/Lookin + QMUI/LookinServer)是 iOS 开发常用的 UI 调试工具(类似 Reveal,免费开源):macOS 端连上跑着 LookinServer 的 Debug 包,就能看到实时视图树、改属性、看约束。它也有 MCP 服务(10 个工具:get_hierarchy / get_view / get_view_attributes / get_screenshot / search_views ……),让 AI 能直接读运行中的 App 视图层级。

但原生的 Lookin MCP 是 HTTP/SSE 常驻服务,接入不同 AI 工具时各有各的别扭。我们做了 lookin-harness,把它的能力桥接成标准 stdio MCP

1
2
3
4
5
6
7
8
lookin-harness/
├── bridge.py # 标准 MCP stdio 桥(10 工具,FALLBACK 静态兜底)
├── lookin_client.py # 核心客户端:端口嗅探 + 会话保持 + 代理绕行
├── lookin_cli.py # 独立 CLI:doctor / status / search / hierarchy / attrs / screenshot…
├── install.sh # 多 IDE 自安装(WorkBuddy / Qoder / Claude / Antigravity / 项目级)
├── .mcp.json # 接入模板
├── prompts/ui-verify.md # UI 实现验证提示词模板
└── docs/ # 工具速查 + 实战坑位表

调通路上踩过的四个坑

  1. 本地回环被代理劫持。 环境里有 HTTP_PROXY 时,urllib 会把 127.0.0.1 的请求也送进代理,拿回 502 Bad Gateway 而不是 Connection refused——端口探测和报错全部失真。解法:客户端显式用 ProxyHandler({}) 绕开系统代理。这是排查时最容易误导人的一个。

  2. MCP 会话是「有状态」的。 Lookin 的 MCP 服务用 per-session transport:initialize 握手后要从响应头拿 MCP-Session-Id,后续所有请求必须带上;会话断了必须重建。最初没按这个来,表现为「偶尔能调通、过一会全失败」。

  3. 「先开 IDE 后开 Lookin」就废了。 很多 MCP 客户端只在启动时拉一次工具列表,拉失败就把整个 server 判死、之后不再重试。Lookin.app 没起时,工具列表直接拉不到。解法是 FALLBACK_TOOLS 静态兜底:桥接层内置一份从实时 tools/list 原样抄来的 10 工具清单,App 没起时也返回工具(工具永远可见),把真实的连接错误推迟到真正调用工具时才报——那时信息更准确,也不至于让 IDE 误杀 server。

  4. 后台假死最难查。 App 切到后台时链路握手会失败,但 TCP socket 已经建立(ESTABLISHED)且永不重建——看起来「连上了」,实际拿不到任何数据。修法只有一条:重启 Lookin.app 并把目标 App 拉回前台(LookinServer 在 didBecomeActive 之后才开始监听)。为此我们把「五步链路自检」做成了 doctor 命令:MCP 端口 → 协议握手 → App 连接 → LookinServer 传输层 → 本机 App,一次定位卡在哪一步。

两个「纸上没写」的真机细节

  • iOS App on Mac 上截图是空白的。 macOS 合成器的渲染路径下,get_screenshot 拿不到内容。所以视觉比对不能依赖截图,要用 get_view / get_view_attributes数值(frame、font、color、constraints)比对——这也更精确。
  • search_views 的 text 语义。 它是按文字内容搜的;UILabel 文案为空时,Lookin 会把属性名(比如 titleLabel)填进 text 字段——搜「空文案」会搜出一堆属性名,别被误导。

五、沉淀下来的五条设计原则

两套 harness 做完,我们总结出五条原则,也成了后续所有工具封装的模板:

  1. 项目无关是底线。 README 第一句就写明「不依附任何业务项目,终端 / 脚本 / 任意 AI Agent 可用」。绑定某个项目或 IDE 的封装,换个项目就废。
  2. CLI 优先。 先给一个终端能跑的命令行,再谈 IDE 集成。CLI 是万能接入点:脚本、CI、任何 AI 工具都能调。
  3. 提示词模板化。 识别任务和验证任务各有一份模板,强制「任务 / 范围判定 / 输出结构 / 质量红线」四要素——保证不同项目、不同迭代的产出结构一致,AI 的发挥空间留给内容而不是格式。
  4. 产出落盘、按目录分。 每次识别的结构化结果、截图、原始数据都落盘到 output/,按迭代分目录。AI 会话会丢,落盘的东西不会。
  5. 给失败设计兜底。 FALLBACK 工具清单、doctor 自检、连接错误延迟报告——这套「失败了也要让上层拿到可诊断的信息」的思路,比把错误闷在日志里有用得多。

六、写在最后

这套东西目前还在我们自己的迭代里打磨——还有真机环境的完整复测、Cookie/凭据的自动化刷新、一键安装脚本这些收尾没做完,所以暂时不打算封装发布

不过方向是明确的:MCP 生态会越来越丰富,但「怎么把 MCP 用好」这件事,值得每个团队自己沉淀一套 harness。等我们把坑填得差不多了,大概率会把这两套 harness 整理共享出来——如果你也在做类似的事情,欢迎到时候来拍砖。


(文中项目信息已脱敏。lanhu-mcp 为开源项目 dsphper/lanhu-mcp;Lookin 为开源项目 hughkli/Lookin + QMUI/LookinServer。)



技术分享  

效率工具 iOS MCP AI 开发

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!