mcpField
P
PositionGuard

PositionGuard

远程服务
positionguardai.com地图与出行12 周前更新

关于 PositionGuard

PositionGuard MCP 服务让 AI 助手查询群组成员是否在指定区域,仅返回成员同意分享的信息;不读取坐标,并将不可用或未披露的状态标为未知。

主要功能

  1. 01查询成员所在区域及最近确认位置
  2. 02列出群组和区域名称
  3. 03查询区域成员及人数
  4. 04尊重成员与单个区域的分享设置
  5. 05只读操作,不获取坐标或历史

适用场景

  1. 01询问某位成员是否在家或学校
  2. 02查看某个区域有哪些已披露成员
  3. 03统计区域内成员数并识别过期位置

MCP 相关

提供 `list_groups`、`list_areas`、`where_is_member`、`who_is_at_area` 和 `count_members_at_area` 等只读 MCP 工具。支持 Streamable HTTP、SSE 和 stdio 传输。

配置

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

服务地址https://mcp.positionguardai.com/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 配置后重启。需要授权的服务会在首次连接时提示登录。

工具

详细介绍

positionguard-mcp

一个 MCP 服务,让 AI 助手可以查询 PositionGuard 中的 位置状态:Earl 在滑板公园吗、谁在家、俱乐部里有多少人。它只会回答每位成员同意向 助手分享的信息;如果成员没有同意,就会回答 unknown。

该服务是公共 REST API 的确定性客户端。它持有一个 API 密钥,调用三个只读端点,并将返回 的数据映射为一组精简、明确的词汇。服务内部没有模型,也没有特权访问:所有保证都由 api.positionguardai.com 执行,该服务会检查密钥并运行同意门控。这个服务无法扩大 API 返回的范围,只能发起查询。

它会查询什么,以及不会查询什么

这个服务有意向助手提供少于其所能提供的信息,而且你可以确切了解提供了什么。

  • 三个作用域,而非四个。 授予 presence:read、counts:read 和 groups:read。不要授予 areas:read:它会开放 /groups/{id}/areas,该端点会返回区域中心坐标,而这个服务从不调用它。区域名称和 ID 来自 /area-counts,该端点在设计上不包含坐标。即使未来的修改要求获取 /areas,客户端 也会拒绝,并且有测试验证这一拒绝行为。
  • 使用 Assistant 密钥,而非 Integration 密钥。 在开发者门户中创建类型为 Assistant 的密钥。只有开启了 允许 AI agents 查看我是否在某个区域 的成员,才会对 Assistant 密钥可见;否则密钥会得到 unknown。Integration 密钥在技术上可用,但会绕过 该同意门控。是否这样做由密钥持有者决定;参考配置不会演示这种用法。
  • 绝不记录响应正文、密钥或姓名。 日志行包含路径、HTTP 状态码、项目数量、耗时、工具 名称,以及工具返回的 status。密钥只会在启动时出现一次,并且仅显示前 16 个字符,与 门户中显示的前缀相同。
  • unknown 不等于“已离开”。 未选择加入、处于全局 Ghost 模式、暂停分享,或手机有一段 时间未上报位置的成员,在网络响应中看起来都一样,都会映射为 unknown;前三种情况都在 test/fixtures/ 中提供了测试数据,并断言结果相同。每个区域也是如此:如果成员在某个 区域,但对助手隐藏了该区域,就不会在该区域的列表中出现;这种缺失同样表示 unknown, 绝不表示“人不在这里”。以 Ghost 模式加入公开群组的成员根本不会出现在该群组名单中,而 匿名加入的成员则会显示为“Anonymous”;API 会在这个服务获取群组名单之前处理这些情况。 工具描述会明确告诉模型,unknown 表示它不知道。过时的最近已知位置绝不会作为当前位置 返回:它会显示为 unknown,或显示为 last_known_at_area 并附上其时间(见下文);人数 统计会包含位置过时的成员,并注明这一点。
  • 不缓存。 API 会缓存 15 秒。再增加一层缓存,就多了一个可能延迟反映撤回同意的环节。
  • 只读。 没有写入工具、坐标、消息或历史记录。每个工具都标注为 readOnlyHint。

工具

每个回答都是带有 status 字段的 JSON。ok 表示问题已得到回答。unknown 表示未能回答, reason 会用一个词说明原因。API 故障会作为 MCP 工具错误返回,并用一句话包含 HTTP 状态码, 且绝不会重试。

