Skip to main content
Glama

Runnywhere — 随时随地规划跑步路线!

Kakao PlayMCP Agentic Player 10 竞赛参赛作品。在AI聊天中输入 "从市政府出发5公里,没有上坡,鲸鱼形状",就会在首尔步行道路网络上生成可跑步的路线。 将首尔坡度(海拔·等高线)、行人信号灯、路灯位置数据反映到跑步友好度评分(RFS)中,提供平地优先·夜间安心路线。同时反映首尔市公共卫生间和OSM便利店数据,将"经过卫生间/便利店"等请求用于路线候选选择。 PRD:../runart-mcp-prd/PRD.md

执行

python3 -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
python -m runart.server           # http://localhost:8000/mcp (Streamable HTTP, JSON)
pytest                            # 테스트 (시나리오 수용 테스트 포함)
python scripts/loadtest.py 1000 10 # 콜드 미스 포함 부하 테스트 (평균 100ms / p99 3s)

PlayMCP 评审用 JSON 报告按如下方式保存。

RUNART_LOADTEST_REPORT=artifacts/playmcp-loadtest.json python scripts/loadtest.py 1000 10

地址搜索、重试、路线生成在内的 MCP Tool 整体响应适用 2.85 秒上限, 内部路线生成和外部地理编码共享更短的相同截止时间。

环境变量:HOST(本地默认 127.0.0.1,容器 0.0.0.0)· PORT(默认 8000)· RUNART_BASE_URL(预览链接域名)· RUNART_RELEASE_SHA(部署 Git SHA,与 Docker 构建参数联动)· KAKAO_JAVASCRIPT_KEY(KakaoMap Web API,必需)· KAKAO_REST_API_KEY(地理编码,可选)· RUNART_TOKEN_SECRET(32 位以上图鉴·接力令牌签名密钥,生产环境必需)· RUNART_LEGAL_CONTACT(政策咨询邮箱,公开部署时必需)· WEB_CONCURRENCY(Web 工作进程数,默认 1)· RUNART_POOL_WORKERS(路线搜索进程数,默认 2)· RATE_LIMIT_RPS(每 IP,默认 20)· RUNART_MAX_BODY_BYTES(MCP 请求体,默认 65,536)· RUNART_MAX_CONCURRENT_MCP(并发 MCP HTTP 请求,默认 4)· RUNART_ROUTE_EDIT(路线编辑,默认 1)· RUNART_MAX_CONCURRENT_ROUTE_EDITS(并发编辑重新计算,默认 1)· RUNART_ETL_LOCAL_ONLY=1(保留现有 OSM 属性,仅重新反映本地坡度/信号灯/路灯)

如果没有运行图(data/seoul_graph.pkl),则使用 首尔市政府周边演示网格 运行(用于确认整个管道运行)。提交竞赛前务必执行 ETL:

pip install -e '.[etl]'
python etl/build_graph.py         # OSM 서울 전역 보행망 -> data/seoul_graph.pkl
python scripts/build_animal_presets.py --workers 2 --fresh  # 고유 역 좌표 × 동물 4종 품질 우선 사전 계산
RUNART_ETL_LOCAL_ONLY=1 python etl/build_rfs.py
# 로컬 서울시 경사도 + 보행자 신호등 + 가로등 위치 + 공중화장실을 반영

当前快照(data/snapshot.json,2026-07-11):首尔全域步行图 163,848 个节点 / 232,006 条边,坡度反映在 232,006 条边上,基于 26,769 个行人信号灯点的过街评分,基于 19,316 个路灯点的照明评分。便利设施包括便利店 6,693 个、卫生间 4,985 个、公园 2,237 个、饮水台 213 个。

pickle 格式的图·设施·基础设施文件在加载前与 src/runart/data_integrity.py 的 SHA-256 进行比对。仅当通过 ETL 重新创建这三个文件时,使用 RUNART_ALLOW_UNVERIFIED_DATA=1 临时解除验证,并在审核后将新的校验和反映到代码中。生产环境中不设置解除验证的变量。

