返回博客

MCP 协议在 Android 端的应用:AI 工具调用新范式

2025 年底,Anthropic 推出了 Model Context Protocol (MCP)——一种开放协议,用于为 AI 模型提供标准化的工具和资源访问接口。经过大半年的发展,MCP 已经从一个概念成长为 AI 应用开发的主流协议标准。

本文将深入探讨 MCP 协议在 Android 端的应用场景、架构设计,并通过一个完整的 Kotlin 实现,展示如何在 Android 应用中通过 MCP 协议调用 AI 工具。

📌 阅读前提:本文假设你了解 Android 开发基础(Kotlin、协程),并对 AI 模型的基本概念(如 Function Calling、Tool Use)有初步了解。

什么是 MCP?

MCP(Model Context Protocol)是一种开放协议,旨在标准化 AI 模型与外部工具和数据源的交互方式。你可以把它理解为「AI 世界的 USB-C 接口」——它为 AI 模型提供了一种统一的方式来使用各种工具和访问各种数据源。

核心概念

组件角色举例
HostAI 应用Android App、IDE 插件
Server工具/资源提供者文件系统、数据库、日历 API
Client协议客户端(Host 内部)维护与 Server 的连接
Tool可调用的具体能力搜索文件、发送邮件、查询天气
Resource可查询的数据源数据库表、API 返回结果

协议流程

┌─────────────┐    discover tools     ┌─────────────┐
│   Android   │  ──────────────────>  │    MCP      │
│   App       │                       │   Server    │
│   (Host)    │  <──────────────────  │             │
│             │     tool list         │             │
│   ┌─────┐   │                       │             │
│   │MCP  │   │    call tool          │  ┌────────┐ │
│   │Client│   │  ──────────────────>  │  │ Tool A │ │
│   └─────┘   │                       │  │ Tool B │ │
│             │     tool result       │  │ Tool C │ │
│             │  <──────────────────  │  └────────┘ │
└─────────────┘                       └─────────────┘

为什么 Android 需要 MCP?

传统上,在 Android 中集成 AI 功能有两种方式:

  1. 硬编码 Function Calling:手动定义每个工具的 JSON Schema,模型调用后自己解析结果
  2. 自建工具链:自行实现工具注册、调用、结果返回的整个框架

这两种方式都不够灵活——每增加一个新工具,都要改代码。而且不同应用之间的工具无法复用。

MCP 带来三个核心好处:

Android MCP 架构设计

在 Android 上实现 MCP,我们需要考虑移动端的特殊性:

以下是推荐的 Android MCP 架构:

整体架构

┌─────────────────────────────────────┐
│          Android App                │
│  ┌─────────────────────────────┐    │
│  │      MCP Host Manager       │    │
│  │  ┌─────┐ ┌─────┐ ┌─────┐  │    │
│  │  │MCP C│ │MCP C│ │MCP C│  │    │
│  │  │lient│ │lient│ │lient│  │    │
│  │  └──┬──┘ └──┬──┘ └──┬──┘  │    │
│  └─────┼───────┼───────┼─────┘    │
│        │       │       │           │
│  ┌─────▼──┐ ┌──▼────┐ ┌▼──────┐   │
│  │端侧 MCP│ │云 MCP │ │本地   │   │
│  │ Server │ │Server │ │Service│   │
│  │(AICore)│ │(HTTP) │ │(Binder)│  │
│  └────────┘ └───────┘ └───────┘   │
└─────────────────────────────────────┘

核心组件

MCP Host Manager:管理多个 MCP Client 连接的生命周期,提供统一的工具调用接口。

MCP Client:每个 Server 对应一个 Client,负责协议通信、工具列表缓存、调用路由。

MCP Server:可以在本地(Service)、云端(HTTP)或 AICore 上运行。

Kotlin 实现:一个 MCP 客户端

下面是基于 Kotlin + Ktor 的 MCP 客户端核心实现:

MCP 协议消息定义

// MCP 协议基类
@Serializable
data class McpMessage(
    val jsonrpc: String = "2.0",
    val id: String,
    val method: String,
    val params: JsonObject? = null
)

@Serializable
data class McpResponse(
    val jsonrpc: String = "2.0",
    val id: String,
    val result: JsonObject? = null,
    val error: McpError? = null
)

@Serializable
data class McpError(
    val code: Int,
    val message: String
)

// 工具定义
@Serializable
data class ToolDefinition(
    val name: String,
    val description: String,
    @SerialName("input_schema")
    val inputSchema: JsonObject
)

MCP Client 实现

class McpClient(
    private val endpoint: String,
    private val client: HttpClient = HttpClient(CIO)
) {
    private var tools: List<ToolDefinition> = emptyList()
    private var requestId = 0

    // 初始化:发现并缓存工具列表
    suspend fun initialize(): List<ToolDefinition> {
        val response = sendRequest("initialize", buildJsonObject {
            put("protocolVersion", "2025-03-26")
            put("capabilities", buildJsonObject {
                put("tools", buildJsonObject {})
            })
        })

        // 获取工具列表
        val toolsResponse = sendRequest("tools/list", null)
        tools = parseTools(toolsResponse)
        return tools
    }

    // 调用某个工具
    suspend fun callTool(name: String, args: JsonObject): JsonObject {
        val response = sendRequest("tools/call", buildJsonObject {
            put("name", name)
            put("arguments", args)
        })
        return response.result ?: error("Tool call failed")
    }

    // 发送 JSON-RPC 请求
    private suspend fun sendRequest(
        method: String,
        params: JsonObject?
    ): McpResponse {
        val message = McpMessage(
            id = (++requestId).toString(),
            method = method,
            params = params
        )

        return client.post(endpoint) {
            contentType(ContentType.Application.Json)
            setBody(message)
        }.body()
    }

    private fun parseTools(response: McpResponse): List<ToolDefinition> {
        val toolsArray = response.result
            ?.getJSONArray("tools") ?: return emptyList()
        return Json.decodeFromJsonElement(toolsArray)
    }
}