工具范围返回内容
list_groupsgroups:read{status, groups: [{group_id, name, group_type}]}
list_areascounts:read{status, areas: [{area_id, name, group_id, group_name}]} — 仅名称,不包含计数或几何信息
where_is_memberpresence:read{status: "at_area", area, inside_areas?, since?} | {status: "last_known_at_area", area, inside_areas?, since?, last_confirmed_seconds_ago, note} | {status: "not_at_area"} | {status: "unknown", reason}
who_is_at_areapresence:read{status, area, confirmed: [nickname…], last_known: [{nickname, last_confirmed_seconds_ago}…], members, last_known_note?, undisclosed_note?, count_note?} — 仅包含已披露的成员
count_members_at_areacounts:read{status, member_count, stale_count, undisclosed_count, note}

where_is_member 会以不区分大小写的方式查找昵称,可在单个群组中查找,也可跨所有群组查找。其 reason 为 not_disclosed、stale 或 no_such_member(这是答案而非错误,因此模型不会凭空编造答案)。只要服务端统计的区域成员数多于答案列出的成员数,who_is_at_area 就会添加 count_note(“此区域有 N 人被计入,列出 M 人”),其中 N 为 member_count + undisclosed_count:公开群组不会为通过 Ghost 加入的成员返回任何行;超过成员上限时,除调用者自己的行外,也不会返回其他行;成员可能在场,但未向该区域的助手披露,因此当计数显示并非完整时,列表绝不会被描述为完整。成员未披露时,备注会说明人数,并提示“不要将列出的姓名清单报告为完整名单”。当 undisclosed_count 或 stale_count 不为零时,member_count 是下限,note 会提示将其报告为“至少 N 人”。如果 API 完全不提供计数(已归档区域),答案会是 unknown,原因是 count_unavailable,绝不会是零。

区域包含区域。 一个群组可以在城市内设有住所。API 会列出成员所在的该群组所有区域,并按从最内层到最外层的顺序排列(inside_areas);where_is_member 会将最内层区域作为 area 返回,并同时附上完整列表,因此可以根据列表回答“Fred 是否在洛杉矶”。who_is_at_area 会将查询的区域与该列表进行匹配,因此在家的人也会被列为在城市内。成员可以按区域选择助手可见的内容:如果某人分享了 Home,但没有分享 Los Angeles,返回的列表只会包含 Home,不会标记缺失的区域。因此,inside_areas 中缺少某个区域,并不能证明成员不在该区域内——工具描述中对此有说明——唯一能看出信息被隐藏的地方是城市的 undisclosed_count,这就是 count_note 会读取它的原因。只有当 API 为指定区域记录了进入时间时,才会提供 since。对于不发送 inside_areas 的服务端,答案仍与之前一样,使用单个 current_area。

数据新鲜度与最后已知位置答案。 PositionGuard 服务端可以在成员手机无响应时,将其保留在最后一次确认所在的区域,并将这些行标记为 position_fresh: false,同时附上位置的时效。where_is_member 会将其回答为 last_known_at_area,并附上 last_confirmed_seconds_ago 和备注(“10 小时前最后确认在 Lake House;之后没有更新位置”),绝不会回答为 at_area。who_is_at_area 会将其列在 last_known 下,而非 confirmed 下;count_members_at_area 的备注会说明计数中有多少人最近未经确认。工具描述会告诉模型传达最后已知位置答案及其时效,绝不能将其说成当前在场。since 始终表示成员进入区域的时间,而不是其最后一次确认的时间。对于不发送 position_fresh 的服务端,答案与 0.1.0 中相同。

服务端响应如何映射到 status,已在 src/core/mapping.ts 中详细说明,并且会在模型接触服务端之前,使用 test/fixtures/ 中捕获的响应进行测试。

配置

环境变量必填默认值
POSITIONGUARD_API_KEY是— 必须以 pg_live_ 开头;否则服务会拒绝启动
POSITIONGUARD_API_BASE否https://api.positionguardai.com/api/v1
TRANSPORT否http(可流式传输的 HTTP + SSE)或 stdio
PORT否8788(HTTP 传输)
HOST否0.0.0.0(HTTP 传输);在容器外使用 127.0.0.1

启动时,服务会调用一次 GET /groups。若返回 401 或 403,服务会退出并提示如何修复。若群组列表为空,服务会发出警告后启动。每次调用工具时都会重新检查密钥,因此启动时 API 短暂不可达只会记录日志,不会导致启动失败。

传输方式

同一条代码路径,三种接入方式。此版本的 HTTP 传输没有身份验证:请在私有 Docker 网络或 localhost 上运行服务,切勿将其暴露在外。

路径传输方式适用对象
/mcp可流式传输的 HTTP,无状态Open WebUI
/sse(+ /messages)SSEHome Assistant 的 mcp 集成,该集成仅支持 SSE
stdio(TRANSPORT=stdio)stdioClaude Desktop 和其他启动器
/healthz—Docker 健康检查;返回 {"ok":true}

配置方案

