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

```
├── amap-coordinate-server
│   ├── .gitignore
│   ├── package-lock.json
│   ├── package.json
│   ├── README.md
│   ├── src
│   │   └── index.ts
│   └── tsconfig.json
└── amap-route-server
    ├── .gitignore
    ├── package-lock.json
    ├── package.json
    ├── README.md
    ├── src
    │   └── index.ts
    └── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/amap-coordinate-server/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
```

--------------------------------------------------------------------------------
/amap-route-server/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | build/
3 | *.log
4 | .env*
```

--------------------------------------------------------------------------------
/amap-route-server/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # amap-route-server MCP Server
 2 | 
 3 | A Model Context Protocol server for AMap Route Planning.
 4 | 
 5 | This server provides tools to calculate routes using the AMap API for different transportation modes.
 6 | 
 7 | ## Features
 8 | 
 9 | ### Tools
10 | 
11 | -   `walking_route`: Calculates a walking route between two points.
12 | -   `transit_route`: Calculates a transit route between two points.
13 | -   `driving_route`: Calculates a driving route between two points.
14 | -   `bicycling_route`: Calculates a bicycling route between two points.
15 | -   `distance`: Calculates the distance between two points.
16 | 
17 | ## Development
18 | 
19 | Install dependencies:
20 | 
21 | ```bash
22 | npm install
23 | ```
24 | 
25 | Build the server:
26 | 
27 | ```bash
28 | npm run build
29 | ```
30 | 
31 | For development with auto-rebuild:
32 | 
33 | ```bash
34 | npm run watch
35 | ```
36 | 
37 | ## Installation
38 | 
39 | To use with Claude Desktop, add the server config:
40 | 
41 | On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
42 | 
43 | On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
44 | 
45 | ```json
46 | {
47 |   "mcpServers": {
48 |     "amap-route-server": {
49 |       "command": "/path/to/amap-route-server/build/index.js",
50 |       "env": {
51 |         "AMAP_API_KEY": "YOUR_AMAP_API_KEY"
52 |       }
53 |     }
54 |   }
55 | }
56 | ```
57 | 
58 | **Note:** You need to obtain an AMap API key and set it as the `AMAP_API_KEY` environment variable.
59 | 
60 | ### Debugging
61 | 
62 | Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the \[MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
63 | 
64 | ```bash
65 | npm run inspector
66 | ```
67 | 
68 | The Inspector will provide a URL to access debugging tools in your browser.
69 | 
```

--------------------------------------------------------------------------------
/amap-coordinate-server/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # amap-coordinate-server MCP Server
 2 | 
 3 | A Model Context Protocol server for AMap Coordinate Conversion and Place Search.
 4 | 
 5 | This server provides tools to convert coordinates between different systems and search for places using the AMap API.
 6 | 
 7 | ## Features
 8 | 
 9 | ### Tools
10 | 
11 | -   `coordinate_convert`: Converts coordinates between different coordinate systems (GPS, mapbar, baidu, autonavi).
12 | -   `keyword_search`: Searches for places by keyword.
13 | -   `around_search`: Searches for places around a specific location.
14 | -   `polygon_search`: Searches for places within a given polygon.
15 | -   `id_search`: Searches for a place by its ID.
16 | -   `aoi_boundary_query`: Queries the boundary of an Area of Interest (AOI).
17 | 
18 | ## Development
19 | 
20 | Install dependencies:
21 | 
22 | ```bash
23 | npm install
24 | ```
25 | 
26 | Build the server:
27 | 
28 | ```bash
29 | npm run build
30 | ```
31 | 
32 | For development with auto-rebuild:
33 | 
34 | ```bash
35 | npm run watch
36 | ```
37 | 
38 | ## Installation
39 | 
40 | To use with Claude Desktop, add the server config:
41 | 
42 | On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
43 | 
44 | On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
45 | 
46 | ```json
47 | {
48 |   "mcpServers": {
49 |     "amap-coordinate-server": {
50 |       "command": "/path/to/amap-coordinate-server/build/index.js",
51 |       "env": {
52 |         "AMAP_API_KEY": "YOUR_AMAP_API_KEY"
53 |       }
54 |     }
55 |   }
56 | }
57 | ```
58 | 
59 | **Note:** You need to obtain an AMap API key and set it as the `AMAP_API_KEY` environment variable.
60 | 
61 | ### Debugging
62 | 
63 | Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the \[MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
64 | 
65 | ```bash
66 | npm run inspector
67 | ```
68 | 
69 | The Inspector will provide a URL to access debugging tools in your browser.
70 | 
```

--------------------------------------------------------------------------------
/amap-coordinate-server/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/amap-route-server/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "Node16",
 5 |     "moduleResolution": "Node16",
 6 |     "outDir": "./build",
 7 |     "rootDir": "./src",
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/amap-route-server/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "GAODENEW",
 3 |   "version": "0.1.0",
 4 |   "description": "CHINA!",
 5 |   "private": true,
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "GAODENEW": "./build/index.js"
 9 |   },
10 |   "files": [
11 |     "build"
12 |   ],
13 |   "scripts": {
14 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
15 |     "prepare": "npm run build",
16 |     "watch": "tsc --watch",
17 |     "inspector": "npx @modelcontextprotocol/inspector build/index.js"
18 |   },
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "0.6.0",
21 |     "node-fetch": "^3.3.2"
22 |   },
23 |   "devDependencies": {
24 |     "@types/node": "^20.11.24",
25 |     "typescript": "^5.3.3"
26 |   }
27 | }
28 | 
```

--------------------------------------------------------------------------------
/amap-coordinate-server/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "amap-coordinate-server",
 3 |   "version": "0.1.0",
 4 |   "description": "A Model Context Protocol server",
 5 |   "private": true,
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "amap-coordinate-server": "build/index.js"
 9 |   },
