地图控制库

一个Android库,通过自然语言控制Mapbox地图,集成AI代理如Claude,支持实时地图操作和多种标注功能。

  • by moritzzzzz
  • Kotlin
  • 本地部署
  • 更新于
在 GitHub 查看 moritzzzzz/android-mapbox-map-tools-mcp-v11

使用说明

安卓Mapbox MCP包装器

一个Android库,使像Claude这样的AI代理能够通过自然语言控制Mapbox地图。该项目用模型上下文协议(MCP)工具定义封装了Mapbox Maps SDK v11,使地图可以通过LLM聊天界面进行控制。

Android相当于: mapbox地图工具mcp (JavaScript/Web版本)

演示

演示应用程序包括一个聊天界面,您可以在其中与Claude交谈以实时控制地图:

  • “给我看看巴黎” → 地图平移到巴黎
  • 在伦敦、罗马和马德里添加标记 → 添加3个标记
  • “画一条从纽约到洛杉矶的路线” → 画一条线
  • “切换到卫星视图” → 更改地图样式

特性

  • 🗺️ 7 MCP工具 用于综合地图控制
  • 🤖 Claude API集成 具有对话式UI
  • 📍 点注释 具有可定制的颜色和弹出窗口
  • 🛣️ 路线/线路图 具有样式选项
  • 🗺️ 多边形叠加 具有填充和笔划自定义功能
  • 📷 相机控制 (平移、缩放、调整边界)
  • 🎨 样式切换 (街道、卫星、户外、黑暗)
  • 🧹 层级管理 选择性清算

在项目中使用库

通过JitPack将Mapbox MCP Tools库添加到您的Android项目中:

步骤1:添加JitPack存储库

在你的 项目级 settings.gradle.kts (或 build.gradle):

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }  // Add this line
    }
}

步骤2:添加依赖关系

在你的 应用程序级别 build.gradle.kts:

dependencies {
    // Mapbox MCP Tools Library
    implementation("com.github.moritzzzzz:android-mapbox-map-tools-mcp-v11:v1.0.0")

    // Required: Mapbox Maps SDK (if not already included)
    implementation("com.mapbox.maps:android:11.17.1")

    // Required: Kotlin Serialization
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2")
}

第三步:使用图书馆

import com.mapbox.maps.MapView
import com.mapbox.mcp.MapboxMapTools

class YourActivity : AppCompatActivity() {
    private lateinit var mapView: MapView
    private lateinit var mapboxMapTools: MapboxMapTools

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Initialize MapView
        mapView = findViewById(R.id.mapView)

        // Wait for map style to load
        mapView.mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) {
            // Create MapboxMapTools wrapper
            mapboxMapTools = MapboxMapTools(mapView)

            // Get tool definitions for your LLM
            val tools = mapboxMapTools.getToolsForLLM()
            // Send these to Claude API or your LLM provider...

            // Execute a tool
            val result = mapboxMapTools.executeTool(
                "pan_map_to_location",
                mapOf(
                    "latitude" to 48.8566,
                    "longitude" to 2.3522,
                    "zoom" to 12.0
                )
            )
        }
    }
}

**完整集成示例:**请参阅 演示应用程序源代码 以实现与Claude API集成的完整工作实现。


快速入门-运行演示

先决条件

您需要两个API密钥(都是免费的):

  1. Mapbox访问令牌 -在中配置 res/values/mapbox_access_token.xml!
  2. API密钥 -通过安全配置 local.properties

首次设置:复制 local.properties.example 到 local.properties 并添加您的Claude API密钥。看 API密钥设置 了解详情。

跑步步骤

  1. 克隆并打开

    git clone <your-repo-url>
    cd android_mapbox_mcp_wrapper/mcp_tools_demo_app
    

    打开 mcp_tools_demo_app Android Studio中的文件夹。

  2. 同步渐变

    • Android Studio将提示您同步
    • 单击“立即同步”并等待其完成
  3. 运行应用程序

    • 点击绿色的“运行”按钮(或按Shift+F10)
    • 选择设备或模拟器
    • 等待应用程序安装并启动
  4. 开始聊天!

    • 在聊天框中键入消息
    • 试试:“给我看看纽约市”
    • 观察地图对自然语言命令的响应

就是这样!该应用程序已预先配置并准备好使用。


配置

使用您自己的API密钥