动物路线预设将 stations.py 的第 289 行按相同坐标基准合并后,分别对狗·猫·鲸鱼·兔子进行最长 11km 的全距离搜索。不应用运行时的 3 秒限制或提前终止,优先选择参考轮廓相似度,仅在相似度相近时选择更短的路线。结果保存在 data/animal_station_presets.json.gz 中,没有合适路线的组合也明确保存,以防止运行时重新搜索。图发生变化时,指纹会改变,现有预设自动失效。

运行时首先使用请求地点的精确预设,如果没有,则在周边 2km 范围内查找同一动物的验证路线,并明确标注实际出发站·移动距离·步行时间。在不降低质量门槛的情况下,将站×动物即时推荐范围从 421 个组合扩大到 905 个组合。

Related MCP server: Strava Coach MCP Server

结构

路径

角色(PRD 映射)

src/runart/server.py

MCP 工具 6 个 + 预览/GPX/共享路由(§5.1, §5.6)

src/runart/course.py

RFS 加权循环路线生成,±5% 距离允许(§5.3)

src/runart/shapes.py

动物形状模板·吸附·相似度门限 0.7(§5.4)

src/runart/rfs.py

跑步友好度评分 — 基础/夜间加权配置文件(§5.7)

src/runart/facilities.py

路线 10m 半径便利设施(§5.5)

src/runart/models.py

自包含 course_id — 无状态(§5.1)

etl/

离线数据管道 — 路线生成过程中不调用数据 API(§5.7)

路线·安全·设施数据预先加载到容器中,运行时不会向外部查询。但是,将用户输入的任意首尔地址转换为坐标的地理编码,在设置了 KAKAO_REST_API_KEY 时选择性使用 Kakao Local API,而 289 个地铁站和主要地名无需网络即可解析。

工具(7 个,均无状态·幂等)

create_seoul_running_course · list_available_shapes · find_facilities_near_course · refine_course · get_course_status · record_animal_completion · extend_shape_relay

首尔动物地图(/animals)允许在一个屏幕上浏览 421 个经过验证的 GPS 艺术作品。完赛记录通过自包含的 passport_token 延续,无需服务器数据库或登录,提供 4 种图鉴·地区 4 种徽章·每周最近未发现动物。Shape Relay(/relay/{token})也将最多 8 个社区的同一动物 course_id 包含在自包含令牌中,并列比较并叠加显示为共同 GPS 作品。因此保持 PlayMCP 推荐的无状态/无会话结构。

部署(PlayMCP in KC)

docker build --build-arg RUNART_RELEASE_SHA=$(git rev-parse HEAD) -t runnywhere .
docker run -p 8000:8000 -e RUNART_BASE_URL=https://<kc-endpoint> runnywhere

MCP 端点:https://<kc-endpoint>/mcp — 在 PlayMCP 注册前使用 MCP Inspector 进行验证。

许可·数据·安全

源代码以 MIT License 发布。OSM 衍生数据库遵循 ODbL 1.0,首尔市坡度 OA-22241·路灯 OA-22205·行人信号灯 OA-22356·公共卫生间 OA-22586·首尔交通公社站地址使用公共领域第一类。站坐标以首尔交通公社 1–8 号线坐标公共数据(使用许可无限制)为准。使用 NASA SRTM 30m 作为海拔回退。安心 CCTV 点因服务终止不再使用,仅使用 OSM surveillance 标签。

详细来源·加工·再分发条件请参考 DATA_LICENSES.md,依赖声明请参考 THIRD_PARTY_NOTICES.md。Web UI 的 /terms、/privacy、/data-licenses 可查看使用·安全、信息处理、来源。路线仅供参考,非实时导航,用户需自行确认现场通行·施工·天气·健康状况。

Related MCP Connectors

Related MCP Servers