mcpField
F
forkcaster

forkcaster

远程服务
forkcaster.xyz社交媒体31 天前更新

关于 forkcaster

forkcaster 将 Farcaster 帖子引用解析为受支持客户端应用的深层链接,并提供可分享的帖子页面。其公开 MCP 端点无需认证即可返回客户端 URL 和作者的签约状态。

主要功能

  1. 01解析帖子并生成客户端深层链接
  2. 02服务端渲染帖子页面
  3. 03以 JSON 返回帖子数据
  4. 04检查作者签约状态

适用场景

  1. 01不使用 Farcaster 应用分享帖子
  2. 02查找指定客户端的帖子链接
  3. 03为 Agent 获取帖子详情

MCP 相关

公开的 Streamable HTTP 端点提供 `get_cast_link` 工具,无需认证。该工具将帖子引用解析为受支持客户端的 URL,并返回作者的签约状态。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://forkcaster.xyz/mcp
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

forkcaster — Agent 简介

受众:编码 Agent。优先记录事实,而非长篇描述。架构或命令变更时,请更新此文件。

意图

一个镜像 Farcaster cast URL 的微型网站,方便用户在不使用 Farcaster 应用的情况下分享。

  • 模式:/{username}/{castHash},其中 castHash 匹配 0x[0-9a-fA-F]+——短格式或完整格式
  • 示例:/zoo/0x895ecc74 和 /decent-artlu/0xbb54368f → SSR cast 卡片 + 链接
  • 数据:在多个提供方之间竞速(worker/cast-source.ts,rpc-racer 模式)——见下文“Cast source race”。shim(https://shim.artlu.xyz/wc/{username}/{hash},由所有者运行的 Snapchain 读取器,配有保活 cron)是完整性的基准,也是唯一的封禁信号依赖项(/signed/{fid});farcaster.tv 速度快,但无法识别引用;原始节点 haatz/snap.farcaster.xyz:3381 数据完整,但需要通过 shim /f/{username} 获取 fid 和完整 hash。所有上游调用都限制为 5 秒。
  • Cast 不存在:完整提供方(shim、haatz、snap)给出权威的未命中结果 → 404 页面;没有提供方解析成功 → 仅含链接的页面(200)。所有上游调用都限制为 5 秒(AbortSignal.timeout)——否则 shim 的冷分片查找可能挂起 15 秒以上;超时 ⇒ 无法访问。严格状态码由 JSON 变体负责(见下文)
  • 封禁账户:所有人都能看到嵌入内容——但某些客户端会隐藏未签名作者。自 2026 年 10 月 15 日(Network School 接管)起,账户必须接受“social smart contract”(Network Code);接受后会获得链上访问 NFT。Shim 提供此信息:GET https://shim.artlu.xyz/signed/{fid} → {"signed":true|false}。对于未签名作者:注册表中设置了 requiresSigned 的客户端(目前为 farcaster)会从操作栏中移除;该检查采用失败开放策略——状态未知时不会移除任何内容
  • farcaster.tv 作为 cast 数据来源时无法识别引用(会丢弃 {castId} 嵌入),且并非官方来源——它只作为部分数据层参与竞速(700ms HTML 框,引用内容由客户端补齐)。react-farcaster-embed 自带的默认端点是 farcaster.tv——务必传入 castData,避免其自行获取。实时统计行(回复/转发/点赞)仍由客户端从 farcaster.tv 获取——该服务会发送 access-control-allow-origin: *,也会返回未签名作者的数据;任何失败都只会导致统计行不显示

技术栈

层选型说明
运行时 / 包管理器Bun锁文件:bun.lock;脚本使用 bun run
UI(落地页)Preact 11SPA 资源;入口 src/main.tsx
Cast 页面基于 Cloudflare Worker 的 Hono在 worker/ 中进行 SSR
Cast 数据提供方竞速(cast-source.ts)shim ∥ farcaster.tv ∥ haatz ∥ snap——首个通过验证的结果;HTML 使用完整性来源,JSON 仅使用 shim;见下文“Cast source race”
URL 嵌入卡片unfurl.artlu.workers.dev通过 UNFURL 服务绑定调用(workers.dev→workers.dev 的 fetch 会被拦截,返回 CF 错误 1042);GET /?u={url} → OG 标题/描述/图片(有缓存,失败时回退为仅显示主机名)
Cast 嵌入react-farcaster-embed仅负责渲染——始终提供 castData,不会自行获取
实时统计客户端脚本 → farcaster.tvcast-page.tsx 中的 LIVE_STATS_SCRIPT;从浏览器端填充 SSR 移除统计数据后留下的位置;失败时不显示任何内容(无统计行);SSR 数据路径仍仅使用 Shim
SSRpreact-render-to-string在 await FarcasterEmbed({ castData }) 之后
打包器Vite 8@preact/preset-vite + @cloudflare/vite-plugin
LintBiomebun run lint
类型检查bun check兼容 tsc,内置于 Bun;无 typescript 包
测试bun:testbun test(cast 路由 + 客户端注册表)

命令

bun install
bun run dev          # wrangler dev (local worker + assets)
bun run build        # vite build → dist/
bun run typecheck    # bun check (tsc-compatible; reads tsconfig*.json)
bun run deploy       # build + wrangler deploy
bun run lint         # biome lint .
bun test             # worker tests (cast route + client registry)
bun run cf-typegen   # wrangler types → worker-configuration.d.ts

目录结构

/
├── index.html                 # SPA shell → /src/main.tsx
├── vite.config.ts             # preact + cloudflare + react→preact aliases
├── wrangler.jsonc             # main=worker/index.ts; not_found_handling=none
├── public/farcaster-embed.css # linked from SSR HTML
├── public/logos/              # per-client marks for the action row
├── worker/
│   ├── index.ts               # Hono app; export { app }; default { fetch }
│   ├── client-registry.ts     # client registry (verified templates; zero-dep, vendored-able)
│   ├── clients.ts             # fc_client cookie binding (last-used + auto-open prefs)
│   ├── shim.ts                # shim identity client (routes, ShimCast, /wc /h /f /signed)
│   ├── cast-source.ts         # provider race: shim ∥ haatz ∥ snap ∥ farcaster.tv
│   ├── cast-page.tsx          # resolve (race) → CastData mapping → SSR / 404 / link fallback
│   ├── cast-ref.ts            # MCP cast-ref: zod contract + shim-direct resolution
│   ├── mcp.ts                 # MCP SDK v2 server factory (get_cast_link) — only SDK import site
│   ├── cast-route.test.ts     # bun:test; mock.module + exact-URL fetch mock
│   ├── clients.test.ts        # registry unit tests: templates, gating, signed rule, deeplinks
│   ├── cast-source.test.ts    # race unit tests: eligibility, box, miss/error, abort, adapter mapping
│   ├── race-stats-store.ts    # lmdis snapshot read-through TTL cache (10min TTL / stale 24h / 2s cap)
│   ├── vendor/lmdis-sdk.ts    # vendored lmdis SDK (Upstash-shaped seam; get/set only)
│   └── shims/server-only.ts   # empty stub for Next.js marker package
├── scripts/
│   ├── race-stats.ts          # offline stats job: AE SQL → snapshot → lmdis (dotenvx env; --dry)
│   ├── race-stats-lib.ts      # pure query builders (fixture-tested)
│   └── probe/                 # live-service probes (lmdis, AE SQL, shim timing)
└── src/                       # landing only (App.tsx)

路由

路径处理程序响应
/静态资源 index.html落地页 SPA
/api/Hono{ "name": "Cloudflare" }
/prefsHonoPOST JSON { auto?: "on" | "off", delay?: 0–5 }(至少一个字段)→ 204 + Set-Cookie(fc_client);默认值为 5s 时,cookie 中省略 delay。自动打开偏好设置写入(服务器 cookie — Safari ITP 豁免)
/transparencyHonoHTML 信息页(内容/数据/跟踪/域名 — 域名包含注册到期时间 + RDAP 确认链接 — 以及从 lmdis 快照在服务器端填充的竞速统计表,还有“统计数据截至”行),或通过 ?format=json/Accept 返回对应 JSON(racingStats.status: live | coming-soon);保留的精确路径 — 用户名为 transparency 的 cast URL 仍可正常使用
/race-stats.jsonHono原始统计快照(与 /transparency 使用相同的缓存读取);不存在时返回 404;cache-control: public, max-age=21600
/mcpHono → MCP SDK v2MCP Streamable HTTP 端点(POST JSON-RPC;公开,无需认证)。一个工具:get_cast_link:cast 引用(longhash ∥ fid+shorthash ∥ username+shorthash)+ 目标客户端 → 客户端 URL + 作者签名状态;farcaster.xyz 是规范页面。
/:username/:hash(0x…)Hono SSRHTML:200 cast 卡片 + OG/Twitter 元数据(标题 = DisplayName (@handle),描述 = 合并空白后的 cast 文本,280 个字符,图片 = 第一张图片嵌入内容,否则为头像;仅当图片是 cast 嵌入图片时,卡片才使用 summary_large_image;og:site_name = forkcaster)+ 由注册表驱动的客户端操作栏(见下文“客户端注册表”);作者未签名(/signed/{fid} 返回 false):隐藏 requiresSigned 客户端(farcaster);Shim 报告不存在此 cast 时返回 404;Shim 无法访问时返回仅含链接的页面,状态码为 200
/:username/:hash?format=json(或 Accept: application/json)Hono JSON严格状态码的 Agent 变体 — 见下文“Agent JSON 变体”
其他不存在的路径worker 404 / 不回退到 SPAnot_found_handling: none

多域名(双域名服务): 同一个 worker 服务于 forkcaster.xyz 和 warpcats.com(wrangler.jsonc 中的自定义域名路由)。所有代码均与主机名无关(按请求获取 origin、同源填充脚本、仅限主机的 cookie),且每个页面都会将规范地址设为主域名:cast 页面根据 PRIMARY_ORIGIN 变量输出 <link rel="canonical"> + og:url(未设置时不输出 — 纯 workers.dev 仍保持双域名服务之前的输出),落地页的规范地址则写在 index.html 中。竞速遥测将请求主机名作为 blob 携带,以便按域名细分。Cookie/徽章按设计分别属于各个域名。

Agent JSON 变体(?format=json)

已上线。 解析一次(Shim 获取 + 展开链接 + 引用补全 + 签名检查 → resolveCast()),渲染两次——worker/cast-page.tsx 中的 renderCastHtml() / renderCastJson()。返回类型会根据请求方而变化。

内容协商——显式优先,不通过 UA 嗅探:

信号响应
?format=json 查询参数JSON(文档约定;优先级高于 Accept)
Accept: application/jsonJSON
其他任何情况(浏览器、*/*、聊天链接预览机器人)HTML

决策:

  • 仅提供 JSON——不提供 kv/纯文本格式(kv 有损;JSON 的 token 开销可以忽略)。
  • JSON 使用严格状态码,HTML 使用宽松状态码(有意保持差异):JSON → Shim 报告不存在此 cast 时返回 404,Shim 无法访问时返回 503 + Retry-After: 60。HTML 保留其 404 页面 / 仅含链接的 200 页面。Agent 处理状态码的能力优于处理渲染后的回退内容。
  • 按可用性决定载荷内容——仅当数据存在时才包含字段:作者、ISO 8601 时间戳、文本、图片嵌入 URL、URL 嵌入(展开成功时附加展开标题,否则仅提供原始 URL)、引用嵌入、规范 farcaster.xyz + Firefly 链接。
  • 引用始终作为指针保留,不会丢弃:引用补全成功 → forkcaster URL(需要从补全后的 cast 获取用户名);补全失败 → Firefly 完整哈希 URL(引用嵌入包含 {fid, hash},不含用户名)。HTML 的渲染限制(未防护的 author.pfp.url)不适用于 JSON——补全失败时会降级为 Agent 可以获取的 URL。
  • 封禁信号:signed: false 时会输出简短的备注字段;检查结果未知/失败时会静默放行(与 HTML 操作行采用相同的失败时放行语义)。
  • 便于发现:HTML 页面会输出 <link rel="alternate" type="application/json" href="?format=json">。
  • 暂缓处理:之后再通过 UA 允许列表(GPTBot、ClaudeBot、……)实现变体切换,作为渐进式增强。必须使用允许列表——Telegram/Discord/iMessage 预览机器人仍须接收 HTML + OG 元数据。
  • 目前没有页面级缓存(Shim 即为缓存);若以后添加边缘缓存,变体必须纳入缓存键。

MCP

https://forkcaster.xyz/mcp(也可用 warpcats.com/mcp)——MCP Streamable HTTP 端点,公开、无需身份验证、无状态。提供一个工具:get_cast_link——将 Farcaster cast(完整的 40 位十六进制哈希,或 fid/用户名 + 短哈希)解析为任一受支持客户端的深层链接 URL,并提供作者的签名合约状态。接线位置:worker/mcp.ts(SDK)+ worker/cast-ref.ts(zod 合约,直接通过 shim 解析)。

注册表条目:server.json(仓库根目录,官方注册表架构 2025-12-11,名称为 xyz.forkcaster/mcp)。要发布,请安装官方发布 CLI——它是 GitHub release 提供的二进制文件。⚠️ 切勿对 npm 包 mcp-publisher 使用 bunx/npx——它是名称冲突的无关浏览器自动化项目:

curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" | tar xz mcp-publisher && sudo mv mcp-publisher /usr/local/bin/

一次性域名验证:生成 ed25519 密钥对(openssl genpkey -algorithm Ed25519 -out key.pem),添加它输出的 apex TXT 记录(v=MCPv1; k=ed25519; p=<public key>),然后:

mcp-publisher login dns forkcaster.xyz --private-key <hex>   # signs the challenge → xyz.forkcaster namespace
mcp-publisher publish                                        # submits server.json to registry.modelcontextprotocol.io

key.pem 是发布凭证——请妥善保管,切勿提交。

Cast 来源竞速

Cast 查询会让四个提供方同时竞速(worker/cast-source.ts,采用 rpc-racer 模式:并行请求,每个提供方可单独取消,超时上限为 5s;第一个通过验证的结果获胜,其他请求会被取消;获胜结果必须能解析出请求的哈希,否则会降级为错误)。

完备性矩阵(根据 2026 年 10 月的测量结果),对照内部 ShimCast 契约(文本、哈希、Unix 秒级时间戳、原始 {url}/{castId} 嵌入内容、内联用户数据):

提供方能解析(用户名、哈希)?引用({castId})结论
shim✅ 短哈希 + 完整哈希✅完整——规范来源,随时可获胜
haatz(haatz.quilibrium.com/v1)⚠️ 仅完整哈希 + 通过 shim /f/{username} 获取 fid✅完整——适用于完整哈希请求
snap(snap.farcaster.xyz:3381,官方网关;443 会卡住)⚠️ 与 haatz 相同✅完整——适用于完整哈希请求
farcaster.tv✅ 短哈希(前缀匹配)❌ 静默丢弃不完整——无法识别引用

HTML 路径(700ms 完整性等待窗口): 完整的提供方随时可获胜;如果 farcaster.tv 获胜但无法识别引用,则会暂缓结果,直到等待窗口结束,然后返回不完整页面——这是 SWR 权衡,而 OG 元数据不受影响:标题、描述和图片从不依赖引用,因此聊天机器人的缓存嵌入卡片始终完整。不完整内容只会出现在实时浏览器中,并会自行修复:不完整页面会附带 QUOTE_FILL_SCRIPT,该脚本会请求 ?embeds=quotes(由 shim 解析、已补全引用的 SSR 片段,no-store),然后将其注入页面——与实时统计脚本遵循相同的静默降级契约。不会引入服务端缓存:最近使用徽标和签名抑制功能不受缓存键影响。

JSON 路径: 仅使用 shim(boxMs: null)——始终完整,状态严格区分(404 / 503 + Retry-After),始终遵守绝不丢弃引用的不变量。

未命中语义: shim 未命中时会立即解析为 not-found(快速返回 404);任何完整提供方未命中时(haatz/snap 原始节点返回 400)均具有权威性 ⇒ 即使已返回不完整结果,也返回 404;仅 farcaster.tv 返回 404 时不会产生 404(Cast 可能实际存在)。其他情况全部失败 ⇒ 返回仅含链接的页面(HTML)/ 503(JSON),照常采用失败开放策略。

封禁信号: 不参与竞速——/signed/{fid} 仍依赖 shim,与 Cast 内容相互独立,并受 HTML 等待窗口限制,照常采用失败开放策略。

遥测: 每次解析都会写入一条 Analytics Engine 数据点(RACE_STATS 绑定,通过 waitUntil 非阻塞执行):index = 获胜提供方(或结果类型),doubles = 总耗时(毫秒)/等待窗口/是否不完整,blob = 各提供方的 id:kind:ms 记录(因竞速取消的失败请求记为 abort,而非 error)。调整等待窗口时,可通过 AE SQL API 查询(scripts/probe/、scripts/race-stats.ts);测试和没有 executionCtx 的调用方会跳过遥测。

后续工作:引用补全也可以与 haatz/snap 竞速(/h/{fullHash} 与 castById——castId 嵌入内容中带有 fid);愿意以降低完备性换取低延迟的 ?format=json 使用方可以选择加入竞速。

竞速统计(/transparency)

竞速统计表离线填充——渲染路径不使用缓存,也不处理统计数据。bun run stats(环境变量见 .env.example)通过 SQL API 查询 Analytics Engine——按样本加权(sum(_sample_interval)、quantileExactWeighted;绝不使用原始 count())——组装带版本号的快照(v: 1;每个提供方的 wins/requests/p50/p95/errorRate,以及结果计数),并通过随附的 Upstash 风格 SDK,将其作为一个 lmdis 键(lmdis.artlu.xyz 上的 race-stats,由所有者运行、采用 Redis 风格的 KV)发布。仅在成功时覆盖;--dry 可预览。

透明度路由通过每个隔离实例的 TTL 缓存读取快照(worker/race-stats-store.ts:TTL 为 10 min,失败后退避 60s,最多提供 24h 内的最近一次成功数据,读取上限为 2s),并填充统计表、“统计截至”行以及 JSON 副本中的 racingStats——快照缺失或不可达时,静默显示“即将推出”的短横线。/race-stats.json 提供原始快照(不存在时返回 404)。SQL 方言和存储行为通过 scripts/probe/ 实时验证(AE 方言不支持 CONCAT,且仅支持 toUInt32/toUInt8 转换;SQL 错误以纯文本 422 返回;SQL API 会拒绝 Account Owned Tokens——请使用具有 Account Analytics:Read 权限的 User token)。

**中止遥测:**竞速提前结束时落败的请求会记录为 provider:abort:<ms>(而非 error),以确保公开的 errorRate 如实反映情况——700ms 截止会有意终止缓慢完成的请求;5s 硬超时仍计为错误。raceCast 会在中止后排空待处理的结算(最长 25ms),避免计时记录不完整。

客户端注册表(操作栏、上次使用徽标)

cast 页面上的“Open in …”按钮由数据注册表 worker/clients.ts 渲染——添加客户端只需更改数据。

  • 架构(ClientDefinition):id(稳定的 slug,cookie 值)、title、logoUrl(由 public/logos/ 提供)、web(每个 cast 对应的 https 模板)、deeplink(可选的原生移动端目标——启用下文所述的点击时 scheme 尝试;缺省 ⇒ 仅限 Web)、requiresSigned(仅在已知 signed:false 时隐藏;未知时默认显示)。
  • 模板会插入 {username}、{hash}(路由格式,短哈希或完整哈希)和 {fullHash}(由 Shim 解析)。引擎还支持可选的 {fid} 占位符及 missingVars 门控(需要该值的客户端在值缺失时会被跳过)——留作未来条目使用。解析时会对值进行百分号编码,渲染时会进行 HTML 转义。
  • 移动端深层链接与 Web 目标:每个客户端对应一个按钮;href 始终是 web URL。通用链接在移动端已能打开已安装的应用——已逐一验证:Farcaster 的 AASA 声明了所有 farcaster.xyz 路径,Firefly 的 AASA 明确声明了 /post/*(Android:已通过 assetlinks.json 确认 com.farcaster.mobile 和 io.dimension.firefly)。结构化的 deeplink: { scheme, androidPackage? } 仅在移动端添加原生尝试:按钮会获得 data-scheme + data-intent(intent:// 格式包含 S.browser_fallback_url = Web URL),并由条件脚本在粗指针设备上拦截点击——Android 使用 intent(由 Chrome 原生回退),其他设备则尝试 scheme;若应用未打开,则回退到 Web href(约 1.8 秒,并检测页面可见性)。只有实际渲染的客户端包含 deeplink 时才会加载该脚本。Farcaster 当前使用 farcaster://{username}/{fullHash}——已根据开源应用验证(farcasterxyz/client):应用会将 farcaster:// 重写为 https://farcaster.xyz/,并将其余部分作为 Web 路径处理;cast URL 格式为 /{username}/{hash},支持完整哈希或短哈希(≥8 位十六进制);旧版 /casts/:fname/:hash 路由已移除。Firefly 不提供 scheme——没有任何文档记录;其 Web URL 在两个平台上都已关联应用。
  • 客户端名单——全部五个客户端均已验证每个 cast 的 URL:farcaster(/{username}/{hash})、firefly、neynar、quilcast 和 vibeshift(基于完整哈希;neynar 已对照 fc-clients-cast-action 的 src/lib/deeplink.ts 验证;quilcast 已对照 backmeupplz/quilcast 的 server/index.mjs 验证——/c/{fullHash},40 位十六进制,可选带 0x,并已在线验证;仅限浏览器的客户端,没有原生应用;vibeshift 使用 ?view=cast&castHash={fullHash}&castFid={fid}——需要 cast 发布者的 fid,通过 {fid} 门控,因此在不含 fid 的界面中会跳过;由所有者提供并经用户验证)。
  • 上次使用 cookie:点击任何带 data-client 的按钮时,都会通过 CLIENT_SCRIPT 写入 fc_client=<id>(有效期 1 年,SameSite=Lax);收到下一次请求时,worker 会读取它,并在服务端渲染(SSR)该客户端按钮上的小型“上次使用”徽标。未知的 cookie 值不会渲染(注册表白名单)。没有 cookie ⇒ 不显示徽标;没有 JS ⇒ 链接仍然可用,只是徽标不会更新。Cookie 条件 HTML:如果将来添加边缘缓存,徽标必须加入缓存键。
  • Logo:托管在 public/logos/ 中,每个客户端对应一个静态文件——farcaster 和 quilcast 使用 SVG,firefly、neynar 和 vibeshift 使用 PNG(vibeshift:其 android-chrome 图标缩小至 64px;站点的 favicon.svg 是无关的模板默认图标,并非品牌标志)。按钮的 <img> 统一渲染 logoUrl;不使用针对单个客户端的代码路径。

Shim → CastData 映射

各提供方返回的数据结构各不相同;cast-source.ts 会将所有数据规范为 ShimCast(Shim 的原始 Snapchain 数据结构)。随后,worker/cast-page.tsx 中的 toCastData() 会将其转换为 react-farcaster-embed 所需的格式:

  • timestamp 是 Unix 秒数 → 乘以 1000(嵌入组件会执行 new Date(ts))
  • embeds 是无类型的 {url} / {castId} 项 → 分别归入 images / urls / casts;图片判断依据是主机为 imagedelivery.net 或 URL 带有图片扩展名。引用内容会通过 Shim GET /h/{fullHash}(深度为 1)补全数据,并按普通 cast 映射;补全失败时(例如 cast 已被清除),会丢弃该引用。URL 嵌入会通过 openGraph 渲染为链接卡片(见上文的链接预览)
  • 消息级数据不包含互动计数 → replies / reactions / recasts 均填充为 { count: 0 },并将 tags 设为 []——嵌入组件包会不做检查就读取 e.recasts.count 和 e.tags.length,缺少这些数据时会崩溃(它也会不做检查就读取 quote.author.pfp.url——切勿输出作者数据尚未补全的引用)。这些填充值会显示为硬编码的零计数,因此会从 SSR 输出中移除统计行(STATS_ROW);同一容器中的 Farcaster 徽标会保留
  • author 从 user 映射而来(pfpUrl → pfp.url,bio → profile.bio.text)

Agent 约定

  • 第一方代码使用 Preact,而不是 React。Vite 别名会将 react* 映射到供嵌入组件库使用的 Preact。
  • Cast 路由由服务端处理(Hono),而非客户端路由。
  • 测试:导入 ./index.ts 前,先执行 mock.module("server-only"|react*);按精确的 Shim URL 模拟 globalThis.fetch——意外 URL 会触发错误,借此测试回退路径。
  • TS worker:jsxImportSource: preact;相对导入需要使用 .tsx 扩展名(nodenext);测试文件已从 tsconfig.worker.json 中排除。
  • 密钥:.env* / .dev.vars* 已加入 Git 忽略列表。

关键文件

任务修改文件
Shim 请求 / 映射 / SSR 回退worker/cast-page.tsx
提供方竞速 / cast 数据来源worker/cast-source.ts
客户端列表 / 操作行数据worker/clients.ts
路由worker/index.ts
别名vite.config.ts、tsconfig.worker.json 的 paths
着陆页src/App.tsx
部署 / CFwrangler.jsonc

状态

已实现以 Shim 为首选的 SSR 数据路径,并在 shim / farcaster.tv / haatz / snap 之间进行竞速(cast-source.ts);HTML 会在 700ms 超时窗口内返回不含引用数据的胜出结果,并在客户端自动补全引用;JSON 保持 Shim 数据完整且严格。实时统计数据仍在客户端从 farcaster.tv 获取。Agent JSON 变体(?format=json)已上线。由注册表驱动的操作行已上线:最近使用徽标、Farcaster 原生深层链接(farcaster://,已验证),以及四个已验证的单 cast 客户端 URL。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。