---
title: 地图MCP协议
source: https://vjmap.com/guide/aimcp.html
---

# 地图MCP协议

  传统的 CAD 地图应用都是由人来操作的，用户需要学习复杂的 CAD 操作命令和地图管理流程，操作成本相对较高。如果能让 AI 来帮我们操作地图，是不是就非常方便？

  如果所有 CAD 地图应用都能做智能化改造，让 AI 能够理解和操作地图数据，每个人都拥有一个虚拟的"地图智能助理"，我们只需要聊天一样跟地图智能助理"聊天"，用自然语言提出我们的地图需求，智能助理会自动帮我们操作地图应用，实现我们的需求，这将大大提升人们在地图处理、CAD 图纸分析、空间数据管理等方面的工作效率和体验！

  `唯杰地图`基于 MCP 协议实现了 AI 代替人操作 CAD 地图应用这项技术，并应用到我们的唯杰地图引擎中，实现了唯杰地图系统的智能化改造。使用 MCP协议工具，天然地支持被 AI 识别和操控，包括地图浏览、CAD 图纸查询、空间数据提取、图形绘制等操作。同时还提供了一套前端 SDK，支持现有地图业务快速接入 AI、实现智能化，目前支持 Vue、React、Angular 等前端框架。

   由于是基于标准的 MCP 协议实现的，具备通用性和广泛的适用性，可以通过各种不同类型的 MCP Host 来控制地图应用，比如可以通过网页上的 AI 对话框来控制地图应用，也可以通过`Tace`、`Cursor` 等 IDE 工具，或者通过 `Dify`、`Coze` 等智能体平台来操控，甚至可以通过手机App、微信小程序等方式远程遥控你的地图应用。我们可以与 AI 对话，让 AI 帮我们操作各类地图应用，实现我们的地图相关需求。


## 唯杰地图后台服务MCP地址

官网唯杰地图服务MCP地址

```json
 "vjmapsvr": {
   "url": "https://vjmap.com/server/mcp?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M"
}
```

### MCP 服务使用说明

把本服务的图纸管理、查询、导出等能力，以 MCP 工具提供给 AI编辑器，如Trae、Qoder 、Cursor、Claude Desktop 等 AI 客户端。传输方式为 Streamable HTTP。

#### 如何指定工作区

连接时绑定（推荐）：

http://https://vjmap.com/server/mcp?workspace=share?token=xxxxxx

不配 workspace 就走默认工作区。调用时也可再传 workspace 覆盖 URL；要强制回默认工作区，传 workspace=__default__。

需要先列出工作区时，这个分类默认不加载，URL 要显式打开：

http://https://vjmap.com/server/mcp?tools=workspace?token=xxxxxx

再调用 cad_list_workspaces。

#### 怎么用

鉴权：请求头 Authorization: Bearer <token>，或头 token，或 URL?token=。用户图纸权限仍然生效。

接入示例：

{
  "mcpServers": {
    "vjmapsvr": {
      "url": "http://https://vjmap.com/server/mcp?workspace=share",
      "headers": {
        "Authorization": "Bearer <你的token>"
      }
    }
  }
}

只要查询和图纸列表时，可再加 ?tools=query,map。

默认加载：map、query、export、admin。

按需加载（配置或 URL 的 tools 里写分类/工具名才出现）：draw、geom、symbol、workspace。

写操作工具还要 enable_write: true。生产环境建议 disable_tools 排除 admin。



## 唯杰地图前端MCP地址

后端MCP地址只能调用后端图纸能力。前端MCP地址可以与页面相结合，对页面中的地图进行操作，如移动或加数据展示效果。

### 效果展示：

