ARTICLE · 1325092
一条 URL,把「附近」接进 AI 助手:我做 PowPow MCP 的 34 个工具和几个真实教训
在 ChatGPT 里问一句「故宫周围有什么有趣的嘛?」,返回的不是一段泛泛的景点介绍,而是一张带地图的卡片:7 个公开数字人、20 条带位置的帖子,最近的一个距定位点 205 米。
而且工具会主动提醒一句:它把「故宫」理解成了「故宫博物院」,如果跟你说的不是同一个地方,请先确认。
下面这段是线上服务的真实返回,不是我编的示例:
PowPow 附近发现:故宫 半径 1.0 公里注意:按地名「故宫」定位到「故宫博物院」。若与用户想问的地点不符,请先与用户确认。共 7 个公开数字人、0 位用户、20 条公开帖子。数字人(7):- 紫微北极大帝 · 位于 北京故宫,取”紫微垣”象 · 距你 205 米众星拱之的北极星主,掌方向与位置。居紫微垣以统御众星、掌天经地纬与四时运行…- 故宫讲解员 · 位于 39.919628, 116.39891… · 距你 256 米一个精通历史的故宫讲解员- 老舍 · 位于 老舍故居 · 距你 440 米我是老舍(1899-1966)。我现在在我故居,丰富胡同19号是我在北京的住所…
这篇文章不讲「MCP 是什么」——这类科普已经很多了。我想聊的是:把一个基于位置的社交 App 做成远程 MCP 服务时,我实际做了哪些取舍,以及哪些坑是文档里不会写、但真会把人卡住的。
它其实只有一条 URL
PowPow(泡泡)是一款面向中国大陆的位置社交应用:用户在地图上发带位置的帖子、创建能对话的数字人(AI 角色)、参与线下打卡活动。我把它包成了一个远程 MCP 服务端,源码已开源,也上了官方 MCP Registry。
https://global.powpow.online/api/mcp | |
任何支持 MCP 的客户端,填这一条地址就行:
https://global.powpow.online/api/mcp不需要申请 API key,不需要手工配 client_id,不需要注册开发者账号。