Mapbox访问令牌

  1. 获取令牌:参观 Mapbox帐户 (免费版可用)
  2. 更新令牌:打开 app/src/main/res/values/mapbox_access_token.xml
  3. 用您的令牌替换现有令牌:
    <string name="mapbox_access_token">YOUR_MAPBOX_TOKEN_HERE</string>
    

API密钥

  1. 拿到钥匙:参观 拟人控制台 (需要帐户)
  2. 复制模板:
    cp local.properties.example local.properties
    
  3. 添加您的密钥:编辑 local.properties 并替换占位符:
    claude.api.key=sk-ant-api03-YOUR_KEY_HERE
    
  4. 重建:运行 ./gradlew clean assembleDebug

备注: local.properties 是合法的,永远不会被承诺。这使您的API密钥保持安全!

有关更多详细信息,请参阅 API_KEY_SETUP.md.

高级配置

在 Config.kt,您可以配置:

object Config {
    // Claude API Key (loaded from local.properties at build time)
    val CLAUDE_API_KEY = BuildConfig.CLAUDE_API_KEY

    // Model selection (sonnet is faster, opus is more capable)
    const val CLAUDE_MODEL = "claude-sonnet-4-5-20250929"
    // Options: "claude-sonnet-4-5-20250929", "claude-opus-4-5-20251101"

    // Maximum tokens for responses
    const val MAX_TOKENS = 4096
}

在自己的应用程序中使用库

安装选项

选项1:JitPack(推荐) -请参阅 在项目中使用库 上方

选项2:手动复制 -复制 mapbox-mcp-tools 模块到您的项目中:

  1. 复制 mapbox-mcp-tools 将文件夹放入您的Android项目中
  2. 增添 settings.gradle.kts:
    include(":mapbox-mcp-tools")
    
  3. 在应用程序中添加依赖项 build.gradle.kts:
    dependencies {
        implementation(project(":mapbox-mcp-tools"))
        implementation("com.mapbox.maps:android:11.17.1")
    }
    

步骤2:初始化MapboxMapTools

import com.mapbox.maps.MapView
import com.mapbox.maps.Style
import com.mapbox.mcp.MapboxMapTools
import com.mapbox.mcp.models.ToolResult

class YourActivity : AppCompatActivity() {
    private lateinit var mapView: MapView
    private lateinit var mapboxMapTools: MapboxMapTools

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Create and setup MapView
        mapView = MapView(this)
        setContentView(mapView)

        // Load map style first
        mapView.mapboxMap.loadStyleUri(Style.MAPBOX_STREETS) {
            // Initialize tools after style loads
            mapboxMapTools = MapboxMapTools(mapView)

            // Now you can use the tools!
            useMapTools()
        }
    }

    private fun useMapTools() {
        // Get tool definitions (for sending to LLM)
        val tools = mapboxMapTools.getToolsForLLM()
        println("Available tools: ${tools.map { it.name }}")

        // Execute a tool directly
        val result = mapboxMapTools.executeTool(
            "add_points_to_map",
            mapOf(
                "points" to listOf(
                    mapOf(
                        "lat" to 40.7128,
                        "lng" to -74.0060,
                        "title" to "New York City",
                        "description" to "The Big Apple"
                    )
                ),
                "iconColor" to "#FF5722",
                "iconSize" to 1.5
            )
        )

        // Handle result
        when (result) {
            is ToolResult.Success -> {
                Log.d("Map", "Success: ${result.data}")
            }
            is ToolResult.Error -> {
                Log.e("Map", "Error: ${result.message}")
            }
        }
    }
}

步骤3:工具执行示例

添加标记

mapboxMapTools.executeTool("add_points_to_map", mapOf(
    "points" to listOf(
        mapOf("lat" to 48.8566, "lng" to 2.3522, "title" to "Paris"),
        mapOf("lat" to 51.5074, "lng" to -0.1278, "title" to "London")
    ),
    "layerName" to "cities",
    "iconColor" to "#4CAF50"
))

绘制路线

mapboxMapTools.executeTool("add_route_to_map", mapOf(
    "coordinates" to listOf(
        listOf(-122.4194, 37.7749),  // San Francisco
        listOf(-118.2437, 34.0522)   // Los Angeles
    ),
    "lineColor" to "#2196F3",
    "lineWidth" to 5.0
))

平移到位置

