#
tokens: 7065/50000 10/10 files
lines: off (toggle) GitHub
raw markdown copy
# 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:
--------------------------------------------------------------------------------

```
node_modules/
build/
*.log
.env*
```

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

```
node_modules/
build/
*.log
.env*
```

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

```markdown
# amap-route-server MCP Server

A Model Context Protocol server for AMap Route Planning.

This server provides tools to calculate routes using the AMap API for different transportation modes.

## Features

### Tools

-   `walking_route`: Calculates a walking route between two points.
-   `transit_route`: Calculates a transit route between two points.
-   `driving_route`: Calculates a driving route between two points.
-   `bicycling_route`: Calculates a bicycling route between two points.
-   `distance`: Calculates the distance between two points.

## Development

Install dependencies:

```bash
npm install
```

Build the server:

```bash
npm run build
```

For development with auto-rebuild:

```bash
npm run watch
```

## Installation

To use with Claude Desktop, add the server config:

On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`

On Windows: `%APPDATA%/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "amap-route-server": {
      "command": "/path/to/amap-route-server/build/index.js",
      "env": {
        "AMAP_API_KEY": "YOUR_AMAP_API_KEY"
      }
    }
  }
}
```

**Note:** You need to obtain an AMap API key and set it as the `AMAP_API_KEY` environment variable.

### Debugging

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:

```bash
npm run inspector
```

The Inspector will provide a URL to access debugging tools in your browser.

```

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

```markdown
# amap-coordinate-server MCP Server

A Model Context Protocol server for AMap Coordinate Conversion and Place Search.

This server provides tools to convert coordinates between different systems and search for places using the AMap API.

## Features

### Tools

-   `coordinate_convert`: Converts coordinates between different coordinate systems (GPS, mapbar, baidu, autonavi).
-   `keyword_search`: Searches for places by keyword.
-   `around_search`: Searches for places around a specific location.
-   `polygon_search`: Searches for places within a given polygon.
-   `id_search`: Searches for a place by its ID.
-   `aoi_boundary_query`: Queries the boundary of an Area of Interest (AOI).

## Development

Install dependencies:

```bash
npm install
```

Build the server:

```bash
npm run build
```

For development with auto-rebuild:

```bash
npm run watch
```

## Installation

To use with Claude Desktop, add the server config:

On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`

On Windows: `%APPDATA%/Claude/claude_desktop_config.json`

```json
{
  "mcpServers": {
    "amap-coordinate-server": {
      "command": "/path/to/amap-coordinate-server/build/index.js",
      "env": {
        "AMAP_API_KEY": "YOUR_AMAP_API_KEY"
      }
    }
  }
}
```

**Note:** You need to obtain an AMap API key and set it as the `AMAP_API_KEY` environment variable.

### Debugging

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:

```bash
npm run inspector
```

The Inspector will provide a URL to access debugging tools in your browser.

```

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

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

```

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

```json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "outDir": "./build",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

```

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

```json
{
  "name": "GAODENEW",
  "version": "0.1.0",
  "description": "CHINA!",
  "private": true,
  "type": "module",
  "bin": {
    "GAODENEW": "./build/index.js"
  },
  "files": [
    "build"
  ],
  "scripts": {
    "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
    "prepare": "npm run build",
    "watch": "tsc --watch",
    "inspector": "npx @modelcontextprotocol/inspector build/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "0.6.0",
    "node-fetch": "^3.3.2"
  },
  "devDependencies": {
    "@types/node": "^20.11.24",
    "typescript": "^5.3.3"
  }
}

```

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

```json
{
  "name": "amap-coordinate-server",
  "version": "0.1.0",
  "description": "A Model Context Protocol server",
  "private": true,
  "type": "module",
  "bin": {
    "amap-coordinate-server": "build/index.js"
  },
  "files": [
    "build"
  ],
  "scripts": {
    "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
    "prepare": "npm run build",
    "watch": "tsc --watch",
    "inspector": "npx @modelcontextprotocol/inspector build/index.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^0.6.0",
    "axios": "^1.8.4"
  },
  "devDependencies": {
    "@types/node": "^20.11.24",
    "typescript": "^5.3.3"
  },
  "main": "index.js",
  "keywords": [],
  "author": "",
  "license": "ISC"
}

```

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

```typescript
#!/usr/bin/env node