10 |   "files": [
11 |     "build"
12 |   ],
13 |   "scripts": {
14 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
15 |     "prepare": "npm run build",
16 |     "watch": "tsc --watch",
17 |     "inspector": "npx @modelcontextprotocol/inspector build/index.js"
18 |   },
19 |   "dependencies": {
20 |     "@modelcontextprotocol/sdk": "^0.6.0",
21 |     "axios": "^1.8.4"
22 |   },
23 |   "devDependencies": {
24 |     "@types/node": "^20.11.24",
25 |     "typescript": "^5.3.3"
26 |   },
27 |   "main": "index.js",
28 |   "keywords": [],
29 |   "author": "",
30 |   "license": "ISC"
31 | }
32 | 
```

--------------------------------------------------------------------------------
/amap-route-server/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | /**
  4 |  * This is a template MCP server that implements a simple notes system.
  5 |  * It demonstrates core MCP concepts like resources and tools by allowing:
  6 |  * - Listing notes as resources
  7 |  * - Reading individual notes
  8 |  * - Creating new notes via a tool
  9 |  * - Summarizing all notes via a prompt
 10 |  */
 11 | 
 12 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
 13 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
 14 | import {
 15 |   CallToolRequestSchema,
 16 |   ListResourcesRequestSchema,
 17 |   ListToolsRequestSchema,
 18 |   ReadResourceRequestSchema,
 19 |   ListPromptsRequestSchema,
 20 |   GetPromptRequestSchema,
 21 | } from "@modelcontextprotocol/sdk/types.js";
 22 | import fetch from 'node-fetch';
 23 | 
 24 | /**
 25 |  * Type alias for a note object.
 26 |  */
 27 | type Note = { title: string, content: string };
 28 | 
 29 | /**
 30 |  * Simple in-memory storage for notes.
 31 |  * In a real implementation, this would likely be backed by a database.
 32 |  */
 33 | const notes: { [id: string]: Note } = {
 34 |   "1": { title: "First Note", content: "This is note 1" },
 35 |   "2": { title: "Second Note", content: "This is note 2" }
 36 | };
 37 | 
 38 | /**
 39 |  * Create an MCP server with capabilities for resources (to list/read notes),
 40 |  * tools (to create new notes), and prompts (to summarize notes).
 41 |  */
 42 | const server = new Server(
 43 |   {
 44 |     name: "amap-route-server",
 45 |     version: "0.1.0",
 46 |   },
 47 |   {
 48 |     capabilities: {
 49 |       resources: {},
 50 |       tools: {},
 51 |       prompts: {},
 52 |     },
 53 |   }
 54 | );
 55 | 
 56 | /**
 57 |  * Handler for listing available notes as resources.
 58 |  * Each note is exposed as a resource with:
 59 |  * - A note:// URI scheme
 60 |  * - Plain text MIME type
 61 |  * - Human readable name and description (now including the note title)
 62 |  */
 63 | server.setRequestHandler(ListResourcesRequestSchema, async () => {
 64 |   return {
 65 |     resources: Object.entries(notes).map(([id, note]) => ({
 66 |       uri: `note:///${id}`,
 67 |       mimeType: "text/plain",
 68 |       name: note.title,
 69 |       description: `A text note: ${note.title}`
 70 |     }))
 71 |   };
 72 | });
 73 | 
 74 | /**
 75 |  * Handler for reading the contents of a specific note.
 76 |  * Takes a note:// URI and returns the note content as plain text.
 77 |  */
 78 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
 79 |   const url = new URL(request.params.uri);
 80 |   const id = url.pathname.replace(/^\//, '');
 81 |   const note = notes[id];
 82 | 
 83 |   if (!note) {
 84 |     throw new Error(`Note ${id} not found`);
 85 |   }
 86 | 
 87 |   return {
 88 |     contents: [{
 89 |       uri: request.params.uri,
 90 |       mimeType: "text/plain",
 91 |       text: note.content
 92 |     }]
 93 |   };
 94 | });
 95 | 
 96 | /**
 97 |  * Handler that lists available tools.
 98 |  */
 99 | server.setRequestHandler(ListToolsRequestSchema, async () => {
100 |   return {
101 |     tools: [
102 |       {
103 |         name: "walking_route",
104 |         description: "Get walking route",
105 |         inputSchema: {
106 |           type: "object",
107 |           properties: {
108 |             origin: {
109 |               type: "string",
110 |               description: "Origin longitude and latitude"
111 |             },
112 |             destination: {
113 |               type: "string",
114 |               description: "Destination longitude and latitude"
115 |             }
116 |           },
117 |           required: ["origin", "destination"]
118 |         }
119 |       },
120 |       {
121 |         name: "transit_route",
122 |         description: "Get transit route",
123 |         inputSchema: {
124 |           type: "object",
125 |           properties: {
126 |             origin: {
127 |               type: "string",
128 |               description: "Origin longitude and latitude"
129 |             },
130 |             destination: {
131 |               type: "string",
132 |               description: "Destination longitude and latitude"
133 |             },
134 |             city: {
135 |               type: "string",
136 |               description: "City name"
137 |             }
138 |           },
139 |           required: ["origin", "destination", "city"]
140 |         }
141 |       },
142 |       {
143 |         name: "driving_route",
144 |         description: "Get driving route",
145 |         inputSchema: {
146 |           type: "object",
147 |           properties: {
148 |             origin: {
149 |               type: "string",
150 |               description: "Origin longitude and latitude"
151 |             },
152 |             destination: {
153 |               type: "string",
154 |               description: "Destination longitude and latitude"
155 |             }
156 |           },
157 |           required: ["origin", "destination"]
158 |         }
159 |       },
160 |       {
161 |         name: "bicycling_route",
162 |         description: "Get bicycling route",
163 |         inputSchema: {
164 |           type: "object",
165 |           properties: {
166 |             origin: {
167 |               type: "string",
168 |               description: "Origin longitude and latitude"
169 |             },
170 |             destination: {
171 |               type: "string",
172 |               description: "Destination longitude and latitude"
173 |             }
174 |           },
175 |           required: ["origin", "destination"]
176 |         }
177 |       },
178 |       {
179 |         name: "distance",
180 |         description: "Get distance between two points",
181 |         inputSchema: {
182 |           type: "object",
183 |           properties: {
184 |             origins: {
185 |               type: "string",
186 |               description: "Origin longitude and latitude, separated by |"
187 |             },
188 |             destination: {
189 |               type: "string",
190 |               description: "Destination longitude and latitude"
191 |             }
192 |           },
193 |           required: ["origins", "destination"]
194 |         }
195 |       }
196 |     ]
197 |   };
198 | });
199 | 
200 | /**
201 |  * Handler for the create_note tool.
202 |  * Creates a new note with the provided title and content, and returns success message.
203 |  */
204 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
205 |   const apiKey = "ae4775b98c50d997cab4bcd6c769bf9b";
206 |   switch (request.params.name) {
207 |     case "walking_route": {
208 |       const origin = String(request.params.arguments?.origin);
209 |       const destination = String(request.params.arguments?.destination);
210 |       if (!origin || !destination) {
211 |         throw new Error("Origin and destination are required");
212 |       }
213 |       const url = `https://restapi.amap.com/v3/direction/walking?origin=${origin}&destination=${destination}&key=${apiKey}`;
214 |       const response = await fetch(url);
215 |       const data = await response.json();
216 |       return {
217 |         content: [{
218 |           type: "text",
219 |           text: JSON.stringify(data)
220 |         }]
221 |       };
222 |     }
223 |     case "transit_route": {
224 |       const origin = String(request.params.arguments?.origin);
225 |       const destination = String(request.params.arguments?.destination);
226 |       const city = String(request.params.arguments?.city);
227 |       if (!origin || !destination || !city) {
228 |         throw new Error("Origin, destination and city are required");
229 |       }
230 |       const url = `https://restapi.amap.com/v3/direction/transit/integrated?origin=${origin}&destination=${destination}&city=${city}&key=${apiKey}`;
231 |       const response = await fetch(url);
232 |       const data = await response.json();
233 |       return {
234 |         content: [{
235 |           type: "text",
236 |           text: JSON.stringify(data)
237 |         }]
238 |       };
239 |     }
240 |     case "driving_route": {
241 |       const origin = String(request.params.arguments?.origin);
242 |       const destination = String(request.params.arguments?.destination);
243 |       if (!origin || !destination) {
244 |         throw new Error("Origin and destination are required");
245 |       }
246 |       const url = `https://restapi.amap.com/v3/direction/driving?origin=${origin}&destination=${destination}&key=${apiKey}`;
247 |       const response = await fetch(url);
248 |       const data = await response.json();
249 |       return {
250 |         content: [{
251 |           type: "text",
252 |           text: JSON.stringify(data)
253 |         }]
254 |       };
255 |     }
256 |     case "bicycling_route": {
257 |       const origin = String(request.params.arguments?.origin);
258 |       const destination = String(request.params.arguments?.destination);
259 |       if (!origin || !destination) {
260 |         throw new Error("Origin and destination are required");
261 |       }
262 |       const url = `https://restapi.amap.com/v4/direction/bicycling?origin=${origin}&destination=${destination}&key=${apiKey}`;
263 |       const response = await fetch(url);
264 |       const data = await response.json();
265 |       return {
266 |         content: [{
267 |           type: "text",
268 |           text: JSON.stringify(data)
269 |         }]
270 |       };
271 |     }
272 |     case "distance": {
273 |       const origins = String(request.params.arguments?.origins);
274 |       const destination = String(request.params.arguments?.destination);
275 |       if (!origins || !destination) {
276 |         throw new Error("Origins and destination are required");
277 |       }
278 |       const url = `https://restapi.amap.com/v3/distance?origins=${origins}&destination=${destination}&key=${apiKey}`;
279 |       const response = await fetch(url);
280 |       const data = await response.json();
281 |       return {
282 |         content: [{
283 |           type: "text",
284 |           text: JSON.stringify(data)
285 |         }]
286 |       };
287 |     }
288 |     default:
289 |       throw new Error("Unknown tool");
290 |   }
291 | });
292 | 
293 | /**
294 |  * Handler that lists available prompts.
295 |  * Exposes a single "summarize_notes" prompt that summarizes all notes.
296 |  */
297 | server.setRequestHandler(ListPromptsRequestSchema, async () => {
298 |   return {
299 |     prompts: [
300 |       {
301 |         name: "summarize_notes",
302 |         description: "Summarize all notes",
303 |       }
304 |     ]
305 |   };
306 | });
307 | 
308 | /**
309 |  * Handler for the summarize_notes prompt.
310 |  * Returns a prompt that requests summarization of all notes, with the notes' contents embedded as resources.
311 |  */
312 | server.setRequestHandler(GetPromptRequestSchema, async (request) => {
313 |   if (request.params.name !== "summarize_notes") {
314 |     throw new Error("Unknown prompt");
315 |   }
316 | 
317 |   const embeddedNotes = Object.entries(notes).map(([id, note]) => ({
318 |     type: "resource" as const,
319 |     resource: {
320 |       uri: `note:///${id}`,
321 |       mimeType: "text/plain",
322 |       text: note.content
323 |     }
324 |   }));
325 | 
326 |   return {
327 |     messages: [
328 |       {
329 |         role: "user",
330 |         content: {
331 |           type: "text",
332 |           text: "Please summarize the following notes:"
333 |         }
334 |       },
335 |       ...embeddedNotes.map(note => ({
336 |         role: "user" as const,
337 |         content: note
338 |       })),
339 |       {
340 |         role: "user",
341 |         content: {
342 |           type: "text",
343 |           text: "Provide a concise summary of all the notes above."
344 |         }
345 |       }
346 |     ]
347 |   };
348 | });
349 | 
350 | /**
351 |  * Start the server using stdio transport.
352 |  * This allows the server to communicate via standard input/output streams.
353 |  */
354 | async function main() {
355 |   const transport = new StdioServerTransport();
356 |   await server.connect(transport);
357 |   console.log("Amap route server started");
358 | }
359 | 
360 | main().catch((error) => {
361 |   console.error("Server error:", error);
362 |   process.exit(1);
363 | });
364 | 
```

--------------------------------------------------------------------------------
/amap-coordinate-server/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import {
  5 |   CallToolRequestSchema,
  6 |   ErrorCode,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 | } from '@modelcontextprotocol/sdk/types.js';
 10 | import axios from 'axios';
 11 | 
 12 | const API_KEY = process.env.AMAP_API_KEY;
 13 | 
 14 | if (!API_KEY) {
 15 |   throw new Error('AMAP_API_KEY environment variable is required');
 16 | }
 17 | 
 18 | interface CoordinateConvertArgs {
 19 |   locations: string;
 20 |   coordsys?: string;
 21 |   output?: string;
 22 | }
 23 | 
 24 | interface KeywordSearchArgs {
 25 |   keywords: string;
 26 |   types?: string;
 27 |   city?: string;
 28 |   citylimit?: boolean;
 29 |   children?: number;
 30 |   offset?: number;
 31 |   page?: number;
 32 |   extensions?: string;
 33 | }
 34 | 
 35 | interface AroundSearchArgs {
 36 |   location: string;
 37 |   keywords?: string;
 38 |   types?: string;
 39 |   city?: string;
 40 |   radius?: number;
 41 |   sortrule?: string;
 42 |   offset?: number;
 43 |   page?: number;
 44 |   extensions?: string;
 45 | }
 46 | 
 47 | interface PolygonSearchArgs {
 48 |   polygon: string;
 49 |   keywords?: string;
 50 |   types?: string;
 51 |   offset?: number;
 52 |   page?: number;
 53 |   extensions?: string;
 54 | }
 55 | 
 56 | interface IDSearchArgs {
 57 |   id: string;
 58 | }
 59 | 
 60 | interface AOIBoundaryQueryArgs {
 61 |   id: string;
 62 | }
 63 | 
 64 | type SearchArgs =
 65 |   | CoordinateConvertArgs
 66 |   | KeywordSearchArgs
 67 |   | AroundSearchArgs
 68 |   | PolygonSearchArgs
 69 |   | IDSearchArgs
 70 |   | AOIBoundaryQueryArgs;
 71 | 
 72 | const isValidSearchArgs = (args: any): args is SearchArgs => {
 73 |   if (typeof args !== 'object' || args === null) {
 74 |     return false;
 75 |   }
 76 | 
 77 |   if ('locations' in args) {
 78 |     return (
 79 |       typeof args.locations === 'string' &&
 80 |       (args.coordsys === undefined || typeof args.coordsys === 'string') &&
 81 |       (args.output === undefined || typeof args.output === 'string')
 82 |     );
 83 |   } else if ('keywords' in args) {
 84 |     return typeof args.keywords === 'string';
 85 |   } else if ('location' in args) {
 86 |     return typeof args.location === 'string';
 87 |   } else if ('polygon' in args) {
 88 |     return typeof args.polygon === 'string';
 89 |   } else if ('id' in args) {
 90 |     return typeof args.id === 'string';
 91 |   }
 92 | 
 93 |   return false;
 94 | };
 95 | 
 96 | class AmapCoordinateServer {
 97 |   private server: Server;
 98 | 
 99 |   constructor() {
100 |     this.server = new Server(
101 |       {
102 |         name: 'amap-coordinate-server',
103 |         version: '0.1.0',
104 |       },
105 |       {
106 |         capabilities: {
107 |           resources: {},
108 |           tools: {},
109 |         },
110 |       }
111 |     );
112 | 
113 |     this.setupToolHandlers();
114 | 
115 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
116 |     process.on('SIGINT', async () => {
117 |       await this.server.close();
118 |       process.exit(0);
119 |     });
120 |   }
121 | 
122 |   private setupToolHandlers() {
123 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
124 |       tools: [
125 |         {
126 |           name: 'coordinate_convert',
127 |           description: 'Convert coordinates using AMap API',
128 |           inputSchema: {
129 |             type: 'object',
130 |             properties: {
131 |               locations: {
132 |                 type: 'string',
133 |                 description:
134 |                   'Coordinates to convert (longitude,latitude|longitude,latitude)',
135 |               },
136 |               coordsys: {
137 |                 type: 'string',
138 |                 description: 'Original coordinate system (gps, mapbar, baidu, autonavi)',
139 |                 enum: ['gps', 'mapbar', 'baidu', 'autonavi'],
140 |               },
141 |               output: {
142 |                 type: 'string',
143 |                 description: 'Output format (JSON, XML)',
144 |                 enum: ['JSON', 'XML'],
145 |               },
146 |             },
147 |             required: ['locations'],
148 |           },
149 |         },
150 |         {
151 |           name: 'keyword_search',
152 |           description: 'Search for places by keyword using AMap API',
153 |           inputSchema: {
154 |             type: 'object',
155 |             properties: {
156 |               keywords: {
157 |                 type: 'string',
158 |                 description: 'Keywords for the search',
159 |               },
160 |               types: {
161 |                 type: 'string',
162 |                 description: 'POI types',
163 |               },
164 |               city: {
165 |                 type: 'string',
166 |                 description: 'City to search in',
167 |               },
168 |               citylimit: {
169 |                 type: 'boolean',
170 |                 description: 'Limit results to the specified city',
171 |               },
172 |               children: {
173 |                 type: 'number',
174 |                 description: 'Whether to show child POIs',
175 |               },
176 |               offset: {
177 |                 type: 'number',
178 |                 description: 'Number of results per page',
179 |               },
180 |               page: {
181 |                 type: 'number',
182 |                 description: 'Page number',
183 |               },
184 |               extensions: {
185 |                 type: 'string',
186 |                 description: 'Return extensions',
187 |               },
188 |             },
189 |             required: ['keywords'],
190 |           },
191 |         },
192 |         {
193 |           name: 'around_search',
194 |           description: 'Search for places around a location using AMap API',
195 |           inputSchema: {
196 |             type: 'object',
197 |             properties: {
198 |               location: {
199 |                 type: 'string',
200 |                 description: 'Location to search around (longitude,latitude)',
201 |               },
202 |               keywords: {
203 |                 type: 'string',
204 |                 description: 'Keywords for the search',
205 |               },
206 |               types: {
207 |                 type: 'string',
208 |                 description: 'POI types',
209 |               },
210 |               city: {
211 |                 type: 'string',
212 |                 description: 'City to search in',
213 |               },
214 |               radius: {
215 |                 type: 'number',
216 |                 description: 'Search radius',
217 |               },
218 |               sortrule: {
219 |                 type: 'string',
220 |                 description: 'Sort rule',
221 |               },
222 |               offset: {
223 |                 type: 'number',
224 |                 description: 'Number of results per page',
225 |               },
226 |               page: {
227 |                 type: 'number',
228 |                 description: 'Page number',
229 |               },
230 |               extensions: {
231 |                 type: 'string',
232 |                 description: 'Return extensions',
233 |               },
234 |             },
235 |             required: ['location'],
236 |           },
237 |         },
238 |         {
239 |           name: 'polygon_search',
240 |           description: 'Search for places within a polygon using AMap API',
241 |           inputSchema: {
242 |             type: 'object',
243 |             properties: {
244 |               polygon: {
245 |                 type: 'string',
246 |                 description:
247 |                   'Polygon to search within (longitude,latitude|longitude,latitude|...)',
248 |               },
249 |               keywords: {
250 |                 type: 'string',
251 |                 description: 'Keywords for the search',
252 |               },
253 |               types: {
254 |                 type: 'string',
255 |                 description: 'POI types',
256 |               },
257 |               offset: {
258 |                 type: 'number',
259 |                 description: 'Number of results per page',
260 |               },
261 |               page: {
262 |                 type: 'number',
263 |                 description: 'Page number',
264 |               },
265 |               extensions: {
266 |                 type: 'string',
267 |                 description: 'Return extensions',
268 |               },
269 |             },
270 |             required: ['polygon'],
271 |           },
272 |         },
273 |         {
274 |           name: 'id_search',
275 |           description: 'Search for a place by ID using AMap API',
276 |           inputSchema: {
277 |             type: 'object',
278 |             properties: {
279 |               id: {
280 |                 type: 'string',
281 |                 description: 'ID of the place to search for',
282 |               },
283 |             },
284 |             required: ['id'],
285 |           },
286 |         },
287 |         {
288 |           name: 'aoi_boundary_query',
289 |           description: 'Query AOI boundary using AMap API',
290 |           inputSchema: {
291 |             type: 'object',
292 |             properties: {
293 |               id: {
294 |                 type: 'string',
295 |                 description: 'ID of the AOI to query',
296 |               },
297 |             },
298 |             required: ['id'],
299 |           },
300 |         },
301 |       ],
302 |     }));
303 | 
304 |     this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
305 |       const { name, arguments: args } = request.params;
306 | 
307 |       switch (name) {
308 |         case 'coordinate_convert':
309 |           if (!isValidSearchArgs(args)) {
310 |             throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
311 |           }
312 | 
313 |           const { locations, coordsys, output } = args as CoordinateConvertArgs;
314 | 
315 |           try {
316 |             const response = await axios.get(
317 |               'https://restapi.amap.com/v3/assistant/coordinate/convert',
318 |               {
319 |                 params: {
320 |                   locations: locations,
321 |                   coordsys: coordsys,
322 |                   output: output,
323 |                   key: API_KEY,
324 |                 },
325 |               }
326 |             );
327 | 
328 |           return {
329 |             content: [
330 |               {
331 |                 type: 'text',
332 |                 text: JSON.stringify(response.data, null, 2),
333 |               },
334 |             ],
335 |           };
336 |         } catch (error: any) {
337 |           console.error(error);
338 |           return {
339 |             content: [
340 |               {
341 |                 type: 'text',
342 |                 text: `AMap API error: ${error.message}`,
343 |               },
344 |             ],
345 |             isError: true,
346 |           };
347 |         }
348 |         break;
349 |       case 'keyword_search':
350 |         if (!isValidSearchArgs(args)) {
351 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
352 |         }
353 | 
354 |         const { keywords: keywords_ks, types: types_ks, city: city_ks, citylimit: citylimit_ks, children: children_ks, offset: offset_ks, page: page_ks, extensions: extensions_ks } =
355 |           args as KeywordSearchArgs;
356 | 
357 |         try {
358 |           const response = await axios.get(
359 |             'https://restapi.amap.com/v3/place/text',
360 |             {
361 |               params: {
362 |                 key: API_KEY,
363 |                 keywords: keywords_ks,
364 |                 types: types_ks,
365 |                 city: city_ks,
366 |                 citylimit: citylimit_ks,
367 |                 children: children_ks,
368 |                 offset: offset_ks,
369 |                 page: page_ks,
370 |                 extensions: extensions_ks,
371 |               },
372 |             }
373 |           );
374 | 
375 |           return {
376 |             content: [
377 |               {
378 |                 type: 'text',
379 |                 text: JSON.stringify(response.data, null, 2),
380 |               },
381 |             ],
382 |           };
383 |         } catch (error: any) {
384 |           console.error(error);
385 |           return {
386 |             content: [
387 |               {
388 |                 type: 'text',
389 |                 text: `AMap API error: ${error.message}`,
390 |               },
391 |             ],
392 |             isError: true,
393 |           };
394 |         }
395 |         break;
396 |       case 'around_search':
397 |         if (!isValidSearchArgs(args)) {
398 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
399 |         }
400 | 
401 |         const { location, keywords: keywords_as, types: types_as, city: city_as, radius: radius_as, sortrule: sortrule_as, offset: offset_as, page: page_as, extensions: extensions_as } =
402 |           args as AroundSearchArgs;
403 | 
404 |           try {
405 |             const response = await axios.get(
406 |               'https://restapi.amap.com/v3/place/around',
407 |               {
408 |                 params: {
409 |                   key: API_KEY,
410 |                   location: location,
411 |                   keywords: keywords_as,
412 |                   types: types_as,
413 |                   city: city_as,
414 |                   radius: radius_as,
415 |                   sortrule: sortrule_as,
416 |                   offset: offset_as,
417 |                   page: page_as,
418 |                   extensions: extensions_as,
419 |                 },
420 |               }
421 |             );
422 | 
423 |           return {
424 |             content: [
425 |               {
426 |                 type: 'text',
427 |                 text: JSON.stringify(response.data, null, 2),
428 |               },
429 |             ],
430 |           };
431 |         } catch (error: any) {
432 |           console.error(error);
433 |           return {
434 |             content: [
435 |               {
436 |                 type: 'text',
437 |                 text: `AMap API error: ${error.message}`,
438 |               },
439 |             ],
440 |             isError: true,
441 |           };
442 |         }
443 |         break;
444 |       case 'polygon_search':
445 |         if (!isValidSearchArgs(args)) {
446 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
447 |         }
448 | 
449 |         const { polygon, keywords: keywords_ps, types: types_ps, offset: offset_ps, page: page_ps, extensions: extensions_ps } =
450 |           args as PolygonSearchArgs;
451 | 
452 |         try {
453 |           const response = await axios.get(
454 |             'https://restapi.amap.com/v3/place/polygon',
455 |             {
456 |               params: {
457 |                 key: API_KEY,
458 |                 polygon: polygon,
459 |                 keywords: keywords_ps,
460 |                 types: types_ps,
461 |                 offset: offset_ps,
462 |                 page: page_ps,
463 |                 extensions: extensions_ps,
464 |               },
465 |             }
466 |           );
467 | 
468 |           return {
469 |             content: [
470 |               {
471 |                 type: 'text',
472 |                 text: JSON.stringify(response.data, null, 2),
473 |               },
474 |             ],
475 |           };
476 |         } catch (error: any) {
477 |           console.error(error);
478 |           return {
479 |             content: [
480 |               {
481 |                 type: 'text',
482 |                 text: `AMap API error: ${error.message}`,
483 |               },
484 |             ],
485 |             isError: true,
486 |           };
487 |         }
488 |         break;
489 |       case 'id_search':
490 |         if (!isValidSearchArgs(args)) {
491 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
492 |         }
493 | 
494 |         const { id: id_is } = args as IDSearchArgs;
495 | 
496 |         try {
497 |           const response = await axios.get(
498 |             'https://restapi.amap.com/v3/place/detail',
499 |             {
500 |               params: {
501 |                 key: API_KEY,
502 |                 id: id_is,
503 |               },
504 |             }
505 |           );
506 | 
507 |           return {
508 |             content: [
509 |               {
510 |                 type: 'text',
511 |                 text: JSON.stringify(response.data, null, 2),
512 |               },
513 |             ],
514 |           };
515 |         } catch (error: any) {
516 |           console.error(error);
517 |           return {
518 |             content: [
519 |               {
520 |                 type: 'text',
521 |                 text: `AMap API error: ${error.message}`,
522 |               },
523 |             ],
524 |             isError: true,
525 |           };
526 |         }
527 |         break;
528 |       case 'aoi_boundary_query':
529 |         if (!isValidSearchArgs(args)) {
530 |           throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
531 |         }
532 | 
533 |         const { id: id_abq } = args as AOIBoundaryQueryArgs;
534 | 
535 |         try {
536 |           const response = await axios.get(
537 |             'https://restapi.amap.com/v5/aoi/polyline',
538 |             {
539 |               params: {
540 |                 key: API_KEY,
541 |                 id: id_abq,
542 |               },
543 |             }
544 |           );
545 | 
546 |           return {
547 |             content: [
548 |               {
549 |                 type: 'text',
550 |                 text: JSON.stringify(response.data, null, 2),
551 |               },
552 |             ],
553 |           };
554 |         } catch (error: any) {
555 |           console.error(error);
556 |           return {
557 |             content: [
558 |               {
559 |                 type: 'text',
560 |                 text: `AMap API error: ${error.message}`,
561 |               },
562 |             ],
563 |             isError: true,
564 |           };
565 |         }
566 |         break;
567 |       default:
568 |         throw new McpError(
569 |           ErrorCode.MethodNotFound,
570 |           `Unknown tool: ${request.params.name}`
571 |         );
572 |       }
573 |     });
574 |   }
575 | 
576 |   async run() {
577 |     const transport = new StdioServerTransport();
578 |     await this.server.connect(transport);
579 |     console.error('AMap Coordinate MCP server running on stdio');
580 |   }
581 | }
582 | 
583 | const server = new AmapCoordinateServer();
584 | server.run().catch(console.error);
585 | 
```