#
tokens: 14725/50000 10/10 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── img
│   ├── agent_result.png
│   ├── appbuilder.png
│   ├── claude_final_result.png
│   ├── claude_result.png
│   ├── claude_setting_developer.png
│   ├── claude_setting_result.png
│   ├── claude_setting.png
│   ├── cursor_run_mcp_success.png
│   ├── cursor_setting.png
│   ├── cursor_test_1.png
│   ├── cursor_test_2.png
│   ├── logo.png
│   ├── mcp_run_success.png
│   ├── thinking_progress.png
│   └── uv_install_success.png
├── LICENSE
├── README_zh.md
├── README.md
└── src
    └── baidu-map
        ├── node
        │   ├── .gitignore
        │   ├── index.ts
        │   ├── package-lock.json
        │   ├── package.json
        │   ├── README.md
        │   └── tsconfig.json
        └── python
            ├── .gitignore
            ├── .python-version
            ├── LICENSE
            ├── pyproject.toml
            ├── README.md
            ├── src
            │   └── mcp_server_baidu_maps
            │       ├── __init__.py
            │       ├── __main__.py
            │       └── map.py
            └── uv.lock
```

# Files

--------------------------------------------------------------------------------
/src/baidu-map/python/.python-version:
--------------------------------------------------------------------------------

```
1 | 3.11
2 | 
```

--------------------------------------------------------------------------------
/src/baidu-map/node/.gitignore:
--------------------------------------------------------------------------------

```
1 | /dist
2 | /node_modules
```

--------------------------------------------------------------------------------
/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 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | <div align="center">
  2 |   <p>
  3 |       <img align="center" src="img/logo.png", width=700></a>
  4 |   </p>
  5 | 
  6 | <!-- language -->
  7 | [中文](./README_zh.md)| English 
  8 | 
  9 | <!-- icon -->
 10 | <br>
 11 | 
 12 | [![stars](https://img.shields.io/github/stars/baidu-maps/mcp?color=ccf)](https://github.com/baidu-maps/mcp)
 13 | ![python](https://img.shields.io/badge/python-3.10~3.12-aff.svg)
 14 | [![MIT License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
 15 | [![pypi](https://img.shields.io/pypi/v/mcp-server-baidu-maps)](https://pypi.org/project/mcp-server-baidu-maps/)
 16 | [![npm](https://img.shields.io/npm/v/@baidumap/mcp-server-baidu-map)](https://www.npmjs.com/package/@baidumap/mcp-server-baidu-map)
 17 | 
 18 | </div>
 19 | <br>
 20 | 
 21 | ## 🚀 Introduction
 22 | 
 23 | **Baidu Map MCP Server** is a fully MCP-compliant, open-source Location-Based Service (LBS) solution, providing a comprehensive suite of geospatial APIs and tools for developers and AI agents. As the first map service provider in China to support the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction), Baidu Map MCP Server bridges the gap between large language models (LLMs), AI agents, and real-world location data and services.
 24 | 
 25 | With Baidu Map MCP Server, you can easily empower your applications, LLMs, and agents with advanced mapping, geocoding, POI search, route planning, weather, traffic, and more — all via standardized, developer-friendly MCP interfaces.
 26 | 
 27 | **Key Features:**
 28 | - **Full MCP Protocol Support:** Seamless integration with any MCP-compliant agent, LLM, or platform.
 29 | - **Rich LBS Capabilities:** Geocoding, reverse geocoding, POI search, route planning (driving, walking, cycling, transit), weather, IP location, real-time traffic, and more.
 30 | - **Cross-Platform SDKs:** Official Python and TypeScript SDKs, easy CLI and cloud deployment.
 31 | - **Enterprise-Grade Data:** Powered by Baidu Maps' authoritative, up-to-date geospatial data.
 32 | - **High Performance & Stability:** Recommended SSE (Server-Sent Events) access for low latency and high reliability.
 33 | - **Open Source & Extensible:** MIT licensed, easy to customize and extend.
 34 | 
 35 | Whether you are building a travel assistant, logistics platform, smart city solution, or an LLM-powered agent, Baidu Map MCP Server provides the essential geospatial intelligence and tools you need.
 36 | 
 37 | The MCP Server architecture enables:
 38 | - **Seamless AI Integration**: Allows LLMs and agents to understand and process location data naturally
 39 | - **Contextual Understanding**: Provides rich geospatial context for more intelligent decision-making
 40 | - **Standardized Interfaces**: Consistent API design following MCP principles for easy integration
 41 | - **Scalable Implementation**: Suitable for projects of any size, from small applications to enterprise solutions
 42 | 
 43 | Whether you're building a navigation app, delivery service, smart city solution, or enhancing an AI agent with location awareness, Baidu Map MCP Server provides the tools and infrastructure you need to succeed.
 44 | 
 45 | 
 46 | ## 🛠️ Supported Tools & APIs
 47 | 
 48 | Baidu Map MCP Server provides the following MCP-compliant APIs (tools):
 49 | 
 50 | | Tool Name                | Description                                                                                  |
 51 | |--------------------------|----------------------------------------------------------------------------------------------|
 52 | | `map_geocode`            | Convert address to geographic coordinates.                                                   |
 53 | | `map_reverse_geocode`    | Get address, region, and POI info from coordinates.                                         |
 54 | | `map_search_places`      | Search for global POIs by keyword, type, region, or within a radius.                               |
 55 | | `map_place_details`      | Get detailed info for a POI by its unique ID.                                               |
 56 | | `map_directions_matrix`  | Batch route planning for multiple origins/destinations (driving, walking, cycling).         |
 57 | | `map_directions`         | Plan routes between two points (driving, walking, cycling, transit).                        |
 58 | | `map_weather`            | Query real-time and forecast weather by region or coordinates.                              |
 59 | | `map_ip_location`        | Locate city and coordinates by IP address.                                                  |
 60 | | `map_road_traffic`       | Query real-time traffic conditions for roads or regions.                                    |
 61 | | `map_poi_extract`*       | Extract POI info from free text (requires advanced permission).                             |
 62 | 
 63 | > *Some advanced features require additional permissions. See [Authorization](#authorization) for details.
 64 | 
 65 | All APIs follow the MCP protocol and can be called from any MCP-compliant client, LLM, or agent platform.
 66 | 
 67 | ## ⚡ Quick Start
 68 | 
 69 | ### 1. Get Your API Key
 70 | 
 71 | Register and create a server-side API Key (AK) at [Baidu Maps Open Platform](https://lbsyun.baidu.com/apiconsole/key).
 72 | **Be sure to enable “MCP (SSE)” service for best performance.**
 73 | 
 74 | ### 2. Python Integration
 75 | 
 76 | Install the SDK:
 77 | ```bash
 78 | pip install mcp-server-baidu-maps
 79 | ```
 80 | 
 81 | **Run as a script:**
 82 | ```bash
 83 | python -m mcp_server_baidu_maps
 84 | ```
 85 | 
 86 | **Configure in your MCP client (e.g., Claude, Cursor):**
 87 | ```json
 88 | {
 89 |   "mcpServers": {
 90 |     "baidu-maps": {
 91 |       "command": "python",
 92 |       "args": ["-m", "mcp_server_baidu_maps"],
 93 |       "env": {
 94 |         "BAIDU_MAPS_API_KEY": "<YOUR_API_KEY>"
 95 |       }
 96 |     }
 97 |   }
 98 | }
 99 | ```
100 | 
101 | ### 3. Node.js/TypeScript Integration
102 | 
103 | Install:
104 | ```bash
105 | npm install @baidumap/mcp-server-baidu-map
106 | ```
107 | 
108 | **Configure in your MCP client:**
109 | ```json
110 | {
111 |   "mcpServers": {
112 |     "baidu-map": {
113 |       "command": "npx",
114 |       "args": [
115 |         "-y",
116 |         "@baidumap/mcp-server-baidu-map"
117 |       ],
118 |       "env": {
119 |         "BAIDU_MAP_API_KEY": "<YOUR_API_KEY>"
120 |       }
121 |     }
122 |   }
123 | }
124 | ```
125 | 
126 | ### 4. Recommended: Use SSE for low-latency, stable access
127 | 
128 | See [SSE Quickstart](https://lbsyun.baidu.com/faq/api?title=mcpserver/quickstart).
129 | 
130 | ### 5. More Platforms
131 | 
132 | - **Claude/Agent/千帆AppBuilder**: See [README_zh.md](./README_zh.md) for detailed integration guides and advanced configuration.
133 | 
134 | ---
135 | 
136 | ## 🚀 Advanced Use Cases
137 | 
138 | - **Travel Planning Assistant:**  
139 |   Use `map_search_places`, `map_directions`, and `map_weather` to build an agent that plans optimal sightseeing routes, checks weather, and recommends POIs.
140 | 
141 | - **Batch Route Matrix:**  
142 |   Use `map_directions_matrix` to calculate multiple routes and durations for logistics or delivery optimization.
143 | 
144 | - **Text-to-POI Extraction:**  
145 |   Use `map_poi_extract` to extract POIs from user input or travel notes (requires advanced permission).
146 | 
147 | - **Real-time Traffic & Weather-aware Navigation:**  
148 |   Combine `map_road_traffic` and `map_weather` for dynamic, context-aware travel suggestions.
149 | 
150 | - **Integration with Claude, Qianfan, AppBuilder:**  
151 |   Seamlessly connect Baidu Map MCP Server to LLMs and agent frameworks for natural language geospatial reasoning.
152 | 
153 | **See [README_zh.md](./README_zh.md) for more detailed Chinese documentation, configuration, and examples.**
154 | 
155 | ---
156 | 
157 | ## ⛰️ Advanced Tutorials
158 | - [Geocoding API Guide](https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding)
159 | - [POI Search API Guide](https://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-placeapi)
160 | - [Route Planning API Guide](https://lbsyun.baidu.com/index.php?title=webapi/direction-api)
161 | - [MCP Integration Guide](https://lbsyun.baidu.com/index.php?title=mcp/guide)
162 | - [SDK Development Guide](https://lbsyun.baidu.com/index.php?title=mcp/sdk)
163 | 
164 | ## 👩‍👩‍👧‍👦 Contributors
165 | 
166 | <a href="https://github.com/baidu-maps/mcp/graphs/contributors">
167 |   <img src="https://contrib.rocks/image?repo=baidu-maps/mcp&max=400&columns=20"  width="200"/>
168 | </a>
169 | 
170 | 
171 | ## 🌟 Star History
172 | 
173 | [![Star History Chart](https://api.star-history.com/svg?repos=baidu-maps/mcp&type=Date)](https://star-history.com/#baidu-maps/mcp&Date)
174 | 
175 | 
176 | ## 📄 License
177 | [MIT](./LICENSE) © baidu-maps
178 | 
```

--------------------------------------------------------------------------------
/src/baidu-map/python/src/mcp_server_baidu_maps/__main__.py:
--------------------------------------------------------------------------------

```python
1 | from mcp_server_baidu_maps import main
2 | 
3 | main()
```

--------------------------------------------------------------------------------
/src/baidu-map/python/src/mcp_server_baidu_maps/__init__.py:
--------------------------------------------------------------------------------

```python
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/node/tsconfig.json:
--------------------------------------------------------------------------------

```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/pyproject.toml:
--------------------------------------------------------------------------------

```toml
 1 | [project]
 2 | name = "mcp-server-baidu-maps"
 3 | version = "0.2.4"
 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 = "[email protected]" }]
 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/node/package.json:
--------------------------------------------------------------------------------

```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/index.ts:
--------------------------------------------------------------------------------

```typescript
   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 | 
```