/**
 * This is a template MCP server that implements a simple notes system.
 * It demonstrates core MCP concepts like resources and tools by allowing:
 * - Listing notes as resources
 * - Reading individual notes
 * - Creating new notes via a tool
 * - Summarizing all notes via a prompt
 */

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListResourcesRequestSchema,
  ListToolsRequestSchema,
  ReadResourceRequestSchema,
  ListPromptsRequestSchema,
  GetPromptRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fetch from 'node-fetch';

/**
 * Type alias for a note object.
 */
type Note = { title: string, content: string };

/**
 * Simple in-memory storage for notes.
 * In a real implementation, this would likely be backed by a database.
 */
const notes: { [id: string]: Note } = {
  "1": { title: "First Note", content: "This is note 1" },
  "2": { title: "Second Note", content: "This is note 2" }
};

/**
 * Create an MCP server with capabilities for resources (to list/read notes),
 * tools (to create new notes), and prompts (to summarize notes).
 */
const server = new Server(
  {
    name: "amap-route-server",
    version: "0.1.0",
  },
  {
    capabilities: {
      resources: {},
      tools: {},
      prompts: {},
    },
  }
);

/**
 * Handler for listing available notes as resources.
 * Each note is exposed as a resource with:
 * - A note:// URI scheme
 * - Plain text MIME type
 * - Human readable name and description (now including the note title)
 */
server.setRequestHandler(ListResourcesRequestSchema, async () => {
  return {
    resources: Object.entries(notes).map(([id, note]) => ({
      uri: `note:///${id}`,
      mimeType: "text/plain",
      name: note.title,
      description: `A text note: ${note.title}`
    }))
  };
});

/**
 * Handler for reading the contents of a specific note.
 * Takes a note:// URI and returns the note content as plain text.
 */
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  const url = new URL(request.params.uri);
  const id = url.pathname.replace(/^\//, '');
  const note = notes[id];

  if (!note) {
    throw new Error(`Note ${id} not found`);
  }

  return {
    contents: [{
      uri: request.params.uri,
      mimeType: "text/plain",
      text: note.content
    }]
  };
});

/**
 * Handler that lists available tools.
 */
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "walking_route",
        description: "Get walking route",
        inputSchema: {
          type: "object",
          properties: {
            origin: {
              type: "string",
              description: "Origin longitude and latitude"
            },
            destination: {
              type: "string",
              description: "Destination longitude and latitude"
            }
          },
          required: ["origin", "destination"]
        }
      },
      {
        name: "transit_route",
        description: "Get transit route",
        inputSchema: {
          type: "object",
          properties: {
            origin: {
              type: "string",
              description: "Origin longitude and latitude"
            },
            destination: {
              type: "string",
              description: "Destination longitude and latitude"
            },
            city: {
              type: "string",
              description: "City name"
            }
          },
          required: ["origin", "destination", "city"]
        }
      },
      {
        name: "driving_route",
        description: "Get driving route",
        inputSchema: {
          type: "object",
          properties: {
            origin: {
              type: "string",
              description: "Origin longitude and latitude"
            },
            destination: {
              type: "string",
              description: "Destination longitude and latitude"
            }
          },
          required: ["origin", "destination"]
        }
      },
      {
        name: "bicycling_route",
        description: "Get bicycling route",
        inputSchema: {
          type: "object",
          properties: {
            origin: {
              type: "string",
              description: "Origin longitude and latitude"
            },
            destination: {
              type: "string",
              description: "Destination longitude and latitude"
            }
          },
          required: ["origin", "destination"]
        }
      },
      {
        name: "distance",
        description: "Get distance between two points",
        inputSchema: {
          type: "object",
          properties: {
            origins: {
              type: "string",
              description: "Origin longitude and latitude, separated by |"
            },
            destination: {
              type: "string",
              description: "Destination longitude and latitude"
            }
          },
          required: ["origins", "destination"]
        }
      }
    ]
  };
});

