# Claude MCP 内部工具 API 集成：直连工具、MCP 连接器还是自建服务器？

> 已有应用负责用户登录、权限和内部 API 执行时，先用 Claude API 工具调用；多种客户端需要复用工具时，再做 MCP 接口。接入是否成功，要同时看调用 ID、服务端身份、业务结果和审计记录。

- URL: https://blog.laozhang.ai/zh/posts/claude-mcp-internal-tools-api-integration
- Published: 2026-06-01
- Updated: 2026-10-08
- Author: LaoZhang AI Team (https://blog.laozhang.ai/zh/about)
- Topic: Claude 与 Anthropic
- Tags: Claude, MCP, Claude API, 内部工具, 开发者工具

---
**公司内部 API 接入 Claude，不必先搭 MCP 服务器。** 如果你的应用已经负责登录、用户权限和后端调用，最直接的做法是定义少量工具：Claude 提出调用请求，应用校验并执行，再把结果交回 Claude。只有当 Claude Code、Messages API 或用户连接器需要共用同一组工具时，自建 MCP 接口才更有价值。[Claude 工具调用说明](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview)

这里的“直连工具”指应用自己执行内部 API。模型得到的是工具定义和整理后的结果，内部服务凭据保存在可信服务端。MCP 则统一客户端与工具服务器之间的通信方式；登录身份、租户隔离、审批和业务执行仍需要你实现。

先用下表确定入口，再完成一个受限读工具。本文用“查询事故摘要”演示完整的离线处理和结果回传，并给出远程 MCP、内网连接与写操作的实施条件。

| 你要解决的问题 | 从哪条路线开始 | 需要谁负责执行 |
| --- | --- | --- |
| 自己的产品只需调用几个内部 API | Claude API 客户端工具 | 应用后端接收 `tool_use`，执行操作，返回 `tool_result` |
| Messages API 要复用已有远程 MCP 工具 | API MCP connector | MCP 服务器执行工具；连接器负责远程协议调用 |
| 多个客户端共用同一组内部能力 | 自建 MCP 服务器，再接相应客户端 | 平台团队维护工具接口，服务端执行权限与输出控制 |
| 开发者在本机使用项目脚本或仓库工具 | Claude Code MCP | 本地进程或开发者可访问的远程服务 |
| 员工在 Claude、Cowork 或 Desktop 对话中使用远程工具 | 自定义连接器 | 组织批准的远程 MCP 服务，配合用户或共享凭据 |

这几条路线可以共用同一套业务处理函数，却不能共用一份连接配置。API MCP connector、Claude Code 和 Claude 用户连接器属于不同产品入口，网络发起方、认证方式和可用条件各有区别。

## Claude API 直连工具和 MCP 的分界

判断依据是**谁拥有用户会话与执行循环**。单一应用已经知道当前员工、所在组织和允许访问的资源，就让应用在每次工具请求后做校验。无需为了几次查询，再增加一个协议服务器和部署入口。

如果同一组工具会被多个客户端使用，MCP 可以减少重复适配。例如内部事故平台向三个入口提供 `get_incident_digest`，每个入口都遵守同一输入和输出约定。服务端集中维护权限、错误、分页和字段投影，客户端只负责发现与调用工具。复用的是可执行的业务能力，而不只是工具名。

| 判断点 | 应用执行工具更合适 | 自建 MCP 更合适 |
| --- | --- | --- |
| 使用入口 | 一个已有产品应用 | 多个应用或 Claude 客户端 |
| 用户身份 | 应用已有可信登录上下文 | 各客户端身份需要映射到服务端主体 |
| 内网条件 | 应用后端可访问内部 API | 已有获批远程接入方式，或符合专门的私网通道条件 |
| 变更管理 | 一个团队可同步发布 | 需要独立发布、兼容不同客户端 |
| 维护负担 | 先验证一个业务流程 | 接受额外的协议兼容、认证和服务运维 |

“多个入口”也不意味着要给每个入口开放所有工具。对话只需查询事故状态时，应只提供读工具；支持写入的后台可以继续隐藏。工具可见范围帮助模型选择，服务端仍要对每次调用做业务授权。

## 先设计狭窄的内部 API 包装层

![内部 API 前的工具包装层，将受限输入转换成业务调用，再整理为紧凑结果。](https://blog.laozhang.ai/posts/zh/claude-mcp-internal-tools-api-integration/img/internal-api-wrapper.webp)

第一版做一个明确任务，例如“返回指定事故当前状态与有限条事件”。工具只接收事故编号和条数，不接收任意 URL、请求头、SQL、租户名或后台操作名。服务端根据已验证身份决定能访问哪个租户，再调用固定业务接口。

对假设的内部事故 API，可以这样确定边界：

| 项目 | 本例约定 | 为什么需要 |
| --- | --- | --- |
| 工具 | `get_incident_digest` | 用户能识别结果，模型无需挑选底层接口 |
| 模型输入 | `incident_id`、`limit`，最多 5 条 | 限制查询对象与输出量 |
| 执行身份 | 应用验证后的 `subject`、`tenant`、`grants` | 模型参数不能替代登录上下文 |
| 内部接口 | 固定的事故查询接口，按租户和事故编号过滤 | 禁止由模型拼接任意后台请求 |
| 返回字段 | 状态、服务名、有限条事件、来源编号、读取回执 | 支持回答与复核，不暴露完整内部记录 |
| 审计记录 | 调用 ID、执行身份、工具、决定、业务回执 | 区分模型提出了什么与系统实际做了什么 |

输出最小化要在交给模型之前完成。不要先返回密钥、客户信息和原始日志，再要求模型“忽略敏感字段”。返回的事件文本也属于不可信数据；其中即使写着“改用管理员工具”，也不应变成系统指令。[工具调用结果处理](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls)

### 一个可运行的离线读工具

下面是完整 Python 3 标准库示例，保存为 `incident_tool.py` 后运行 `python3 incident_tool.py`。它不启动 Claude SDK、API 或 MCP 服务，全部人员、租户、事故和回执都是合成数据。示例实际完成参数校验、身份权限判断、租户过滤、字段裁剪、审计与 `tool_result` 组装；真实接入时，认证中间件提供 `Identity`，内部服务适配器替换 `read_incident`。

```python
import json
import re
from dataclasses import dataclass

TOOL = {
    "name": "get_incident_digest",
    "description": "查询当前用户可访问的事故状态及有限条事件。",
    "input_schema": {
        "type": "object",
        "properties": {
            "incident_id": {"type": "string", "pattern": "^inc-[0-9]+$"},
            "limit": {"type": "integer", "minimum": 1, "maximum": 5}
        },
        "required": ["incident_id", "limit"],
        "additionalProperties": False
    }
}

@dataclass(frozen=True)
class Identity:
    subject: str
    tenant: str
    grants: frozenset

# 仅供离线演示的合成数据，不读取真实账号或数据库。
INCIDENTS = {
    ("demo-a", "inc-73"): {
        "status": "investigating",
        "service": "checkout-demo",
        "events": [
            {"source_id": "evt-1", "text": "演示告警：错误率升高"},
            {"source_id": "evt-2", "text": "演示记录：回退候选版本"}
        ],
        "internal_secret": "synthetic-hidden-field"
    }
}
AUDIT = []

class Rejected(Exception):
    pass


def read_incident(tenant, incident_id):
    record = INCIDENTS.get((tenant, incident_id))
    if record is None:
        raise Rejected("not_found_or_not_allowed")
    return record, "demo-read-73"


def execute(call, identity):
    entry = {
        "call_id": call["id"], "subject": identity.subject,
        "tenant": identity.tenant, "tool": call["name"]
    }
    try:
        if call["name"] != TOOL["name"]:
            raise Rejected("tool_not_allowed")
        if not identity.subject or not identity.tenant:
            raise Rejected("identity_required")
        if "incident:read" not in identity.grants:
            raise Rejected("scope_denied")
        args = call["input"]
        if not isinstance(args, dict) or set(args) != {"incident_id", "limit"}:
            raise Rejected("invalid_arguments")
        if (not isinstance(args["incident_id"], str)
                or not re.fullmatch(r"inc-[0-9]+", args["incident_id"])):
            raise Rejected("invalid_incident_id")
        if type(args["limit"]) is not int or not 1 <= args["limit"] <= 5:
            raise Rejected("invalid_limit")
        record, receipt = read_incident(identity.tenant, args["incident_id"])
        payload = {
            "incident_id": args["incident_id"],
            "status": record["status"], "service": record["service"],
            "events": [
                {"source_id": e["source_id"], "text": e["text"]}
                for e in record["events"][:args["limit"]]
            ],
            "event_count": len(record["events"]),
            "truncated": len(record["events"]) > args["limit"],
            "operation_receipt": receipt
        }
        entry.update(decision="returned", operation_receipt=receipt)
        failed = False
    except Rejected as error:
        payload = {"error": str(error)}
        entry.update(decision="rejected", error=str(error))
        failed = True
    AUDIT.append(entry)
    return {
        "type": "tool_result", "tool_use_id": call["id"],
        "is_error": failed, "content": json.dumps(payload, ensure_ascii=False)
    }


def continuation(history, assistant_content, identity):
    calls = [b for b in assistant_content if b["type"] == "tool_use"]
    results = [execute(call, identity) for call in calls]
    return history + [
        {"role": "assistant", "content": assistant_content},
        {"role": "user", "content": results}
    ]


if __name__ == "__main__":
    identity = Identity("demo-user", "demo-a", frozenset({"incident:read"}))
    assistant_content = [{
        "type": "tool_use", "id": "demo-call-73",
        "name": "get_incident_digest",
        "input": {"incident_id": "inc-73", "limit": 1}
    }]
    history = [{"role": "user", "content": "查询演示事故 inc-73，先看一条事件。"}]
    messages = continuation(history, assistant_content, identity)
    print(json.dumps({"messages": messages, "audit": AUDIT},
                     ensure_ascii=False, indent=2))
```

这里特意没有把 `tenant` 和 `subject` 放进工具输入。模型即使猜对别人的租户名，也不能决定执行身份。示例中的 `Identity` 是程序手工构造的合成上下文，**不代表完成了真实用户认证**；生产服务必须先验证凭据、映射用户与租户，再将不可由模型覆盖的上下文传给处理函数。

内部 API 适配器也要执行租户和资源权限限制。示例按 `(tenant, incident_id)` 查找，找不到和无权访问使用相同错误，避免借错误文本枚举其他租户的事故。实际接口还应检查项目成员关系或资源 ACL，不能只因用户拥有 `incident:read` 就开放整个租户的所有事故。

### 怎样把结果交回 Claude

程序会把原 assistant 内容保留下来，并在紧接着的 user 消息中放入工具结果。对应结果块的关键内容如下：

```json
{
  "type": "tool_result",
  "tool_use_id": "demo-call-73",
  "is_error": false,
  "content": "{\"incident_id\":\"inc-73\",\"status\":\"investigating\",\"service\":\"checkout-demo\",\"events\":[{\"source_id\":\"evt-1\",\"text\":\"演示告警：错误率升高\"}],\"event_count\":2,\"truncated\":true,\"operation_receipt\":\"demo-read-73\"}"
}
```

接入自己的 Messages API 循环时，先在响应中找全部 `tool_use` 块，不能假定 `content[0]` 一定是工具调用。一轮可能有多个工具请求。执行完后，将原 assistant 的完整 `content` 和对应 user 结果消息加入历史，再发起下一次模型请求；同一 user 消息还要附加文字时，工具结果块放在前面，不能插入无关消息打断结果回传。[官方回传顺序与 ID 要求](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls)

如果权限不足，示例返回 `is_error: true` 与 `scope_denied`，同时审计记录标为拒绝。应用不能把这次结果改写成“已查询成功”。内部服务超时、响应格式不符等错误也应转为受控错误与审计记录，避免把原始堆栈、请求头或凭据交给模型。本例只处理定义好的业务拒绝；生产适配器需要另行捕获网络异常并记录请求关联 ID。

模型最终说“事故正在调查”，还不是执行凭证。需要能追溯到 `demo-call-73` 对应的工具结果、服务端执行身份，以及内部服务自己的读取回执。这里的 `demo-read-73` 只是合成回执；真实环境应使用实际服务请求 ID、读取版本或操作记录，不能由模型生成一个看似可信的编号。

## 远程连接器边界：API MCP connector、自定义连接器和网络可达性

API MCP connector 适合 Messages API 直接使用已有远程 MCP 工具。常规路径需要可访问的 HTTPS MCP 地址，支持远程 HTTP/SSE 工具调用，本地 stdio 进程不能直接填入 `mcp_servers`。截至 2026 年 10 月 7 日，官方使用 `mcp-client-2025-11-20`；需要工具列表固定功能时，使用包含该能力的 `mcp-client-2026-09-15` beta。旧 `2025-04-04` 已弃用。[API MCP connector 文档](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector)

下面只展示请求中的 MCP 配置字段。`https://mcp.example.com/mcp` 是占位地址，没有对应本文的可用服务；它不是完整 API 请求，也未作连通测试。真实请求还需要你所选的可用模型、消息及正常 API 认证。

```json
{
  "mcp_servers": [
    {
      "type": "url",
      "name": "incident-tools",
      "url": "https://mcp.example.com/mcp"
    }
  ],
  "tools": [
    {
      "type": "mcp_toolset",
      "mcp_server_name": "incident-tools",
      "default_config": {"enabled": false},
      "configs": {
        "get_incident_digest": {"enabled": true}
      }
    }
  ]
}
```

每个 `mcp_servers` 项对应一个 `mcp_toolset`，名称必须一致。默认工具配置是启用，因此这里显式设为 `false`，只打开需要的读工具。配置中工具名拼错，文档说明可能产生警告而不直接报错；验收必须对照服务器实际工具列表，不能把“请求没报错”当成白名单有效。[工具集配置规则](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector)

需要认证时，由应用按已批准的流程取得并刷新服务器访问令牌，再通过连接器支持的 `authorization_token` 字段传入。不要把凭据写进工具描述或对话，也不要把客户端给 MCP 的 token 原样转发给内部事故 API。MCP 服务与下游业务服务的授权需要分别处理。[MCP HTTP 授权规范](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)

### 固定工具列表，固定了什么？

`mcp-client-2026-09-15` 的工具列表固定功能会返回 `mcp_tool_listing`。继续对话时，要原样保留包含列表的 assistant 消息，每次请求继续携带相同 beta。也可以把列表里的工具复制到 `MCPToolset.tools`，减少重新读取服务器列表的需要；按工具名设置的启用配置仍然适用。[工具列表固定说明](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#pin-an-mcp-servers-tool-list-beta)

它固定的是 Claude 使用的工具目录和定义。服务器实现可能更新，租户权限可能撤销，事故数据也会变化。后台 ACL、用户授权和实际工具执行必须继续校验。发布新版本时，应对照批准的工具名和 schema 检查变化，不能用“列表已固定”代替业务访问控制。

API connector 的响应使用 `mcp_tool_use` 与 `mcp_tool_result`，不同于前面由应用执行的 `tool_use` 与 `tool_result`。排查时同时记录服务器名、调用 ID、对应 `tool_use_id` 和错误状态，再关联 MCP 服务端的操作记录；不能把两条路线的消息块直接互换。[连接器响应格式](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector)

### 内网 API 一定要开放公网吗？

不一定。普通连接器路径需要远程服务可达，但应用后端自己调用内网 API，可以继续使用已有内网连接。若不能公开 MCP 服务，优先考虑这个应用执行路线。

Anthropic 另有 **MCP tunnels 研究预览**：通过经批准的出站通道连接私网 MCP 服务，无需给源服务开入站公网入口。它需要预览访问权限及相应基础设施，适用于 Messages API 和同一工作区下的 Managed Agents，不能推定可用于 Claude 用户侧自定义连接器。预览也没有正式服务连续性保证。[MCP tunnels 适用范围](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview)

“私网通道”说明连接方式，不表示数据始终留在公司。Anthropic 仍会收到完成模型任务所需的工具结果；通道涉及的第三方也有其文档所述元数据范围。截至本次更新，API 数据保留表将 MCP connector 和 MCP tunnels 列为不符合 ZDR 与 HIPAA eligibility 的功能。普通 Messages API 的适用资格还取决于具体安排和模型条件，不能由此推导所有路线都零保留或都不合规。[API 数据保留条件](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention)

## Claude Code 和 Desktop 属于本地工作流分支

![本地 stdio、开发者 HTTP 与云端远程连接器的网络发起位置和认证边界示意](https://blog.laozhang.ai/posts/zh/claude-mcp-internal-tools-api-integration/img/local-remote-boundary.webp)

开发者主要使用本机脚本、仓库和工具时，可以走 Claude Code MCP。下面是连接配置的文档式示例，不会创建本文的事故服务；只有可执行程序或远程地址已经存在并获准使用时，才具有连接意义。

```bash
# 本地进程：-- 后面是可执行程序及其参数
claude mcp add --scope project --transport stdio incident-local -- ./incident-mcp

# 远程 HTTP：显式声明传输方式
claude mcp add --scope project --transport http incident-remote https://mcp.example.com/mcp
```

远程 URL 不能省略传输类型后当成本地命令。Claude Code 当前推荐远程 HTTP；文档中的 HTTP 到 SSE 自动回退有 v2.1.265 及以上等版本条件，不能据此假定每个旧客户端都能自动适配。[Claude Code MCP 配置与传输说明](https://code.claude.com/docs/en/mcp)

作用域也要明确：默认 local 为当前项目、当前用户保存；project 使用项目 `.mcp.json`，适合共享非敏感配置；user 作用于该用户的多个项目。配置成功之后，还要检查服务器状态、工具是否可用、认证是否完成，以及实际调用结果。交互式项目服务器批准与非交互运行的行为有区别，不要以为任何运行方式都必定弹出确认。[Claude Code 作用域与审批规则](https://code.claude.com/docs/en/mcp)

用户侧远程连接器则从 Claude 的自定义连接器入口添加名称和服务器 URL，按检测到的认证方式完成授权，再在对话中启用。当前官方帮助覆盖 Free、Pro、Max、Team 和 Enterprise，其中 Free 可添加一个自定义连接器；组织环境还受管理员或连接器库管理角色和成员授权影响。[自定义连接器官方帮助](https://support.claude.com/zh-CN/articles/11175166-使用远程-mcp-开始自定义连接器)

即使在 Desktop 或 Cowork 中使用远程连接器，请求仍来自 Anthropic 云端。员工电脑能通过公司 VPN 打开地址，不等于云端能访问。Desktop 的本地 MCP 配置是另一种机制，不能把本地 stdio 可用性直接套到这些远程入口。共享固定 header 凭据时，成员共用其实际权限范围，也不会自动产生按人隔离。[远程连接与共享认证条件](https://support.claude.com/zh-CN/articles/11175166-使用远程-mcp-开始自定义连接器)

如果工具调用后上下文迅速增加，继续查 [Claude Code MCP 上下文占用与输出压缩](https://blog.laozhang.ai/zh/posts/claude-code-mcp-context-overload)。如果问题是本地操作需要哪些确认，参照 [Claude Code 权限模式与跳过确认的边界](https://blog.laozhang.ai/zh/posts/claude-code-dangerously-skip-permissions)。减少提示次数不能替代 MCP 认证或内部 API 授权。

## 自建 MCP 服务器时，复用业务函数而非照搬请求格式

从本例迁到 MCP，可以保留参数校验、可信身份上下文、租户过滤和结果投影。新增的 MCP 适配层负责发布工具定义、接收调用、映射已认证主体，以及将业务结果转换成协议结果。业务处理函数不应根据某个客户端名称决定租户。

尤其要区分 schema 字段：Claude API 工具用 `input_schema`，MCP 工具定义用 `inputSchema`，还可以声明 `outputSchema`。二者可以表达相似约束，但 JSON 外形不能直接混用。`readOnlyHint` 等注解属于工具元数据，不能确保服务端只读；服务器仍须验证输入、访问权限并控制输出。[MCP 工具规范](https://modelcontextprotocol.io/specification/2026-07-28/server/tools)

协议版本也不能凭“latest”推定。MCP 2026-07-28 修订采用每请求携带协议版本与客户端能力的无会话核心；相应 `params._meta` 要有 `protocolVersion` 和 `clientCapabilities`，该修订不沿用旧核心的 `initialize` 与会话头流程。已有服务器或 SDK 可能仍使用兼容的旧版本，API connector 也不因协议发布就自动支持全部新行为。应按实际部署的客户端、服务器及版本实现，不拼接两套握手方法。[MCP 修订说明](https://modelcontextprotocol.io/specification/2026-07-28/changelog)、[必需请求元数据](https://modelcontextprotocol.io/specification/2026-07-28/basic/index)

其中可选的 `clientInfo` 是客户端自报信息，不能当作登录员工身份。受保护的 HTTP 服务应验证令牌目标资源、有效期与权限范围，再映射到业务主体；业务操作还要核对租户和资源。协议提供了认证机制，不会代替你公司的授权规则。[HTTP 授权规范](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)

## 写操作怎么加：先预览，再让后端批准执行

读工具跑通后，如果确实需要“关闭事故”“回退部署”等写操作，把预览与执行拆开。预览返回明确变更内容和目标版本；审批记录由可信业务系统生成，执行工具只能引用它。让模型传一个 `approved: true`，没有审批意义。

以关闭事故为例，至少完成下列关系：

| 步骤 | 服务端应保存或校验 | 成功判断 |
| --- | --- | --- |
| 生成预览 | 事故编号、租户、当前版本、拟变更状态、发起人 | 返回预览 ID，尚未修改事故 |
| 审批 | 审批人权限、预览内容摘要、有效期、允许的操作 | 后台生成与该预览绑定的审批 ID |
| 执行 | 当前调用者权限、租户、审批状态、版本、幂等键 | 内部 API 返回操作 ID 与执行状态 |
| 核对结果 | 按操作 ID 查询结果，必要时重新读取目标资源 | 实际状态与批准的变更一致 |

审批还要绑定具体参数。批准“关闭 inc-73”不能被拿去关闭 inc-74，也不能在审批后偷偷替换目标租户或变更内容。执行时若资源版本已经变化，就重新生成预览，避免按照过期状态操作。对于无法回滚的动作，在审批界面说明其后果。

超时尤其需要区分：应用没收到响应，不证明内部服务没有执行。已有幂等键和操作查询接口时，先查该次操作，再决定是否重试；没有这些能力的非幂等写接口，应停止自动重放并交给明确的恢复流程。模型层的调用 ID 用来关联对话，业务幂等键和操作 ID 用来控制与核对写入，不能互相替代。这是应用设计要求，不是 MCP 自动附带的保证。

## 生产安全清单：把“配置好了”与“执行正确”分开验收

验收应从一个受限读任务走到实际回答。前面的程序只验证离线处理，不证明服务已部署、协议连通或真实账号隔离。接入环境由负责团队获准配置后，按下面的证据链确认结果。

| 验收位置 | 需要看到什么 | 不能仅凭什么判断 |
| --- | --- | --- |
| 入口与网络 | 实际调用方能连接目标服务，认证完成 | 本机浏览器能打开地址、配置文件存在 |
| 工具范围 | 本轮实际工具目录与批准定义一致 | 工具名称写在提示词或启用配置中 |
| 执行身份 | 服务端记录认证主体、租户和授权决定 | 模型输入、`clientInfo` 或共享凭据的显示名 |
| 业务调用 | 内部服务请求 ID、操作或读取回执 | 只有模型的 `tool_use` 请求 |
| 结果回传 | 调用 ID 对应结果块，错误状态准确，敏感字段已裁剪 | 最终回答声称“我查到了” |
| 写入结果 | 审批与参数一致，幂等和最终状态可追溯 | 审批写在 prompt 中、超时后盲目重试 |

离线检查可以先发现低成本错误：本例把 `limit` 改为 6 应被拒绝，额外传 `tenant` 应被拒绝，缺少读权限应被拒绝，换到合成租户 `demo-b` 不能拿到 `demo-a` 的事故，成功结果也不能带 `internal_secret`。这些检查能验证示例处理逻辑，真实服务还必须用获准测试身份核对认证、下游权限、异常路径与日志关联。

生产审计应记录时间、调用关联 ID、认证主体、目标资源、策略决定、延迟及内部操作结果，但不保存原始 token 或无关敏感正文。对话日志与业务审计职责不同：前者解释模型如何回答，后者解释系统实际读取或修改了什么。

如果这些关系无法串起来，先继续完善一个读工具。一个查询结果可复核的小接口，比已经“连上”却无法判断谁读了什么的整套后台工具更有用。

## 常见问题

### Claude 接入内部 API 必须用 MCP 吗？

不必须。自己的应用负责用户会话与执行时，用 Claude API 工具调用就能接入：接收 `tool_use`、校验并执行、返回 `tool_result`。多个客户端需要复用稳定工具接口时，再考虑 MCP。[工具调用说明](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview)

### API MCP connector 能直接连接本地 stdio 吗？

不能把本地进程直接当作这条远程连接路径。普通 API connector 使用远程 HTTPS HTTP/SSE 服务；符合访问条件的 MCP tunnels 研究预览可以连接私网服务，但不是通用本地 stdio 接口，也不适用于 Claude 用户连接器。[API connector](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector)、[私网预览通道](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview)

### Free 用户能添加自定义连接器吗？

按当前官方帮助，Free 可添加一个自定义连接器。其他计划和组织环境有各自的管理、认证条件；地址仍需能从 Anthropic 云端访问，不能只在员工 VPN 内可达。这说的是用户侧连接器，与按 API 请求使用的 MCP connector 不同。[自定义连接器帮助](https://support.claude.com/zh-CN/articles/11175166-使用远程-mcp-开始自定义连接器)

### 工具列表固定后，权限也固定了吗？

没有。`mcp-client-2026-09-15` 固定 Claude 使用的工具目录；服务实现、数据和授权仍可能变化。服务端必须继续按真实身份、租户、资源及操作校验访问。[固定工具列表文档](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#pin-an-mcp-servers-tool-list-beta)

### 看到 `tool_use` 就说明内部 API 已经执行了吗？

没有。客户端工具的 `tool_use` 是模型提出的调用请求。应用执行后才生成匹配 `tool_use_id` 的结果；是否完成业务操作，要进一步看内部服务回执与审计记录。最终自然语言回答不能代替这些证据。[执行与结果回传](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls)

### 共享连接器凭据能自动区分每位员工吗？

不能。共享固定凭据会共享其实际权限范围；若要按员工和租户隔离，需要合适的成员授权、可信身份映射及服务端资源校验。模型声称“我是某位员工”不能提供授权依据。[共享认证说明](https://support.claude.com/zh-CN/articles/11175166-使用远程-mcp-开始自定义连接器)

### 写工具超时后可以直接重试吗？

先确认操作状态。超时可能发生在业务服务已执行之后，有幂等键与操作查询机制时按原请求查结果；缺少这些机制的非幂等写操作，不应自动重复执行。把恢复策略写进应用和业务服务，而不是只让模型“谨慎重试”。

## 参考来源

本文引用的外部页面，按正文出现顺序排列。最后更新于 2026-10-08。

- [Claude 工具调用说明](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview) (platform.claude.com)
- [工具调用结果处理](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls) (platform.claude.com)
- [API MCP connector 文档](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) (platform.claude.com)
- [MCP HTTP 授权规范](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization) (modelcontextprotocol.io)
- [MCP tunnels 适用范围](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview) (platform.claude.com)
- [API 数据保留条件](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention) (platform.claude.com)
- [Claude Code MCP 配置与传输说明](https://code.claude.com/docs/en/mcp) (code.claude.com)
- [自定义连接器官方帮助](https://support.claude.com/zh-CN/articles/11175166-%E4%BD%BF%E7%94%A8%E8%BF%9C%E7%A8%8B-mcp-%E5%BC%80%E5%A7%8B%E8%87%AA%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E5%99%A8) (support.claude.com)
- [MCP 工具规范](https://modelcontextprotocol.io/specification/2026-07-28/server/tools) (modelcontextprotocol.io)
- [MCP 修订说明](https://modelcontextprotocol.io/specification/2026-07-28/changelog) (modelcontextprotocol.io)
- [必需请求元数据](https://modelcontextprotocol.io/specification/2026-07-28/basic/index) (modelcontextprotocol.io)