mapboxMapTools.executeTool("pan_map_to_location", mapOf(
    "latitude" to 40.7128,
    "longitude" to -74.0060,
    "zoom" to 12.0,
    "animated" to true
))

清除图层

// Clear all layers
mapboxMapTools.executeTool("clear_map_layers", emptyMap())

// Clear specific layers
mapboxMapTools.executeTool("clear_map_layers", mapOf(
    "layerNames" to listOf("cities", "routes")
))

使用多个MCP工具集/扩展功能

您可以将Mapbox MCP工具与其他MCP服务器或工具提供商结合使用,让Claude一次访问多种功能。

架构概述

Claude API
    ↓
Your App sends combined tool list:
    ├─ Mapbox Tools (this library)
    ├─ Weather API Tools (hypothetical)
    └─ Database Tools (hypothetical)
    ↓
Your App routes execution to correct provider

步骤1:创建多个工具提供程序

class WeatherTools {
    fun getToolsForLLM(): List<ToolDefinition> {
        return listOf(
            ToolDefinition(
                name = "get_weather",
                description = "Get current weather for a location",
                inputSchema = InputSchema(
                    type = "object",
                    properties = mapOf(
                        "city" to Property("string", "City name"),
                        "country" to Property("string", "Country code (optional)")
                    ),
                    required = listOf("city")
                )
            )
        )
    }

    fun executeTool(name: String, params: Map<String, Any?>): ToolResult {
        return when (name) {
            "get_weather" -> {
                val city = params["city"] as? String ?: return ToolResult.Error("Missing city")
                // Call your weather API here...
                ToolResult.Success("Weather in $city: Sunny, 72°F")
            }
            else -> ToolResult.Error("Unknown tool: $name")
        }
    }
}

步骤2:更新ChatManager以组合工具

修改 ChatManager.kt 接受多个工具提供商:

class ChatManager(
    private val claudeApiClient: ClaudeApiClient,
    private val mapboxMapTools: MapboxMapTools,
    private val weatherTools: WeatherTools  // Add additional providers
) {
    suspend fun processMessage(userMessage: String): String {
        // ... existing code ...

        // Combine all tool definitions
        val allTools = buildList {
            addAll(mapboxMapTools.getToolsForLLM())
            addAll(weatherTools.getToolsForLLM())
            // Add more tool providers here...
        }

        Log.d(TAG, "Available tools: ${allTools.map { it.name }}")

        // Send to Claude with all tools
        val response = claudeApiClient.sendMessage(
            messages = conversationHistory.toList(),
            tools = allTools
        )

        // ... rest of existing code ...
    }

    private suspend fun executeToolCall(toolUseBlock: ContentBlock): String {
        val toolName = toolUseBlock.name ?: return "Error: No tool name"
        val params = convertJsonElementMapToAny(toolUseBlock.input ?: emptyMap())

        Log.d(TAG, "Executing tool: $toolName with params: $params")

        // Route to appropriate tool provider based on tool name
        val result = when {
            toolName.startsWith("add_") ||
            toolName.startsWith("pan_") ||
            toolName.startsWith("fit_") ||
            toolName.startsWith("clear_") ||
            toolName.startsWith("set_") -> {
                // Mapbox tools
                mapboxMapTools.executeTool(toolName, params)
            }
            toolName == "get_weather" -> {
                // Weather tools
                weatherTools.executeTool(toolName, params)
            }
            else -> {
                ToolResult.Error("Unknown tool: $toolName")
            }
        }

        return when (result) {
            is ToolResult.Success -> result.data ?: "Success"
            is ToolResult.Error -> "Error: ${result.message}"
        }
    }
}

步骤3:更新主活动初始化

class MainActivity : AppCompatActivity() {
    private lateinit var mapboxMapTools: MapboxMapTools
    private lateinit var weatherTools: WeatherTools
    private lateinit var chatManager: ChatManager

    private fun initializeChatManager() {
        val claudeApiClient = ClaudeApiClient(CLAUDE_API_KEY)
        weatherTools = WeatherTools()  // Initialize additional provider

        chatManager = ChatManager(
            claudeApiClient,
            mapboxMapTools,
            weatherTools  // Pass additional provider
        )

        Log.d(TAG, "ChatManager initialized with ${
            mapboxMapTools.getToolsForLLM().size + weatherTools.getToolsForLLM().size
        } tools")
    }
}