/**
 * Handler for the create_note tool.
 * Creates a new note with the provided title and content, and returns success message.
 */
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const apiKey = "ae4775b98c50d997cab4bcd6c769bf9b";
  switch (request.params.name) {
    case "walking_route": {
      const origin = String(request.params.arguments?.origin);
      const destination = String(request.params.arguments?.destination);
      if (!origin || !destination) {
        throw new Error("Origin and destination are required");
      }
      const url = `https://restapi.amap.com/v3/direction/walking?origin=${origin}&destination=${destination}&key=${apiKey}`;
      const response = await fetch(url);
      const data = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(data)
        }]
      };
    }
    case "transit_route": {
      const origin = String(request.params.arguments?.origin);
      const destination = String(request.params.arguments?.destination);
      const city = String(request.params.arguments?.city);
      if (!origin || !destination || !city) {
        throw new Error("Origin, destination and city are required");
      }
      const url = `https://restapi.amap.com/v3/direction/transit/integrated?origin=${origin}&destination=${destination}&city=${city}&key=${apiKey}`;
      const response = await fetch(url);
      const data = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(data)
        }]
      };
    }
    case "driving_route": {
      const origin = String(request.params.arguments?.origin);
      const destination = String(request.params.arguments?.destination);
      if (!origin || !destination) {
        throw new Error("Origin and destination are required");
      }
      const url = `https://restapi.amap.com/v3/direction/driving?origin=${origin}&destination=${destination}&key=${apiKey}`;
      const response = await fetch(url);
      const data = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(data)
        }]
      };
    }
    case "bicycling_route": {
      const origin = String(request.params.arguments?.origin);
      const destination = String(request.params.arguments?.destination);
      if (!origin || !destination) {
        throw new Error("Origin and destination are required");
      }
      const url = `https://restapi.amap.com/v4/direction/bicycling?origin=${origin}&destination=${destination}&key=${apiKey}`;
      const response = await fetch(url);
      const data = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(data)
        }]
      };
    }
    case "distance": {
      const origins = String(request.params.arguments?.origins);
      const destination = String(request.params.arguments?.destination);
      if (!origins || !destination) {
        throw new Error("Origins and destination are required");
      }
      const url = `https://restapi.amap.com/v3/distance?origins=${origins}&destination=${destination}&key=${apiKey}`;
      const response = await fetch(url);
      const data = await response.json();
      return {
        content: [{
          type: "text",
          text: JSON.stringify(data)
        }]
      };
    }
    default:
      throw new Error("Unknown tool");
  }
});

/**
 * Handler that lists available prompts.
 * Exposes a single "summarize_notes" prompt that summarizes all notes.
 */
server.setRequestHandler(ListPromptsRequestSchema, async () => {
  return {
    prompts: [
      {
        name: "summarize_notes",
        description: "Summarize all notes",
      }
    ]
  };
});

/**
 * Handler for the summarize_notes prompt.
 * Returns a prompt that requests summarization of all notes, with the notes' contents embedded as resources.
 */
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
  if (request.params.name !== "summarize_notes") {
    throw new Error("Unknown prompt");
  }

  const embeddedNotes = Object.entries(notes).map(([id, note]) => ({
    type: "resource" as const,
    resource: {
      uri: `note:///${id}`,
      mimeType: "text/plain",
      text: note.content
    }
  }));

  return {
    messages: [
      {
        role: "user",
        content: {
          type: "text",
          text: "Please summarize the following notes:"
        }
      },
      ...embeddedNotes.map(note => ({
        role: "user" as const,
        content: note
      })),
      {
        role: "user",
        content: {
          type: "text",
          text: "Provide a concise summary of all the notes above."
        }
      }
    ]
  };
});

/**
 * Start the server using stdio transport.
 * This allows the server to communicate via standard input/output streams.
 */
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.log("Amap route server started");
}

main().catch((error) => {
  console.error("Server error:", error);
  process.exit(1);
});

```

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

```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ErrorCode,
  ListToolsRequestSchema,
  McpError,
} from '@modelcontextprotocol/sdk/types.js';
import axios from 'axios';

const API_KEY = process.env.AMAP_API_KEY;

if (!API_KEY) {
  throw new Error('AMAP_API_KEY environment variable is required');
}

interface CoordinateConvertArgs {
  locations: string;
  coordsys?: string;
  output?: string;
}

interface KeywordSearchArgs {
  keywords: string;
  types?: string;
  city?: string;
  citylimit?: boolean;
  children?: number;
  offset?: number;
  page?: number;
  extensions?: string;
}

interface AroundSearchArgs {
  location: string;
  keywords?: string;
  types?: string;
  city?: string;
  radius?: number;
  sortrule?: string;
  offset?: number;
  page?: number;
  extensions?: string;
}

interface PolygonSearchArgs {
  polygon: string;
  keywords?: string;
  types?: string;
  offset?: number;
  page?: number;
  extensions?: string;
}

interface IDSearchArgs {
  id: string;
}