![chatmcp.gif](https://vjmap.com/blogimages/chatmcp.gif)

[唯杰地图云端管理平台](https://vjmap.com/app/cloud/#/) https://vjmap.com/app/cloud/#/

![image-20250803183709135](https://vjmap.com/blogimages/202508031837207.png)

![image-20250803180303071](https://vjmap.com/blogimages/202508031803174.png)


点击界面左上角的MCP地址，可查看此次会话的MCP地址

![image-20250803175643751](https://vjmap.com/blogimages/202508031756861.png)



**可复制当前会话的`MCP地址`  到其他`MCP客户端`如`cursor`、`trae`或`cherry studio`中对当前地图进行提问** 

如在`cursor`中通过MCP地址调用地图相关操作
![mcpcursor.gif](https://vjmap.com/blogimages/mcpcursor.gif)



### MCP架构原理与流程

唯杰地图MCP系统采用服务端-前端分离架构，通过MCP（Model Context Protocol）协议实现双向通信。系统支持服务端工具和前端工具的混合调用，实现复杂的地图操作和交互功能。


#### 整体架构

![image-20250803182907607](https://vjmap.com/blogimages/202508031829665.png)


### 后端MCP工具 

| 工具名称               | 分类    | 类型 | 工具描述                                                     | 主要参数                                                     |
| ---------------------- | ------- | ---- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **listmaps**           | map     | 后端 | 获取地图列表信息，支持获取所有地图或指定地图的版本信息       | `mapid`(地图ID)、`version`(版本号)、`mapIds`(地图ID数组)、`workspace`(工作区)、`pagination`(分页)、`curPage`(当前页)、`pageCount`(每页数量) |
| **createMap**          | drawing | 后端 | 新建地图工具，支持两种创建方式：1、通过fileid和mapid创建地图；2、通过组合成新地图API创建 | `createType`(创建类型)、`mapid`(地图ID)、`fileid`(文件ID)、`uploadname`(文件名)、`geom`(几何渲染)、`sourceMapid`(源地图ID)、`sourceVersion`(源版本)、`sourceClipbounds`(裁剪范围)、`fourParameter`(四参数)、`layers`(图层列表)、`workspace`(工作区) |
| **deletemap**          | delete  | 后端 | 删除地图功能，支持删除指定版本或所有版本的地图。重要：删除操作不可逆，请谨慎使用！ | `mapid`(地图ID)、`version`(版本号)、`retainVersionMaxCount`(保留版本数)、`workspace`(工作区) |
| **getMapImage**        | map     | 后端 | 根据范围和要显示的图层列表获取地图图像，返回二进制图片PNG格式。支持指定图层显示/隐藏，自动计算图片尺寸比例 | `mapid`(地图ID)、`version`(版本号)、`bounds`(范围)、`pictureWidth`(图片宽度)、`layerOn`(显示图层)、`layerOff`(隐藏图层)、`backgroundColor`(背景色)、`transparent`(透明背景)、`styleName`(样式名)、`workspace`(工作区)、`returnBase64`(返回base64) |
| **fullSearch**         | query   | 后端 | CAD图全文搜索文档，支持在CAD图纸中搜索文字内容、图层、块名称等信息 | `query`(搜索关键词)、`map_ver`(地图版本)、`workspace`(工作区)、`type`(文档类型)、`bounding_box`(范围)、`time_range`(时间范围)、`limit`(结果数量)、`offset`(偏移量)、`fields`(返回字段)、`facet`(聚合信息) |
| **queryFeatures**      | query   | 后端 | 查询地图实体，支持条件查询、矩形范围查询、点查询和表达式查询四种查询类型 | `mapid`(地图ID)、`version`(版本号)、`queryType`(查询类型)、`sql`(SQL语句)、`bounds`(范围)、`point`(点坐标)、`radius`(半径)、`expression`(表达式)、`workspace`(工作区) |
| **extractTable**       | query   | 后端 | 自动提取CAD图纸中的表格数据，支持指定坐标范围或全图提取。当需要查询图纸相关信息时，应优先调用此工具提取表格数据进行分析，可获取图纸中相关结构化数据信息 | `mapid`(地图ID)、`version`(版本号)、`bounds`(提取范围)、`workspace`(工作区) |
| **sqlDocHelper**       | query   | 后端 | 获取查询地图实体的SQL编写文档和表结构说明，为AI生成SQL语句提供参考 | 无参数                                                       |
| **createDwgDocHelper** | drawing | 后端 | 获取创建图文档的参数说明和实体类型定义，为AI生成图形实体JSON数组提供参考 | 无参数                                                       |

### 前端工具

| 工具名称                      | 分类    | 类型 | 工具描述                                                     | 主要参数                                                     |
| ----------------------------- | ------- | ---- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| **map_get_info**              | map     | 前端 | 获取当前地图的详细信息，包括缩放级别、中心点、旋转角度、倾斜角度、显示范围、地图参数、图层信息和工作区名称、缩略图地址等。返回的坐标为CAD坐标系统。 | 无参数                                                       |
| **map_open_or_switch**        | map     | 前端 | 打开或切换图功能 - 根据mapid和version参数打开指定的图。打开成功后会自动更新地图上下文数据到后台。 | `mapid`(地图ID)、`version`(版本号)、`isKeepOldLayers`(保留旧图层)、`isVectorStyle`(矢量样式)、`isSetCenter`(设置中心)、`isFitBounds`(适应范围)、`layeron`(开启图层)、`layeroff`(关闭图层)、`backcolor`(背景色) |
| **map_view_control**          | map     | 前端 | 地图视图控制工具 - 支持缩放、平移、旋转、俯仰、缩放至地图范围等操作。所有坐标参数使用CAD坐标(x,y) | `operation`(操作类型)、`zoom`(缩放级别)、`center`(中心点)、`bearing`(旋转角度)、`pitch`(俯仰角度)、`bounds`(范围)、`duration`(动画时长) |
| **map_execute_code**          | runcode | 前端 | 执行自定义JavaScript代码，用于复杂的地图操作和自定义功能实现(需要唯杰地图帮助文档MCP一起使用) | `code`(JavaScript代码)、`description`(代码描述)              |
| **map_draw_geojson**          | draw    | 前端 | 根据GeoJSON数据绘制要素，支持所有标准GeoJSON几何类型。坐标使用CAD坐标系，样式属性在properties中配置 | `geojsonData`(GeoJSON数据，包含几何对象和样式属性)           |
| **map_delete_drawn_features** | draw    | 前端 | 删除绘制的要素，支持删除指定实例或清空所有绘制图层           | `instanceId`(实例ID)、`clearAll`(清空所有)                   |
| **map_create_markers**        | draw    | 前端 | 根据GeoJSON数据创建一个或多个标记，每个标记的样式配置从其properties中读取，支持自定义样式、拖拽、弹窗等功能 | `geojsonData`(GeoJSON数据，包含Point几何和标记配置属性)      |
| **map_delete_markers**        | draw    | 前端 | 删除地图上的标记，支持删除指定标记或清空所有标记             | `markerId`(标记ID)、`clearAll`(清空所有)                     |


 **用户可通过SDK自定义业务方面的MCP工具**

### MCP URL地址组成

VJMap MCP系统的URL地址支持工具过滤功能，可以通过URL参数来控制可用的工具分类和具体工具。

#### URL格式

```
/ai/mcp?sessionId={sessionId}&include_categories={categories}&exclude_categories={categories}&include_tools={tools}&exclude_tools={tools}&token={token}
```

官方默认mcp地址为

```
https://vjmap.com/server/ai/mcp?sessionId={前端每次会话的sessionID}&include_categories=query,map,draw,custom&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M
```

如果只需要后端MCP工具，无需与前端交互sessionId参数可不填写。如
```
https://vjmap.com/server/ai/mcp?include_categories=query,map&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M
```

#### 参数说明

| 参数名               | 类型   | 必填 | 描述                                   | 示例值                                    |
| -------------------- | ------ | ---- | -------------------------------------- | ----------------------------------------- |
| `sessionId`          | string | 是   | 会话ID，用于标识当前会话               | `session_123456`                          |
| `token`              | string | 是   | 访问令牌，用于身份验证                 | `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` |
| `include_categories` | string | 否   | 包含的工具分类，多个分类用逗号分隔     | `query,map,drawing`                       |
| `exclude_categories` | string | 否   | 排除的工具分类，多个分类用逗号分隔     | `delete,utility`                          |
| `include_tools`      | string | 否   | 包含的具体工具名称，多个工具用逗号分隔 | `listmaps,fullSearch`                     |
| `exclude_tools`      | string | 否   | 排除的具体工具名称，多个工具用逗号分隔 | `deletemap`                               |

#### 工具分类

系统支持以下工具分类：

| 分类名称       | 分类值    | 描述               | 包含的工具                                                   |
| -------------- | --------- | ------------------ | ------------------------------------------------------------ |
| 地图管理       | `map`     | 地图的基本CRUD操作 | `listmaps`, `getMapImage`, `map_get_info`, `map_open_or_switch`, `map_view_control` |
| 数据查询       | `query`   | 数据查询和搜索相关 | `fullSearch`, `queryFeatures`, `extractTable`, `sqlDocHelper` |
| 图形处理       | `drawing` | 图形创建和处理相关 | `createMap`, `createDwgDocHelper`, `map_draw_geojson`, `map_create_markers` |
| 删除工具       | `delete`  | 删除地图相关       | `deletemap`                                                  |
| 绘图工具       | `draw`    | 前端绘图相关       | `map_draw_geojson`, `map_delete_drawn_features`, `map_create_markers`, `map_delete_markers` |
| 运行代码       | `runcode` | 代码执行相关       | `map_execute_code`                                           |
| 前端自定义分类 | `custom`  | 前端自定义分类     |                                                              |

#### 使用示例

##### 示例1：只包含查询和地图工具
```
/ai/mcp?sessionId=session_123456&include_categories=query,map&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**说明：** 只启用查询类工具（`fullSearch`, `queryFeatures`, `extractTable`, `sqlDocHelper`）和地图类工具（`listmaps`, `getMapImage`, `map_get_info`, `map_open_or_switch`, `map_view_control`）

##### 示例2：排除删除工具
```
/ai/mcp?sessionId=session_123456&exclude_categories=delete&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**说明：** 启用除删除类工具外的所有工具，确保用户无法执行删除操作

##### 示例3：只包含特定工具
```
/ai/mcp?sessionId=session_123456&include_tools=listmaps,fullSearch,map_get_info&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**说明：** 只启用三个特定工具：`listmaps`（获取地图列表）、`fullSearch`（全文搜索）、`map_get_info`（获取地图信息）

##### 示例4：排除特定工具
```
/ai/mcp?sessionId=session_123456&exclude_tools=deletemap,map_execute_code&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**说明：** 启用所有工具，但排除`deletemap`（删除地图）和`map_execute_code`（执行代码）这两个可能有安全风险的工具

##### 示例5：组合使用包含和排除
```
/ai/mcp?sessionId=session_123456&include_categories=query,map&exclude_tools=deletemap&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```
**说明：** 只启用查询和地图类工具，但进一步排除`deletemap`工具，提供更精细的控制

#### 注意事项

1. **优先级规则：** `include_tools` 和 `exclude_tools` 的优先级高于 `include_categories` 和 `exclude_categories`
2. **参数冲突：** 如果同一个工具既在 `include_tools` 中又在 `exclude_tools` 中，`exclude_tools` 优先
3. **空值处理：** 如果某个参数为空或未提供，系统会使用默认行为（启用所有工具）
4. **安全性：** 建议在生产环境中使用 `exclude_categories=delete` 或 `exclude_tools=deletemap` 来防止意外删除操作
5. **URL编码：** 如果参数值包含特殊字符，请进行URL编码

在`cursor`中加入MCP地址进行问答，效果如下
![image-20250803191926787](https://vjmap.com/blogimages/202508031919853.png)

```json
{
  "mcpServers": {
    "vjmap": {
      "url": "https://vjmap.com/server/ai/mcp?include_categories=query,map&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M"
    }
  }
}
```

如果需要与前端交互时，可在AI对话框中MCP工具中复制MCP地址。

![image-20250803192608314](https://vjmap.com/blogimages/202508031926432.png)

```json
{
  "mcpServers": {
    "vjmap": {
      "url": "https://vjmap.com/server/ai/mcp?sessionId=session-6323558e&include_categories=query,map,draw,custom&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MSwiVXNlcm5hbWUiOiJyb290MSIsIk5pY2tOYW1lIjoicm9vdDEiLCJBdXRob3JpdHlJZCI6InJvb3QiLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjoxOTQyMzg5NTc0LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTYyNzAyODU3NH0.l1pP9FXu6ARDaaa-6ma0lp7ftbIk2t6rgmSmTqXry10"
    }
  }
}
```
注：每次会话的sessionId是不同的，上面的地址应该根据当前的会话来生成

### MCP 前端SDK及以自定义工具示例

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>vjmap demo</title>
    <link rel="stylesheet" type="text/css" href="https://vjmap.com/server/_demo/js/vjmap/vjmap.min.css">
    <script type="text/javascript" src="https://vjmap.com/server/_demo/js/vjmap/vjmap.min.js"></script>
</head>

<body style=" margin: 0;overflow: hidden;background-color:white;font-size: 16px">
    <div id="map" style="left:0;right:0;top:0;bottom:0;position: absolute;z-index: 0;"></div>
</body>
<script>
    (async () => {
        document.body.style.background = "#022B4F"; // 背景色改为深色
        const env = {
            serviceUrl: "https://vjmap.com/server/api/v1",
            accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M",
            exampleMapId: "sys_zp"
        };
        let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
        // 打开地图
        let res = await svc.openMap({
            mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在，可上传新图形新建ID)
            mapopenway: vjmap.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
            style: vjmap.openMapDarkStyle() // div为深色背景颜色时，这里也传深色背景样式
        })
        if (res.error) {
            message.error(res.error)
        }
        // 获取地图的范围
        let mapExtent = vjmap.GeoBounds.fromString(res.bounds);
        // 建立坐标系
        let prj = new vjmap.GeoProjection(mapExtent);

        // 新建地图对象
        let map = new vjmap.Map({
            container: 'map', // container ID
            style: svc.rasterStyle(), // 栅格瓦片样式
            center: prj.toLngLat(mapExtent.center()), // 中心点
            zoom: 2,
            renderWorldCopies: false
        });
        // 地图关联服务对象和坐标系
        map.attach(svc, prj);
        // 使地图全部可见
        map.fitMapBounds();
        await map.onLoad(); // 等待地图加载完成



        let enableAiMcpChat = true;
        if (enableAiMcpChat) {
            if (typeof VjmapMcpSdk !== "object") {
                let svc = map.getService();
                const _url = svc.baseUrl() + "version";
                // @ts-ignore
                let res = await svc._get(_url, {});
                let version = '';
                if (res && "data" in res) {
                    let data = res["data"];
                    version = data.version
                }
                // 版本变化了，需不用缓存重新下载下
                // vjchat.umd.js 中没有打包 vjmap, 需要把vjmap做为全局对象
                window.vjmap = vjmap;
                // 如果没有环境
                await vjmap.addScript([{
                    src: "https://vjmap.com/server/_cloud/lib/vjmap-mcp-sdk.umd.js" + `?ver=${version}`
                }])
                await vjmap.addScript([{
                    src: "https://vjmap.com/server/_cloud/lib/ai-chat-lib.umd.js" + `?ver=${version}`
                }])

                let apiUrl = map.getService().baseUrl();
                let token = map.getService().accessToken;

                // 初始化MCP连接，使用新的简化API
                console.log('初始化MCP连接...')
                let mcpInstance = await VjmapMcpSdk.initializeMCP({
                    apiBase: apiUrl,
                    autoConnect: true,
                    mapInstance: map
                })

                const sessionId = mcpInstance.state.sessionId
                // 注册地图相关工具
                await mcpInstance.registerMapTools()

                // 注册自定义工具示例
                await registerCustomTool(mcpInstance, VjmapMcpSdk.z)

                chatContainer = document.createElement('div')
                chatContainer.id = 'ai-chat-container'
                chatContainer.style.cssText = `
                            position: absolute;
                            top: 0;
                            left: 0;
                            width: 100%;
                            height: 100%;
                            pointer-events: none;
                            z-index: 1000;
                        `

                // 为聊天容器添加CSS规则，让其子元素可以接收事件
                const style = document.createElement('style')
                style.textContent = `
                            #ai-chat-container > * {
                            pointer-events: auto !important;
                            }
                        `
                if (!document.head.querySelector('style[data-ai-chat]')) {
                    style.setAttribute('data-ai-chat', 'true')
                    document.head.appendChild(style)
                }
                document.body.appendChild(chatContainer)
                let chatLib = AiChatLib.createAiChatLib({
                    container: chatContainer,
                    apiUrl: apiUrl,
                    token: token,
                    sessionId: sessionId,
                    mcpAddresses: [
                        '{apiUrl}/ai/mcp?sessionId={sessionId}&include_categories=query,map,draw,custom&token={token}'
                    ],
                    systemPrompt: '',
                    quickQuestions: [
                        '介绍下当前图形绘制了什么',
                        '定位到当前图中的一个表格',
                        "查找当前图中文本中有'图'的文字并在相应位置加上点标记"
                    ],
                    maxHistoryCount: 10,
                    window: {
                        width: 500,
                        height: 780,
                        right: 3,
                        theme: 'dark',
                        draggable: true,
                        title: '唯杰地图AI问答'
                    },
                    debug: true,
                    autoFocus: true
                })
            }
        }
    })();

    // flashPos 函数实现
    const flashPos = (bounds) => {
        map.fitMapBounds(vjmap.GeoBounds.fromArray(bounds), { padding: 300 })
        return new Promise((resolve) => {
            const routePath = vjmap.GeoBounds.fromArray(bounds).toPointArray();
            routePath.push(routePath[0])
            let geoLineDatas = [];
            geoLineDatas.push({
                points: map.toLngLat(routePath),
                properties: {
                    opacity: 1.0
                }
            })

            let polylines = new vjmap.Polyline({
                data: geoLineDatas,
                lineColor: 'yellow',
                lineWidth: 3,
                lineOpacity: ['get', 'opacity'],
                isHoverPointer: false,
                isHoverFeatureState: false
            });
            polylines.addTo(map);

            vjmap.createAnimation({
                from: 1,
                to: 10,
                duration: 1000,
                onUpdate: (e) => {
                    const data = polylines.getData();
                    if (data && data.features && data.features[0]) {
                        data.features[0].properties.opacity = parseInt(e.toString()) % 2 ? 1.0 : 0;
                        polylines.setData(data);
                    }
                },
                onStop: () => {
                    polylines.remove()
                    resolve({})
                },
                onComplete: () => {
                    polylines.remove()
                    resolve({})
                }
            })
        })
    }

    // 注册自定义工具示例
    async function registerCustomTool(mcpInstance, z) {
        if (!mcpInstance) return

        // 使用 zod 定义工具输入 schema
        // https://github.com/colinhacks/zod
        const inputSchema = z.object({
            bounds: z.array(z.number()).length(4).describe('边界坐标数组 [minX, minY, maxX, maxY]')
        })

        // 创建工具定义
        const tool = VjmapMcpSdk.createTool(
            'map_flash_position',
            '在地图上闪烁显示指定边界区域',
            inputSchema,
            'custom'
        )

        // 创建工具处理函数
        const handler = async (args) => {
            try {
                const validatedArgs = inputSchema.parse(args)
                const { bounds } = validatedArgs

                // 调用 flashPos 函数
                await flashPos(bounds)

                return {
                    content: [{
                        type: 'text',
                        text: `已在地图上闪烁显示边界区域: [${bounds.join(', ')}]`
                    }]
                }
            } catch (error) {
                return {
                    content: [{
                        type: 'text',
                        text: `工具执行失败: ${error instanceof Error ? error.message : String(error)}`
                    }],
                    isError: true
                }
            }
        }

        // 注册工具
        mcpInstance.registerTool(tool, handler, "custom")

        // 重要：注册工具到服务器，这样服务端才能获取到自定义工具
        try {
            const serviceManager = mcpInstance.getServiceManager()
            if (serviceManager) {
                await serviceManager.registerToolsToServer()
                console.log('自定义工具已成功注册到服务器')
            }
        } catch (error) {
            console.error('注册自定义工具到服务器失败:', error)
        }
    }


</script>

</html>
```
上述代码中`ai-chat-lib.umd.js`是ai 会话的`ui`库。

上述代码中`vjmap-mcp-sdk.umd.js`是vjmap mcp 的`sdk`库。主要是用来于服务端通信， 同时提供接口让用户自定义工具, 这库也可以用`npm`进行安装。用法如下


### 唯杰地图MCP SDK 安装

```bash
npm install vjmcpsdk
```

### 唯杰地图MCP SDK 用法

```js
import vjmap from vjmap
import { initializeMCP, createTool, z } from vjmcpsdk

let apiUrl = map.getService().baseUrl();
let token = map.getService().accessToken;

// 初始化MCP连接，使用新的简化API
console.log('初始化MCP连接...')
let mcpInstance = await initializeMCP({
    apiBase: apiUrl,
    autoConnect: true,
    mapInstance: map
})

const sessionId = mcpInstance.state.sessionId
// 注册地图相关工具
await mcpInstance.registerMapTools()

// 注册自定义工具示例 (如果要自定义工具，则用下面的示例)
await registerCustomTool(mcpInstance, z)


 // flashPos 函数实现
const flashPos = (bounds) => {
    map.fitMapBounds(vjmap.GeoBounds.fromArray(bounds), { padding: 300 })
    return new Promise((resolve) => {
        const routePath = vjmap.GeoBounds.fromArray(bounds).toPointArray();
        routePath.push(routePath[0])
        let geoLineDatas = [];
        geoLineDatas.push({
            points: map.toLngLat(routePath),
            properties: {
                opacity: 1.0
            }
        })

        let polylines = new vjmap.Polyline({
            data: geoLineDatas,
            lineColor: 'yellow',
            lineWidth: 3,
            lineOpacity: ['get', 'opacity'],
            isHoverPointer: false,
            isHoverFeatureState: false
        });
        polylines.addTo(map);

        vjmap.createAnimation({
            from: 1,
            to: 10,
            duration: 1000,
            onUpdate: (e) => {
                const data = polylines.getData();
                if (data && data.features && data.features[0]) {
                    data.features[0].properties.opacity = parseInt(e.toString()) % 2 ? 1.0 : 0;
                    polylines.setData(data);
                }
            },
            onStop: () => {
                polylines.remove()
                resolve({})
            },
            onComplete: () => {
                polylines.remove()
                resolve({})
            }
        })
    })
}

// 注册自定义工具示例
async function registerCustomTool(mcpInstance, z) {
    if (!mcpInstance) return

    // 使用 zod 定义工具输入 schema
    const inputSchema = z.object({
        bounds: z.array(z.number()).length(4).describe('边界坐标数组 [minX, minY, maxX, maxY]')
    })

    // 创建工具定义
    const tool = createTool(
        'map_flash_position',
        '在地图上闪烁显示指定边界区域',
        inputSchema,
        'custom'
    )

    // 创建工具处理函数
    const handler = async (args) => {
        try {
            const validatedArgs = inputSchema.parse(args)
            const { bounds } = validatedArgs

            // 调用 flashPos 函数
            await flashPos(bounds)

            return {
                content: [{
                    type: 'text',
                    text: `已在地图上闪烁显示边界区域: [${bounds.join(', ')}]`
                }]
            }
        } catch (error) {
            return {
                content: [{
                    type: 'text',
                    text: `工具执行失败: ${error instanceof Error ? error.message : String(error)}`
                }],
                isError: true
            }
        }
    }

    // 注册工具
    mcpInstance.registerTool(tool, handler, "custom")

    // 重要：注册工具到服务器，这样服务端才能获取到自定义工具
    try {
        const serviceManager = mcpInstance.getServiceManager()
        if (serviceManager) {
            await serviceManager.registerToolsToServer()
            console.log('自定义工具已成功注册到服务器')
        }
    } catch (error) {
        console.error('注册自定义工具到服务器失败:', error)
    }
}

```

### 后台设置
在后台数据目录的`data/ai/aisvr_config.yaml`中进行配置

![image-20250803190902021](https://vjmap.com/blogimages/202508031909069.png)
