MCP 关联应用集成标准

MCP 服务器会建立框架,用于将应用的功能(MCP 工具)连接到 Connected Apps Platform。为了让它能够更可靠地选择、调用和处理服务的结果,您的 MCP 配置必须严格遵守以下标准。

指导原则

对于每个函数,请重点关注用户意图和用例,而不是函数的功能。说明是您向模型传达工具用途和适用场景的主要方式。

版本控制

为了支持可扩缩且强大的 MCP 部署,请采用利用基于路径的版本控制(例如 /v1、/v2)的结构化 URI 架构。这样做有助于您保持向后兼容性,并控制新功能。通过使用特定于提供商的子网域(例如 https://gemini.mcp.company.com/mcp/v1)来补充此功能,可以实现精细的流量管理,并根据不同 AI 模型的独特上下文和处理行为优化工具定义。

MCP 协议版本兼容性

Connected Apps Platform 支持 Model Context Protocol (MCP) 规范,最高版本为 2025-11-25。尚不支持较新的规范版本。

  • 开发者责任:您有责任确保 MCP 服务器在 initialize 握手期间以及所有工具和架构定义中严格遵守 Connected Apps Platform (2025-11-25) 支持的协议版本。
  • 平台向后兼容性:随着 Connected Apps Platform 未来采用更新的 MCP 规范版本,我们的客户端将保持与之前支持的协议版本的向后兼容性,以便现有的生产集成继续正常运行。
  • 管理升级:当您准备好采用新支持的 MCP 规范或引入架构更改时,请在新的版本化 URI 路径(例如 /mcp/v2)上公开这些更新,同时保留现有端点 (/mcp/v1) 以处理活跃流量。

允许在应用版本之间更改 MCP 架构。我们建议您利用此功能,并对 MCP 端点进行版本控制,以支持新功能的温和发布,或严格依赖向后兼容的更改。

传输协议规范

Connected Apps Platform 严格支持版本 2025-03-26 及更高版本的 Streamable HTTP 传输 Model Context Protocol 规范。它不支持 2024-11-05 规范中描述的具有 SSE 传输功能的旧版 HTTP。

  • 单个 HTTP 端点。一站式管理中心内提供的 MCP 端点(例如 https://api.example.com/mcp)是适用的 Google 产品通过标准 HTTP POST 发送所有 JSON-RPC 请求(initialize、tools/list、tools/call)的唯一网址。
  • 可流式传输的 HTTP 中的 SSE 流式传输。不支持旧版多端点 SSE 传输,但可流式传输的 HTTP 支持 text/event-stream 等服务器发送事件。来自适用 Google 产品的传出请求包含 Accept: application/json, text/event-stream,这意味着您的服务器可以直接在 HTTP POST 响应正文中返回标准 application/json 载荷或使用 Content-Type: text/event-stream 流式传输增量响应。
  • GET stream & 405 Method Not Allowed. 客户端可以尝试在端点上使用可选的 GET 流来接收服务器到客户端的通知。如果您的服务器是无状态或仅请求-响应,则 Google 适用产品的客户端代理会明确支持并完全处理返回 HTTP 405 Method Not Allowed。

服务器说明

Connected Apps Platform 经过优化,可提取服务器指令,从而实现对模型行为的一定程度的控制,而这是其他方式无法实现的。

按照服务器说明操作。

视为具有使用上下文的“模型提示”

在向模型提供提示时,请遵循以下准则。

  • 以简明扼要的“提示”或指南形式编写指令,帮助 LLM 了解服务器的总体用途和功能。
  • 描述服务器的功能,而不是列出功能或描述模型应如何使用服务器的工具和资源。如果模型正确理解了“内容”,则可以根据用户体验历程很好地确定“方式”。
  • 假设此文本将直接添加到模型的系统提示中。保持清晰、具有指导性且高效利用 token。

互补而非重复

请在此处提供适用于所有工具的全局上下文,避免与各个工具的说明重复。

服务器指令示例

以下示例展示了正确编写服务器指令的注意事项。

建议 不推荐

现在你是一名专业的 GitHub 代码库维护者。此服务器提供对代码库元数据、问题跟踪和 PR 工作流的深度访问权限。您可以使用它来维护项目健康状况、自动进行问题分类并确保代码符合标准。除非另有说明,否则假设所有操作都是在经过身份验证的组织上下文中执行的。优先识别过时会话或未关联的 PR,以保持代码库井然有序。

简明扼要、具有指导性,且与模型相辅相成

  • 定义“做什么”(项目健康状况、分类),而不是“怎么做”
  • 提及适用于所有工具的身份验证范围

此服务器具有适用于 GitHub 的工具。当用户询问问题时,您应使用 list_issues 工具。您可以使用 create_pull_request 提交 PR。请谨慎使用这些工具,帮助用户管理其代码。在调用工具之前,请务必检查代码库名称。如果用户要求提供摘要,请先调用工具,然后总结输出

  • 不要重新列出工具名称,
  • 不要告诉模型“如何”思考,这可能会与模型的内置推理发生冲突,而内置推理会使用用户上下文做出正确的选择。
  • 未说明服务器访问权限的性质或其具体限制)

工具指南

以下指南介绍了为应用中的各种功能或工具创建 MCP 服务器配置的最佳实践。

工具命名惯例

请遵循以下工具命名准则:

使用直观、人类可读的名称

使用含义清晰、直观的人类可读名称,而不是含义模糊的名称。例如,get_user_information 比 userInfo 更直接。

注意大小写样式

请遵循以下工具函数名称和应用触发器的大小写规则:

  • 工具函数的大小写。对于 MCP 架构中定义的工具函数名称,请使用 snake_case 或 camelCase(例如 get_user_information 或 publishDraft)。
  • 应用触发器标识名的大小写。应用触发器和提及(例如 @MyTwoWordApp)不区分大小写。该平台会规范化用户输入,包括小写 (@mytwowordapp)、PascalCase (@MyTwoWordApp) 和 camelCase (@myTwoWordApp)。
  • 显示名称格式。使用 PascalCase 或标准空格注册您的官方应用名称,以便在界面元素中清晰地显示。
  • 拼写错误处理。虽然系统会自动处理大小写变体,但字符拼写错误(例如 @mytwowrodapp)依赖于后备 intent 识别,而不是直接字符串匹配。开发者应在文档中鼓励用户准确拼写标识名。

使用明确的“动词-名词”命名方式

使用具体的 verb_noun 命名,避免含糊不清,例如,publish_draft 比 handle_content 更好。

工具粒度

请遵循以下有关工具粒度的准则。

将工具视为原子端点

将工具视为原子端点,不包含内部工具条件或具有各自必需参数的多种功能。精细的工具使模型能够以逻辑方式串联步骤,从而减少幻觉。

使用更扁平的架构

如果您需要深度嵌套的对象或复杂的 oneOf / anyOf 架构逻辑来验证输入,则您的工具可能过于宽泛。

遵守预汇总和载荷护栏

虽然对于范围较小的载荷,协议并未严格强制要求预先汇总数据,但在实际处理大型记录集、纵向历史记录和多源数据集时,强烈建议在后端进行预先汇总。 Connected Apps Platform 会针对上下文窗口限制、执行延迟时间和模型推理步骤强制执行保护措施。为遵守这些护栏,请遵循以下准则:

  • 在后端进行过滤和汇总。在将响应返回给适用的 Google 产品之前,请务必在 MCP 服务器上过滤、预汇总或汇总大型数据流。
  • 避免原始转储。切勿将原始数据库行或完整的未编入索引的日志转储到工具返回载荷中。

省略内部和元工具

在服务器的 tools/list 响应中,仅公开面向模型的功能:

  • 过滤辅助工具:省略任何不打算由模型调用的内部、管理或元工具(例如,服务器健康检查、内部设置例程或开发者实用程序辅助工具)。
  • 上下文窗口效率:排除不必要的工具可使 MCP 架构保持简洁,减少上下文窗口 token 消耗,并防止模型工具路由混淆。如果 MCP 服务器公开了数十个工具或深度嵌套的“超级工具”架构,则会在审核期间被标记,以便进行修复。

工具粒度注意事项

以下示例展示了工具命名和粒度使用方面的注意事项。

建议 不推荐

具有清晰名称和参数的精细工具

每个工具的输入架构都是严格的。如果 LLM 想要创建用户,则必须提供电子邮件地址。如果想要删除,则必须提供 ID。无需猜测。

...
@mcp.tool()
def create_user(email: str, role: str = "viewer") -> str:
    """Register a new user. Returns the new User ID."""
    # Logic is purely creation
    return "user_123"

@mcp.tool()
def delete_user(user_id: str) -> str:
    """Permanently remove a user by their ID."""
    # Logic is purely deletion
    return f"User {user_id} deleted"

@mcp.tool()
def update_user_role(user_id: str, new_role: str) -> str:
    """Change an existing user's permission level."""
    return f"User {user_id} is now {new_role}"

    ...

工具名称:manage_user

Description: "Use this tool to create, update, delete, or retrieve users."

...
@mcp.tool()
def manage_user(
    action: Literal["create", "update", "delete", "get"],
    user_id: Optional[str] = None,
    email: Optional[str] = None,
    role: Optional[str] = "viewer"
) -> str:
    """
    Use this to manage users.
    WARNING: logic is hidden inside Python, not visible in the schema.
    """
    if action == "create":
        if not email: return "Error: Email required for creation" # Runtime error, not schema error
        return f"Created user {email}"
    elif action == "delete":
        if not user_id: return "Error: User ID required"
        return f"Deleted {user_id}"
    
    return "Action completed"
    """
    ...

声明工具注解以确保安全

在工具定义中配置协议注解,以传达执行行为并在适用的 Google 产品中触发内置安全关卡:

  • 运行时确认关卡:适用的 Google 产品使用 annotations.destructiveHint: true 和 annotations.openWorldHint: true 作为关键标志来触发运行时用户确认提示。在状态更改、写入或破坏性操作中声明 destructiveHint: true,并为与开放世界或外部环境交互的工具设置 openWorldHint: true,以便界面在执行前原生提示用户进行确认。
  • 只读查询提示:在仅提取数据而不修改后端状态的查询工具上设置 readOnlyHint: true。
  • 显式注解默认值:根据 Model Context Protocol 规范,省略 readOnlyHint 会导致客户端默认采用 readOnlyHint: false 和 destructiveHint: true,以确保安全。在所有工具上明确声明注解可确保可预测的模型路由和适当的执行安全性。

工具说明

说明是模型用来确定工具能否解决当前问题的唯一上下文。请遵守以下有关撰写说明的准则:

编写指令,而不是注释

以指令形式编写工具说明,而不是以代码注释形式编写,因为代码注释通常是被动的。LLM 能够很好地响应指令。

说明“如何”

好的描述可以弥合“我有一个工具”和“我知道如何将此工具连接到对话中”之间的差距。

说明原因

将此工具与类似工具区分开来,例如“此工具供内部用户使用,customer_update 供外部用户使用”。

告诉模型在哪里可以找到实参,例如“来自 order_search 工具”。

指定格式

指定单位(米与英尺)和格式(ISO 日期、语义版本)。

避免模型自行判断

不要指示模型使用其“最佳判断”或建议可选的、无指导的操作。

工具说明示例

以下示例展示了在编写工具说明时应遵循的最佳实践和应避免的做法。

建议 不推荐

可信数据来源

“更新用户的电子邮件。必须严格使用 search_users 工具返回的 UUID“id”。请勿推断或猜测用户 ID。”

(它明确将一个工具的输出与此工具的输入关联起来。)

“更新用户的邮箱。”

(模型可能会猜测一个 ID,例如 12345。)

格式和限制

“安排会议。“date”必须采用 ISO 8601 格式 (YYYY-MM-DD)。如果用户说“明天”或其他相对时间,请根据当前上下文计算日期。”

“安排在指定日期开会。”

(对人类来说看起来正确 [例如“明天”],但未通过架构验证 [需要“2025-10-12”])

输出预期

“检索服务器日志。返回最后 50 行原始文本。如需进行分析,请请求较小的时间范围,以免超出 token 限制。”

“获取服务器日志。”

(模型可能会调用一个工具,期望获得摘要,但却得到了一个 5MB 的原始 JSON 转储,这可能会导致用户体验不佳。)

@mcp.tool()
def update_campaign_status(campaign_id: str, status: str) -> str:
    """
    Promotes or pauses an advertising campaign.
    
    CRITICAL USAGE RULES:
    1. 'campaign_id': Must be the 32-character UUID retrieved from 'list_campaigns'.
    2. 'status': Must be exactly one of: ['active', 'paused', 'archived'].
    
    Returns: A confirmation string with the new status and timestamp.
    """
    # Logic...

    ...

此说明相当于一份简明手册。它负责处理来源(从何处获取 ID)、限制条件(有效枚举)和操作。

@mcp.tool()
def update_campaign_status(id: str, status: str) -> str:
    """
    Updates the campaign status in the database.
    """
    # Logic...

这完全依赖于变量名称来完成所有工作。这会让模型猜测“status”的有效值

工具参数

除了工具本身之外,还要描述参数,使其清晰明确。

显式类型

使用强类型和特定类型(string、integer、boolean、array)。

对固定值集使用枚举

如果某个参数仅接受一组固定值(例如 daylight、cool、warm),请在 enum 数组中列出这些值。这可以显著提高准确性。

明确说明必需参数

明确定义哪些参数是函数运行所必需的。

应用语义架构匹配

集成应用时,可能需要将工具参数与您正在开发的行业进行语义架构匹配。您将在初始配置过程中收到预期的行业架构(JSON 架构)。

工具参数示例

以下示例展示了处理工具参数时的正确做法和错误做法。

建议 不推荐

参数格式和单位

radius:半径(以米为单位)。必须是大于 0 的浮点数。”

(防止单位幻觉)

radius: "圆的半径。"

ID 格式和上下文

user_id:“数据库 UUID(例如 550e8400-e29b…)。请勿在此处使用电子邮件地址。”

注意:作为一种最佳实践,所有数字 ID 字段都应视为字符串值。具体而言,如果您的 ID 长度可能超过 10 位,则可能会被内部系统截断(强制放入 32 位容器中),并且模型在未来的工具调用中会使用此版本。

(防止类型错误)

user_id:“用户的 ID。”

返回值预期

“更新记录并返回更新后的 JSON 对象,包括新的时间戳。”

(告知模型,它无需在“更新”后立即调用“获取”工具来验证更改。)

“更新记录。”


@mcp.tool()
def search_logs(query: str, limit: int = 10) -> str:
    """
    Searches server error logs using Lucene syntax (e.g. 'level:ERROR AND service:auth').
    
    Args:
        query: A Lucene-formatted search string.
        limit: Max results to return. capped at 50.
    
    Returns:
        A formatted string of log entries with timestamps.
    """
    ...
  
@mcp.tool()
def search_logs(query: str, limit: int = 10) -> str:
    """Searches the logs."""
    ...

LLM 不知道“query”支持什么语法(SQL?Regex? Plain text?) 它不知道最大“限制”是多少。

响应和错误处理

根据回答即是下一个提示的核心原则,工具会通过返回数据载荷来报告其底层执行的结果,然后该载荷会直接粘贴到 LLM 的上下文窗口中。结果是成功还是失败决定了接下来会发生什么:

  • 如果成功:模型需要返回值来了解发生了什么,以便决定下一步。
  • 如果失败:模型需要知道失败的原因以及如何解决。崩溃(500 错误)会中断对话;而描述性出错提示则允许模型自行纠正。

无论工具的底层逻辑是成功还是失败,您都必须设置返回值载荷的格式,以便模型可以轻松解析。在打包响应载荷时,请遵循以下最佳实践。

使用 JSON

在 TextContent 中设置结构化数据的格式(临时限制)。由于 Connected Apps Platform 尚不支持 structuredContent,因此请手动序列化数据。即使返回的是一个简单的列表,也请json.dumps()。

在回答中包含网址

返回的网址应相对较短,且不包含过多参数。建议使用网址缩短服务来节省 token 数量并降低幻觉风险。

自描述性反幻觉载荷

始终将原始代码或内部 ID 与人类可读的显示名称、明确的测量单位和参考范围配对。切勿返回压缩的字典键或未映射的数字代码,以免模型被迫推断上下文。

实施强大的错误处理机制

返回清晰、有意义的错误消息,以便模型了解出了什么问题并通知用户。请参阅 MCP 错误处理。

使用 try/except

将工具逻辑封装在 try/except 块中,并返回字符串化的错误。

提供可操作的错误

在出错提示中建议下一步操作(例如,“请先尝试使用工具 X”)。

确认操作

请勿针对有副作用的工具(创建/更新/删除)返回空字符串。

响应和错误处理示例

以下示例展示了与响应和错误处理相关的最佳实践和不当做法。

建议 不推荐

显式序列化


...
import json

@mcp.tool()
def query_metrics(metric_id: str) -> str:
    result = {"id": metric_id, "value": 42, "unit": "ms"}
    # GOOD: Returns '{"id": "cpu", "value": 42}' -> Valid JSON
    return json.dumps(result, indent=2)

...
@mcp.tool()
def query_metrics(metric_id: str) -> str:
    result = {"id": metric_id, "value": 42, "unit": "ms"}
    # BAD: Returns "{'id': 'cpu', 'value': 42}" -> Invalid JSON
    return str(result)

捕获并通知


...
@mcp.tool()
def get_user_details(user_id: str) -> str:
    try:
        user = db.get_user(user_id)
        if not user:
             # GOOD: Informative error returned as content
            return f"Error: User with ID '{user_id}' not found. Please verify the ID using 'search_users'."
        return json.dumps(user)
    except Exception as e:
        return f"Error: Database connection failed ({str(e)}). Please try again later."

(从技术上讲,该工具“成功”了 [返回了一个字符串],但该字符串包含错误详情。模型读取此信息后,会意识到“哦,该 ID 不存在”,并可以向用户询问正确的 ID。)


...
@mcp.tool()
def get_user_details(user_id: str) -> str:
    # BAD: Unhandled exception if ID not found
    user = db.get_user(user_id)
    return json.dumps(user)

(如果 get_user 失败,服务器会抛出 500 错误。LLM 收到一般执行错误,但不知道原因(是 ID 错误?数据库宕机?权限遭拒?)。它很可能会重试完全相同的错误输入。)

空白回复

...
@mcp.tool()
def post_story(story_content: str) -> str:
    service_name = "story_service"
    api_client.post("/stories", json={"content": story_content})
    # GOOD: Explicit confirmation of state change.
    return f"Service '{service_name}' successfully posted content. Status is now 'posted'."

...
@mcp.tool()
def post_story(storyContent: str):
    subprocess.post(["postsrv", "story", storyContent])
    # BAD: Returns null/empty string. Model is confused.

LLM 通常会因空回答而感到困惑。它们可能会产生幻觉,认为“工具失败了”,或者只是重复调用。

自描述性反幻觉载荷

始终将原始代码或内部 ID 与人类可读的显示名称、明确的测量单位和正常参考范围配对。

{"lab_code": "2345-7", "display_name": "Glucose [Mass/volume] in Blood", "value": 105, "unit": "mg/dL", "reference_range": "70-99 mg/dL"}

(这可以准确地告诉模型该值的含义,而无需强制其推断单位或参考阈值。)

原始 ID、自定义压缩或未映射的代码

返回原始内部 ID、自定义字典缩写或不带标签的数字代码。

{"code": "2345-7", "v": 105}

(这会迫使模型猜测 105 指的是什么,从而导致幻觉单位、缺少上下文或解释不准确。)

MCP 错误处理

妥善处理错误至关重要。

  • 对于可恢复的错误(例如用户 ID 无效或缺少可选参数),请在工具响应中返回包含描述性错误详情的普通文本字符串。这样,模型就可以检查反馈、了解问题所在,并自行更正或提示用户进行澄清。
  • 对于终端错误(例如速率限制、身份验证或权限失败,或后端服务器服务中断),请引发带有相应错误代码的 McpError,以便平台能够系统地处理故障。

错误响应正文示例 (JSON)

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32302,
    "message": "User permission denied for the requested operation.",
    "data": null
  },
  "id": 1
}

Message 包含 MCP 的 ErrorData 字段的 JSON 转储。通过返回正确的 code 和模型可见的 message,Connected Apps Platform 可以读取出错提示,并向用户传达有用的自然语言解释。例如,“抱歉,我找不到具有该 ID 的场馆。请您检查一下名称。”

MCP 允许客户端使用 JSON-RPC 2.0 规范连接到 MCP 服务器。JSON-RPC 针对常见错误(例如无效请求、解析错误等)预定义了一些错误。本指南介绍了 MCP 服务器如何发送自定义错误。

状态
代码
消息 用法 需要明确
返回
吗?
用户/客户错误
-32300 USER_RATE_LIMITED 用户已达到用量限额上限。 是
-32301 MISSING_REQUIRED_INFORMATION 输入请求不包含所需的所有信息 是
-32302 USER_PERMISSION_DENIED 用户拒绝授予使用该工具的权限。例如,用户需要拥有企业账号、满足年龄限制、位于特定语言区域等,或者未订阅该工具的企业版。 是
应用错误/业务逻辑错误
-32400 RUNTIME_ERROR 服务器代码执行引发了错误 是
-32401 NULL_POINTER_EXCEPTION 尝试运行空指针/对象 是
-32402 OUT_OF_MEMORY 服务器代码中没有足够的内存可分配给对象 是
基础设施错误
-32500 DEADLINE_EXCEEDED 请求用时超过了允许的时间。可能由多种原因导致,例如服务器过载、网络问题等。 是
-32501 RESOURCE_EXHAUSTED 服务器内存不足、磁盘可用空间不足、线程不足、CPU 时间不足等。 是
-32502 SERVICE_UNAVAILABLE 依赖服务(例如其他微服务、数据库、缓存等)不可用 是
JSON-RPC 错误(这些错误属于 MCP 传输的一部分)
-32700 PARSE_ERROR 服务器无法解析该请求 否
-32600 INVALID_REQUEST 客户端请求格式不正确 否
-32601 METHOD_NOT_FOUND MCP 工具名称无效 否
-32602 INVALID_PARAMS 请求参数无效,包括缺少参数或参数类型不匹配 否
-32603 INTERNAL_ERROR 默认回答 否

以下示例展示了如何使用官方 Python SDK (mcp) 在服务器中引发 MCP 错误。引发包含 ErrorData 载荷的 McpError,SDK 会自动将其序列化为所需的 JSON-RPC 错误格式,并填充错误状态。

from mcp import types
from mcp.shared.exceptions import McpError

@mcp.tool()
def foo_tool() -> list[types.TextContent]:
  """Always returns an error."""
  raise McpError(
    types.ErrorData(
        code=-32302, # USER_PERMISSION_DENIED
        message="Message to show to the model."
    ),
  )

工具上下文

适用的 Google 产品支持 Tool Context API,以便将信号传递给 MCP 服务器。此 API 用于需要敏感信息的有效用例,例如,不属于核心工具定义的元数据,如需要本地化的工具的语言区域。Tool Context API 仅通过一站式管理中心公开。

当您在一站式管理中心内为应用注册 current_user_location_fine 等信号时,适用的 Google 产品会使用额外的 _meta 条目来扩充 MCP tools/call 请求,以提供所请求的数据。支持的信号集包括:

  • current_user_location_fine(仅限 Gemini,适用于允许的行业)
  • user_locale
  • current_user_location_coarse
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "find-restaurant",
    "arguments": {"query": "restaurants near me"},
    "_meta": {
      "current_user_location_fine": {
        "latitude_degrees": 37.7749,
        "longitude_degrees": -122.4194,
        "accuracy_meters": 112.4221
      },
      "user_locale": {
        "language_code": "en",
        "region_code": "US"
      }
    }
  }
}

如需解压这些数据,请执行以下操作:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("remote_mcp")

@mcp.tool()
async def find_restaurants(query: str, ctx: Context) -> str:
   # Access context directly from _meta
   request_context = ctx.request_context
   meta_dict = ctx.request_context.meta.model_dump() if ctx.request_context.meta else {}

   location_context = meta_dict.get("current_user_location_fine", {})
   lat = location_context.get("latitude_degrees")
   lng = location_context.get("longitude_degrees")
   if lat and lng:
       return f"Finding '{query}' near ({lat}, {lng})"
   return f"Finding '{query}' (no location provided)"

用户体验呈现

MCP 应用

适用的 Google 产品支持针对特定用户体验历程集成 MCP 应用,以便构建自定义界面。请按照规范中的常规集成说明进行操作。

在适用的 Google 产品上集成 MCP 应用时,请注意以下事项。

注册时提取资源

适用的 Google 产品会在工具提取期间提取界面资源,类似于工具列表和工具说明。这意味着,任何资源更新(例如 JavaScript 中的更改)都不会自动被检测到,需要工具重新提取。

单个界面资源的大小不得超过 15 MB,并且服务器上的累计界面资源不得超过 100 MB。

界面资源必须使用以下受支持的 MIME 类型之一:text/html、text/javascript、text/css 或 text/html;profile=mcp-app。非标准或平台专属 MIME 类型在推送到预览时将无法通过验证。

CSP 准则

适用的 Google 产品遵循官方 MCP 应用规范,其中包括 CSP [1]、[2],并且会屏蔽任何违反 CSP 指令的请求。

如果使用适用的 Google 产品,则还需要将 blob: 和 data: 添加到 CSP。默认情况下,系统不会添加这些内容。开发者可自行选择是否将其添加到 CSP。

Script-src 是一个例外

我们仅允许使用以下指令:unsafe-inline(默认添加)、wasm-unsafe-eval 和 data:(如果包含在 resource_domains 中)。如果 iframe 正在加载外部脚本,则可以通过将 JS 捆绑到 HTML 中或使用子资源完整性 (SRI) 哈希来解决此问题。

  • 方案 1:将 JS 内嵌/打包到 HTML 中(最简单)

    • 打包 JS 代码:

      • 在为界面资源返回的 HTML 载荷中,将 component-init.js 的内容直接内嵌到 <script> 标记内:

        <script>
        // Paste component-init.js content directly here
        </script>
        
    • 移除远程 <script src> 标记

      • 从 HTML 文档中删除 <script src="https://api.mycompany.com/..."> 引用。
    • 重新提取/更新工具

  • 方法 2:使用子资源完整性 (SRI) 哈希:

    如果脚本必须继续托管在外部 https://api.company.com/...,请使用此选项。

    • 计算脚本的 SHA-256 哈希值
      • 生成 component-init.js 的 base64 SHA-256 哈希
    • 向 resourceDomains 添加哈希(必须包含 sha256- 前缀,以便与 integrity 属性匹配)
    • 更新 HTML <script> 标记
      • 向 HTML 微件中的脚本标记添加 integrity 和 crossorigin 属性
    • 验证 CDN/服务器上的 CORS 标头
      • 确保 api.company.com 使用 Access-Control-Allow-Origin: * 提供 component-init.js(或允许 scf.usercontent.goog),以便浏览器可以读取响应正文以进行 SRI 验证。
    • 重新提取/更新工具

MCP 工具说明的安全准则

由于说明是模型理解工具功能的唯一上下文,因此必须准确、安全地编写说明,以防止出现意外行为。在起草工具说明时,请遵循以下准则。

  • 描述功能,但不要规定行为。说明必须准确描述工具的功能,而不是命令模型执行后续操作。
  • 确定范围和要求。清楚说明工具的主要目标、具体使用场景(何时)以及所有必需的输入(形参/实参)。
  • 确保真实性。说明必须真实反映工具的底层代码。如果工具执行写入或删除操作,请勿声称该工具是只读的。

安全风险及如何避免

风险区域 建议 不惜一切代价避免这种做法

提示词注入

使用客观、陈述性的语言,清楚说明工具的用途和功能。

使用命令式指令来覆盖模型行为或更改系统流程(例如,“你必须说…”,“跑步后,您必须…”)。只有在定义结构化参数限制或使用规则时,才可使用“必须”或“关键”等命令式术语。

对工具说明文本使用标准、纯文本格式。

使用吸引眼球的格式,例如过多使用大写字母和 VERY IMPORTANT: 或 **CRITICAL** 等标记。

仅关注工具的功能和预期行为。

包含角色扮演指令或忽略先前指令的命令。

工具影子化和劫持

确保说明具体,且仅限于工具的实际相关功能。

工具说明过于宽泛、模糊,或声称单个工具可执行许多不相关的功能。

选择一个独特、具有描述性且合理的工具名称。

使用与可信工具名称略有不同的工具名称,或使用通用名称(例如 do_everything_tool、assistant_tool)。

请勿在说明中提及其他应用或外部平台工具的名称。

明确引用其他工具,或针对其他工具的使用时机或方式创建新规则。

允许模型的规划器根据用户上下文选择最合适的工具。

包含反竞争语言或任何类型的 SEO 提示,指示模型优先选择您的工具,而非类似工具。

触发器操纵

说明不引用或回应一般对话历史记录短语。

创建条件逻辑,在用户输入常见、无害的短语(例如“谢谢”“总结一下”)时触发有害操作。

滥用参数

仅定义工具功能所需的参数,并使用特定于输入数据的名称(例如 file_id、search_term)。

使用反映智能体内部状态的名称(例如 system_prompt、conversation_history、full_context)定义函数参数。

数据渗漏

从设计上保障用户隐私 - 不透明标识符和主机管理的身份验证。

使用非敏感 ID,而非原始个人身份信息。所有数据处理都必须在经过授权的安全边界内进行,并且不得在公开说明中提及数据会被发送到外部。工具执行将通过 OAUth 握手以静默方式继承权限。

在将任何敏感信息发送到适用的 Google 产品之前,应先对其进行清理。

以任何违反适用 Google 产品服务条款的方式,向用户、个人或商家数据或实体请求个人身份信息 (PII)、受保护健康信息 (PHI) 或任何其他个人和/或敏感信息。

提及或要求将任何用户数据(查询、位置、上下文)发送到未经授权的第三方网址、日志记录服务或外部系统。

功能和命名最佳实践

除了确保工具说明的安全之外,您还必须确保模型能够可靠地选择和执行该工具,而不会产生混淆。请遵循以下功能和命名最佳实践:

  • 参数准确性。确保说明中的所有参数名称和类型与工具的实际实现完全一致。
  • 合理的命名。工具的名称应能清晰、明确地提示其功能。避免使用过于宽泛的名称,例如“execute”。名称还必须与更广泛的工具生态系统保持一致。

附录:基础架构和网络许可清单

如果您的托管基础架构、API 网关或防火墙按来源 IP 地址限制传入连接,请将以下 Google 出站 CIDR 块列入许可清单:

  • 108.177.64.0/20
  • 142.250.88.0/22
  • 172.217.80.0/20
  • 192.178.20.0/22
  • 192.179.0.0/20
  • 74.125.232.0/24
  • 136.121.40.0/21

请确保您的环境允许来自这些 IP 范围的流量通过 HTTPS 端口 443,以便适用的 Google 产品可以访问您的远程 MCP 服务器,从而进行 MCP 初始化、工具发现和请求执行。