interface AOIBoundaryQueryArgs {
  id: string;
}

type SearchArgs =
  | CoordinateConvertArgs
  | KeywordSearchArgs
  | AroundSearchArgs
  | PolygonSearchArgs
  | IDSearchArgs
  | AOIBoundaryQueryArgs;

const isValidSearchArgs = (args: any): args is SearchArgs => {
  if (typeof args !== 'object' || args === null) {
    return false;
  }

  if ('locations' in args) {
    return (
      typeof args.locations === 'string' &&
      (args.coordsys === undefined || typeof args.coordsys === 'string') &&
      (args.output === undefined || typeof args.output === 'string')
    );
  } else if ('keywords' in args) {
    return typeof args.keywords === 'string';
  } else if ('location' in args) {
    return typeof args.location === 'string';
  } else if ('polygon' in args) {
    return typeof args.polygon === 'string';
  } else if ('id' in args) {
    return typeof args.id === 'string';
  }

  return false;
};

class AmapCoordinateServer {
  private server: Server;

  constructor() {
    this.server = new Server(
      {
        name: 'amap-coordinate-server',
        version: '0.1.0',
      },
      {
        capabilities: {
          resources: {},
          tools: {},
        },
      }
    );

    this.setupToolHandlers();

    this.server.onerror = (error) => console.error('[MCP Error]', error);
    process.on('SIGINT', async () => {
      await this.server.close();
      process.exit(0);
    });
  }

