├── LICENSE
├── README.md
├── img
├── agent_result.png
├── appbuilder.png
├── claude_final_result.png
├── claude_result.png
├── claude_setting.png
├── claude_setting_developer.png
├── claude_setting_result.png
├── cursor_run_mcp_success.png
├── cursor_setting.png
├── cursor_test_1.png
├── cursor_test_2.png
├── mcp_run_success.png
├── thinking_progress.png
└── uv_install_success.png
└── src
└── baidu-map
├── node
├── .gitignore
├── README.md
├── index.ts
├── package-lock.json
├── package.json
└── tsconfig.json
└── python
├── .gitignore
├── .python-version
├── LICENSE
├── README.md
├── pyproject.toml
├── src
└── mcp_server_baidu_maps
│ ├── __init__.py
│ ├── __main__.py
│ └── map.py
└── uv.lock
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 baidu-maps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 百度地图 MCP Server
2 |
3 | ## 概述
4 |
5 | 百度地图API现已全面兼容[MCP协议](https://modelcontextprotocol.io/),是国内首家兼容MCP协议的地图服务商。
6 |
7 | 百度地图提供的MCP Server,包含10个符合MCP协议标准的API接口,涵盖逆地理编码、地点检索、路线规划等。
8 |
9 | 依赖`MCP Python SDK`和`MCP Typescript SDK`开发,任意支持MCP协议的智能体助手(如`Claude`、`Cursor`以及`千帆AppBuilder`等)都可以快速接入。
10 |
11 | **强烈推荐通过[SSE](https://lbsyun.baidu.com/faq/api?title=mcpserver/quickstart)接入百度地图MCP Server, 以获得更低的延迟和更高的稳定性。请不要忘记在[控制台](https://lbsyun.baidu.com/apiconsole/key)为你的AK勾选上`MCP(SSE)`服务。**
12 |
13 | ## 工具
14 |
15 | 1. 地理编码 `map_geocode`
16 | - 描述: 将地址解析为对应的位置坐标, 地址结构越完整, 地址内容越准确, 解析的坐标精度越高
17 | - 参数: `address` 地址信息
18 | - 输出: `location` 纬经度坐标
19 |
20 | 2. 逆地理编码 `map_reverse_geocode`
21 | - 描述: 根据纬经度坐标, 获取对应位置的地址描述, 所在行政区划, 道路以及相关POI等信息
22 | - 参数:
23 | - `latitude` 纬度坐标
24 | - `longitude`经度坐标
25 | - 输出: `formatted_address`, `uid`, `addressComponent` 等语义化地址信息
26 |
27 | 3. 地点检索 `map_search_places`
28 | - 描述: 支持检索城市内的地点信息(最小到`city`级别), 也可支持圆形区域内的周边地点信息检索
29 | - 参数:
30 | - `query` 检索关键词, 可用名称或类型, 多关键字使用英文逗号隔开, 如: `query=天安门,美食`
31 | - `tag` 检索的类型偏好, 格式为`tag=美食`或者`tag=美食,酒店`
32 | - `region` 检索的行政区划, 格式为`region=cityname`或`region=citycode`
33 | - `location` 圆形检索中心点纬经度坐标, 格式为`location=lat,lng`
34 | - `radius` 圆形检索的半径
35 | - 输出: POI列表, 包含`name`, `location`, `address`等
36 |
37 | 4. 地点详情检索 `map_place_details`
38 | - 描述: 根据POI的uid,检索其相关的详情信息, 如评分、营业时间等(不同类型POI对应不同类别详情数据)
39 | - 参数: `uid`POI的唯一标识
40 | - 输出: POI详情, 包含`name`, `location`, `address`, `brand`, `price`等
41 |
42 | 5. 批量算路 `map_directions_matrix`
43 | - 描述: 根据起点和终点坐标计算路线规划距离和行驶时间,支持驾车、骑行、步行。步行时任意起终点之间的距离不得超过200KM,驾车批量算路一次最多计算100条路线,起终点个数之积不能超过100。
44 | - 参数:
45 | - `origins` 起点纬经度列表, 格式为`origins=lat,lng`,多个起点用`|`分隔
46 | - `destinations` 终点纬经度列表, 格式为`destinations=lat,lng`,多个终点用`|`分隔
47 | - `model` 算路类型,可选取值包括 `driving`, `walking`, `riding`,默认使用`driving`
48 | - 输出: 每条路线的耗时和距离, 包含`distance`, `duration`等
49 |
50 | 6. 路线规划 `map_directions`
51 | - 描述: 根据起终点位置名称或经纬度坐标规划出行路线和耗时, 可指定驾车、步行、骑行、公交等出行方式
52 | - 参数:
53 | - `origin` 起点位置名称或纬经度, 格式为`origin=lat,lng`
54 | - `destination` 终点位置名称或纬经度, 格式为`destination=lat,lng`
55 | - `model` 出行类型, 可选取值包括 `driving`, `walking`, `riding`, `transit`, 默认使用`driving`
56 | - 输出: 路线详情,包含`steps`, `distance`, `duration`等
57 |
58 | 7. 天气查询 `map_weather`
59 | - 描述: 通过行政区划或是经纬度坐标查询实时天气信息及未来5天天气预报
60 | - 参数:
61 | - `district_id` 行政区划编码
62 | - `location` 经纬度坐标, 格式为`location=lng, lat`
63 | - 输出: 天气信息, 包含`temperature`, `weather`, `wind`等
64 |
65 | 8. IP定位 `map_ip_location`
66 | - 描述: 通过所给IP获取具体位置信息和城市名称, 可用于定位IP或用户当前位置。可选参数`ip`,如果为空则获取本机IP地址(支持IPv4和IPv6)。
67 | - 参数:
68 | - `ip`(可选)需要定位的IP地址
69 | - 输出: 当前所在城市和城市中点`location`
70 |
71 | 9. 实时路况查询 `map_road_traffic`
72 | - 描述: 查询实时交通拥堵情况, 可通过指定道路名和区域形状(矩形, 多边形, 圆形)进行实时路况查询。
73 | - 参数:
74 | - `model` 路况查询类型 (可选值包括`road`, `bound`, `polygon`, `around`, 默认使用`road`)
75 | - `road_name` 道路名称和道路方向, `model=road`时必传 (如:`朝阳路南向北`)
76 | - `city` 城市名称或城市adcode, `model=road`时必传 (如:`北京市`)
77 | - `bounds` 区域左下角和右上角的纬经度坐标, `model=bound`时必传 (如:`39.9,116.4;39.9,116.4`)
78 | - `vertexes` 多边形区域的顶点纬经度坐标, `model=polygon`时必传 (如:`39.9,116.4;39.9,116.4;39.9,116.4;39.9,116.4`)
79 | - `center` 圆形区域的中心点纬经度坐标, `model=around`时必传 (如:`39.912078,116.464303`)
80 | - `radius` 圆形区域的半径(米), 取值`[1,1000]`, `model=around`时必传 (如:`200`)
81 | - 输出: 路况信息, 包含`road_name`, `traffic_condition`等
82 |
83 | 10. POI智能提取 `map_poi_extract`
84 | - 描述: 当所给的`API_KEY`带有**高级权限**才可使用, 根据所给文本内容提取其中的相关POI信息。
85 | - 参数: `text_content` 用于提取POI的文本描述信息 (完整的旅游路线,行程规划,景点推荐描述等文本内容, 例如: 新疆独库公路和塔里木湖太美了, 从独山子大峡谷到天山神秘大峡谷也是很不错的体验)
86 | - 输出:相关的POI信息,包含`name`, `location`等
87 |
88 |
89 | ## 开始
90 |
91 | 使用百度地图MCP Server主要通过两种形式,分别是`Python`和`Typescript`,下面分别介绍。
92 |
93 | ### 获取AK
94 |
95 | 在选择两种方法之前,你需要在[百度地图开放平台](https://lbsyun.baidu.com/apiconsole/key)的控制台中创建一个服务端AK,通过AK你才能够调用百度地图API能力。
96 |
97 |
98 | ### Python接入
99 |
100 | 如果你希望自定义百度地图MCP Server的能力,可以通过[源码](./src/baidu-map/python/src/mcp_server_baidu_maps/map.py)接入,方式详见[Python接入文档](./src/baidu-map/python/README.md)。
101 |
102 | 在v1.1版本更新中,我们通过pypi发布了百度地图MCP Server:*mcp-server-baidu-maps*,你可以使用任意Python包管理工具轻松获取并快速配置使用。
103 |
104 | #### 安装
105 |
106 | ##### 使用uv(推荐)
107 | 使用[`uv`](https://docs.astral.sh/uv/)时不需要特殊安装,我们将使用[`uvx`](https://docs.astral.sh/uv/guides/tools/)直接运行*mcp-server-baidu-maps*
108 |
109 | ##### 使用pip
110 | 或者你可以通过pip来安装*mcp-server-baidu-maps*
111 | ```bash
112 | pip install mcp-server-baidu-maps
113 | ```
114 |
115 | 安装后,我们可以使用以下命令将其作为脚本运行:
116 | ```bash
117 | python -m mcp_server_baidu_maps
118 | ```
119 |
120 | #### 配置
121 | 在任意MCP客户端(如Claude.app)中添加如下配置,部分客户端下可能需要做一些格式化调整。
122 |
123 | 其中*BAIDU_MAPS_API_KEY*对应的值需要替换为你自己的AK。
124 |
125 |
126 | Using uvx
127 |
128 | ```json
129 | {
130 | "mcpServers": {
131 | "baidu-maps": {
132 | "command": "uvx",
133 | "args": ["mcp-server-baidu-maps"],
134 | "env": {
135 | "BAIDU_MAPS_API_KEY": ""
136 | }
137 | }
138 | }
139 | }
140 | ```
141 |
142 |
143 |
144 | Using pip installation
145 |
146 | ```json
147 | {
148 | "mcpServers": {
149 | "baidu-maps": {
150 | "command": "python",
151 | "args": ["-m", "mcp_server_baidu_maps"],
152 | "env": {
153 | "BAIDU_MAPS_API_KEY": ""
154 | }
155 | }
156 | }
157 | }
158 | ```
159 |
160 |
161 | 保存配置后,重启你的MCP客户端,即可使用百度地图MCP Server。
162 |
163 | ### Typescript接入
164 |
165 | #### nodejs安装
166 | 通过Typescript接入,你只需要安装[node.js](https://nodejs.org/en/download)。
167 |
168 | 当你在终端可以运行
169 |
170 | ```bash
171 | node -v
172 | ```
173 |
174 | 则说明你的`node.js`已经安装成功。
175 |
176 | #### 配置
177 | 打开`Claude for Desktop`的`Setting`,切换到`Developer`,点击`Edit Config`,用任意的IDE打开配置文件。
178 |
179 | 
180 |
181 |
182 |
183 | 
184 |
185 |
186 |
187 | 将以下配置添加到配置文件中,BAIDU_MAP_API_KEY 是访问百度地图开放平台API的AK,在[此页面](https://lbs.baidu.com/faq/search?id=299&title=677)中申请获取:
188 |
189 | ```json
190 | {
191 | "mcpServers": {
192 | "baidu-map": {
193 | "command": "npx",
194 | "args": [
195 | "-y",
196 | "@baidumap/mcp-server-baidu-map"
197 | ],
198 | "env": {
199 | "BAIDU_MAP_API_KEY": "xxx"
200 | }
201 | }
202 | }
203 | }
204 | ```
205 | 如果是window 系统, json 需要添加单独的配置:
206 | ```json
207 | "mcpServers": {
208 | "baidu-map": {
209 | "command": "cmd",
210 | "args": [
211 | "/c",
212 | "npx",
213 | "-y",
214 | "@baidumap/mcp-server-baidu-map"
215 | ],
216 | "env": {
217 | "BAIDU_MAP_API_KEY": "xxx"
218 | },
219 | }
220 | }
221 | ```
222 | 重启Claude,此时设置面板已经成功加载了百度地图MCP Server。在软件主界面对话框处可以看到有8个可用的MCP工具,点击可以查看详情。
223 |
224 | 
225 |
226 | 
227 |
228 | #### 效果
229 |
230 | 接下来就可以进行提问,验证出行规划小助手的能力了。
231 | 
232 |
233 |
234 | ### 通过千帆AppBuilder平台接入
235 |
236 | 千帆平台接入,目前支持SDK接入或是API接入,通过AppBuilder构建一个应用,每个应用拥有一个独立的app\_id,在python文件中调用对应的app\_id,再调用百度地图 Python MCP Tool即可。
237 |
238 | 模板代码可向下跳转,通过SDK Agent &&地图MCP Server,拿到导航路线及路线信息,并给出出行建议。
239 |
240 |
241 | #### Agent配置
242 |
243 | 前往[千帆平台](https://console.bce.baidu.com/ai_apaas/personalSpace/app),新建一个应用,并发布。
244 |
245 | 
246 |
247 | 将Agent的思考轮数调到6。发布应用。
248 |
249 | #### 调用
250 |
251 | 此代码可以当作模板,以SDK的形式调用千帆平台上已经构建好且已发布的App,再将MCP Server下载至本地,将文件相对路径写入代码即可。
252 |
253 | ***(注意:使用实际的app_id、token、query、mcp文件)***
254 |
255 | ```python
256 | import os
257 | import asyncio
258 | import appbuilder
259 | from appbuilder.core.console.appbuilder_client.async_event_handler import (
260 | AsyncAppBuilderEventHandler,
261 | )
262 | from appbuilder.mcp_server.client import MCPClient
263 | class MyEventHandler(AsyncAppBuilderEventHandler):
264 | def __init__(self, mcp_client):
265 | super().__init__()
266 | self.mcp_client = mcp_client
267 | def get_current_weather(self, location=None, unit="摄氏度"):
268 | return "{} 的温度是 {} {}".format(location, 20, unit)
269 | async def interrupt(self, run_context, run_response):
270 | thought = run_context.current_thought
271 | # 绿色打印
272 | print("\033[1;31m", "-> Agent 中间思考: ", thought, "\033[0m")
273 | tool_output = []
274 | for tool_call in run_context.current_tool_calls:
275 | tool_res = ""
276 | if tool_call.function.name == "get_current_weather":
277 | tool_res = self.get_current_weather(**tool_call.function.arguments)
278 | else:
279 | print(
280 | "\033[1;32m",
281 | "MCP工具名称: {}, MCP参数:{}\n".format(tool_call.function.name, tool_call.function.arguments),
282 | "\033[0m",
283 | )
284 | mcp_server_result = await self.mcp_client.call_tool(
285 | tool_call.function.name, tool_call.function.arguments
286 | )
287 | print("\033[1;33m", "MCP结果: {}\n\033[0m".format(mcp_server_result))
288 | for i, content in enumerate(mcp_server_result.content):
289 | if content.type == "text":
290 | tool_res += mcp_server_result.content[i].text
291 | tool_output.append(
292 | {
293 | "tool_call_id": tool_call.id,
294 | "output": tool_res,
295 | }
296 | )
297 | return tool_output
298 | async def success(self, run_context, run_response):
299 | print("\n\033[1;34m", "-> Agent 非流式回答: ", run_response.answer, "\033[0m")
300 | async def agent_run(client, mcp_client, query):
301 | tools = mcp_client.tools
302 | conversation_id = await client.create_conversation()
303 | with await client.run_with_handler(
304 | conversation_id=conversation_id,
305 | query=query,
306 | tools=tools,
307 | event_handler=MyEventHandler(mcp_client),
308 | ) as run:
309 | await run.until_done()
310 | ### 用户Token
311 | os.environ["APPBUILDER_TOKEN"] = (
312 | ""
313 | )
314 | async def main():
315 | appbuilder.logger.setLoglevel("DEBUG")
316 | ### 发布的应用ID
317 | app_id = ""
318 | appbuilder_client = appbuilder.AsyncAppBuilderClient(app_id)
319 | mcp_client = MCPClient()
320 |
321 | ### 注意这里的路径为MCP Server文件在本地的相对路径
322 | await mcp_client.connect_to_server(".//map.py")
323 | print(mcp_client.tools)
324 | await agent_run(
325 | appbuilder_client,
326 | mcp_client,
327 | '开车导航从北京到上海',
328 | )
329 | await appbuilder_client.http_client.session.close()
330 | if __name__ == "__main__":
331 | loop = asyncio.get_event_loop()
332 | loop.run_until_complete(main())
333 | ```
334 |
335 | #### 效果
336 |
337 | 经过Agent自己的思考,通过调用MCPServer 地点检索、地理编码服务、路线规划服务等多个tool,拿到导航路线及路线信息,并给出出行建议。
338 |
339 | 实际用户请求:***“请为我计划一次北京赏花一日游。尽量给出更舒适的出行安排,当然,也要注意天气状况。”***
340 |
341 | #### 思考过程
342 |
343 | 
344 |
345 | #### Agent结果
346 |
347 | 
348 |
349 | ## 说明
350 |
351 | 在百度地图MCP Server中传入的部分参数规格:
352 |
353 | 行政区划编码均采用[百度adcode映射表](https://lbsyun.baidu.com/faq/api?title=webapi/download)。
354 |
355 | 经纬度坐标均采用国测局经纬度坐标`bd09ll`,详见[百度坐标系](https://lbsyun.baidu.com/index.php?title=coordinate)。
356 |
357 | 类型等中文字符串参数应符合[百度POI类型](https://lbs.baidu.com/index.php?title=open/poitags)标准。
358 |
359 | ## 许可
360 |
361 | [MIT](./LICENSE) © baidu-maps
362 |
363 | ## 授权
364 |
365 | 百度地图MCP Server中的部分高级能力需要申请**高级权限**才可使用。如有需要的话,请[联系](https://lbsyun.baidu.com/apiconsole/fankui?typeOne=%E4%BA%A7%E5%93%81%E9%9C%80%E6%B1%82&typeTwo=%E9%AB%98%E7%BA%A7%E6%9C%8D%E5%8A%A1)我们。
366 |
367 |
368 | ## 反馈
369 |
370 | 在使用百度地图MCP Server时遇到的任何问题,欢迎通过`issue`或是[百度地图开放平台](https://lbsyun.baidu.com/apiconsole/fankui?typeOne=30046&typeTwo=53524&typeThree=1032776)反馈给我们,我们也欢迎每一个积极的`PR`,非常感谢各位的支持与贡献❤️
371 |
372 | ## 更新
373 |
374 | 团队目前主要关注Remote形式的服务供应,对于开源部分的更新会相对较少,请谅解。
375 |
376 | | 版本 | 功能说明 | 更新日期 |
377 | | ---- | ------------------------------ | ------------- |
378 | | V1.0 | 百度地图MCP Server正式上线 | 2025-03-21 |
379 | | V1.1 | 补充`uvx`、`pip`形式的快速接入 | 2025-03-28 |
380 | | V1.2 | 补充`千帆AppBuilder`接入方式 | 2025-04-05 |
381 | | V2.0 | 支持MCP`1.9.0`版协议 | 2025-05-16 |
382 |
--------------------------------------------------------------------------------
/img/agent_result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/agent_result.png
--------------------------------------------------------------------------------
/img/appbuilder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/appbuilder.png
--------------------------------------------------------------------------------
/img/claude_final_result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/claude_final_result.png
--------------------------------------------------------------------------------
/img/claude_result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/claude_result.png
--------------------------------------------------------------------------------
/img/claude_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/claude_setting.png
--------------------------------------------------------------------------------
/img/claude_setting_developer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/claude_setting_developer.png
--------------------------------------------------------------------------------
/img/claude_setting_result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/claude_setting_result.png
--------------------------------------------------------------------------------
/img/cursor_run_mcp_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/cursor_run_mcp_success.png
--------------------------------------------------------------------------------
/img/cursor_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/cursor_setting.png
--------------------------------------------------------------------------------
/img/cursor_test_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/cursor_test_1.png
--------------------------------------------------------------------------------
/img/cursor_test_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/cursor_test_2.png
--------------------------------------------------------------------------------
/img/mcp_run_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/mcp_run_success.png
--------------------------------------------------------------------------------
/img/thinking_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/thinking_progress.png
--------------------------------------------------------------------------------
/img/uv_install_success.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baidu-maps/mcp/35a02364ce86675bb6002e5c17df387e5028ebe2/img/uv_install_success.png
--------------------------------------------------------------------------------
/src/baidu-map/node/.gitignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /node_modules
--------------------------------------------------------------------------------
/src/baidu-map/node/README.md:
--------------------------------------------------------------------------------
1 | # Baidu Map MCP Server
2 |
3 | MCP Server for the Baidu Map API.
4 |
5 | ## Tools
6 |
7 | 1. `map_geocode`
8 | - 地理编码服务
9 | - Input:
10 | - `address` (string): 待解析的地址。最多支持84个字节。
11 | 可以输入两种样式的值,分别是
12 | 1. 标准的结构化地址信息,如北京市海淀区上地十街十号【推荐,地址结构越完整,解析精度越高】
13 | 2. 支持“*路与*路交叉口”描述方式,如北一环路和阜阳路的交叉路口
14 | 第二种方式并不总是有返回结果,只有当地址库中存在该地址描述时才有返回。
15 | - Returns:
16 | - `location`: { lat: number, lng: number }
17 | - `precise`: number
18 | - `confidence`: number
19 | - `comprehension`: number
20 | - `level`: string
21 |
22 | 2. `map_reverse_geocode`
23 | - 全球逆地理编码
24 | - Inputs:
25 | - `latitude` (number)
26 | - `longitude` (number)
27 | - Returns:
28 | - `place_id`: string
29 | - `location`: { lng: number, lat: number }
30 | - `formatted_address`: string
31 | - `formatted_address_poi`: string
32 | - `business`: string
33 | - `business_info`: Array of {
34 | - `name`: string
35 | - `location`: { lng: number, lat: number }
36 | - `adcode`: number
37 | - `distance`: number
38 | - `direction`: string
39 | }
40 | - `addressComponent`: {
41 | - `country`: string
42 | - `province`: string
43 | - `city`: string
44 | - `district`: string
45 | - `street`: string
46 | - `street_number`: string
47 | - (and other detailed address components)
48 | }
49 | - `pois`: Array of POI information
50 | - `roads`: Array of nearby roads
51 | - `poiRegions`: Array of POI regions
52 | - `sematic_description`: string
53 | - `cityCode`: number
54 |
55 | 3. `map_search_places`
56 | - 地点检索服务(包括城市检索、圆形区域检索、多边形区域检索)
57 | - Inputs:
58 | - `query` (string): 检索关键字
59 | - `region` (string, 可选): 检索行政区划区域,如"北京"
60 | - `bounds` (string, 可选): 检索多边形区域,格式如"38.76623,116.43213,39.54321,116.46773"
61 | - `location` (string, 可选): 圆形区域检索中心点,格式如"39.915,116.404"
62 | 注意:region、bounds、location 三个参数必须且只能选择其中一个
63 | - Returns:
64 | - `result_type`: string
65 | - `query_type`: string
66 | - `places`: Array of {
67 | - `name`: string
68 | - `location`: { lat: number, lng: number }
69 | - `address`: string
70 | - `province`: string
71 | - `city`: string
72 | - `area`: string
73 | - `street_id`: string
74 | - `telephone`: string
75 | - `detail`: number
76 | - `uid`: string
77 | }
78 |
79 | 4. `map_place_details`
80 | - 地点详情检索服务
81 | - Inputs:
82 | - `uid` (string): poi的uid
83 | - `scope` (string, 可选): 检索结果详细程度
84 | - 1 或空: 返回基本信息
85 | - 2: 返回检索POI详细信息
86 | - Returns:
87 | 基本信息 (scope=1):
88 | - `uid`: string
89 | - `street_id`: string
90 | - `name`: string
91 | - `location`: { lng: number, lat: number }
92 | - `address`: string
93 | - `province`: string
94 | - `city`: string
95 | - `area`: string
96 | - `detail`: number
97 |
98 | 详细信息 (scope=2):
99 | 包含基本信息,并额外返回:
100 | - `detail_info`: {
101 | - `tag`: string
102 | - `navi_location`: { lng: number, lat: number }
103 | - `new_catalog`: string
104 | - `shop_hours`: string
105 | - `detail_url`: string
106 | - `type`: string
107 | - `overall_rating`: string
108 | - `image_num`: string
109 | - `comment_num`: string
110 | - `content_tag`: string
111 | }
112 |
113 | 5. `map_distance_matrix`
114 | - 计算多个出发地和目的地的距离和路线用时
115 | - Inputs:
116 | - `origins` (string[])
117 | - `destinations` (string[])
118 | - `mode` (optional): "driving" | "walking" | "riding" | "motorcycle"
119 | - Returns: distances and durations matrix
120 |
121 | 6. `map_directions`
122 | - 路线规划服务
123 | - Inputs:
124 | - `origin` (string)
125 | - `destination` (string)
126 | - `mode` (optional): "driving" | "walking" | "riding" | "transit"
127 | - Returns: route details with steps, distance, duration
128 |
129 | 7. `map_weather`
130 | - 通过行政区划代码查询实时天气信息及未来5天天气预报
131 | - Input: `districtId` (string)
132 | - Returns: location, now, forecasts
133 |
134 | 8. `map_ip_location`
135 | - 根据IP定位来获取位置
136 | - Input: `ip` (string)
137 | - Returns: formatted_address, address_detail, point
138 |
139 | 9. `map_road_traffic`
140 | - 根据城市和道路名称查询具体道路的实时路况信息
141 | - Inputs:
142 | - `roadName` (string)
143 | - `city` (string)
144 | - Returns: description, evaluation and road traffic
145 |
146 | 10. `map_poi_extract`
147 | - 提取文本内容中的POI信息
148 | - Inputs: `textContent` (string) POI文本描述内容
149 | - Returns:
150 | - `jumpUrl` string
151 | - `title` string
152 | - `desc` string
153 | - `image` string
154 | - `poi` Array of POI information
155 | ## Setup
156 |
157 | ### API Key
158 | Get a Baidu Map API key by following the instructions [here](https://lbsyun.baidu.com/faq/search?id=299&title=677).
159 |
160 | ### Usage with Claude Desktop
161 |
162 | Add the following to your `claude_desktop_config.json`:
163 |
164 | ### NPX
165 |
166 | ```json
167 | {
168 | "mcpServers": {
169 | "baidu-map": {
170 | "command": "npx",
171 | "args": [
172 | "-y",
173 | "@baidumap/mcp-server-baidu-map"
174 | ],
175 | "env": {
176 | "BAIDU_MAP_API_KEY": ""
177 | }
178 | }
179 | }
180 | }
181 | ```
182 |
183 | ## License
184 |
185 | This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
186 |
--------------------------------------------------------------------------------
/src/baidu-map/node/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5 | import {
6 | CallToolRequestSchema,
7 | ListToolsRequestSchema,
8 | Tool,
9 | } from "@modelcontextprotocol/sdk/types.js";
10 | import fetch from "node-fetch";
11 |
12 | // Response interfaces
13 | interface BaiduMapResponse {
14 | status: number;
15 | msg?: string;
16 | message?: string;
17 | }
18 |
19 | interface GeocodeResponse extends BaiduMapResponse {
20 | result: {
21 | location: {
22 | lat: number;
23 | lng: number;
24 | }
25 | precise: number;
26 | confidence: number;
27 | comprehension: number;
28 | level: string;
29 | };
30 | }
31 |
32 | interface ReverseGeocodeResponse extends BaiduMapResponse {
33 | result: {
34 | location: {
35 | lng: number;
36 | lat: number;
37 | };
38 | formatted_address: string;
39 | edz: {
40 | name: string;
41 | };
42 | business: string;
43 | business_info: Array<{
44 | name: string;
45 | location: {
46 | lng: number;
47 | lat: number;
48 | };
49 | adcode: number;
50 | distance: number;
51 | direction: string;
52 | }>;
53 | addressComponent: {
54 | country: string;
55 | country_code: number;
56 | country_code_iso: string;
57 | country_code_iso2: string;
58 | province: string;
59 | city: string;
60 | city_level: number;
61 | district: string;
62 | town: string;
63 | town_code: string;
64 | distance: string;
65 | direction: string;
66 | adcode: string;
67 | street: string;
68 | street_number: string;
69 | };
70 | pois: any[];
71 | roads: any[];
72 | poiRegions: any[];
73 | sematic_description: string;
74 | formatted_address_poi: string;
75 | cityCode: number;
76 | };
77 | }
78 |
79 | interface PlacesSearchResponse extends BaiduMapResponse {
80 | result_type?: string;
81 | query_type?: string;
82 | results?: Array<{
83 | name: string;
84 | location: {
85 | lat: number;
86 | lng: number;
87 | };
88 | address: string;
89 | province: string;
90 | city: string;
91 | area: string;
92 | street_id?: string;
93 | telephone?: string;
94 | detail: number;
95 | uid: string;
96 | }>;
97 | // region 参数时的返回结构
98 | result?: Array<{
99 | name: string;
100 | location: {
101 | lat: number;
102 | lng: number;
103 | };
104 | address: string;
105 | province: string;
106 | city: string;
107 | area: string;
108 | street_id?: string;
109 | telephone?: string;
110 | detail: number;
111 | uid: string;
112 | }>;
113 | }
114 |
115 | // PlaceDetails Base Response
116 | interface PlaceDetailsBaseResponse extends BaiduMapResponse {
117 | result: {
118 | uid: string;
119 | street_id: string;
120 | name: string;
121 | location: {
122 | lng: number;
123 | lat: number;
124 | };
125 | address: string;
126 | province: string;
127 | city: string;
128 | area: string;
129 | detail: number;
130 | };
131 | }
132 | // scope=2 时的详细信息
133 | interface PlaceDetailsFullResponse extends BaiduMapResponse {
134 | result: PlaceDetailsBaseResponse['result'] & {
135 | detail_info: {
136 | tag: string;
137 | navi_location: {
138 | lng: number;
139 | lat: number;
140 | };
141 | new_catalog: string;
142 | shop_hours: string;
143 | detail_url: string;
144 | type: string;
145 | overall_rating: string;
146 | image_num: string;
147 | comment_num: string;
148 | content_tag: string;
149 | };
150 | };
151 | }
152 |
153 | type PlaceDetailsResponse = PlaceDetailsBaseResponse | PlaceDetailsFullResponse;
154 |
155 | interface DistanceMatrixResponse extends BaiduMapResponse {
156 | result: Array<{
157 | distance: {
158 | text: string;
159 | value: string;
160 | };
161 | duration: {
162 | text: string;
163 | value: string;
164 | };
165 | }>;
166 | }
167 |
168 | interface DirectionsResponse extends BaiduMapResponse {
169 | result: {
170 | routes: Array<{
171 | distance: number;
172 | duration: number;
173 | steps: Array<{
174 | instruction: string;
175 | }>
176 | }>;
177 | };
178 | }
179 |
180 | interface WeatherResponse extends BaiduMapResponse {
181 | result: {
182 | location: {
183 | province: string,
184 | city: string,
185 | name: string,
186 | },
187 | now: {
188 | text: string,
189 | temp: number,
190 | feels_like: number,
191 | rh: number,
192 | wind_class: string,
193 | wind_dir: string,
194 | uptime: number,
195 | },
196 | forecasts: Array<{
197 | text_day: string,
198 | text_night: string,
199 | high: number,
200 | low: number,
201 | wc_day: string,
202 | wd_day: string,
203 | wc_night: string,
204 | wd_night: string,
205 | date: string,
206 | week: string,
207 | }>,
208 | indexes?: Array<{
209 | name: string,
210 | brief: string,
211 | detail: string,
212 | }>,
213 | alerts: Array<{
214 | type: string,
215 | level: string,
216 | title: string,
217 | desc: string,
218 | }>,
219 | forecast_hours?: Array<{
220 | text: string,
221 | temp_fc: number,
222 | wind_class: string,
223 | rh: number,
224 | prec_1h: number,
225 | clouds: number,
226 | data_time: number,
227 | }>
228 | }
229 | }
230 |
231 | interface IPLocationResponse extends BaiduMapResponse {
232 | address: string,
233 | content: {
234 | address: string,
235 | address_detail: {
236 | city: string,
237 | city_code: number,
238 | province: string
239 | },
240 | point: {
241 | x: string,
242 | y: string,
243 | }
244 | }
245 | }
246 |
247 | interface RoadTrafficResponse extends BaiduMapResponse {
248 | description: string,
249 | evaluation: {
250 | status: number,
251 | status_desc: string,
252 | },
253 | road_traffic: {
254 | road_name: string,
255 | congestion_sections?: Array<{
256 | section_desc: string,
257 | status: number,
258 | speed: number,
259 | congestion_distance: number,
260 | congestion_trend: string,
261 | }>
262 | }
263 | }
264 |
265 |
266 | interface MarkSubmitResponse extends BaiduMapResponse {
267 | result: {
268 | session_id: string,
269 | map_id: string,
270 | }
271 | }
272 |
273 | interface MarkResultResponse extends BaiduMapResponse {
274 | result: {
275 | data: Array<{
276 | answer_type: string,
277 | create_time: string,
278 | link: {
279 | title: string,
280 | desc: string,
281 | jump_url: string,
282 | image: string,
283 | poi: Array<{
284 | uid: string,
285 | name: string,
286 | location: any,
287 | admin_info: any,
288 | price: number,
289 | shop_hours: string,
290 | }>
291 | }
292 | }>
293 | }
294 | }
295 |
296 | function getApiKey(): string {
297 | const apiKey = process.env.BAIDU_MAP_API_KEY;
298 | if (!apiKey) {
299 | console.error("BAIDU_MAP_API_KEY environment variable is not set");
300 | process.exit(1);
301 | }
302 | return apiKey;
303 | }
304 |
305 | const BAIDU_MAP_API_KEY = getApiKey();
306 |
307 | // Tool definitions
308 | const GEOCODE_TOOL: Tool = {
309 | name: "map_geocode",
310 | description: "地理编码服务",
311 | inputSchema: {
312 | type: "object",
313 | properties: {
314 | address: {
315 | type: "string",
316 | description: "待解析的地址(最多支持84个字节。可以输入两种样式的值,分别是:1、标准的结构化地址信息,如北京市海淀区上地十街十号【推荐,地址结构越完整,解析精度越高】2、支持“*路与*路交叉口”描述方式,如北一环路和阜阳路的交叉路口第二种方式并不总是有返回结果,只有当地址库中存在该地址描述时才有返回。)"
317 | }
318 | },
319 | required: ["address"]
320 | }
321 | };
322 |
323 | const REVERSE_GEOCODE_TOOL: Tool = {
324 | name: "map_reverse_geocode",
325 | description: "全球逆地理编码",
326 | inputSchema: {
327 | type: "object",
328 | properties: {
329 | latitude: {
330 | type: "number",
331 | description: "Latitude coordinate"
332 | },
333 | longitude: {
334 | type: "number",
335 | description: "Longitude coordinate"
336 | }
337 | },
338 | required: ["latitude", "longitude"]
339 | }
340 | };
341 |
342 | const SEARCH_PLACES_TOOL: Tool = {
343 | name: "map_search_places",
344 | description: "地点检索服务(包括城市检索、圆形区域检索、多边形区域检索)",
345 | inputSchema: {
346 | type: "object",
347 | properties: {
348 | query: {
349 | type: "string",
350 | description: "检索关键字"
351 | },
352 | region: {
353 | type: "string",
354 | description: "检索行政区划区域"
355 | },
356 | bounds: {
357 | type: "string",
358 | description: "检索多边形区域"
359 | },
360 | location: {
361 | type: "string",
362 | description: "圆形区域检索中心点,不支持多个点"
363 | },
364 | },
365 | required: ["query"],
366 | }
367 | };
368 |
369 |
370 | const PLACE_DETAILS_TOOL: Tool = {
371 | name: "map_place_details",
372 | description: "地点详情检索服务",
373 | inputSchema: {
374 | type: "object",
375 | properties: {
376 | uid: {
377 | type: "string",
378 | description: "poi的uid"
379 | },
380 | scope: {
381 | type: "string",
382 | description: "检索结果详细程度。取值为1 或空,则返回基本信息;取值为2,返回检索POI详细信息"
383 | }
384 | },
385 | required: ["uid"]
386 | }
387 | };
388 |
389 |
390 | const DISTANCE_MATRIX_TOOL: Tool = {
391 | name: "map_distance_matrix",
392 | description: "计算多个出发地和目的地的距离和路线用时",
393 | inputSchema: {
394 | type: "object",
395 | properties: {
396 | origins: {
397 | type: "array",
398 | items: { type: "string" },
399 | description: "起点的纬度,经度。"
400 | },
401 | destinations: {
402 | type: "array",
403 | items: { type: "string" },
404 | description: "终点的纬度,经度。"
405 | },
406 | mode: {
407 | type: "string",
408 | description: "路线类型,可选值:driving(驾车)、walking(步行)、riding(骑行)、motorcycle(摩托车)",
409 | enum: ["driving", "walking", "riding", "motorcycle"]
410 | }
411 | },
412 | required: ["origins", "destinations"]
413 | }
414 | };
415 |
416 | const DIRECTIONS_TOOL: Tool = {
417 | name: "map_directions",
418 | description: "路线规划服务, 计算出发地到目的地的距离、路线用时、路线方案",
419 | inputSchema: {
420 | type: "object",
421 | properties: {
422 | origin: {
423 | type: "string",
424 | description: "起点经纬度,格式为:纬度,经度;小数点后不超过6位,40.056878,116.30815"
425 | },
426 | destination: {
427 | type: "string",
428 | description: "终点经纬度,格式为:纬度,经度;小数点后不超过6位,40.056878,116.30815"
429 | },
430 | mode: {
431 | type: "string",
432 | description: "路线规划类型,可选值:driving(驾车)、walking(步行)、riding(骑行)、transit(公交)",
433 | enum: ["driving", "walking", "riding", "transit"]
434 | }
435 | },
436 | required: ["origin", "destination"]
437 | }
438 | };
439 |
440 | const WEATHER_TOOL: Tool = {
441 | name: "map_weather",
442 | description: '通过行政区划代码或者经纬度坐标获取实时天气信息和未来5天天气预报',
443 | inputSchema: {
444 | type: "object",
445 | properties: {
446 | districtId: {
447 | type: "string",
448 | description: "行政区划代码(适用于区、县级别)"
449 | },
450 | location: {
451 | type: "string",
452 | description: "经纬度,经度在前纬度在后,逗号分隔,格式如116.404,39.915"
453 | }
454 | },
455 | }
456 | }
457 |
458 | const IP_LOCATION_TOOL: Tool = {
459 | name: "map_ip_location",
460 | description: "通过IP地址获取位置信息",
461 | inputSchema: {
462 | type: "object",
463 | properties: {
464 | ip: {
465 | type: "string",
466 | description: "IP地址",
467 | }
468 | },
469 | required: ["ip"],
470 | }
471 | }
472 |
473 | const ROAD_TRAFFIC_TOOL: Tool = {
474 | name: "map_road_traffic",
475 | description: "根据城市和道路名称查询具体道路的实时拥堵评价和拥堵路段、拥堵距离、拥堵趋势等信息",
476 | inputSchema: {
477 | type: "object",
478 | properties: {
479 | roadName: {
480 | type: "string",
481 | description: "道路名称",
482 | },
483 | city: {
484 | type: "string",
485 | description: "城市名称"
486 | },
487 | bounds: {
488 | type: "string",
489 | description: "矩形区域,左下角和右上角的经纬度坐标点,坐标对间使用;号分隔,格式为:纬度,经度;纬度,经度,如39.912078,116.464303;39.918276,116.475442"
490 | },
491 | vertexes: {
492 | type: "string",
493 | description: "多边形边界点,经纬度顺序为:纬度,经度; 顶点顺序需按逆时针排列, 格式如vertexes=39.910528,116.472926;39.918276,116.475442;39.916671,116.459056;39.912078,116.464303"
494 | },
495 | center: {
496 | type: "string",
497 | description: "中心点坐标,如39.912078,116.464303"
498 | },
499 | radius: {
500 | type: "number",
501 | description: "查询半径,单位:米"
502 | }
503 | },
504 | }
505 | }
506 |
507 | const MARK_SUBMIT_POI_TOOL: Tool = {
508 | name: "map_poi_extract",
509 | description: "POI智能标注",
510 | inputSchema: {
511 | type: "object",
512 | properties: {
513 | textContent: {
514 | type: "string",
515 | description: "描述POI的文本内容"
516 | }
517 | },
518 | required: ["textContent"],
519 | }
520 | }
521 |
522 | const MAPS_TOOLS = [
523 | GEOCODE_TOOL,
524 | REVERSE_GEOCODE_TOOL,
525 | SEARCH_PLACES_TOOL,
526 | PLACE_DETAILS_TOOL,
527 | DISTANCE_MATRIX_TOOL,
528 | DIRECTIONS_TOOL,
529 | WEATHER_TOOL,
530 | IP_LOCATION_TOOL,
531 | ROAD_TRAFFIC_TOOL,
532 | MARK_SUBMIT_POI_TOOL
533 | ] as const;
534 |
535 | // API handlers
536 | async function handleGeocode(address: string) {
537 | const url = new URL("https://api.map.baidu.com/geocoding/v3/");
538 | url.searchParams.append("address", address);
539 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
540 | url.searchParams.append("output", "json");
541 | url.searchParams.append("from", "node_mcp");
542 |
543 | const response = await fetch(url.toString());
544 | const data = await response.json() as GeocodeResponse;
545 | if (data.status !== 0) {
546 | return {
547 | content: [{
548 | type: "text",
549 | text: `Geocoding failed: ${data.message || data.status}`
550 | }],
551 | isError: true
552 | };
553 | }
554 |
555 | return {
556 | content: [{
557 | type: "text",
558 | text: JSON.stringify({
559 | location: data.result.location,
560 | precise: data.result.precise,
561 | confidence: data.result.confidence,
562 | comprehension: data.result.comprehension,
563 | level: data.result.level
564 | }, null, 2)
565 | }],
566 | isError: false
567 | };
568 | }
569 |
570 | async function handleReverseGeocode(latitude: number, longitude: number) {
571 | const url = new URL("https://api.map.baidu.com/reverse_geocoding/v3/");
572 | url.searchParams.append("location", `${latitude},${longitude}`);
573 | url.searchParams.append("extensions_poi", "1");
574 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
575 | url.searchParams.append("output", "json");
576 | url.searchParams.append("from", "node_mcp");
577 |
578 | const response = await fetch(url.toString());
579 | const data = await response.json() as ReverseGeocodeResponse;
580 |
581 | if (data.status !== 0) {
582 | return {
583 | content: [{
584 | type: "text",
585 | text: `Reverse geocoding failed: ${data.message || data.status}`
586 | }],
587 | isError: true
588 | };
589 | }
590 |
591 | return {
592 | content: [{
593 | type: "text",
594 | text: JSON.stringify({
595 | place_id: data.result.pois[0] ? data.result.pois[0].uid : null,
596 | location: data.result.location,
597 | formatted_address: data.result.formatted_address,
598 | formatted_address_poi: data.result.formatted_address_poi,
599 | business: data.result.business,
600 | business_info: data.result.business_info,
601 | addressComponent: data.result.addressComponent,
602 | edz: data.result.edz,
603 | pois: data.result.pois,
604 | roads: data.result.roads,
605 | poiRegions: data.result.poiRegions,
606 | sematic_description: data.result.sematic_description,
607 | cityCode: data.result.cityCode
608 | }, null, 2)
609 | }],
610 | isError: false
611 | };
612 | }
613 |
614 | async function handlePlaceSearch(
615 | query: string,
616 | region?: string,
617 | bounds?: string,
618 | location?: string
619 | ) {
620 | const url = new URL("https://api.map.baidu.com/place/v2/search");
621 | url.searchParams.append("query", query);
622 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
623 | url.searchParams.append("output", "json");
624 | url.searchParams.append("from", "node_mcp");
625 | if (region) {
626 | url.searchParams.append("region", region);
627 | }
628 | if (bounds) {
629 | url.searchParams.append("bounds", bounds);
630 | }
631 | if (location) {
632 | url.searchParams.append("location", location);
633 | }
634 |
635 | const response = await fetch(url.toString());
636 | const data = await response.json() as PlacesSearchResponse;
637 | if (data.status !== 0) {
638 | return {
639 | content: [{
640 | type: "text",
641 | text: `Place search failed: ${data.message || data.status}`
642 | }],
643 | isError: true
644 | };
645 | }
646 |
647 | // 处理不同参数返回的数据结构
648 | const places = data.results || data.result || [];
649 |
650 | return {
651 | content: [{
652 | type: "text",
653 | text: JSON.stringify({
654 | result_type: data.result_type,
655 | query_type: data.query_type,
656 | results: places.map((place) => ({
657 | name: place.name,
658 | location: place.location,
659 | address: place.address,
660 | province: place.province,
661 | city: place.city,
662 | area: place.area,
663 | street_id: place.street_id,
664 | telephone: place.telephone,
665 | detail: place.detail,
666 | uid: place.uid
667 | }))
668 | }, null, 2)
669 | }],
670 | isError: false
671 | };
672 | }
673 |
674 | async function handlePlaceDetails(uid: string, scope?: string) {
675 | const url = new URL("https://api.map.baidu.com/place/v2/detail");
676 | url.searchParams.append("uid", uid);
677 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
678 | url.searchParams.append("output", "json");
679 | url.searchParams.append("from", "node_mcp");
680 | if (scope) {
681 | url.searchParams.append("scope", scope);
682 | }
683 |
684 | const response = await fetch(url.toString());
685 | const data = await response.json() as PlaceDetailsResponse;
686 |
687 | if (data.status !== 0) {
688 | return {
689 | content: [{
690 | type: "text",
691 | text: `Place details request failed: ${data.message || data.status}`
692 | }],
693 | isError: true
694 | };
695 | }
696 |
697 | return {
698 | content: [{
699 | type: "text",
700 | text: JSON.stringify({
701 | uid: data.result.uid,
702 | name: data.result.name,
703 | location: data.result.location,
704 | address: data.result.address,
705 | province: data.result.province,
706 | city: data.result.city,
707 | area: data.result.area,
708 | street_id: data.result.street_id,
709 | detail: data.result.detail,
710 | ...(('detail_info' in data.result) ? {
711 | detail_info: data.result.detail_info
712 | } : {})
713 | }, null, 2)
714 | }],
715 | isError: false
716 | };
717 | }
718 |
719 | async function handleDistanceMatrix(
720 | origins: string[],
721 | destinations: string[],
722 | mode: "driving" | "walking" | "riding" | "motorcycle" = "driving"
723 | ) {
724 | const url = new URL("https://api.map.baidu.com/routematrix/v2/" + mode);
725 | url.searchParams.append("origins", origins.join("|"));
726 | url.searchParams.append("destinations", destinations.join("|"));
727 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
728 | url.searchParams.append("output", "json");
729 | url.searchParams.append("from", "node_mcp");
730 |
731 | const response = await fetch(url.toString());
732 | const data = await response.json() as DistanceMatrixResponse;
733 |
734 | if (data.status !== 0) {
735 | return {
736 | content: [{
737 | type: "text",
738 | text: `Distance matrix request failed: ${data.msg || data.status}`
739 | }],
740 | isError: true
741 | };
742 | }
743 |
744 | return {
745 | content: [{
746 | type: "text",
747 | text: JSON.stringify({
748 | results: data.result.map((row) => ({
749 | elements: {
750 | duration: row.duration,
751 | distance: row.distance
752 | }
753 | }))
754 | }, null, 2)
755 | }],
756 | isError: false
757 | };
758 | }
759 |
760 | async function handleDirections(
761 | origin: string,
762 | destination: string,
763 | mode: "driving" | "walking" | "riding" | "transit" = "driving"
764 | ) {
765 | const url = new URL("https://api.map.baidu.com/directionlite/v1/" + mode);
766 | url.searchParams.append("origin", origin);
767 | url.searchParams.append("destination", destination);
768 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
769 | url.searchParams.append("from", "node_mcp");
770 |
771 | const response = await fetch(url.toString());
772 | const data = await response.json() as DirectionsResponse;
773 |
774 | if (data.status !== 0) {
775 | return {
776 | content: [{
777 | type: "text",
778 | text: `Directions request failed: ${data.msg || data.status}`
779 | }],
780 | isError: true
781 | };
782 | }
783 | return {
784 | content: [{
785 | type: "text",
786 | text: JSON.stringify({
787 | routes: data.result.routes.map((route) => ({
788 | distance: route.distance,
789 | duration: route.duration,
790 | steps: route.steps.map((step) => ({
791 | instructions: step.instruction,
792 | }))
793 | }))
794 | }, null, 2)
795 | }],
796 | isError: false
797 | };
798 | }
799 |
800 | async function handleWeather(
801 | districtId?: string,
802 | location?: string,
803 | ) {
804 | const url = new URL("https://api.map.baidu.com/weather/v1/");
805 | url.searchParams.append("data_type", "all");
806 | url.searchParams.append("coordtype", "bd09ll");
807 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
808 | url.searchParams.append("from", "node_mcp");
809 | if (location) {
810 | url.searchParams.append("location", location);
811 | }
812 | if (districtId) {
813 | url.searchParams.append("district_id", districtId);
814 | }
815 |
816 | const response = await fetch(url.toString());
817 | const data = await response.json() as WeatherResponse;
818 |
819 | if (data.status !== 0) {
820 | return {
821 | content: [{
822 | type: "text",
823 | text: `Weather searth failed: ${data.message || data.status}`
824 | }],
825 | isError: true
826 | }
827 | }
828 |
829 | return {
830 | content: [{
831 | type: "text",
832 | text: JSON.stringify({
833 | location: data.result.location,
834 | now: data.result.now,
835 | forecasts: data.result.forecasts,
836 | forecast_hours: data.result.forecast_hours,
837 | indexes: data.result.indexes,
838 | alerts: data.result.alerts,
839 | }, null, 2)
840 | }],
841 | isError: false
842 | }
843 | }
844 |
845 | async function handleIPLocation(
846 | ip: string,
847 | ) {
848 | const url = new URL("https://api.map.baidu.com/location/ip");
849 | url.searchParams.append("ip", ip);
850 | url.searchParams.append("coor", "bd09ll");
851 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
852 | url.searchParams.append("from", "node_mcp");
853 |
854 | const response = await fetch(url.toString());
855 | const data = await response.json() as IPLocationResponse;
856 |
857 | if (data.status !== 0) {
858 | return {
859 | content: [{
860 | type: "text",
861 | text: `IP address searth failed: ${data.message || data.status}`
862 | }],
863 | isError: true
864 | }
865 | }
866 |
867 | return {
868 | content: [{
869 | type: "text",
870 | text: JSON.stringify({
871 | formatted_address: data.address,
872 | address_detail: data.content.address_detail,
873 | point: data.content.point,
874 | }, null, 2)
875 | }],
876 | isError: false
877 | }
878 | }
879 |
880 | async function handleRoadTraffic(
881 | roadName?: string,
882 | city?: string,
883 | bounds?: string,
884 | vertexes?: string,
885 | center?: string,
886 | radius?: number,
887 | ) {
888 | const url = new URL("https://api.map.baidu.com");
889 | if (roadName && city) {
890 | url.pathname = "/traffic/v1/road";
891 | url.searchParams.append("road_name", roadName);
892 | url.searchParams.append("city", city);
893 | }
894 | if (bounds) {
895 | url.pathname = "/traffic/v1/bound";
896 | url.searchParams.append("bounds", bounds);
897 | }
898 | if (vertexes) {
899 | url.pathname = "/traffic/v1/polygon";
900 | url.searchParams.append("vertexes", vertexes);
901 | }
902 | if (center && radius) {
903 | url.pathname = "/traffic/v1/around";
904 | url.searchParams.append("center", center);
905 | url.searchParams.append("radius", String(radius));
906 | }
907 | url.searchParams.append("ak", BAIDU_MAP_API_KEY);
908 | url.searchParams.append("from", "node_mcp");
909 |
910 | const response = await fetch(url.toString());
911 | const data = await response.json() as RoadTrafficResponse;
912 |
913 | if (data.status !== 0) {
914 | return {
915 | content: [{
916 | type: "text",
917 | text: `road traffic search failed: ${data.message || data.status}`,
918 | }],
919 | isError: true
920 | }
921 | }
922 |
923 | return {
924 | content: [{
925 | type: "text",
926 | text: JSON.stringify({
927 | description: data.description,
928 | evaluation: data.evaluation,
929 | road_traffic: data.road_traffic,
930 | }, null, 2)
931 | }],
932 | isError: false
933 | }
934 | }
935 |
936 | async function handlePoiExtract(
937 | textContent: string
938 | ) {
939 | const submitUrl = "https://api.map.baidu.com/api_mark/v1/submit";
940 | const params = new URLSearchParams();
941 | params.append("text_content", textContent);
942 | params.append("id", "75274677"); // 设备id
943 | params.append("msg_type", "text");
944 | params.append("ak", BAIDU_MAP_API_KEY);
945 | params.append("from", "node_mcp");
946 |
947 | const submitResponse = await fetch(submitUrl, {
948 | method: "POST",
949 | headers: {
950 | "Content-Type": "application/x-www-form-urlencoded"
951 | },
952 | body: params.toString(),
953 | });
954 | const submitData = await submitResponse.json() as MarkSubmitResponse;
955 |
956 | if (submitData.status !== 0) {
957 | return {
958 | content: [{
959 | type: "text",
960 | text: `mark submit failed: ${submitData.message || submitData.status}`
961 | }],
962 | isError: true
963 | }
964 | }
965 |
966 | const url = "https://api.map.baidu.com/api_mark/v1/result";
967 | const mapId = submitData.result.map_id;
968 | params.delete("text_content");
969 | params.delete("msg_type");
970 | params.append("map_id", mapId);
971 |
972 | // 每1s轮询查找数据,等待时间最长20s
973 | const maxTime = 20 * 1000; // 20s
974 | const intervalTime = 1000; // 1s
975 | let elapsedTime = 0;
976 | async function checkResult() {
977 | const response = await fetch(url, {
978 | method: "POST",
979 | headers: {
980 | "Content-Type": "application/x-www-form-urlencoded"
981 | },
982 | body: params.toString(),
983 | });
984 | const data = await response.json() as MarkResultResponse;
985 | const result = data.result;
986 | if (result) {
987 | return data;
988 | }
989 | return null;
990 | }
991 |
992 | let data = await checkResult();
993 | while (!data && elapsedTime < maxTime) {
994 | await new Promise(resolve => setTimeout(resolve, intervalTime));
995 | elapsedTime += intervalTime;
996 | data = await checkResult();
997 | }
998 |
999 | if (!data) {
1000 | return {
1001 | content: [{
1002 | type: "text",
1003 | text: `poi result is null`
1004 | }],
1005 | isError: true
1006 | }
1007 | }
1008 | return {
1009 | content: [{
1010 | type: "text",
1011 | text: JSON.stringify({
1012 | jumpUrl: data.result.data[0].link.jump_url,
1013 | title: data.result.data[0].link.title,
1014 | desc: data.result.data[0].link.desc,
1015 | image: data.result.data[0].link.image,
1016 | poi: data.result.data[0].link.poi,
1017 | }, null, 2)
1018 | }],
1019 | isError: false
1020 | }
1021 |
1022 | }
1023 |
1024 | // Server setup
1025 | const server = new Server(
1026 | {
1027 | name: "mcp-server/baidu-map",
1028 | version: "1.0.0",
1029 | },
1030 | {
1031 | capabilities: {
1032 | tools: {},
1033 | },
1034 | },
1035 | );
1036 |
1037 | // Set up request handlers
1038 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
1039 | tools: MAPS_TOOLS,
1040 | }));
1041 |
1042 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
1043 | try {
1044 | switch (request.params.name) {
1045 | case "map_geocode": {
1046 | const { address } = request.params.arguments as { address: string };
1047 | return await handleGeocode(address);
1048 | }
1049 |
1050 | case "map_reverse_geocode": {
1051 | const { latitude, longitude } = request.params.arguments as {
1052 | latitude: number;
1053 | longitude: number;
1054 | };
1055 | return await handleReverseGeocode(latitude, longitude);
1056 | }
1057 |
1058 | case "map_search_places": {
1059 | const { query, region, bounds, location } = request.params.arguments as {
1060 | query: string;
1061 | region?: string;
1062 | bounds?: string;
1063 | location?: string;
1064 | };
1065 | return await handlePlaceSearch(query, region, bounds, location);
1066 | }
1067 |
1068 | case "map_place_details": {
1069 | const { uid, scope } = request.params.arguments as {
1070 | uid: string;
1071 | scope?: string;
1072 | };
1073 | return await handlePlaceDetails(uid, scope);
1074 | }
1075 |
1076 | case "map_distance_matrix": {
1077 | const { origins, destinations, mode } = request.params.arguments as {
1078 | origins: string[];
1079 | destinations: string[];
1080 | mode?: "driving" | "walking" | "riding" | "motorcycle";
1081 | };
1082 | return await handleDistanceMatrix(origins, destinations, mode);
1083 | }
1084 |
1085 | case "map_directions": {
1086 | const { origin, destination, mode } = request.params.arguments as {
1087 | origin: string;
1088 | destination: string;
1089 | mode?: "driving" | "walking" | "riding" | "transit";
1090 | };
1091 | return await handleDirections(origin, destination, mode);
1092 | }
1093 | case "map_weather": {
1094 | const {districtId, location} = request.params.arguments as {
1095 | districtId: string;
1096 | location: string,
1097 | };
1098 | return await handleWeather(districtId, location);
1099 | }
1100 | case "map_ip_location": {
1101 | const {ip} = request.params.arguments as {
1102 | ip: string;
1103 | };
1104 | return await handleIPLocation(ip);
1105 | }
1106 | case "map_road_traffic": {
1107 | const {roadName, city, bounds, vertexes, center, radius} = request.params.arguments as {
1108 | roadName?: string;
1109 | city?: string;
1110 | bounds?: string;
1111 | vertexes?: string;
1112 | center?: string;
1113 | radius?: number;
1114 | };
1115 | return await handleRoadTraffic(roadName, city, bounds, vertexes, center, radius);
1116 | }
1117 | case "map_poi_extract": {
1118 | const {textContent} = request.params.arguments as {
1119 | textContent: string;
1120 | };
1121 | return await handlePoiExtract(textContent);
1122 | }
1123 |
1124 | default:
1125 | return {
1126 | content: [{
1127 | type: "text",
1128 | text: `Unknown tool: ${request.params.name}`
1129 | }],
1130 | isError: true
1131 | };
1132 | }
1133 | } catch (error) {
1134 | return {
1135 | content: [{
1136 | type: "text",
1137 | text: `Error: ${error instanceof Error ? error.message : String(error)}`
1138 | }],
1139 | isError: true
1140 | };
1141 | }
1142 | });
1143 |
1144 | async function runServer() {
1145 | const transport = new StdioServerTransport();
1146 | await server.connect(transport);
1147 | console.error("Baidu Map MCP Server running on stdio");
1148 | }
1149 |
1150 | runServer().catch((error) => {
1151 | console.error("Fatal error running server:", error);
1152 | process.exit(1);
1153 | });
1154 |
--------------------------------------------------------------------------------
/src/baidu-map/node/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@modelcontextprotocol/server-baidu-map",
3 | "version": "0.6.2",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "@modelcontextprotocol/server-baidu-map",
9 | "version": "0.6.2",
10 | "license": "MIT",
11 | "dependencies": {
12 | "@modelcontextprotocol/sdk": "1.0.1",
13 | "@types/node-fetch": "^2.6.12",
14 | "node-fetch": "^3.3.2"
15 | },
16 | "bin": {
17 | "mcp-server-baidu-map": "dist/index.js"
18 | },
19 | "devDependencies": {
20 | "shx": "^0.3.4",
21 | "typescript": "^5.6.2"
22 | }
23 | },
24 | "node_modules/@modelcontextprotocol/sdk": {
25 | "version": "1.0.1",
26 | "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.0.1.tgz",
27 | "integrity": "sha512-slLdFaxQJ9AlRg+hw28iiTtGvShAOgOKXcD0F91nUcRYiOMuS9ZBYjcdNZRXW9G5JQ511GRTdUy1zQVZDpJ+4w==",
28 | "license": "MIT",
29 | "dependencies": {
30 | "content-type": "^1.0.5",
31 | "raw-body": "^3.0.0",
32 | "zod": "^3.23.8"
33 | }
34 | },
35 | "node_modules/@types/node": {
36 | "version": "22.13.10",
37 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
38 | "integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
39 | "license": "MIT",
40 | "dependencies": {
41 | "undici-types": "~6.20.0"
42 | }
43 | },
44 | "node_modules/@types/node-fetch": {
45 | "version": "2.6.12",
46 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
47 | "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
48 | "license": "MIT",
49 | "dependencies": {
50 | "@types/node": "*",
51 | "form-data": "^4.0.0"
52 | }
53 | },
54 | "node_modules/asynckit": {
55 | "version": "0.4.0",
56 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
57 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
58 | "license": "MIT"
59 | },
60 | "node_modules/balanced-match": {
61 | "version": "1.0.2",
62 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
63 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
64 | "dev": true,
65 | "license": "MIT"
66 | },
67 | "node_modules/brace-expansion": {
68 | "version": "1.1.11",
69 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
70 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
71 | "dev": true,
72 | "license": "MIT",
73 | "dependencies": {
74 | "balanced-match": "^1.0.0",
75 | "concat-map": "0.0.1"
76 | }
77 | },
78 | "node_modules/bytes": {
79 | "version": "3.1.2",
80 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
81 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
82 | "license": "MIT",
83 | "engines": {
84 | "node": ">= 0.8"
85 | }
86 | },
87 | "node_modules/call-bind-apply-helpers": {
88 | "version": "1.0.2",
89 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
90 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
91 | "license": "MIT",
92 | "dependencies": {
93 | "es-errors": "^1.3.0",
94 | "function-bind": "^1.1.2"
95 | },
96 | "engines": {
97 | "node": ">= 0.4"
98 | }
99 | },
100 | "node_modules/combined-stream": {
101 | "version": "1.0.8",
102 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
103 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
104 | "license": "MIT",
105 | "dependencies": {
106 | "delayed-stream": "~1.0.0"
107 | },
108 | "engines": {
109 | "node": ">= 0.8"
110 | }
111 | },
112 | "node_modules/concat-map": {
113 | "version": "0.0.1",
114 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
115 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
116 | "dev": true,
117 | "license": "MIT"
118 | },
119 | "node_modules/content-type": {
120 | "version": "1.0.5",
121 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
122 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
123 | "license": "MIT",
124 | "engines": {
125 | "node": ">= 0.6"
126 | }
127 | },
128 | "node_modules/data-uri-to-buffer": {
129 | "version": "4.0.1",
130 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
131 | "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
132 | "license": "MIT",
133 | "engines": {
134 | "node": ">= 12"
135 | }
136 | },
137 | "node_modules/delayed-stream": {
138 | "version": "1.0.0",
139 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
140 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
141 | "license": "MIT",
142 | "engines": {
143 | "node": ">=0.4.0"
144 | }
145 | },
146 | "node_modules/depd": {
147 | "version": "2.0.0",
148 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
149 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
150 | "license": "MIT",
151 | "engines": {
152 | "node": ">= 0.8"
153 | }
154 | },
155 | "node_modules/dunder-proto": {
156 | "version": "1.0.1",
157 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
158 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
159 | "license": "MIT",
160 | "dependencies": {
161 | "call-bind-apply-helpers": "^1.0.1",
162 | "es-errors": "^1.3.0",
163 | "gopd": "^1.2.0"
164 | },
165 | "engines": {
166 | "node": ">= 0.4"
167 | }
168 | },
169 | "node_modules/es-define-property": {
170 | "version": "1.0.1",
171 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
172 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
173 | "license": "MIT",
174 | "engines": {
175 | "node": ">= 0.4"
176 | }
177 | },
178 | "node_modules/es-errors": {
179 | "version": "1.3.0",
180 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
181 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
182 | "license": "MIT",
183 | "engines": {
184 | "node": ">= 0.4"
185 | }
186 | },
187 | "node_modules/es-object-atoms": {
188 | "version": "1.1.1",
189 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
190 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
191 | "license": "MIT",
192 | "dependencies": {
193 | "es-errors": "^1.3.0"
194 | },
195 | "engines": {
196 | "node": ">= 0.4"
197 | }
198 | },
199 | "node_modules/es-set-tostringtag": {
200 | "version": "2.1.0",
201 | "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
202 | "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
203 | "license": "MIT",
204 | "dependencies": {
205 | "es-errors": "^1.3.0",
206 | "get-intrinsic": "^1.2.6",
207 | "has-tostringtag": "^1.0.2",
208 | "hasown": "^2.0.2"
209 | },
210 | "engines": {
211 | "node": ">= 0.4"
212 | }
213 | },
214 | "node_modules/fetch-blob": {
215 | "version": "3.2.0",
216 | "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
217 | "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
218 | "funding": [
219 | {
220 | "type": "github",
221 | "url": "https://github.com/sponsors/jimmywarting"
222 | },
223 | {
224 | "type": "paypal",
225 | "url": "https://paypal.me/jimmywarting"
226 | }
227 | ],
228 | "license": "MIT",
229 | "dependencies": {
230 | "node-domexception": "^1.0.0",
231 | "web-streams-polyfill": "^3.0.3"
232 | },
233 | "engines": {
234 | "node": "^12.20 || >= 14.13"
235 | }
236 | },
237 | "node_modules/form-data": {
238 | "version": "4.0.2",
239 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
240 | "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
241 | "license": "MIT",
242 | "dependencies": {
243 | "asynckit": "^0.4.0",
244 | "combined-stream": "^1.0.8",
245 | "es-set-tostringtag": "^2.1.0",
246 | "mime-types": "^2.1.12"
247 | },
248 | "engines": {
249 | "node": ">= 6"
250 | }
251 | },
252 | "node_modules/formdata-polyfill": {
253 | "version": "4.0.10",
254 | "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
255 | "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
256 | "license": "MIT",
257 | "dependencies": {
258 | "fetch-blob": "^3.1.2"
259 | },
260 | "engines": {
261 | "node": ">=12.20.0"
262 | }
263 | },
264 | "node_modules/fs.realpath": {
265 | "version": "1.0.0",
266 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
267 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
268 | "dev": true,
269 | "license": "ISC"
270 | },
271 | "node_modules/function-bind": {
272 | "version": "1.1.2",
273 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
274 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
275 | "license": "MIT",
276 | "funding": {
277 | "url": "https://github.com/sponsors/ljharb"
278 | }
279 | },
280 | "node_modules/get-intrinsic": {
281 | "version": "1.3.0",
282 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
283 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
284 | "license": "MIT",
285 | "dependencies": {
286 | "call-bind-apply-helpers": "^1.0.2",
287 | "es-define-property": "^1.0.1",
288 | "es-errors": "^1.3.0",
289 | "es-object-atoms": "^1.1.1",
290 | "function-bind": "^1.1.2",
291 | "get-proto": "^1.0.1",
292 | "gopd": "^1.2.0",
293 | "has-symbols": "^1.1.0",
294 | "hasown": "^2.0.2",
295 | "math-intrinsics": "^1.1.0"
296 | },
297 | "engines": {
298 | "node": ">= 0.4"
299 | },
300 | "funding": {
301 | "url": "https://github.com/sponsors/ljharb"
302 | }
303 | },
304 | "node_modules/get-proto": {
305 | "version": "1.0.1",
306 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
307 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
308 | "license": "MIT",
309 | "dependencies": {
310 | "dunder-proto": "^1.0.1",
311 | "es-object-atoms": "^1.0.0"
312 | },
313 | "engines": {
314 | "node": ">= 0.4"
315 | }
316 | },
317 | "node_modules/glob": {
318 | "version": "7.2.3",
319 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
320 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
321 | "deprecated": "Glob versions prior to v9 are no longer supported",
322 | "dev": true,
323 | "license": "ISC",
324 | "dependencies": {
325 | "fs.realpath": "^1.0.0",
326 | "inflight": "^1.0.4",
327 | "inherits": "2",
328 | "minimatch": "^3.1.1",
329 | "once": "^1.3.0",
330 | "path-is-absolute": "^1.0.0"
331 | },
332 | "engines": {
333 | "node": "*"
334 | },
335 | "funding": {
336 | "url": "https://github.com/sponsors/isaacs"
337 | }
338 | },
339 | "node_modules/gopd": {
340 | "version": "1.2.0",
341 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
342 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
343 | "license": "MIT",
344 | "engines": {
345 | "node": ">= 0.4"
346 | },
347 | "funding": {
348 | "url": "https://github.com/sponsors/ljharb"
349 | }
350 | },
351 | "node_modules/has-symbols": {
352 | "version": "1.1.0",
353 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
354 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
355 | "license": "MIT",
356 | "engines": {
357 | "node": ">= 0.4"
358 | },
359 | "funding": {
360 | "url": "https://github.com/sponsors/ljharb"
361 | }
362 | },
363 | "node_modules/has-tostringtag": {
364 | "version": "1.0.2",
365 | "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
366 | "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
367 | "license": "MIT",
368 | "dependencies": {
369 | "has-symbols": "^1.0.3"
370 | },
371 | "engines": {
372 | "node": ">= 0.4"
373 | },
374 | "funding": {
375 | "url": "https://github.com/sponsors/ljharb"
376 | }
377 | },
378 | "node_modules/hasown": {
379 | "version": "2.0.2",
380 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
381 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
382 | "license": "MIT",
383 | "dependencies": {
384 | "function-bind": "^1.1.2"
385 | },
386 | "engines": {
387 | "node": ">= 0.4"
388 | }
389 | },
390 | "node_modules/http-errors": {
391 | "version": "2.0.0",
392 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
393 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
394 | "license": "MIT",
395 | "dependencies": {
396 | "depd": "2.0.0",
397 | "inherits": "2.0.4",
398 | "setprototypeof": "1.2.0",
399 | "statuses": "2.0.1",
400 | "toidentifier": "1.0.1"
401 | },
402 | "engines": {
403 | "node": ">= 0.8"
404 | }
405 | },
406 | "node_modules/iconv-lite": {
407 | "version": "0.6.3",
408 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
409 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
410 | "license": "MIT",
411 | "dependencies": {
412 | "safer-buffer": ">= 2.1.2 < 3.0.0"
413 | },
414 | "engines": {
415 | "node": ">=0.10.0"
416 | }
417 | },
418 | "node_modules/inflight": {
419 | "version": "1.0.6",
420 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
421 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
422 | "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
423 | "dev": true,
424 | "license": "ISC",
425 | "dependencies": {
426 | "once": "^1.3.0",
427 | "wrappy": "1"
428 | }
429 | },
430 | "node_modules/inherits": {
431 | "version": "2.0.4",
432 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
433 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
434 | "license": "ISC"
435 | },
436 | "node_modules/interpret": {
437 | "version": "1.4.0",
438 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
439 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
440 | "dev": true,
441 | "license": "MIT",
442 | "engines": {
443 | "node": ">= 0.10"
444 | }
445 | },
446 | "node_modules/is-core-module": {
447 | "version": "2.16.1",
448 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
449 | "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
450 | "dev": true,
451 | "license": "MIT",
452 | "dependencies": {
453 | "hasown": "^2.0.2"
454 | },
455 | "engines": {
456 | "node": ">= 0.4"
457 | },
458 | "funding": {
459 | "url": "https://github.com/sponsors/ljharb"
460 | }
461 | },
462 | "node_modules/math-intrinsics": {
463 | "version": "1.1.0",
464 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
465 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
466 | "license": "MIT",
467 | "engines": {
468 | "node": ">= 0.4"
469 | }
470 | },
471 | "node_modules/mime-db": {
472 | "version": "1.52.0",
473 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
474 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
475 | "license": "MIT",
476 | "engines": {
477 | "node": ">= 0.6"
478 | }
479 | },
480 | "node_modules/mime-types": {
481 | "version": "2.1.35",
482 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
483 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
484 | "license": "MIT",
485 | "dependencies": {
486 | "mime-db": "1.52.0"
487 | },
488 | "engines": {
489 | "node": ">= 0.6"
490 | }
491 | },
492 | "node_modules/minimatch": {
493 | "version": "3.1.2",
494 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
495 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
496 | "dev": true,
497 | "license": "ISC",
498 | "dependencies": {
499 | "brace-expansion": "^1.1.7"
500 | },
501 | "engines": {
502 | "node": "*"
503 | }
504 | },
505 | "node_modules/minimist": {
506 | "version": "1.2.8",
507 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
508 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
509 | "dev": true,
510 | "license": "MIT",
511 | "funding": {
512 | "url": "https://github.com/sponsors/ljharb"
513 | }
514 | },
515 | "node_modules/node-domexception": {
516 | "version": "1.0.0",
517 | "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
518 | "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
519 | "funding": [
520 | {
521 | "type": "github",
522 | "url": "https://github.com/sponsors/jimmywarting"
523 | },
524 | {
525 | "type": "github",
526 | "url": "https://paypal.me/jimmywarting"
527 | }
528 | ],
529 | "license": "MIT",
530 | "engines": {
531 | "node": ">=10.5.0"
532 | }
533 | },
534 | "node_modules/node-fetch": {
535 | "version": "3.3.2",
536 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
537 | "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
538 | "license": "MIT",
539 | "dependencies": {
540 | "data-uri-to-buffer": "^4.0.0",
541 | "fetch-blob": "^3.1.4",
542 | "formdata-polyfill": "^4.0.10"
543 | },
544 | "engines": {
545 | "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
546 | },
547 | "funding": {
548 | "type": "opencollective",
549 | "url": "https://opencollective.com/node-fetch"
550 | }
551 | },
552 | "node_modules/once": {
553 | "version": "1.4.0",
554 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
555 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
556 | "dev": true,
557 | "license": "ISC",
558 | "dependencies": {
559 | "wrappy": "1"
560 | }
561 | },
562 | "node_modules/path-is-absolute": {
563 | "version": "1.0.1",
564 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
565 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
566 | "dev": true,
567 | "license": "MIT",
568 | "engines": {
569 | "node": ">=0.10.0"
570 | }
571 | },
572 | "node_modules/path-parse": {
573 | "version": "1.0.7",
574 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
575 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
576 | "dev": true,
577 | "license": "MIT"
578 | },
579 | "node_modules/raw-body": {
580 | "version": "3.0.0",
581 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
582 | "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
583 | "license": "MIT",
584 | "dependencies": {
585 | "bytes": "3.1.2",
586 | "http-errors": "2.0.0",
587 | "iconv-lite": "0.6.3",
588 | "unpipe": "1.0.0"
589 | },
590 | "engines": {
591 | "node": ">= 0.8"
592 | }
593 | },
594 | "node_modules/rechoir": {
595 | "version": "0.6.2",
596 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
597 | "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
598 | "dev": true,
599 | "dependencies": {
600 | "resolve": "^1.1.6"
601 | },
602 | "engines": {
603 | "node": ">= 0.10"
604 | }
605 | },
606 | "node_modules/resolve": {
607 | "version": "1.22.10",
608 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
609 | "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
610 | "dev": true,
611 | "license": "MIT",
612 | "dependencies": {
613 | "is-core-module": "^2.16.0",
614 | "path-parse": "^1.0.7",
615 | "supports-preserve-symlinks-flag": "^1.0.0"
616 | },
617 | "bin": {
618 | "resolve": "bin/resolve"
619 | },
620 | "engines": {
621 | "node": ">= 0.4"
622 | },
623 | "funding": {
624 | "url": "https://github.com/sponsors/ljharb"
625 | }
626 | },
627 | "node_modules/safer-buffer": {
628 | "version": "2.1.2",
629 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
630 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
631 | "license": "MIT"
632 | },
633 | "node_modules/setprototypeof": {
634 | "version": "1.2.0",
635 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
636 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
637 | "license": "ISC"
638 | },
639 | "node_modules/shelljs": {
640 | "version": "0.8.5",
641 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
642 | "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
643 | "dev": true,
644 | "license": "BSD-3-Clause",
645 | "dependencies": {
646 | "glob": "^7.0.0",
647 | "interpret": "^1.0.0",
648 | "rechoir": "^0.6.2"
649 | },
650 | "bin": {
651 | "shjs": "bin/shjs"
652 | },
653 | "engines": {
654 | "node": ">=4"
655 | }
656 | },
657 | "node_modules/shx": {
658 | "version": "0.3.4",
659 | "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
660 | "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==",
661 | "dev": true,
662 | "license": "MIT",
663 | "dependencies": {
664 | "minimist": "^1.2.3",
665 | "shelljs": "^0.8.5"
666 | },
667 | "bin": {
668 | "shx": "lib/cli.js"
669 | },
670 | "engines": {
671 | "node": ">=6"
672 | }
673 | },
674 | "node_modules/statuses": {
675 | "version": "2.0.1",
676 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
677 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
678 | "license": "MIT",
679 | "engines": {
680 | "node": ">= 0.8"
681 | }
682 | },
683 | "node_modules/supports-preserve-symlinks-flag": {
684 | "version": "1.0.0",
685 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
686 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
687 | "dev": true,
688 | "license": "MIT",
689 | "engines": {
690 | "node": ">= 0.4"
691 | },
692 | "funding": {
693 | "url": "https://github.com/sponsors/ljharb"
694 | }
695 | },
696 | "node_modules/toidentifier": {
697 | "version": "1.0.1",
698 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
699 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
700 | "license": "MIT",
701 | "engines": {
702 | "node": ">=0.6"
703 | }
704 | },
705 | "node_modules/typescript": {
706 | "version": "5.8.2",
707 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
708 | "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
709 | "dev": true,
710 | "license": "Apache-2.0",
711 | "bin": {
712 | "tsc": "bin/tsc",
713 | "tsserver": "bin/tsserver"
714 | },
715 | "engines": {
716 | "node": ">=14.17"
717 | }
718 | },
719 | "node_modules/undici-types": {
720 | "version": "6.20.0",
721 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
722 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
723 | "license": "MIT"
724 | },
725 | "node_modules/unpipe": {
726 | "version": "1.0.0",
727 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
728 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
729 | "license": "MIT",
730 | "engines": {
731 | "node": ">= 0.8"
732 | }
733 | },
734 | "node_modules/web-streams-polyfill": {
735 | "version": "3.3.3",
736 | "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
737 | "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
738 | "license": "MIT",
739 | "engines": {
740 | "node": ">= 8"
741 | }
742 | },
743 | "node_modules/wrappy": {
744 | "version": "1.0.2",
745 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
746 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
747 | "dev": true,
748 | "license": "ISC"
749 | },
750 | "node_modules/zod": {
751 | "version": "3.24.2",
752 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
753 | "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
754 | "license": "MIT",
755 | "funding": {
756 | "url": "https://github.com/sponsors/colinhacks"
757 | }
758 | }
759 | }
760 | }
761 |
--------------------------------------------------------------------------------
/src/baidu-map/node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@baidumap/mcp-server-baidu-map",
3 | "version": "1.0.3",
4 | "description": "MCP server for using the Baidu Map API",
5 | "license": "MIT",
6 | "author": "",
7 | "homepage": "",
8 | "bugs": "",
9 | "type": "module",
10 | "bin": {
11 | "mcp-server-baidu-map": "dist/index.js"
12 | },
13 | "files": [
14 | "dist"
15 | ],
16 | "scripts": {
17 | "build": "tsc && shx chmod +x dist/*.js",
18 | "prepare": "npm run build",
19 | "watch": "tsc --watch"
20 | },
21 | "dependencies": {
22 | "@modelcontextprotocol/sdk": "1.0.1",
23 | "@types/node-fetch": "^2.6.12",
24 | "node-fetch": "^3.3.2"
25 | },
26 | "devDependencies": {
27 | "shx": "^0.3.4",
28 | "typescript": "^5.6.2"
29 | }
30 | }
--------------------------------------------------------------------------------
/src/baidu-map/node/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2022",
4 | "module": "Node16",
5 | "moduleResolution": "Node16",
6 | "strict": true,
7 | "esModuleInterop": true,
8 | "skipLibCheck": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "resolveJsonModule": true,
11 | "outDir": "./dist",
12 | "rootDir": "."
13 | },
14 | "include": [
15 | "./**/*.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/src/baidu-map/python/.gitignore:
--------------------------------------------------------------------------------
1 | # Python-generated files
2 | __pycache__/
3 | *.py[oc]
4 | build/
5 | dist/
6 | wheels/
7 | *.egg-info
8 |
9 | # Virtual environments
10 | .venv
11 |
--------------------------------------------------------------------------------
/src/baidu-map/python/.python-version:
--------------------------------------------------------------------------------
1 | 3.11
2 |
--------------------------------------------------------------------------------
/src/baidu-map/python/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 baidu-maps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/baidu-map/python/README.md:
--------------------------------------------------------------------------------
1 | ## Baidu Map MCP Server (Python)
2 | ### 搭建Python虚拟环境
3 | 我们推荐通过`uv`构建虚拟环境来运行MCP server,关于`uv你可以在[这里](https://docs.astral.sh/uv/getting-started/features/)找到一些说明。
4 |
5 | 按照[官方流程](https://modelcontextprotocol.io/quickstart/server),你会安装`Python`包管理工具`uv`。除此之外,你也可以尝试其他方法(如`Anaconda`)来创建你的`Python`虚拟环境。
6 |
7 | 通过`uv`添加`mcp`依赖
8 |
9 | ```bash
10 | uv add "mcp[cli]"
11 | ```
12 |
13 | 验证mcp依赖是否安装成功,执行如下命令
14 | ```bash
15 | uv run mcp
16 | ```
17 |
18 | 当出现下图时代表安装成功
19 |
20 | 
21 |
22 | 通过`uv`安装`python`,最低版本要求为3.11
23 |
24 | ```bash
25 | uv python install 3.11
26 | ```
27 |
28 | ### 获取 MCP Server
29 | 前往百度地图 Mcp Server 官方[开源仓库](https://github.com/baidu-maps/mcp/tree/main/src/baidu-map/python)下载
30 |
31 | ### 配置本地项目
32 | 通过`uv`创建一个项目
33 |
34 | ```bash
35 | uv init mcp_server_baidu_maps
36 | ```
37 |
38 | 将`map.py`拷贝到该目录下,通过如下命令测试mcp server是否正常运行
39 |
40 | ```bash
41 | uv run --with mcp[cli] mcp run {YOUR_PATH}/mcp_server_baidu_maps/map.py
42 | # 如果是mac,需要加转义符
43 | uv run --with mcp\[cli\] mcp run {YOUR_PATH}/mcp_server_baidu_maps/map.py
44 | ```
45 |
46 | 如果没有报错则MCP Server启动成功
47 |
48 | ### 在Cursor中使用
49 |
50 | 打开`Cursor`配置,在MCP中添加MCP Server
51 |
52 | 
53 |
54 | 在文件中添加如下内容后保存
55 |
56 | ```json
57 | {
58 | "mcpServers": {
59 | "baidu-map": {
60 | "command": "uv",
61 | "args": [
62 | "run",
63 | "--with",
64 | "mcp[cli]",
65 | "mcp",
66 | "run",
67 | "{YOUR_PATH}/mcp_server_baidu_maps/map.py"
68 | ],
69 | "env": {
70 | "BAIDU_MAPS_API_KEY": ""
71 | }
72 | }
73 | }
74 | }
75 | ```
76 |
77 | 回到配置,此时百度MCP Server已经启用
78 |
79 | 
80 |
81 | ### 测试
82 |
83 | 行程规划:
84 |
85 | 
86 |
87 | 
--------------------------------------------------------------------------------
/src/baidu-map/python/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "mcp-server-baidu-maps"
3 | version = "0.2.1"
4 | description = "MCP Server Baidu Maps"
5 | readme = "README.md"
6 | requires-python = ">=3.11"
7 | authors = [{ name = "baidu-maps" }]
8 | maintainers = [{ name = "Pineapple274", email = "yuyangyang3838@gmail.com" }]
9 | keywords = ["http", "mcp", "map", "baidu"]
10 | license = { text = "MIT" }
11 | dependencies = [
12 | "mcp[cli]>=1.9.0",
13 | ]
14 |
15 | [project.scripts]
16 | mcp-server-baidu-maps = "mcp_server_baidu_maps:main"
17 |
18 |
--------------------------------------------------------------------------------
/src/baidu-map/python/src/mcp_server_baidu_maps/__init__.py:
--------------------------------------------------------------------------------
1 | # __init__.py
2 | from .map import mcp
3 |
4 | def main():
5 | """MCP Baidu Maps Server - HTTP call Baidu Map API for MCP"""
6 | mcp.run()
7 |
8 | if __name__ == "__main__":
9 | main()
--------------------------------------------------------------------------------
/src/baidu-map/python/src/mcp_server_baidu_maps/__main__.py:
--------------------------------------------------------------------------------
1 | from mcp_server_baidu_maps import main
2 |
3 | main()
--------------------------------------------------------------------------------
/src/baidu-map/python/src/mcp_server_baidu_maps/map.py:
--------------------------------------------------------------------------------
1 | # map.py
2 | import os
3 | import copy
4 | import httpx
5 | from asyncio import sleep
6 |
7 | from mcp.server.fastmcp import FastMCP
8 | import mcp.types as types
9 | import re
10 |
11 | # 创建MCP服务器实例
12 | mcp = FastMCP(
13 | name="mcp-server-baidu-maps",
14 | version="2.0.0",
15 | instructions="This is a MCP server for Baidu Maps."
16 | )
17 |
18 | """
19 |
20 | 获取环境变量中的API密钥, 用于调用百度地图API
21 | 环境变量名为: BAIDU_MAPS_API_KEY, 在客户端侧通过配置文件进行设置传入
22 | 获取方式请参考: https://lbsyun.baidu.com/apiconsole/key;
23 |
24 | """
25 |
26 | api_key = os.getenv('BAIDU_MAPS_API_KEY')
27 | api_url = "https://api.map.baidu.com"
28 |
29 |
30 | def filter_result(data) -> dict:
31 | """
32 | 过滤路径规划结果, 用于剔除冗余字段信息, 保证输出给模型的数据更简洁, 避免长距离路径规划场景下chat中断
33 | """
34 |
35 | # 创建输入数据的深拷贝以避免修改原始数据
36 | processed_data = copy.deepcopy(data)
37 |
38 | # 检查是否存在'result'键
39 | if 'result' in processed_data:
40 | result = processed_data['result']
41 |
42 | # 检查'result'中是否存在'routes'键
43 | if 'routes' in result:
44 | for route in result['routes']:
45 | # 检查每个'route'中是否存在'steps'键
46 | if 'steps' in route:
47 | new_steps = []
48 | for step in route['steps']:
49 | # 提取'instruction'字段, 若不存在则设为空字符串
50 | new_step = {
51 | 'distance': step.get('distance', ''),
52 | 'duration': step.get('duration', ''),
53 | 'instruction': step.get('instruction', '')
54 | }
55 | new_steps.append(new_step)
56 | # 替换原steps为仅含instruction的新列表
57 | route['steps'] = new_steps
58 |
59 | return processed_data
60 |
61 |
62 | def is_latlng(text):
63 | """
64 | 判断输入是否为经纬度坐标.
65 | """
66 |
67 | # 允许有空格,支持正负号和小数
68 | pattern = r'^\s*([+-]?\d+(?:\.\d+)?)\s*,\s*([+-]?\d+(?:\.\d+)?)\s*$'
69 | match = re.match(pattern, text)
70 | if not match:
71 | return False
72 | lat, lng = float(match.group(1)), float(match.group(2))
73 | # 简单经纬度范围校验
74 | return -90 <= lat <= 90 and -180 <= lng <= 180
75 |
76 |
77 | async def map_geocode(
78 | name: str, arguments: dict
79 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
80 | """
81 | 地理编码服务, 将地址解析为对应的位置坐标.
82 | """
83 | try:
84 | address = arguments.get("address", "")
85 |
86 | # 调用百度API
87 | url = f"{api_url}/geocoding/v3/"
88 |
89 | # 设置请求参数
90 | params = {
91 | "ak": f"{api_key}",
92 | "output": "json",
93 | "address": f"{address}",
94 | "from": "py_mcp"
95 | }
96 |
97 | async with httpx.AsyncClient() as client:
98 | response = await client.get(url, params=params)
99 | response.raise_for_status()
100 | result = response.json()
101 |
102 | if result.get("status") != 0:
103 | error_msg = result.get("message", "unknown error")
104 | raise Exception(f"API response error: {error_msg}")
105 |
106 | return [types.TextContent(type="text", text=response.text)]
107 |
108 | except httpx.HTTPError as e:
109 | raise Exception(f"HTTP request failed: {str(e)}") from e
110 | except KeyError as e:
111 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
112 |
113 |
114 | async def map_reverse_geocode(
115 | name: str, arguments: dict
116 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
117 | """
118 | 逆地理编码服务, 根据纬经度坐标获取对应位置的地址描述.
119 | """
120 | try:
121 | latitude = arguments.get("latitude", "")
122 | longitude = arguments.get("longitude", "")
123 |
124 | # 调用百度API
125 | url = f"{api_url}/reverse_geocoding/v3/"
126 |
127 | params = {
128 | "ak": f"{api_key}",
129 | "output": "json",
130 | "location": f"{latitude},{longitude}",
131 | "extensions_road": "true",
132 | "extensions_poi": "1",
133 | "entire_poi": "1",
134 | "from": "py_mcp"
135 | }
136 |
137 | async with httpx.AsyncClient() as client:
138 | response = await client.get(url, params=params)
139 | response.raise_for_status()
140 | result = response.json()
141 |
142 | if result.get("status") != 0:
143 | error_msg = result.get("message", "unknown error")
144 | raise Exception(f"API response error: {error_msg}")
145 |
146 | return [types.TextContent(type="text", text=response.text)]
147 |
148 | except httpx.HTTPError as e:
149 | raise Exception(f"HTTP request failed: {str(e)}") from e
150 | except KeyError as e:
151 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
152 |
153 |
154 | async def map_search_places(
155 | name: str, arguments: dict
156 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
157 | """
158 | 地点检索服务, 支持检索城市内的地点信息或圆形区域内的周边地点信息.
159 | """
160 | try:
161 | query = arguments.get("query", "")
162 | tag = arguments.get("tag", "")
163 | region = arguments.get("region", "全国") # 默认检索全国,防止出错
164 | location = arguments.get("location", "")
165 | radius = arguments.get("radius", "")
166 |
167 | url = f"{api_url}/place/v2/search"
168 |
169 | params = {
170 | "ak": f"{api_key}",
171 | "output": "json",
172 | "query": f"{query}",
173 | "tag": f"{tag}",
174 | "photo_show": "true",
175 | "scope": 2,
176 | "from": "py_mcp"
177 | }
178 |
179 | if location:
180 | params["location"] = f"{location}"
181 | params["radius"] = f"{radius}"
182 | else:
183 | params["region"] = f"{region}"
184 |
185 | async with httpx.AsyncClient() as client:
186 | response = await client.get(url, params=params)
187 | response.raise_for_status()
188 | result = response.json()
189 |
190 | if result.get("status") != 0:
191 | error_msg = result.get("message", "unknown error")
192 | raise Exception(f"API response error: {error_msg}")
193 |
194 | return [types.TextContent(type="text", text=response.text)]
195 |
196 | except httpx.HTTPError as e:
197 | raise Exception(f"HTTP request failed: {str(e)}") from e
198 | except KeyError as e:
199 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
200 |
201 |
202 | async def map_place_details(
203 | name: str, arguments: dict
204 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
205 | """
206 | 地点详情检索服务, 获取指定POI的详情信息.
207 | """
208 | try:
209 | uid = arguments.get("uid", "")
210 |
211 | url = f"{api_url}/place/v2/detail"
212 |
213 | params = {
214 | "ak": f"{api_key}",
215 | "output": "json",
216 | "uid": f"{uid}",
217 | "scope": 2,
218 | "from": "py_mcp"
219 | }
220 |
221 | async with httpx.AsyncClient() as client:
222 | response = await client.get(url, params=params)
223 | response.raise_for_status()
224 | result = response.json()
225 |
226 | if result.get("status") != 0:
227 | error_msg = result.get("message", "unknown error")
228 | raise Exception(f"API response error: {error_msg}")
229 |
230 | return [types.TextContent(type="text", text=response.text)]
231 |
232 | except httpx.HTTPError as e:
233 | raise Exception(f"HTTP request failed: {str(e)}") from e
234 | except KeyError as e:
235 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
236 |
237 |
238 | async def map_directions_matrix(
239 | name: str, arguments: dict
240 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
241 | """
242 | 批量算路服务, 根据起点和终点坐标计算路线规划距离和行驶时间.
243 | """
244 | try:
245 | origins = arguments.get("origins", "")
246 | destinations = arguments.get("destinations", "")
247 | model = arguments.get("model", "driving")
248 |
249 | url = f"{api_url}/routematrix/v2/{model}"
250 |
251 | params = {
252 | "ak": f"{api_key}",
253 | "output": "json",
254 | "origins": f"{origins}",
255 | "destinations": f"{destinations}",
256 | "from": "py_mcp"
257 | }
258 |
259 | async with httpx.AsyncClient() as client:
260 | response = await client.get(url, params=params)
261 | response.raise_for_status()
262 | result = response.json()
263 |
264 | if result.get("status") != 0:
265 | error_msg = result.get("message", "unknown error")
266 | raise Exception(f"API response error: {error_msg}")
267 |
268 | return [types.TextContent(type="text", text=response.text)]
269 |
270 | except httpx.HTTPError as e:
271 | raise Exception(f"HTTP request failed: {str(e)}") from e
272 | except KeyError as e:
273 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
274 |
275 |
276 | async def map_directions(
277 | name: str, arguments: dict
278 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
279 | """
280 | 路线规划服务, 支持驾车、骑行、步行和公交路线规划.
281 | """
282 | try:
283 | model = arguments.get("model", "driving")
284 | origin = arguments.get("origin", "")
285 | destination = arguments.get("destination", "")
286 |
287 | # 检查输入是否为地址文本(不包含逗号)
288 | if not is_latlng(origin):
289 | # 调用地理编码服务获取起点经纬度
290 | geocode_url = f"{api_url}/geocoding/v3/"
291 | geocode_params = {
292 | "ak": f"{api_key}",
293 | "output": "json",
294 | "address": origin,
295 | "from": "py_mcp"
296 | }
297 |
298 | async with httpx.AsyncClient() as client:
299 | geocode_response = await client.get(geocode_url, params=geocode_params)
300 | geocode_response.raise_for_status()
301 | geocode_result = geocode_response.json()
302 |
303 | if geocode_result.get("status") != 0:
304 | error_msg = geocode_result.get("message", "input `origin` invaild, please reinput more detail address")
305 | raise Exception(f"Geocoding API error: {error_msg}")
306 |
307 | location = geocode_result.get("result", {}).get("location", {})
308 | origin = f"{location.get('lat')},{location.get('lng')}"
309 |
310 | if not is_latlng(destination):
311 | # 调用地理编码服务获取终点经纬度
312 | geocode_url = f"{api_url}/geocoding/v3/"
313 | geocode_params = {
314 | "ak": f"{api_key}",
315 | "output": "json",
316 | "address": destination,
317 | "from": "py_mcp"
318 | }
319 |
320 | async with httpx.AsyncClient() as client:
321 | geocode_response = await client.get(geocode_url, params=geocode_params)
322 | geocode_response.raise_for_status()
323 | geocode_result = geocode_response.json()
324 |
325 | if geocode_result.get("status") != 0:
326 | error_msg = geocode_result.get("message", "input `destination` invaild, please reinput more detail address")
327 | raise Exception(f"Geocoding API error: {error_msg}")
328 |
329 | location = geocode_result.get("result", {}).get("location", {})
330 | destination = f"{location.get('lat')},{location.get('lng')}"
331 |
332 | # 调用路线规划服务
333 | url = f"{api_url}/directionlite/v1/{model}"
334 |
335 | params = {
336 | "ak": f"{api_key}",
337 | "output": "json",
338 | "origin": origin,
339 | "destination": destination,
340 | "from": "py_mcp"
341 | }
342 |
343 | async with httpx.AsyncClient() as client:
344 | response = await client.get(url, params=params)
345 | response.raise_for_status()
346 | result = response.json()
347 |
348 | if result.get("status") != 0:
349 | error_msg = result.get("message", "unknown error")
350 | raise Exception(f"API response error: {error_msg}")
351 |
352 | # if model == 'transit':
353 | # return [types.TextContent(type="text", text=response.text)]
354 | # else:
355 | # return [types.TextContent(type="text", text=str(filter_result(result)))]
356 | return [types.TextContent(type="text", text=response.text)]
357 |
358 | except httpx.HTTPError as e:
359 | raise Exception(f"HTTP request failed: {str(e)}") from e
360 | except KeyError as e:
361 | raise Exception(f"Failed to parse response: {str(e)}") from e
362 |
363 |
364 | async def map_weather(
365 | name: str, arguments: dict
366 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
367 | """
368 | 天气查询服务, 查询实时天气信息及未来5天天气预报.
369 | """
370 | try:
371 | location = arguments.get("location", "")
372 | district_id = arguments.get("district_id", "")
373 |
374 | url = f"{api_url}/weather/v1/?"
375 |
376 | params = {
377 | "ak": f"{api_key}",
378 | "data_type": "all",
379 | "from": "py_mcp"
380 | }
381 |
382 | if not location:
383 | params["district_id"] = f"{district_id}"
384 | else:
385 | params["location"] = f"{location}"
386 |
387 | async with httpx.AsyncClient() as client:
388 | response = await client.get(url, params=params)
389 | response.raise_for_status()
390 | result = response.json()
391 |
392 | if result.get("status") != 0:
393 | error_msg = result.get("message", "unknown error")
394 | raise Exception(f"API response error: {error_msg}")
395 |
396 | return [types.TextContent(type="text", text=response.text)]
397 |
398 | except httpx.HTTPError as e:
399 | raise Exception(f"HTTP request failed: {str(e)}") from e
400 | except KeyError as e:
401 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
402 |
403 |
404 | async def map_ip_location(
405 | name: str, arguments: dict
406 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
407 | """
408 | IP定位服务, 通过所给IP获取具体位置信息和城市名称, 可用于定位IP或用户当前位置.
409 | """
410 | try:
411 | ip = arguments.get("ip", "")
412 |
413 | url = f"{api_url}/location/ip"
414 |
415 | params = {
416 | "ak": f"{api_key}",
417 | "from": "py_mcp",
418 | "ip": ip
419 | }
420 |
421 | async with httpx.AsyncClient() as client:
422 | response = await client.get(url, params=params)
423 | response.raise_for_status()
424 | result = response.json()
425 |
426 | if result.get("status") != 0:
427 | error_msg = result.get("message", "unknown error")
428 | raise Exception(f"API response error: {error_msg}")
429 |
430 | return [types.TextContent(type="text", text=response.text)]
431 |
432 | except httpx.HTTPError as e:
433 | raise Exception(f"HTTP request failed: {str(e)}") from e
434 | except KeyError as e:
435 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
436 |
437 |
438 | async def map_road_traffic(
439 | name: str, arguments: dict
440 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
441 | """
442 | 实时路况查询服务, 查询实时交通拥堵情况.
443 | """
444 | try:
445 | model = arguments.get("model", "")
446 | road_name = arguments.get("road_name", "")
447 | city = arguments.get("city", "")
448 | bounds = arguments.get("bounds", "")
449 | vertexes = arguments.get("vertexes", "")
450 | center = arguments.get("center", "")
451 | radius = arguments.get("radius", "")
452 |
453 | url = f"{api_url}/traffic/v1/{model}?"
454 |
455 | params = {
456 | "ak": f"{api_key}",
457 | "output": "json",
458 | "from": "py_mcp"
459 | }
460 |
461 | if model == 'bound':
462 | params['bounds'] = f'{bounds}'
463 | elif model == 'polygon':
464 | params['vertexes'] = f'{vertexes}'
465 | elif model == 'around':
466 | params['center'] = f'{center}'
467 | params['radius'] = f'{radius}'
468 | elif model == 'road':
469 | params['road_name'] = f'{road_name}'
470 | params['city'] = f'{city}'
471 |
472 | async with httpx.AsyncClient() as client:
473 | response = await client.get(url, params=params)
474 | response.raise_for_status()
475 | result = response.json()
476 |
477 | if result.get("status") != 0:
478 | error_msg = result.get("message", "unknown error")
479 | raise Exception(f"API response error: {error_msg}")
480 |
481 | return [types.TextContent(type="text", text=response.text)]
482 |
483 | except httpx.HTTPError as e:
484 | raise Exception(f"HTTP request failed: {str(e)}") from e
485 | except KeyError as e:
486 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
487 |
488 |
489 | async def map_poi_extract(
490 | name: str,
491 | arguments: dict
492 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
493 | """
494 | POI智能提取
495 | """
496 | # 关于高级权限使用的相关问题,请联系我们: https://lbsyun.baidu.com/apiconsole/fankui?typeOne=%E4%BA%A7%E5%93%81%E9%9C%80%E6%B1%82&typeTwo=%E9%AB%98%E7%BA%A7%E6%9C%8D%E5%8A%A1
497 |
498 | try:
499 | text_content = arguments.get("text_content", "")
500 |
501 | # 调用POI智能提取的提交接口
502 | headers = {"Content-Type": "application/x-www-form-urlencoded"}
503 | submit_url = f"{api_url}/api_mark/v1/submit"
504 | result_url = f"{api_url}/api_mark/v1/result"
505 |
506 | # 设置上传用户描述的请求体
507 | submit_body = {
508 | "ak": f"{api_key}",
509 | "id": 0,
510 | "msg_type": "text",
511 | "text_content": f"{text_content}",
512 | "from": "py_mcp"
513 | }
514 |
515 | # 异步请求
516 | async with httpx.AsyncClient() as client:
517 | # 提交任务
518 | submit_resp = await client.post(
519 | submit_url, data=submit_body, headers=headers, timeout=10.0
520 | )
521 | submit_resp.raise_for_status()
522 | submit_result = submit_resp.json()
523 |
524 | if submit_result.get("status") != 0:
525 | error_msg = submit_result.get("message", "unknown error")
526 | raise Exception(f"API response error: {error_msg}")
527 |
528 |
529 | map_id = submit_result.get("result", {}).get("map_id")
530 | if not map_id:
531 | raise Exception("Can not found map_id")
532 |
533 | # 轮询获取结果(最多5次,间隔2秒)
534 | result_body = {"ak": api_key, "id": 0, "map_id": map_id, "from": "py_mcp"}
535 | max_retries = 5
536 | for attempt in range(max_retries):
537 | result_resp = await client.post(
538 | result_url, data=result_body, headers=headers, timeout=10.0
539 | )
540 | result_resp.raise_for_status()
541 | result = result_resp.json()
542 |
543 | if result.get("status") == 0 and result.get("result"):
544 | return result
545 | elif attempt < max_retries - 1:
546 | await sleep(2)
547 |
548 | else:
549 | raise Exception("Timeout to get the result")
550 |
551 | if result.get("status") != 0:
552 | error_msg = result.get("message", "unknown error")
553 | raise Exception(f"API response error: {error_msg}")
554 |
555 | except httpx.HTTPError as e:
556 | raise Exception(f"HTTP request failed: {str(e)}") from e
557 | except KeyError as e:
558 | raise Exception(f"Failed to parse reponse: {str(e)}") from e
559 |
560 |
561 | async def list_tools() -> list[types.Tool]:
562 | """
563 | 列出所有可用的工具。
564 |
565 | Args:
566 | None.
567 |
568 | Returns:
569 | list (types.Tool): 包含了所有可用的工具, 每个工具都包含了名称、描述、输入schema三个属性.
570 | """
571 | return [
572 | types.Tool(
573 | name="map_geocode",
574 | description="地理编码服务: 将地址解析为对应的位置坐标.地址结构越完整, 地址内容越准确, 解析的坐标精度越高.",
575 | inputSchema={
576 | "type": "object",
577 | "required": ["address"],
578 | "properties": {
579 | "address": {
580 | "type": "string",
581 | "description": "待解析的地址.最多支持84个字节.可以输入两种样式的值, 分别是:\n1、标准的结构化地址信息, 如北京市海淀区上地十街十号\n2、支持*路与*路交叉口描述方式, 如北一环路和阜阳路的交叉路口\n第二种方式并不总是有返回结果, 只有当地址库中存在该地址描述时才有返回",
582 | }
583 | },
584 | }
585 | ),
586 | types.Tool(
587 | name="map_reverse_geocode",
588 | description="逆地理编码服务: 根据纬经度坐标, 获取对应位置的地址描述, 所在行政区划, 道路以及相关POI等信息",
589 | inputSchema={
590 | "type": "object",
591 | "required": ["latitude", "longitude"],
592 | "properties": {
593 | "latitude": {
594 | "type": "number",
595 | "description": "纬度 (bd09ll)",
596 | },
597 | "longitude": {
598 | "type": "number",
599 | "description": "经度 (bd09ll)",
600 | },
601 | },
602 | }
603 | ),
604 | types.Tool(
605 | name="map_search_places",
606 | description="地点检索服务: 支持检索城市内的地点信息(最小到city级别), 也可支持圆形区域内的周边地点信息检索."
607 | "\n城市内检索: 检索某一城市内(目前最细到城市级别)的地点信息."
608 | "\n周边检索: 设置圆心和半径, 检索圆形区域内的地点信息(常用于周边检索场景).",
609 | inputSchema={
610 | "type": "object",
611 | "required": ["query"],
612 | "properties": {
613 | "query": {
614 | "type": "string",
615 | "description": "检索关键字, 可直接使用名称或类型, 如'天安门', 且可以至多10个关键字, 用英文逗号隔开",
616 | },
617 | "tag": {
618 | "type": "string",
619 | "description": "检索分类, 以中文字符输入, 如'美食', 多个分类用英文逗号隔开, 如'美食,购物'",
620 | },
621 | "region": {
622 | "type": "string",
623 | "description": "检索的城市名称, 可为行政区划名或citycode, 格式如'北京市'或'131', 不传默认为'全国'",
624 | },
625 | "location": {
626 | "type": "string",
627 | "description": "圆形区域检索的中心点纬经度坐标, 格式为lat,lng",
628 | },
629 | "radius": {
630 | "type": "integer",
631 | "description": "圆形区域检索半径, 单位:米",
632 | },
633 | },
634 | }
635 | ),
636 | types.Tool(
637 | name="map_place_details",
638 | description="地点详情检索服务: 地点详情检索针对指定POI, 检索其相关的详情信息."
639 | "\n通过地点检索服务获取POI uid.使用地点详情检索功能, 传入uid, 即可检索POI详情信息, 如评分、营业时间等(不同类型POI对应不同类别详情数据).",
640 | inputSchema={
641 | "type": "object",
642 | "required": ["uid"],
643 | "properties": {
644 | "uid": {
645 | "type": "string",
646 | "description": "POI的唯一标识",
647 | },
648 | },
649 | }
650 | ),
651 | types.Tool(
652 | name="map_directions_matrix",
653 | description="批量算路服务: 根据起点和终点坐标计算路线规划距离和行驶时间."
654 | "\n批量算路目前支持驾车、骑行、步行."
655 | "\n步行时任意起终点之间的距离不得超过200KM, 超过此限制会返回参数错误."
656 | "\n驾车批量算路一次最多计算100条路线, 起终点个数之积不能超过100.",
657 | inputSchema={
658 | "type": "object",
659 | "required": ["origins", "destinations"],
660 | "properties": {
661 | "origins": {
662 | "type": "string",
663 | "description": "多个起点纬经度坐标, 纬度在前, 经度在后, 多个起点用|分隔",
664 | },
665 | "destinations": {
666 | "type": "string",
667 | "description": "多个终点纬经度坐标, 纬度在前, 经度在后, 多个终点用|分隔",
668 | },
669 | "model": {
670 | "type": "string",
671 | "description": "批量算路类型(driving, riding, walking)",
672 | },
673 | },
674 | }
675 | ),
676 | types.Tool(
677 | name="map_directions",
678 | description="路线规划服务: 根据起终点`位置名称`或`纬经度坐标`规划出行路线."
679 | "\n驾车路线规划: 根据起终点`位置名称`或`纬经度坐标`规划驾车出行路线."
680 | "\n骑行路线规划: 根据起终点`位置名称`或`纬经度坐标`规划骑行出行路线."
681 | "\n步行路线规划: 根据起终点`位置名称`或`纬经度坐标`规划步行出行路线."
682 | "\n公交路线规划: 根据起终点`位置名称`或`纬经度坐标`规划公共交通出行路线.",
683 | inputSchema={
684 | "type": "object",
685 | "required": ["origin", "destination"],
686 | "properties": {
687 | "model": {
688 | "type": "string",
689 | "description": "路线规划类型(driving, riding, walking, transit)",
690 | },
691 | "origin": {
692 | "type": "string",
693 | "description": "起点位置名称或纬经度坐标, 纬度在前, 经度在后",
694 | },
695 | "destination": {
696 | "type": "string",
697 | "description": "终点位置名称或纬经度坐标, 纬度在前, 经度在后",
698 | },
699 | },
700 | }
701 | ),
702 | types.Tool(
703 | name="map_weather",
704 | description="天气查询服务: 通过行政区划或是经纬度坐标查询实时天气信息及未来5天天气预报.",
705 | inputSchema={
706 | "type": "object",
707 | "required": [],
708 | "properties": {
709 | "location": {
710 | "type": "string",
711 | "description": "经纬度坐标, 经度在前纬度在后, 逗号分隔",
712 | },
713 | "district_id": {
714 | "type": "string",
715 | "description": "行政区划代码, 需保证为6位无符号整数",
716 | },
717 | },
718 | }
719 | ),
720 | types.Tool(
721 | name="map_ip_location",
722 | description="IP定位服务: 通过所给IP获取具体位置信息和城市名称, 可用于定位IP或用户当前位置.",
723 | inputSchema={
724 | "type": "object",
725 | "required": [],
726 | "properties": {
727 | "ip": {
728 | "type": "string",
729 | "description": "需要定位的IP地址, 如果为空则获取用户当前IP地址(支持IPv4和IPv6)",
730 | },
731 | },
732 | }
733 | ),
734 | types.Tool(
735 | name="map_road_traffic",
736 | description="实时路况查询服务: 查询实时交通拥堵情况, 可通过指定道路名和区域形状(矩形, 多边形, 圆形)进行实时路况查询."
737 | "\n道路实时路况查询: 查询具体道路的实时拥堵评价和拥堵路段、拥堵距离、拥堵趋势等信息."
738 | "\n矩形区域实时路况查询: 查询指定矩形地理范围的实时拥堵情况和各拥堵路段信息."
739 | "\n多边形区域实时路况查询: 查询指定多边形地理范围的实时拥堵情况和各拥堵路段信息."
740 | "\n圆形区域(周边)实时路况查询: 查询某中心点周边半径范围内的实时拥堵情况和各拥堵路段信息.",
741 | inputSchema={
742 | "type": "object",
743 | "required": ["model"],
744 | "properties": {
745 | "model": {
746 | "type": "string",
747 | "description": "路况查询类型(road, bound, polygon, around)",
748 | },
749 | "road_name": {
750 | "type": "string",
751 | "description": "道路名称和道路方向, model=road时必传 (如:朝阳路南向北)",
752 | },
753 | "city": {
754 | "type": "string",
755 | "description": "城市名称或城市adcode, model=road时必传 (如:北京市)",
756 | },
757 | "bounds": {
758 | "type": "string",
759 | "description": "区域左下角和右上角的纬经度坐标, 纬度在前, 经度在后, model=bound时必传",
760 | },
761 | "vertexes": {
762 | "type": "string",
763 | "description": "多边形区域的顶点纬经度坐标, 纬度在前, 经度在后, model=polygon时必传",
764 | },
765 | "center": {
766 | "type": "string",
767 | "description": "圆形区域的中心点纬经度坐标, 纬度在前, 经度在后, model=around时必传",
768 | },
769 | "radius": {
770 | "type": "integer",
771 | "description": "圆形区域的半径(米), 取值[1,1000], model=around时必传",
772 | },
773 | },
774 | }
775 | ),
776 | types.Tool(
777 | name="map_poi_extract",
778 | description="POI智能提取",
779 | inputSchema={
780 | "type": "object",
781 | "required": ["text_content"],
782 | "properties": {
783 | "text_content": {
784 | "type": "string",
785 | "description": "根据用户提供的文本描述信息, 智能提取出文本中所提及的POI相关信息. (注意: 使用该服务, api_key需要拥有对应的高级权限, 否则会报错)",
786 | },
787 | },
788 | }
789 | )
790 | ]
791 |
792 |
793 | async def dispatch(
794 | name: str, arguments: dict
795 | ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
796 | """
797 | 根据名称调度对应的工具函数, 并返回处理结果.
798 |
799 | Args:
800 | name (str): 工具函数的名称, 可选值为: "map_geocode", "map_reverse_geocode",
801 | "map_search_places", "map_place_details", "map_distance_matrix",
802 | "map_directions", "map_weather", "map_ip_location", "map_road_traffic",
803 | "map_mark".
804 | arguments (dict): 传递给工具函数的参数字典, 包括必要和可选参数.
805 |
806 | Returns:
807 | list[types.TextContent | types.ImageContent | types.EmbeddedResource]: 返回一个列表, 包含文本内容、图片内容或嵌入资源类型的元素.
808 |
809 | Raises:
810 | ValueError: 如果提供了未知的工具名称.
811 | """
812 |
813 | match name:
814 | case "map_geocode":
815 | return await map_geocode(name, arguments)
816 | case "map_reverse_geocode":
817 | return await map_reverse_geocode(name, arguments)
818 | case "map_search_places":
819 | return await map_search_places(name, arguments)
820 | case "map_place_details":
821 | return await map_place_details(name, arguments)
822 | case "map_directions_matrix":
823 | return await map_directions_matrix(name, arguments)
824 | case "map_directions":
825 | return await map_directions(name, arguments)
826 | case "map_weather":
827 | return await map_weather(name, arguments)
828 | case "map_ip_location":
829 | return await map_ip_location(name, arguments)
830 | case "map_road_traffic":
831 | return await map_road_traffic(name, arguments)
832 | case "map_poi_extract":
833 | return await map_poi_extract(name, arguments)
834 | case _:
835 | raise ValueError(f"Unknown tool: {name}")
836 |
837 |
838 | # 注册list_tools方法
839 | mcp._mcp_server.list_tools()(list_tools)
840 | # 注册dispatch方法
841 | mcp._mcp_server.call_tool()(dispatch)
842 |
843 | if __name__ == "__main__":
844 | mcp.run()
845 |
--------------------------------------------------------------------------------
/src/baidu-map/python/uv.lock:
--------------------------------------------------------------------------------
1 | version = 1
2 | revision = 1
3 | requires-python = ">=3.11"
4 |
5 | [[package]]
6 | name = "annotated-types"
7 | version = "0.7.0"
8 | source = { registry = "https://pypi.org/simple" }
9 | sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
10 | wheels = [
11 | { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
12 | ]
13 |
14 | [[package]]
15 | name = "anyio"
16 | version = "4.9.0"
17 | source = { registry = "https://pypi.org/simple" }
18 | dependencies = [
19 | { name = "idna" },
20 | { name = "sniffio" },
21 | { name = "typing-extensions", marker = "python_full_version < '3.13'" },
22 | ]
23 | sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 }
24 | wheels = [
25 | { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 },
26 | ]
27 |
28 | [[package]]
29 | name = "certifi"
30 | version = "2025.4.26"
31 | source = { registry = "https://pypi.org/simple" }
32 | sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705 }
33 | wheels = [
34 | { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618 },
35 | ]
36 |
37 | [[package]]
38 | name = "click"
39 | version = "8.1.8"
40 | source = { registry = "https://pypi.org/simple" }
41 | dependencies = [
42 | { name = "colorama", marker = "sys_platform == 'win32'" },
43 | ]
44 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
45 | wheels = [
46 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
47 | ]
48 |
49 | [[package]]
50 | name = "colorama"
51 | version = "0.4.6"
52 | source = { registry = "https://pypi.org/simple" }
53 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
54 | wheels = [
55 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
56 | ]
57 |
58 | [[package]]
59 | name = "h11"
60 | version = "0.16.0"
61 | source = { registry = "https://pypi.org/simple" }
62 | sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 }
63 | wheels = [
64 | { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 },
65 | ]
66 |
67 | [[package]]
68 | name = "httpcore"
69 | version = "1.0.9"
70 | source = { registry = "https://pypi.org/simple" }
71 | dependencies = [
72 | { name = "certifi" },
73 | { name = "h11" },
74 | ]
75 | sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 }
76 | wheels = [
77 | { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 },
78 | ]
79 |
80 | [[package]]
81 | name = "httpx"
82 | version = "0.28.1"
83 | source = { registry = "https://pypi.org/simple" }
84 | dependencies = [
85 | { name = "anyio" },
86 | { name = "certifi" },
87 | { name = "httpcore" },
88 | { name = "idna" },
89 | ]
90 | sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
91 | wheels = [
92 | { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
93 | ]
94 |
95 | [[package]]
96 | name = "httpx-sse"
97 | version = "0.4.0"
98 | source = { registry = "https://pypi.org/simple" }
99 | sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
100 | wheels = [
101 | { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
102 | ]
103 |
104 | [[package]]
105 | name = "idna"
106 | version = "3.10"
107 | source = { registry = "https://pypi.org/simple" }
108 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
109 | wheels = [
110 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
111 | ]
112 |
113 | [[package]]
114 | name = "markdown-it-py"
115 | version = "3.0.0"
116 | source = { registry = "https://pypi.org/simple" }
117 | dependencies = [
118 | { name = "mdurl" },
119 | ]
120 | sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
121 | wheels = [
122 | { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
123 | ]
124 |
125 | [[package]]
126 | name = "mcp"
127 | version = "1.9.0"
128 | source = { registry = "https://pypi.org/simple" }
129 | dependencies = [
130 | { name = "anyio" },
131 | { name = "httpx" },
132 | { name = "httpx-sse" },
133 | { name = "pydantic" },
134 | { name = "pydantic-settings" },
135 | { name = "python-multipart" },
136 | { name = "sse-starlette" },
137 | { name = "starlette" },
138 | { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
139 | ]
140 | sdist = { url = "https://files.pythonhosted.org/packages/bc/8d/0f4468582e9e97b0a24604b585c651dfd2144300ecffd1c06a680f5c8861/mcp-1.9.0.tar.gz", hash = "sha256:905d8d208baf7e3e71d70c82803b89112e321581bcd2530f9de0fe4103d28749", size = 281432 }
141 | wheels = [
142 | { url = "https://files.pythonhosted.org/packages/a5/d5/22e36c95c83c80eb47c83f231095419cf57cf5cca5416f1c960032074c78/mcp-1.9.0-py3-none-any.whl", hash = "sha256:9dfb89c8c56f742da10a5910a1f64b0d2ac2c3ed2bd572ddb1cfab7f35957178", size = 125082 },
143 | ]
144 |
145 | [package.optional-dependencies]
146 | cli = [
147 | { name = "python-dotenv" },
148 | { name = "typer" },
149 | ]
150 |
151 | [[package]]
152 | name = "mcp-server-baidu-maps"
153 | version = "0.2.0"
154 | source = { virtual = "." }
155 | dependencies = [
156 | { name = "mcp", extra = ["cli"] },
157 | ]
158 |
159 | [package.metadata]
160 | requires-dist = [{ name = "mcp", extras = ["cli"], specifier = ">=1.9.0" }]
161 |
162 | [[package]]
163 | name = "mdurl"
164 | version = "0.1.2"
165 | source = { registry = "https://pypi.org/simple" }
166 | sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
167 | wheels = [
168 | { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
169 | ]
170 |
171 | [[package]]
172 | name = "pydantic"
173 | version = "2.11.4"
174 | source = { registry = "https://pypi.org/simple" }
175 | dependencies = [
176 | { name = "annotated-types" },
177 | { name = "pydantic-core" },
178 | { name = "typing-extensions" },
179 | { name = "typing-inspection" },
180 | ]
181 | sdist = { url = "https://files.pythonhosted.org/packages/77/ab/5250d56ad03884ab5efd07f734203943c8a8ab40d551e208af81d0257bf2/pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d", size = 786540 }
182 | wheels = [
183 | { url = "https://files.pythonhosted.org/packages/e7/12/46b65f3534d099349e38ef6ec98b1a5a81f42536d17e0ba382c28c67ba67/pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb", size = 443900 },
184 | ]
185 |
186 | [[package]]
187 | name = "pydantic-core"
188 | version = "2.33.2"
189 | source = { registry = "https://pypi.org/simple" }
190 | dependencies = [
191 | { name = "typing-extensions" },
192 | ]
193 | sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195 }
194 | wheels = [
195 | { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584 },
196 | { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071 },
197 | { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823 },
198 | { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792 },
199 | { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338 },
200 | { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998 },
201 | { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200 },
202 | { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890 },
203 | { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359 },
204 | { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883 },
205 | { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074 },
206 | { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538 },
207 | { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909 },
208 | { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786 },
209 | { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000 },
210 | { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996 },
211 | { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957 },
212 | { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199 },
213 | { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296 },
214 | { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109 },
215 | { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028 },
216 | { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044 },
217 | { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881 },
218 | { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034 },
219 | { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187 },
220 | { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628 },
221 | { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866 },
222 | { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894 },
223 | { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688 },
224 | { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808 },
225 | { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580 },
226 | { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859 },
227 | { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810 },
228 | { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498 },
229 | { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611 },
230 | { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924 },
231 | { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196 },
232 | { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389 },
233 | { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223 },
234 | { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473 },
235 | { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269 },
236 | { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921 },
237 | { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162 },
238 | { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560 },
239 | { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777 },
240 | { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200 },
241 | { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123 },
242 | { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852 },
243 | { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484 },
244 | { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896 },
245 | { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475 },
246 | { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013 },
247 | { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715 },
248 | { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757 },
249 | ]
250 |
251 | [[package]]
252 | name = "pydantic-settings"
253 | version = "2.9.1"
254 | source = { registry = "https://pypi.org/simple" }
255 | dependencies = [
256 | { name = "pydantic" },
257 | { name = "python-dotenv" },
258 | { name = "typing-inspection" },
259 | ]
260 | sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234 }
261 | wheels = [
262 | { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356 },
263 | ]
264 |
265 | [[package]]
266 | name = "pygments"
267 | version = "2.19.1"
268 | source = { registry = "https://pypi.org/simple" }
269 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
270 | wheels = [
271 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
272 | ]
273 |
274 | [[package]]
275 | name = "python-dotenv"
276 | version = "1.1.0"
277 | source = { registry = "https://pypi.org/simple" }
278 | sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920 }
279 | wheels = [
280 | { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256 },
281 | ]
282 |
283 | [[package]]
284 | name = "python-multipart"
285 | version = "0.0.20"
286 | source = { registry = "https://pypi.org/simple" }
287 | sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 }
288 | wheels = [
289 | { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 },
290 | ]
291 |
292 | [[package]]
293 | name = "rich"
294 | version = "14.0.0"
295 | source = { registry = "https://pypi.org/simple" }
296 | dependencies = [
297 | { name = "markdown-it-py" },
298 | { name = "pygments" },
299 | ]
300 | sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078 }
301 | wheels = [
302 | { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 },
303 | ]
304 |
305 | [[package]]
306 | name = "shellingham"
307 | version = "1.5.4"
308 | source = { registry = "https://pypi.org/simple" }
309 | sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
310 | wheels = [
311 | { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
312 | ]
313 |
314 | [[package]]
315 | name = "sniffio"
316 | version = "1.3.1"
317 | source = { registry = "https://pypi.org/simple" }
318 | sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
319 | wheels = [
320 | { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
321 | ]
322 |
323 | [[package]]
324 | name = "sse-starlette"
325 | version = "2.3.5"
326 | source = { registry = "https://pypi.org/simple" }
327 | dependencies = [
328 | { name = "anyio" },
329 | { name = "starlette" },
330 | ]
331 | sdist = { url = "https://files.pythonhosted.org/packages/10/5f/28f45b1ff14bee871bacafd0a97213f7ec70e389939a80c60c0fb72a9fc9/sse_starlette-2.3.5.tar.gz", hash = "sha256:228357b6e42dcc73a427990e2b4a03c023e2495ecee82e14f07ba15077e334b2", size = 17511 }
332 | wheels = [
333 | { url = "https://files.pythonhosted.org/packages/c8/48/3e49cf0f64961656402c0023edbc51844fe17afe53ab50e958a6dbbbd499/sse_starlette-2.3.5-py3-none-any.whl", hash = "sha256:251708539a335570f10eaaa21d1848a10c42ee6dc3a9cf37ef42266cdb1c52a8", size = 10233 },
334 | ]
335 |
336 | [[package]]
337 | name = "starlette"
338 | version = "0.46.2"
339 | source = { registry = "https://pypi.org/simple" }
340 | dependencies = [
341 | { name = "anyio" },
342 | ]
343 | sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846 }
344 | wheels = [
345 | { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037 },
346 | ]
347 |
348 | [[package]]
349 | name = "typer"
350 | version = "0.15.4"
351 | source = { registry = "https://pypi.org/simple" }
352 | dependencies = [
353 | { name = "click" },
354 | { name = "rich" },
355 | { name = "shellingham" },
356 | { name = "typing-extensions" },
357 | ]
358 | sdist = { url = "https://files.pythonhosted.org/packages/6c/89/c527e6c848739be8ceb5c44eb8208c52ea3515c6cf6406aa61932887bf58/typer-0.15.4.tar.gz", hash = "sha256:89507b104f9b6a0730354f27c39fae5b63ccd0c95b1ce1f1a6ba0cfd329997c3", size = 101559 }
359 | wheels = [
360 | { url = "https://files.pythonhosted.org/packages/c9/62/d4ba7afe2096d5659ec3db8b15d8665bdcb92a3c6ff0b95e99895b335a9c/typer-0.15.4-py3-none-any.whl", hash = "sha256:eb0651654dcdea706780c466cf06d8f174405a659ffff8f163cfbfee98c0e173", size = 45258 },
361 | ]
362 |
363 | [[package]]
364 | name = "typing-extensions"
365 | version = "4.13.2"
366 | source = { registry = "https://pypi.org/simple" }
367 | sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967 }
368 | wheels = [
369 | { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806 },
370 | ]
371 |
372 | [[package]]
373 | name = "typing-inspection"
374 | version = "0.4.0"
375 | source = { registry = "https://pypi.org/simple" }
376 | dependencies = [
377 | { name = "typing-extensions" },
378 | ]
379 | sdist = { url = "https://files.pythonhosted.org/packages/82/5c/e6082df02e215b846b4b8c0b887a64d7d08ffaba30605502639d44c06b82/typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122", size = 76222 }
380 | wheels = [
381 | { url = "https://files.pythonhosted.org/packages/31/08/aa4fdfb71f7de5176385bd9e90852eaf6b5d622735020ad600f2bab54385/typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f", size = 14125 },
382 | ]
383 |
384 | [[package]]
385 | name = "uvicorn"
386 | version = "0.34.2"
387 | source = { registry = "https://pypi.org/simple" }
388 | dependencies = [
389 | { name = "click" },
390 | { name = "h11" },
391 | ]
392 | sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815 }
393 | wheels = [
394 | { url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483 },
395 | ]
396 |
--------------------------------------------------------------------------------