步骤4:尝试组合命令

现在,Claude可以使用多个提供商的工具:

User: "Show me Paris and tell me the weather there"
  ↓
Claude calls:
  1. pan_map_to_location (Mapbox)
  2. get_weather (Weather API)
  ↓
App: "I've centered the map on Paris. The weather is Sunny, 72°F."

高级:动态刀具布线

对于更复杂的场景,请使用工具注册表:

class ToolRegistry {
    private val providers = mutableMapOf<String, ToolProvider>()

    fun register(toolNamePrefix: String, provider: ToolProvider) {
        providers[toolNamePrefix] = provider
    }

    fun getAllTools(): List<ToolDefinition> {
        return providers.values.flatMap { it.getToolsForLLM() }
    }

    fun executeTool(toolName: String, params: Map<String, Any?>): ToolResult {
        // Find provider by checking tool name prefixes or patterns
        val provider = providers.entries.find { (prefix, _) ->
            toolName.startsWith(prefix)
        }?.value

        return provider?.executeTool(toolName, params)
            ?: ToolResult.Error("No provider found for tool: $toolName")
    }
}

// Usage
val registry = ToolRegistry()
registry.register("map", mapboxMapTools)
registry.register("weather", weatherTools)
registry.register("db", databaseTools)

val allTools = registry.getAllTools()
val result = registry.executeTool("map_add_points", params)

MCP服务器集成示例

您可能想要集成的常见MCP服务器:

  1. 文件系统MCP -读/写文件

    implementation("com.github.user:filesystem-mcp-android:1.0.0")
    
  2. 数据库MCP -查询数据库

    implementation("com.github.user:sqlite-mcp-tools:1.0.0")
    
  3. 日历MCP -访问设备日历

    implementation("com.github.user:calendar-mcp-tools:1.0.0")
    
  4. 自定义REST API工具 -包装自己的API

    class MyApiTools {
        fun getToolsForLLM() = listOf(/* your tools */)
        fun executeTool(name: String, params: Map<String, Any?>) = /* execute */
    }
    

多套工具的优点

更丰富的互动 -Claude可以执行复杂的多域任务 模块化 -易于添加/删除工具提供程序 可重用性 -跨不同应用程序共享工具提供商 关注点分离 -每个提供商处理自己的域

最佳实践

  1. 使用清晰的工具命名 -在工具名称前加上域(例如。, map_, weather_, db_)
  2. 文档工具交互 -注意哪些工具配合使用效果好
  3. 优雅地处理错误 -每个提供程序应返回一致的错误格式
  4. 测试工具组合 -确保克劳德能够正确地连接工具
  5. 监控令牌使用情况 -更多的工具=更大的上下文,考虑将相关工具分组

代币成本和性能考虑因素

输入令牌影响

⚠️ 重要提示: 7个Mapbox MCP工具添加 ~1060个输入令牌 每个API请求。

成本影响(克劳德十四行诗4.5):

Input tokens:  1,060 tokens × $3/million  = $0.00318 per request
Output tokens: varies (typically 500-2000 tokens)

Example with typical 1,000 token response:
  Input (tools + message): 1,160 tokens = $0.0035
  Output (response):       1,000 tokens = $0.0150
  ─────────────────────────────────────────────
  Total per request:                    $0.0185

与没有工具的请求相比:

  • 基本输入(仅限消息):~100个令牌=0.0003美元
  • 工具添加10倍以上的输入令牌 (1060对100)
  • 但总成本仅为2倍左右 (产出占主导地位:0.015美元对0.0003美元)

关键见解: 工具显著增加了您的输入令牌数量(约占总输入的40-60%),但输出令牌的总体成本通常更高,因此影响是适度的。

每工具代币估算:

工具 令牌 复杂性
add_points_to_map ~200 高(嵌套模式)
add_route_to_map ~140 中等
add_polygon_to_map ~160 中等
pan_map_to_location ~120 低
fit_map_to_bounds ~130 中等
clear_map_layers ~90 低
set_map_style ~80 低