在 ViewModel 中集成

class McpViewModel : ViewModel() {

    private val mcpClients = mutableMapOf<String, McpClient>()
    private val _tools = MutableStateFlow<List<ToolDefinition>>(emptyList())
    val tools: StateFlow<List<ToolDefinition>> = _tools.asStateFlow()

    // 注册 MCP Server
    fun registerServer(id: String, endpoint: String) {
        viewModelScope.launch {
            val client = McpClient(endpoint)
            try {
                val serverTools = client.initialize()
                mcpClients[id] = client
                _tools.update { it + serverTools }
            } catch (e: Exception) {
                Log.e("MCP", "Failed to connect server $id", e)
            }
        }
    }

    // AI 模型调用工具
    fun processWithTools(userQuery: String, aiClient: AiClient) {
        viewModelScope.launch {
            // 1. 将工具定义发送给 AI 模型
            val aiResponse = aiClient.chat(
                userQuery,
                tools = _tools.value
            )

            // 2. AI 模型决定调用哪个工具
            if (aiResponse.hasToolCall()) {
                val toolCall = aiResponse.toolCall
                val targetClient = findClient(toolCall.name)
                
                // 3. 执行工具调用
                val result = targetClient?.callTool(
                    toolCall.name,
                    toolCall.arguments
                )
                
                // 4. 将结果返回给 AI 继续处理
                val finalResponse = aiClient.chat(
                    userQuery,
                    toolResult = result
                )
                // 展示最终回复
            }
        }
    }
}

端侧 MCP Server:AICore 集成

Android 16+ 的 AICore 可以作为端侧 MCP Server,提供本地 AI 工具:

class OnDeviceMcpServer(private val context: Context) {

    private val aicoreManager = AICoreManager(context)

    // 注册的工具列表
    val tools = listOf(
        ToolDefinition(
            name = "text_summarize",
            description = "对文本进行智能摘要",
            inputSchema = buildJsonObject {
                put("type", "object")
                put("properties", buildJsonObject {
                    put("text", buildJsonObject {
                        put("type", "string")
                        put("description", "要摘要的文本")
                    })
                    put("maxLength", buildJsonObject {
                        put("type", "number")
                        put("description", "摘要最大长度")
                    })
                })
                put("required", buildJsonArray {
                    add("text")
                })
            }
        ),
        ToolDefinition(
            name = "text_classify",
            description = "对文本进行情感分类",
            inputSchema = buildJsonObject {
                put("type", "object")
                put("properties", buildJsonObject {
                    put("text", buildJsonObject {
                        put("type", "string")
                    })
                })
                put("required", buildJsonArray { add("text") })
            }
        )
    )

    // 处理工具调用
    suspend fun handleToolCall(name: String, args: JsonObject): JsonObject {
        return when (name) {
            "text_summarize" -> {
                val text = args["text"]!!.jsonPrimitive.content
                val maxLen = args["maxLength"]?.jsonPrimitive?.int ?: 100
                val summary = aicoreManager.generate(text) {
                    maxOutputTokens = maxLen
                    temperature = 0.3f
                }
                buildJsonObject { put("summary", summary) }
            }
            "text_classify" -> {
                val text = args["text"]!!.jsonPrimitive.content
                val result = aicoreManager.classify(text)
                buildJsonObject { put("label", result.label) }
            }
            else -> error("Unknown tool: $name")
        }
    }
}
💡 设计模式:将 AICore 封装为 MCP Server 有两大好处:一是应用内的 AI 功能按工具粒度解耦,便于测试和扩展;二是同一个 MCP Client 可以同时连接端侧和云端 Server,AI 模型按照工具描述路由请求。

实际应用场景

1. 智能便签应用

用户说「帮我整理这周的购物记录」,App 通过 MCP 调用数据库查询工具、AI 摘要工具、日历工具,自动完成数据提取 -> 智能分析 -> 结果展示的完整流程。

2. 代码助手

Android Studio 插件集成 MCP Client,连接到项目分析 Server、Git 历史 Server、文档搜索 Server。开发者一句话就能完成代码审查、提交信息生成、问题定位。

3. 自动化工具

Tasker 类应用通过 MCP 协议暴露���统能力(WiFi 控制、短信发送、文件操作),用户可以用自然语言编排自动化流程。

最佳实践与注意事项

⚠️ 安全提示:在 Android 上暴露 MCP Server 时,务必通过 Android 权限系统控制敏感工具(如发送短信、访问通讯录)的访问。不要在无权限检查的情况下开放系统级能力。

总结与展望

MCP 协议正在重塑 AI 应用的开发方式。对于 Android 开发者来说,这并不是一个「要不要用」的问题,而是「什么时候开始用」的问题。

核心结论:

我已经将本文的完整示例代码整理为一个 Android 项目模板,你可以在 GitHub 上找到。欢迎 Star 和 PR。