  private setupToolHandlers() {
    this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
      tools: [
        {
          name: 'coordinate_convert',
          description: 'Convert coordinates using AMap API',
          inputSchema: {
            type: 'object',
            properties: {
              locations: {
                type: 'string',
                description:
                  'Coordinates to convert (longitude,latitude|longitude,latitude)',
              },
              coordsys: {
                type: 'string',
                description: 'Original coordinate system (gps, mapbar, baidu, autonavi)',
                enum: ['gps', 'mapbar', 'baidu', 'autonavi'],
              },
              output: {
                type: 'string',
                description: 'Output format (JSON, XML)',
                enum: ['JSON', 'XML'],
              },
            },
            required: ['locations'],
          },
        },
        {
          name: 'keyword_search',
          description: 'Search for places by keyword using AMap API',
          inputSchema: {
            type: 'object',
            properties: {
              keywords: {
                type: 'string',
                description: 'Keywords for the search',
              },
              types: {
                type: 'string',
                description: 'POI types',
              },
              city: {
                type: 'string',
                description: 'City to search in',
              },
              citylimit: {
                type: 'boolean',
                description: 'Limit results to the specified city',
              },
              children: {
                type: 'number',
                description: 'Whether to show child POIs',
              },
              offset: {
                type: 'number',
                description: 'Number of results per page',
              },
              page: {
                type: 'number',
                description: 'Page number',
              },
              extensions: {
                type: 'string',
                description: 'Return extensions',
              },
            },
            required: ['keywords'],
          },
        },
        {
          name: 'around_search',
          description: 'Search for places around a location using AMap API',
          inputSchema: {
            type: 'object',
            properties: {
              location: {
                type: 'string',
                description: 'Location to search around (longitude,latitude)',
              },
              keywords: {
                type: 'string',
                description: 'Keywords for the search',
              },
              types: {
                type: 'string',
                description: 'POI types',
              },
              city: {
                type: 'string',
                description: 'City to search in',
              },
              radius: {
                type: 'number',
                description: 'Search radius',
              },
              sortrule: {
                type: 'string',
                description: 'Sort rule',
              },
              offset: {
                type: 'number',
                description: 'Number of results per page',
              },
              page: {
                type: 'number',
                description: 'Page number',
              },
              extensions: {
                type: 'string',
                description: 'Return extensions',
              },
            },
            required: ['location'],
          },
        },
        {
          name: 'polygon_search',
          description: 'Search for places within a polygon using AMap API',
          inputSchema: {
            type: 'object',
            properties: {
              polygon: {
                type: 'string',
                description:
                  'Polygon to search within (longitude,latitude|longitude,latitude|...)',
              },
              keywords: {
                type: 'string',
                description: 'Keywords for the search',
              },
              types: {
                type: 'string',
                description: 'POI types',
              },
              offset: {
                type: 'number',
                description: 'Number of results per page',
              },
              page: {
                type: 'number',
                description: 'Page number',
              },
              extensions: {
                type: 'string',
                description: 'Return extensions',
              },
            },
            required: ['polygon'],
          },
        },
        {
          name: 'id_search',
          description: 'Search for a place by ID using AMap API',
          inputSchema: {
            type: 'object',
            properties: {
              id: {
                type: 'string',
                description: 'ID of the place to search for',
              },
            },
            required: ['id'],
          },
        },
        {
          name: 'aoi_boundary_query',
          description: 'Query AOI boundary using AMap API',
          inputSchema: {
            type: 'object',
            properties: {
              id: {
                type: 'string',
                description: 'ID of the AOI to query',
              },
            },
            required: ['id'],
          },
        },
      ],
    }));

    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;

      switch (name) {
        case 'coordinate_convert':
          if (!isValidSearchArgs(args)) {
            throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
          }

          const { locations, coordsys, output } = args as CoordinateConvertArgs;

          try {
            const response = await axios.get(
              'https://restapi.amap.com/v3/assistant/coordinate/convert',
              {
                params: {
                  locations: locations,
                  coordsys: coordsys,
                  output: output,
                  key: API_KEY,
                },
              }
            );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          console.error(error);
          return {
            content: [
              {
                type: 'text',
                text: `AMap API error: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
        break;
      case 'keyword_search':
        if (!isValidSearchArgs(args)) {
          throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
        }

        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 } =
          args as KeywordSearchArgs;

        try {
          const response = await axios.get(
            'https://restapi.amap.com/v3/place/text',
            {
              params: {
                key: API_KEY,
                keywords: keywords_ks,
                types: types_ks,
                city: city_ks,
                citylimit: citylimit_ks,
                children: children_ks,
                offset: offset_ks,
                page: page_ks,
                extensions: extensions_ks,
              },
            }
          );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          console.error(error);
          return {
            content: [
              {
                type: 'text',
                text: `AMap API error: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
        break;
      case 'around_search':
        if (!isValidSearchArgs(args)) {
          throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
        }

        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 } =
          args as AroundSearchArgs;

          try {
            const response = await axios.get(
              'https://restapi.amap.com/v3/place/around',
              {
                params: {
                  key: API_KEY,
                  location: 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,
                },
              }
            );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          console.error(error);
          return {
            content: [
              {
                type: 'text',
                text: `AMap API error: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
        break;
      case 'polygon_search':
        if (!isValidSearchArgs(args)) {
          throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
        }

        const { polygon, keywords: keywords_ps, types: types_ps, offset: offset_ps, page: page_ps, extensions: extensions_ps } =
          args as PolygonSearchArgs;

        try {
          const response = await axios.get(
            'https://restapi.amap.com/v3/place/polygon',
            {
              params: {
                key: API_KEY,
                polygon: polygon,
                keywords: keywords_ps,
                types: types_ps,
                offset: offset_ps,
                page: page_ps,
                extensions: extensions_ps,
              },
            }
          );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          console.error(error);
          return {
            content: [
              {
                type: 'text',
                text: `AMap API error: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
        break;
      case 'id_search':
        if (!isValidSearchArgs(args)) {
          throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
        }

        const { id: id_is } = args as IDSearchArgs;

        try {
          const response = await axios.get(
            'https://restapi.amap.com/v3/place/detail',
            {
              params: {
                key: API_KEY,
                id: id_is,
              },
            }
          );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          console.error(error);
          return {
            content: [
              {
                type: 'text',
                text: `AMap API error: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
        break;
      case 'aoi_boundary_query':
        if (!isValidSearchArgs(args)) {
          throw new McpError(ErrorCode.InvalidParams, 'Invalid arguments');
        }

        const { id: id_abq } = args as AOIBoundaryQueryArgs;

        try {
          const response = await axios.get(
            'https://restapi.amap.com/v5/aoi/polyline',
            {
              params: {
                key: API_KEY,
                id: id_abq,
              },
            }
          );

          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify(response.data, null, 2),
              },
            ],
          };
        } catch (error: any) {
          console.error(error);
          return {
            content: [
              {
                type: 'text',
                text: `AMap API error: ${error.message}`,
              },
            ],
            isError: true,
          };
        }
        break;
      default:
        throw new McpError(
          ErrorCode.MethodNotFound,
          `Unknown tool: ${request.params.name}`
        );
      }
    });
  }

  async run() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error('AMap Coordinate MCP server running on stdio');
  }
}

const server = new AmapCoordinateServer();
server.run().catch(console.error);

```