减少代币使用的策略:

  1. 选择性工具加载 -仅发送与当前上下文相关的工具:

    // Only send map control tools for navigation
    val tools = listOf(
        mapboxMapTools.createPanMapToolDefinition(),
        mapboxMapTools.createFitBoundsToolDefinition()
    )
    
  2. 基于上下文的过滤 -启用/禁用工具类别:

    val tools = when (userIntent) {
        Intent.NAVIGATE -> mapboxMapTools.getNavigationTools()
        Intent.ANNOTATE -> mapboxMapTools.getAnnotationTools()
        Intent.ALL -> mapboxMapTools.getToolsForLLM()
    }
    
  3. 缓存 (如果API支持)-工具保持不变,在请求之间缓存它们

  4. 工具说明 -保持描述简洁明了

当多个工具集成为问题时:

  • 3-4套工具(20-30个工具): 仍然可以管理(约3000-4000个代币)
  • 5-8套工具(40-60个工具): 成本明显增加(约6000-8000个代币)
  • 10+套工具(80+套工具): 考虑动态加载或分类

监控您的使用情况:

val toolsJson = json.encodeToString(tools)
val estimatedTokens = toolsJson.length / 3.5  // Rough estimate
Log.d("Tokens", "Sending ~${estimatedTokens.toInt()} tokens in tools")

工具过多的缺点:

  • ⚠️ 延迟增加 -处理更大的请求需要更长的时间
  • ⚠️ 成本更高 -随刀具数量线性增加
  • ⚠️ 语境淡化 -LLM有更多需要“思考”的地方
  • ⚠️ 困惑 -太多类似的工具会降低精度

最佳实践: 从基本工具开始,根据实际使用模式根据需要添加更多工具。


可用工具

该库提供7个MCP工具:

1. add_points_to_map

在地图上添加标记/图钉。

参数:

参数 类型 必填 默认 说明
points 数组 ✅ 是 - 数组 {lat, lng, title?, description?}
layerName 字符串 否 “点” 分组层标识符
iconColor 字符串 否 “#FF0000” 标记的十六进制颜色
iconSize 浮点数 否 1.0 大小倍数

例子:

mapOf(
    "points" to listOf(
        mapOf("lat" to 40.7128, "lng" to -74.0060, "title" to "NYC")
    ),
    "iconColor" to "#FF5722"
)

2. add_route_to_map

在地图上画一条线/路径。

参数:

参数 类型 必填 默认 说明
coordinates 数组 ✅ 是 - 数组 [lng, lat] 成对
layerName 字符串 否 “路由” 层标识符
lineColor 字符串 否 “#3b9ddd” 十六进制颜色
lineWidth 浮点数 否 4.0 宽度(像素)
lineOpacity 浮点数 否 0.8 不透明度(0-1)

3. add_polygon_to_map

在地图上画一个填好的区域。

参数:

参数 类型 必填 默认 说明
coordinates 数组 ✅ 是 - 数组 [lng, lat] 成对形成边界
layerName 字符串 否 “多边形” 图层标识符
fillColor 字符串 否 “#3b9ddd” 十六进制填充颜色
fillOpacity 浮点数 否 0.5 填充不透明度(0-1)
strokeColor 字符串 否 “#000000” 边框颜色
strokeWidth 浮点数 否 2.0 边框宽度

4. pan_map_to_location

将相机移动到特定位置。

参数:

参数 类型 必填 默认 说明
latitude 双 ✅ 是 - 纬度坐标
longitude 双 ✅ 是 - 经度坐标
zoom 双 否 当前 缩放级别(可选)
animated 布尔 否 真 动画转换
duration 长 否 1000 动画持续时间(ms)

5. fit_map_to_bounds

调整相机以显示所有指定点。

参数:

参数 类型 必填 默认 说明
coordinates 数组 ✅ 是 - 数组 [lng, lat] 以适应视野
padding Int 否 50 像素填充
animated 布尔 否 真 动画转换

6. clear_map_layers

从地图中删除注释/图层。

参数:

参数 类型 必填 默认 说明
layerNames 数组 否 空 要清除的层名称(空=全部)

7. set_map_style

更改地图的视觉外观。

参数:

参数 类型 必填 默认 说明
styleUrl 字符串 ✅ 是 - 地图框样式URL

流行款式:

  • mapbox://styles/mapbox/streets-v12 -默认街道地图
  • mapbox://styles/mapbox/outdoors-v12 -户外/徒步旅行
  • mapbox://styles/mapbox/satellite-v9 -卫星图像
  • mapbox://styles/mapbox/satellite-streets-v12 -带有标签的卫星
  • mapbox://styles/mapbox/dark-v11 -黑暗主题
  • mapbox://styles/mapbox/light-v11 -灯光主题