为什么「填一条 URL」就够了
因为复杂度被我全放到了服务端:元数据发现、动态客户端注册(DCR)、PKCE,都由客户端自动完成。链路大致是这样:
客户端匿名请求端点,拿到 401,响应头WWW-Authenticate里带着resource_metadata的地址;顺着资源元数据找到 authorization_servers,再读到授权服务器元数据;客户端自己完成动态注册,拉起浏览器,打开 PowPow 自己托管的同意页; 你登录并确认,客户端用授权码 + PKCE 换到 access token,然后才开始 initialize。
支持的 scope 只有 openid、profile、email 三个。令牌每请求校验,吊销 session 即刻失效。
这里有个特别容易被误判成「配置错了」的现象:这个服务不开放匿名访问,连initialize都不例外,所以第一次连的时候看到 401 是预期行为。它不是报错,是 OAuth 2.1 流程的入口。
我的判断是:远程 MCP 想要真正「零配置」,就得把 401 当成握手信号,而不是错误去绕开。不少接入问题,根子都在客户端把这一步拦下来自己处理了。
四个客户端怎么填,照抄即可
Claude 网页版 / 桌面版走界面:设置 → 连接器 → 添加自定义连接器 → 名称填 PowPow,URL 填上面那条 → 点「连接」,浏览器会跳到 PowPow 授权页。
Claude Code 一行命令:
claude mcp add --transport http powpow https://global.powpow.online/api/mcpCursor 写进项目级 .cursor/mcp.json 或全局 ~/.cursor/mcp.json:
{”mcpServers”: {”powpow”: {”url”: ”https://global.powpow.online/api/mcp”}}}
VS Code(Copilot Chat)写进 .vscode/mcp.json:
{”servers”: {”powpow”: {”type”: ”http”,”url”: ”https://global.powpow.online/api/mcp”}}}
注意这两份 JSON 的字段名不一样:Cursor 用 mcpServers,VS Code 用 servers 并且要多一个 "type": "http"。直接互相复制是最常见的低级错误。
Claude Code 还可以装现成插件,两步到位(额外带一个引导注册账号的 skill):
claude plugin marketplace add durenzidu/powpow-claude-pluginclaude plugin install powpow@powpow
ChatGPT 则是纯图形操作:加号 → 添加自定义 MCP 服务 → 填名称和描述 → 连接选公开端点、URL 填上面那条 → 认证选 OAuth → Create。新开对话用 @ 选中它就能调。
34 个工具,我按「读 / 写」切了一刀
20 个只读、14 个写。按用途分三组:
附近发现(6 个):find_nearby(某地点附近的数字人、用户、帖子)、geocode_place(地名转坐标)、nearby_attractions(景点与商圈)、list_campaigns(线下打卡活动)、search_posts、search_users。
账号与社交(只读):whoami、get_my_account(会员等级与到期)、my_posts、my_digital_humans、my_following / my_followers、list_friends、list_favorites、get_badge_history、get_user_profile、get_post_detail、get_post_replies / get_my_post_replies、get_digital_human。
写操作(14 个):prepare_post、publish_post、delete_post、like_post、unlike_post、reply_to_post、follow_user、unfollow_user、add_favorite、update_favorite、remove_favorite、update_profile、create_digital_human、delete_digital_human。
写工具占了四成还多,这个比例决定了下面那套安全设计不是「锦上添花」,而是必须做的东西。
三个我认为不能省的安全设计
第一,发帖永远是两步。AI 先调 prepare_post 出草稿,你确认之后才调 publish_post 真正发布。关键点是:这个「确认」由服务端强制,不是靠提示词里写一句「请先问我」。提示词约束是靠不住的,模型完全可能忘;只有把发布动作拆成两个工具、把草稿状态放服务端,才拦得住。
第二,给了后悔的余地。通过 AI 创建的帖子或数字人,24 小时内可以由 AI 撤销;更早的内容请在 App 内管理。另外 PowPow「设置 → AI 连接」里可以整个关掉 AI 写权限。工具注解也分开:只读工具标 readOnlyHint: true,删除类写操作标 destructiveHint: true,让客户端只对真正破坏性的操作打断用户。
第三,只限流该限流的。find_nearby / geocode_place / nearby_attractions 限12 次 / 60 秒 / 访问令牌,因为它们会消耗第三方地理编码配额——不限流的话,一个客户端就能把配额刷光。剩下 31 个工具不限流。这个数是实测过的:第 13 次调用会直接返回「请求太频繁」。
一把梭给所有工具套同一个限流当然省事,但会让绝大多数只读查询平白变卡。这种地方我倾向于麻烦一点。
几个不看 schema 一定会踩的坑
参数名不能猜。find_nearby 的半径叫 radius_meters,不是 radius。传 radius 不会报错,会被静默丢掉,然后按默认值 1000 米返回结果——你以为自己查了 500 米,其实查的是 1 公里。我实测过:传 {"radius": 500} 得到 7 个数字人,换成 {"radius_meters": 500} 才是 3 个。相比之下 types 反而是数组,传字符串会明确报输入校验错误,这个至少还会告诉你。
别自己传 GPS 坐标。地理编码走高德,坐标是GCJ-02,不是 WGS-84,服务端不做转换。外部传进来的 WGS-84 坐标会有约300–600 米偏差。想查「某地附近」,用 geocode_place 让服务端解析地名,比自己塞经纬度靠谱得多。
返回值是纯中文。站点本身有 8 种语言(zh-CN / en / ja / ko / fr / ms / ru / th),但 MCP 层不读 locale cookie,原始 payload 永远是中文。模型会帮你翻译,但如果你在做二次解析,别指望能拿到英文。
响应是 SSE。即使你发的是普通 JSON-RPC,响应也以 text/event-stream 返回,要按行读 data: 后面的内容。只认 application/json 的客户端会解析失败,这是我见过最多的接入报错。
想自己部署:源码里有什么
服务跑在Supabase Edge Functions(Deno)上,公开仓库的结构是这样:
powpow-mcp/├── server.json# MCP Registry 元数据(发布到 Registry 的就是这份文件)├── src/│ ├── index.ts# 工具注册与实现│ ├── auth.ts# OAuth 2.1 资源服务器侧│ └── widget-html.ts# 可交互地图 widget(HTML)└── LICENSE
环境变量按需配置:SUPABASE_URL、SUPABASE_ANON_KEY、SUPABASE_SERVICE_ROLE_KEY、MCP_OAUTH 是必需的;AMAP_WEB_SERVICE_KEY 只在需要地理编码时给;MCP_HIDE_WIDGET 和 MCP_ENABLE_PROBE(诊断工具,默认关闭)是可选开关。
部署命令:
supabase functions deploy mcp-server --project-ref --no-verify-jwt仓库不包含任何凭据,部署时所有密钥都从平台环境变量读。网络目的地也只有两个:global.powpow.online(MCP 端点、OAuth 同意页、账号注册)和 xhahsqbaohraqrdhtvay.supabase.co(Supabase Auth,登录与令牌签发)。没有埋点、没有第三方分析、不读取本地文件。
仓库 README 里还放了两张手机截图和三段录屏(完整链路 45 秒、OAuth 授权 18 秒、读取公开帖子 20 秒),这里就不贴图了。
边界,我如实说
覆盖范围集中在中国大陆,坐标体系也是大陆这套; 帖子仅支持纯文字,不能传照片; 头像、私信、通知、订阅、支付都不在 MCP 能力范围内; 不开放匿名访问,必须有一次 OAuth 授权。
服务已在官方 MCP Registry 上架:
io.github.durenzidu/powpow-mcp用到的链接:
源码(MIT): 34 个工具的逐项说明: 官方网站: 隐私政策 / 服务条款 / 支持: · ·
如果你也在做 MCP 服务,上面那几个坑(SSE 响应、静默失效的参数名、GCJ-02 坐标)大概能替你省掉半天。也欢迎在评论区说说你想让 AI 帮你做哪类「附近」的事——如果某个场景现有 34 个工具做不到,我更想听。















































