每种配置方案都标记为已测试或未测试。只有已测试的方案会说明在此服务上实际观察到的行为。

1. 容器中的 Open WebUI + Anthropic + 此服务 — 已测试

docker-compose.example.yml 会在同一个私有网络中运行 Open WebUI 和此服务,且不会发布此服务的端口。将 WEBUI_SECRET_KEY 和 POSITIONGUARD_API_KEY 放入 .env 文件(已加入 gitignore),然后运行:

cp docker-compose.example.yml docker-compose.yml
docker compose up -d

在 Open WebUI 中:前往管理 → 设置 → 连接,添加一个与 OpenAI 兼容的连接,基础 URL 为 https://api.anthropic.com/v1,并填写你的 Anthropic 密钥。前往管理 → 设置 → 外部工具,添加一个类型为 Streamable HTTP 的 MCP 服务,地址为 http://positionguard-mcp:8788/mcp,身份验证选择无(Bearer 搭配空密钥会发送空请求头,服务端会拒绝)。从 0.6.31 起,Open WebUI 原生支持 Streamable HTTP MCP 服务。

关于此方案及其他任何云端模型配置的披露说明:你选择披露的在场信息会发送给模型提供商,用于生成回答。

已使用 Assistant 密钥对接生产 API 验证。启用了此设置的成员会返回所在区域;同一成员关闭设置后会返回未知状态,而非“离开”。如果有成员未披露信息或信息已过期,人数统计会作为下限报告。

2. Claude Desktop,stdio — 已测试

构建一次(npm install && npm run build),然后将以下配置添加到 Claude Desktop 的 claude_desktop_config.json 中:

{
  "mcpServers": {
    "positionguard": {
      "command": "node",
      "args": ["/absolute/path/to/positionguard-mcp/dist/index.js"],
      "env": {
        "POSITIONGUARD_API_KEY": "pg_live_…",
        "TRANSPORT": "stdio"
      }
    }
  }
}

发布此软件包后,可用 "command": "npx", "args": ["-y", "positionguard-mcp"] 替代路径。日志写入 stderr;stdout 用于协议通信。

3. Home Assistant Assist + mcp 集成 + 此服务 — 未测试

使用 HTTP 传输运行服务,并确保 Home Assistant 能访问该服务。添加 Model Context Protocol 集成,并提供 SSE URL:http://<host>:8788/sse。这些工具会显示在对话 Agent 下;请为你与 Assist 搭配使用的 Agent(Anthropic、OpenAI、Ollama 等)启用这些工具。Home Assistant 客户端仅支持 SSE,身份验证只能选择 OAuth 或不启用,因此此服务无身份验证的 SSE 端点会直接使用;请确保网络由你控制。

4. Home Assistant Assist + Ollama + 此服务,完全本地运行 — 未测试

与方案 3 相同,但使用 Ollama 作为对话 Agent。在场信息不会离开你的网络。

5. Open WebUI + Ollama,完全本地运行 — 未测试

与方案 1 相同,但使用 Ollama 作为模型连接,而非 Anthropic。在场信息不会离开你的网络。

速率限制和错误

API 会按密钥进行速率限制。429 会作为工具错误返回给模型,并说明需要等待多久(取自 Retry-After);服务不会重试。其他所有非 2xx 状态也一样:一次请求,一条响应或一个错误,不会有其他处理。

开发

npm install
npm test          # builds, then unit + end-to-end tests over all three transports
npm run dev       # runs from source (tsx)

src/core/ 存放工具、从线路状态到状态的映射,以及 API 客户端。 它不导入任何 Node 专用内容——仅使用 fetch 和 AbortSignal——并且有测试确保这一点,因此当需要托管版本时,同一核心也能通过 SDK 的 Web 标准传输在 Cloudflare Worker 中运行。 src/transports/ 是 Node 端:可流式传输的 HTTP、SSE 和 stdio。

test/fixtures/ 为每种线路状态存放一个响应(test/fixtures/README.md 列出了这些响应及其来源)。运行 npm run capture -- <group_id> 可从实时 API 输出脱敏后的响应,以便更新测试样例;请使用合成测试组。

为什么应用也不开源?

负责中介访问的组件都可供审计:此服务、Home Assistant 集成、Hubitat 应用。你可以准确查看每个组件会请求什么,并确认它请求的内容少于其可能请求的内容。托管服务不开源,因为其中的引擎——历经数年积累的漂移处理、防抖、过期状态区分、聚类和可见性层——才是产品本身,也正是它让坦诚地拒绝回答变得经济可行。会猜测的系统无法说“我不知道”;它只会一直这么说。将 REST API 封装成 MCP 只需一个周末;让状态保持稳定则不然。

许可证

MIT。请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

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

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