克劳德提示示例

演示运行后,尝试以下自然语言命令:

基本导航

  • “给我看看东京”
  • “带我去埃菲尔铁塔”
  • 平移到坐标37.7749,-122.4194
  • “放大中央公园”

添加标记

  • “在自由女神像上加一个红色标记”
  • 在巴黎、伦敦和柏林做标记
  • 在坐标35.6762、139.6503处添加一个标记,标题为“东京塔”

绘制路线

  • “画一条从纽约到波士顿的蓝线”
  • “给我看一条连接旧金山、拉斯维加斯和洛杉矶的路线”
  • 沿以下坐标绘制一条路径:[[0,0],[1,1],[2,0]

多边形

  • “在曼哈顿周围画一个绿色多边形”
  • 创建一个半透明的蓝色区域,覆盖以下点:[[0,0],[1,0],[1,1],[0,1]]

地图样式

  • “切换到卫星视图”
  • “使用暗模式”
  • “改为户外风格”
  • “给我看街道地图”

复杂的多步命令

  • “清除地图,然后向我展示欧洲,并为法国、德国和意大利的首都添加标记”
  • “给我看加州,在旧金山加一个标记,画一条到洛杉矶的线”
  • 切换到卫星视图,缩放到纽约,并在时代广场和中央公园添加标记

组合功能

  • “显示北美,调整视图以显示加拿大、美国和墨西哥,然后在它们的首都添加标记”
  • 清除所有图层,使用缩放级别12平移到巴黎,并添加一个红色标记

建筑

图书馆设计

这 mapbox-mcp-tools 库提供了一个简单、无服务器的API:

MapboxMapTools
├── getToolsForLLM() → List<ToolDefinition>
│   Returns MCP tool schemas for LLM
│
└── executeTool(name, params) → ToolResult
    Executes tools and returns Success/Error

要点:

  • ✅ 无服务器组件-纯包装库
  • ✅ 线程安全(在主线程上运行映射操作)
  • ✅ 有组织注释的图层跟踪
  • ✅ 全面的错误处理

演示应用程序架构

┌─────────────────────────────────┐
│ User types message in chat      │
└──────────────┬──────────────────┘
               ▼
┌─────────────────────────────────┐
│ ChatManager.processMessage()    │
├─────────────────────────────────┤
│ 1. Get tools from library       │
│ 2. Send to Claude API           │
│ 3. Parse tool_use blocks        │
│ 4. Execute via MapboxMapTools   │
│ 5. Send results back to Claude  │
│ 6. Return final response        │
└──────────────┬──────────────────┘
               ▼
┌─────────────────────────────────┐
│ Display response + Update map   │
└─────────────────────────────────┘

流程示例:

User: "Show me Paris"
  ↓
Claude: [analyzes] → tool_use: pan_map_to_location(lat: 48.8566, lng: 2.3522)
  ↓
App: Executes tool → Map pans to Paris
  ↓
Claude: "I've centered the map on Paris, France (48.8566°N, 2.3522°E)"
  ↓
User sees response + map at Paris

故障排除

应用程序无法构建

错误: “无法解析依赖关系…”

  • 修复: 请确保您已同步Gradle。转到文件→ 同步项目与Gradle文件

错误: “无法解析:com.mapbox.maps…”

  • 修复: 检查您的互联网连接。Gradle需要下载依赖项。

地图未加载

症状: 应放置地图的灰色或空白屏幕

  • 修复: 在中检查您的Mapbox访问令牌 mapbox_access_token.xml
  • 修复: 确保您有互联网连接
  • 修复: 检查Logcat是否有错误消息(查看→ 工具窗口→ Logcat)

聊天没有响应

错误: “聊天未初始化。请检查API密钥。”

  • 修复: 验证Claude API密钥 Config.kt 有效且非空

错误: “Claude API错误:401”

  • 修复: 您的Claude API密钥无效或已过期。从获取新的https://console.anthropic.com/

错误: “Claude API错误:429”

  • 修复: 你已达到利率上限。请稍等,然后重试。

地图加载但工具不起作用

症状: 聊天功能正常,但地图不响应命令

  • 修复: 检查一下 MapboxMapTools 在地图样式加载后初始化
  • 修复: 在Logcat中查找以“MapboxMapTools”开头的错误

坐标错误

问题: 标记出现在错误的位置

  • 记得: Mapbox使用 [longitude, latitude] 订单,不是 [lat, lng]
  • 修复: 在工具调用中,确保坐标 [lng, lat]

需求

  • 最小SDK: 29(安卓10)
  • 目标SDK: 36
  • 编译SDK: 36
  • Kotlin: 2.0.21
  • Mapbox SDK: 11.17.1
  • 互联网权限: 地图瓷砖和Claude API需要

安全最佳实践

⚠️ 重要提示: 此演示包含API密钥,以便于测试。对于生产应用程序:

❌ 不要这样做

// DON'T commit API keys to version control
const val CLAUDE_API_KEY = "sk-ant-api03-xxxx"

✅ 改为这样做

选项1:使用BuildConfig

// build.gradle.kts
android {
    defaultConfig {
        buildConfigField(
            "String",
            "CLAUDE_API_KEY",
            "\"${System.getenv("CLAUDE_API_KEY")}\""
        )
    }
}

// Config.kt
const val CLAUDE_API_KEY = BuildConfig.CLAUDE_API_KEY

选项2:使用local.properties

# local.properties (add to .gitignore)
CLAUDE_API_KEY=sk-ant-api03-xxxx
// build.gradle.kts
val localProperties = Properties()
localProperties.load(FileInputStream(rootProject.file("local.properties")))

android {
    defaultConfig {
        buildConfigField(
            "String",
            "CLAUDE_API_KEY",
            "\"${localProperties.getProperty("CLAUDE_API_KEY")}\""
        )
    }
}

选项3:环境变量

export CLAUDE_API_KEY="sk-ant-api03-xxxx"

其他安全提示

  1. 添加到.gitignore:

    Config.kt
    local.properties
    **/api_keys.xml
    
  2. 使用秘密管理服务:

    • AWS机密管理器
    • 谷歌秘密管理员
    • HashiCorp保险库
  3. 实施速率限制 生产中

  4. 监控API使用情况 用于意外活动

  5. 定期旋转按键


项目结构

android_mapbox_mcp_wrapper/
├── README.md                           # This file
└── mcp_tools_demo_app/                 # Android Studio project
    ├── mapbox-mcp-tools/               # Library module
    │   ├── build.gradle.kts
    │   └── src/main/java/com/mapbox/mcp/
    │       ├── MapboxMapTools.kt       # Main API
    │       ├── models/
    │       │   ├── ToolDefinition.kt   # MCP tool schema
    │       │   ├── ToolResult.kt       # Result type
    │       │   ├── Point.kt            # Point data
    │       │   ├── Route.kt            # Route data
    │       │   └── Polygon.kt          # Polygon data
    │       └── internal/
    │           └── (implementation)
    │
    └── app/                            # Demo application
        ├── build.gradle.kts
        └── src/main/java/com/example/mcp_tools_demo/
            ├── MainActivity.kt          # Main UI + integration
            ├── Config.kt               # Configuration (API keys)
            ├── ClaudeApiClient.kt      # Claude API client
            ├── ChatManager.kt          # Conversation orchestrator
            ├── ChatAdapter.kt          # Chat UI adapter
            └── models/
                └── ChatMessage.kt      # UI message model

🤝 贡献

欢迎投稿!需要改进的地方:

  • []其他地图工具(3D地形、地理编码等)
  • []支持更多LLM提供商(OpenAI等)
  • []地图状态查询工具(获取当前位置等)
  • []批量操作以获得更好的性能
  • []单元测试和仪器测试

许可证

MIT许可证

版权所有(c)2025莫里茨福斯特

特此免费向任何获得副本的人授予许可 本软件和相关文档文件(“软件”),以处理 在软件中不受限制,包括但不限于权利 使用、复制、修改、合并、发布、分发、再许可和/或销售 软件的副本,并允许软件的接收者 根据以下条件提供:

上述版权声明和本许可声明应包含在所有 软件的副本或实质性部分。

软件按“原样”提供,不提供任何形式的明示或明示担保 隐含的,包括但不限于适销性保证, 适用于特定目的且不造成伤害。在任何情况下 作者或版权持有人对任何索赔、损害赔偿或其他 因以下原因产生的责任,无论是在合同、侵权或其他诉讼中, 出于或与软件、使用或其他交易有关 软件。


学分


支持


了解更多