MCP 和 Web 集成

AI 服务通过两个集成点扩展模型功能:用于工具调用的 Model Context Protocol (MCP),以及用于页面获取和搜索的可插拔 Web 端点。这两项功能仅在 AI 对话中运行。Web 搜索和抓取允许 AI 在对话期间引用实时互联网内容,对于大多数部署而言,启用至少一种 Web 搜索功能可以提高响应质量。

这些功能完全通过 AI 服务容器上的环境变量进行配置。除了一个搜索端点和一个抓取端点外,不需要额外的基础设施。

先决条件

本页假设以下内容已配置:

  • 带有数据库和 Redis 的运行中的 AI 服务容器(参见 Database and Redis)。
  • 在 PROVIDERS 和 MODELS 中配置的至少一个 LLM 提供商(参见 LLM providers)。
  • 已部署并使用正确的 API Secret 对令牌进行签名的 JWT 令牌端点(参见 JWT authentication)。

Model Context Protocol (MCP)

MCP 允许 AI 服务在对话期间调用外部工具(内部 wiki、API 规范、运维手册、合同数据库和合规检查器)。该服务通过 Streamable HTTP transport 连接到 MCP 服务器。

仅支持 Streamable HTTP transport。基于 Stdio 的 MCP 服务器无法直接连接到 AI 服务。使用前请使用 SDK 的 HTTP transport 适配器对其进行封装(例如 TypeScript SDK 中的 StreamableHTTPServerTransport 或 Python SDK 中的 StreamableHTTPServer)。

MCP 工具仅在 AI conversations 中可用。Reviews 和 quick actions 不会调用 MCP 工具。对于启用 OAuth 的 MCP 服务器,每个用户必须在服务器工具变得可用之前完成授权流程。

配置

将 MCP_SERVERS 环境变量设置为 JSON 对象。每个键是一个服务器标识符;每个值描述连接情况。对于启用 OAuth 的服务器,还需设置 MCP_OAUTH_CALLBACK_URL(参见 OAuth 2.0 authentication)。

-e MCP_SERVERS='{
  "knowledge-hub": {
    "url": "http://host.docker.internal:3001/mcp",
    "options": { "callToolTimeout": 30 }
  }
}'
字段 描述
url MCP 服务器的 HTTP 端点(Streamable HTTP transport)。对于启用 OAuth 的服务器,这必须是支持 OAuth protected resource discovery (RFC 9728) 的端点。参见 MCP server URL for OAuth。
headers 随每个请求发送的 HTTP 头部的 JSON 对象(例如 {"Authorization": "Bearer token"})。参见 Static-token authentication。
oauth OAuth 2.0 配置块。为需要它的 MCP 服务器启用按用户授权。参见 OAuth 2.0 authentication。
tools.disabled 要从 LLM 访问中排除的工具名称数组。
options.callToolTimeout 每次工具调用的超时时间(秒)(默认 60)。

MCP_SERVERS 支持多个服务器条目。向同一 JSON 对象添加其他键:

-e MCP_SERVERS='{
  "knowledge-hub": {
    "url": "http://host.docker.internal:3001/mcp"
  },
  "compliance-checker": {
    "url": "http://host.docker.internal:3002/mcp"
  }
}'

每个服务器的工具都独立命名空间化(例如 knowledge-hub-search_docs 和 compliance-checker-run_check)。

Docker 网络

在 Linux Docker 上,向 AI 服务的 compose 条目中添加 extra_hosts: ["host.docker.internal:host-gateway"],以访问在主机机器上运行的 MCP 服务器。

警告: host-gateway 解析为 Docker 桥接 IP,而不是 127.0.0.1。仅绑定到 127.0.0.1 的主机服务(常见于 Python MCP SDK 示例和 CLI 风格的服务器)在容器内部不可访问(ECONNREFUSED)。请将 MCP 服务器绑定到 0.0.0.0,或将其作为同一 Docker 网络中的同级容器运行。

静态令牌认证

headers 字段会在每次向 MCP 服务器发送请求时附带一组固定的 HTTP 标头。无论哪个最终用户触发了对话,每次工具调用都使用相同的凭据。

-e MCP_SERVERS='{
  "knowledge-hub": {
    "url": "http://host.docker.internal:3001/mcp",
    "headers": {
      "Authorization": "Bearer QUkgc2VydmljZQ==",
      "X-Custom-Header": "custom-value"
    }
  }
}'

如果 MCP 服务器需要每用户上下文但不使用 OAuth,请在对话提示中或在 MCP 服务器自行解析为每用户身份的标头中编码身份信息。

OAuth 2.0 认证

对于需要 OAuth 2.0 授权而不是在 headers 字段中使用静态访问令牌的 MCP 服务器,AI 服务可以作为 OAuth 客户端。该服务实现了带有 PKCE 的 OAuth 2.0 授权码流程,并支持允许此功能的服务器的动态客户端注册 (RFC 7591)。

最终用户通过其浏览器授权连接。每个用户独立进行授权,生成的访问令牌将在后续请求中重复使用。当访问令牌过期时,AI 服务会自动刷新它。

用于 OAuth 的 MCP 服务器 URL

启用 OAuth 后,AI 服务通过向 MCP 服务器 url 发送未认证的请求,并从 401 响应的 WWW-Authenticate 标头中读取 resource_metadata 链接来发现授权服务器(依据 RFC 9728)。

某些 MCP 服务器为未认证访问和 OAuth 保护访问暴露了单独的端点。url 必须指向返回此元数据的端点。使用错误的端点会导致 initialize 调用无限期挂起(请参阅故障排除)。

提示: 要验证正确的端点,请发送未认证的请求并检查 WWW-Authenticate 标头。它应包含一个 resource_metadata URL:curl -sI -X POST https://mcp.example.com/v1/mcp/auth -H "Content-Type: application/json" | grep -i www-authenticate

配置

为 MCP 服务器启用 OAuth 需要两个步骤:

  1. 将 MCP_OAUTH_CALLBACK_URL 设置为集成 Web 应用程序托管的 OAuth 回调页面的 URL。AI 服务将此 URL 用作所有启用 OAuth 的 MCP 服务器的 OAuth redirect_uri 参数(除非通过 oauth.callbackUrl 针对特定服务器进行覆盖)。
  2. 在 MCP_SERVERS 中的目标服务器条目内添加一个 oauth 块。
-e MCP_OAUTH_CALLBACK_URL='https://your-app.example.com/oauth/callback' \
-e MCP_SERVERS='{
  "knowledge-hub": {
    "url": "http://host.docker.internal:3001/mcp",
    "headers": { "Authorization": "Bearer static-token" }
  },
  "external-tools": {
    "url": "https://mcp.example.com/v1/mcp",
    "oauth": {
      "clientId": "",
      "clientSecret": "",
      "scopes": ["read", "write"]
    }
  }
}'

内部 MCP 服务器可以使用静态令牌认证(通过 headers),同时与需要 OAuth 的外部服务器共存。每个服务器都在同一个 MCP_SERVERS 对象内独立配置。MCP_OAUTH_CALLBACK_URL 仅适用于具有 oauth 块的服务器。

字段 描述
oauth.clientId 由 MCP 服务器颁发的 OAuth 2.0 客户端标识符。省略此项以执行动态客户端注册。
oauth.clientSecret OAuth 2.0 客户端密钥。与 clientId 一起用于机密客户端。
oauth.scopes 要从授权服务器请求的 OAuth 范围数组。省略此项以使用默认服务器范围。
oauth.callbackUrl 对 MCP_OAUTH_CALLBACK_URL 的每服务器覆盖。当不同的 MCP 服务器重定向到 Web 应用程序中的不同页面时使用。

动态客户端注册

如果 MCP 服务器支持 RFC 7591 动态客户端注册,则可以在 oauth 块中省略 clientId 和 clientSecret。AI 服务会在首次授权尝试时自动向 MCP 服务器注册自身,并在后续流程中复用生成的注册信息。

授权流程

OAuth 流程由集成 Web 应用程序驱动。AI 服务提供 REST 端点(参见 REST 端点);应用程序负责协调重定向并转发授权码。

  1. 初始化。 应用程序为已登录用户调用 POST /v1/mcp/oauth/{serverName}/initialize。响应包含以下内容之一:
    • { "connected": true } — 用户已拥有有效的访问令牌;无需进一步操作。
    • { "connected": false, "authorizationUrl": "…" } — 将用户的浏览器重定向到 authorizationUrl。
  2. 用户同意。 MCP 服务器的授权页面在用户的浏览器中打开。批准后,服务器会将用户重定向回 MCP_OAUTH_CALLBACK_URL(或 oauth.callbackUrl),并附加 code 和 state 查询参数。
  3. 完成。 回调页面从查询字符串中提取 code 和 state,并将它们转发到 POST /v1/mcp/oauth/{serverName}/complete,请求体为 { "code": "…", "state": "…" }。成功后,用户的连接变为活动状态,后续的 AI 对话可以使用 MCP 服务器的工具。

注意: AI 服务不托管回调页面。请将 MCP_OAUTH_CALLBACK_URL(或每个服务器的 oauth.callbackUrl)作为已授权的重定向 URI 注册到 MCP 服务器——可以通过服务器的开发者控制台进行注册,或者在使用动态客户端注册时自动完成。

重要: 授权会话在 initialize 后十分钟内有效。如果用户花费超过十分钟来完成授权页面,complete 调用将返回 mcp-oauth-invalid-state 错误,并且必须从 initialize 重新开始流程。

回调页面实现

AI 服务不托管回调页面。集成 Web 应用程序必须在 MCP_OAUTH_CALLBACK_URL 处提供一个页面,该页面从重定向 URL 中提取 code 和 state 查询参数,并将它们转发到 AI 服务的 complete 端点。

最小化回调页面:

<script>
  const params = new URLSearchParams(window.location.search);
  fetch('/api/mcp/oauth/my-server/complete', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code: params.get('code'), state: params.get('state') })
  })
    .then(r => r.json())
    .then(data => document.body.textContent = data.connected ? 'Connected.' : 'Failed: ' + JSON.stringify(data));
</script>

将 my-server 替换为来自 MCP_SERVERS 的键。在生产环境中,请添加错误处理、加载指示器以及对缺失 code 或 state 参数的验证。

在上面的示例中,回调页面调用的是集成应用程序自身服务器上的 /api/mcp/oauth/{serverName}/complete,而不是直接调用 AI 服务。这就是下面描述的代理模式。

浏览器集成与代理端点

AI 服务上的 OAuth REST 端点需要 JWT 身份验证,由于 CORS 限制,可能无法直接从浏览器调用。在基于浏览器的集成中,通过应用程序自己的后端代理 OAuth 调用。

后端生成一个 JWT(用于对话的同一令牌),将其附加到请求中,并将调用转发给 AI 服务。这样可以将 JWT 生成保留在服务端,并避免在 AI 服务上进行 CORS 配置。

典型的集成需要四个代理路由:

  • GET /api/mcp/oauth/status → GET {AI_SERVICE_URL}/v1/mcp/oauth/status
  • POST /api/mcp/oauth/{serverName}/initialize → POST {AI_SERVICE_URL}/v1/mcp/oauth/{serverName}/initialize
  • POST /api/mcp/oauth/{serverName}/complete → POST {AI_SERVICE_URL}/v1/mcp/oauth/{serverName}/complete
  • DELETE /api/mcp/oauth/{serverName} → DELETE {AI_SERVICE_URL}/v1/mcp/oauth/{serverName}

REST 端点

所有端点均使用与其他 AI 服务端点相同的 JWT 进行身份验证。操作者用户由令牌标识;每个用户在每个 MCP 服务器上拥有独立的连接状态。

方法 路径 描述
GET /v1/mcp/oauth/status 返回每个启用 OAuth 的 MCP 服务器的连接状态,包含调用用户的 connected 状态以及可选的 expiresAt 时间戳。
POST /v1/mcp/oauth/{serverName}/initialize 启动 OAuth 流程。返回 { "connected": true } 或 { "connected": false, "authorizationUrl": "…" }。
POST /v1/mcp/oauth/{serverName}/complete 完成 OAuth 流程。请求体:{ "code": "…", "state": "…" }。成功时返回 { "connected": true }。
DELETE /v1/mcp/oauth/{serverName} 移除存储的令牌以及调用用户任何正在进行的授权状态。

一旦至少为一个 MCP 服务器配置了 OAuth,这些端点即可用。

连接范围与撤销

OAuth 连接是按用户建立的,不会在不同用户或环境之间共享。

要撤销用户的连接,请发送 DELETE /v1/mcp/oauth/{serverName}。

对于启用 OAuth 的 MCP 服务器,只有在每个用户完成授权流程后才会建立连接。在此之前,该服务器的工具不会暴露给该用户。

工具命名空间

MCP 工具以带命名空间的标识符暴露给 LLM:<server_id>-<tool_name>(例如,knowledge-hub-search_knowledge_base)。tools.disabled 数组仅接受裸工具名称(例如,"search_knowledge_base",而不是带命名空间的形式)。

MCP 服务器示例

以下示例使用官方 MCP TypeScript SDK (@modelcontextprotocol/sdk) 配合 StreamableHTTPServerTransport,后者处理会话管理、SSE 封装以及完整的 Streamable HTTP 传输规范。

知识库 MCP 服务器

创建 package.json:

{
  "name": "knowledge-mcp-server",
  "type": "module",
  "private": true,
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.29.0",
    "express": "^4.18.0",
    "zod": "^3.23.0"
  }
}

安装依赖项:

npm install

创建 knowledge-mcp-server.js:

// knowledge-mcp-server.js
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import express from 'express';
import { z } from 'zod';

const KNOWLEDGE_BASE = {
  'api-guidelines': 'All REST APIs must use JSON, include pagination through Link headers, and return 4xx for client errors with a machine-readable error code.',
  'deployment-process': 'Deployments require: 1) PR approval, 2) passing CI, 3) staging verification, 4) production canary (5% traffic for 30min), 5) full rollout.',
  'security-policy': 'All user data must be encrypted at rest (AES-256) and in transit (TLS 1.3). PII requires additional field-level encryption.',
};

function createServer() {
  const server = new McpServer({
    name: 'knowledge-hub',
    version: '1.0.0'
  });

  server.tool(
    'search_knowledge_base',
    'Search the company knowledge base for policies, guidelines, and procedures',
    { query: z.string().describe('Search query') },
    async ({ query }) => {
      const q = query.toLowerCase();
      const results = Object.entries(KNOWLEDGE_BASE)
        .filter(([key]) => key.includes(q) || q.includes(key.split('-')[0]))
        .map(([key, value]) => `## ${key}\n${value}`)
        .join('\n\n');
      return {
        content: [{ type: 'text', text: results || 'No results found.' }]
      };
    }
  );

  server.tool(
    'get_api_spec',
    'Get the OpenAPI spec for an internal service',
    { service: z.string().describe('Service name (for example user-service, billing-api)') },
    async ({ service }) => {
      return {
        content: [{ type: 'text', text: `Spec not found for: ${service}` }]
      };
    }
  );

  return server;
}

const app = express();
app.use(express.json());

app.all('/mcp', async (req, res) => {
  const server = createServer();
  const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
  await server.connect(transport);
  await transport.handleRequest(req, res, req.body);
  await server.close();
});

app.listen(3001, () => console.log('Knowledge MCP server on http://0.0.0.0:3001/mcp'));

示例服务器绑定到 0.0.0.0,因此可以从 Docker 容器内部访问。当 MCP 服务器在主机上运行时,AI 服务通过 http://host.docker.internal:3001/mcp 连接到它(参见 Docker 网络配置)。

Web search

AI 服务可以将搜索查询转发到外部端点,从而使 AI 对话能够引用实时的 Web 内容。

启用 web search

Web search 需要同时配置以下三个组件:

组件 配置
环境变量 在 AI 服务容器中设置 WEBSEARCH_ENABLED='true' 和 WEBSEARCH_ENDPOINT。可选地,为经过身份验证的搜索后端设置 WEBSEARCH_REQUEST_TIMEOUT(默认 10000ms)和 WEBSEARCH_HEADERS。
MODELS 条目 模型的 MODELS 条目必须包含 capabilities.webSearch: true(布尔值),以便在编辑器中显示 web search 切换开关。参见 MODELS 配置。
JWT 权限 JWT 必须在 auth.ai.permissions 数组中包含 ai:conversations:webSearch。参见 JWT 权限。如果没有此权限,即使环境变量和 MODELS 条目正确,切换开关仍会保持灰色不可用状态。
-e WEBSEARCH_ENABLED='true' \
-e WEBSEARCH_ENDPOINT='http://host.docker.internal:4001/search' \
-e WEBSEARCH_REQUEST_TIMEOUT='10000' \
-e WEBSEARCH_HEADERS='Authorization: Bearer search-api-key, X-Source: tinymce'

重要: WEBSEARCH_HEADERS 使用冒号分隔的 CSV 格式(Header-Name: value, Another: value),而不是 JSON。传递 JSON 对象会导致 ERR_INVALID_HTTP_TOKEN 并静默阻止所有出站搜索请求。

按消息激活(自定义集成)

当用户开启 web search 时,TinyMCE 编辑器会发送 web search 激活标志。直接调用 AI 服务 API 的自定义集成必须在每个应启用 web search 的消息请求体中包含以下内容:

{
  "capabilities": { "webSearch": {} }
}

该值必须是一个空对象({})。这是文档规定的 API 契约(参见 Capability configuration)。服务会拒绝其他格式:

  • "webSearch": true : 被拒绝(schema 期望一个对象,而不是布尔值)。
  • "webSearch": {"enabled": true} : 被拒绝(无法识别的键)。
  • 完全省略:即使所有服务器端配置正确,也不会向模型提供 web search 功能。

如果没有此字段,环境变量、JWT 权限和 MODELS 配置将不足以启用该功能。模型永远不会接收到 web search 工具。

Endpoint contract

方向 Payload
Request 包含 query 字段(搜索字符串)的 JSON 对象。
Response 包含 results 数组的 JSON 对象;每个项包括 url、text、title,以及可选的 author、publishedAt 和 favicon。

请求体:

{ "query": "search string" }

响应体:

{
  "results": [
    {
      "url": "https://example.com/article",
      "text": "Content snippet",
      "title": "Article Title",
      "author": "Author",
      "publishedAt": "2026-04-30T10:00:00Z",
      "favicon": "https://example.com/favicon.ico"
    }
  ]
}

实现示例 (SerpAPI)

// search-service.js
const express = require('express');
const app = express();
app.use(express.json());

app.post('/search', async (req, res) => {
  const response = await fetch(
    `https://serpapi.com/search.json?q=${encodeURIComponent(req.body.query)}&api_key=${process.env.SERP_API_KEY}`
  );
  const data = await response.json();
  const results = (data.organic_results || []).slice(0, 5).map(r => ({
    url: r.link,
    title: r.title,
    text: r.snippet
  }));
  res.json({ results });
});

app.listen(4001);

Web scraping

AI 服务可以将网页获取请求转发到外部 endpoint,从而使 AI 对话能够引用特定页面。

启用 Web scraping

在 AI 服务容器上设置 WEBRESOURCES_ENABLED='true' 和 WEBRESOURCES_ENDPOINT。可选地,设置 WEBRESOURCES_REQUEST_TIMEOUT(默认为 10000ms)。

-e WEBRESOURCES_ENABLED='true' \
-e WEBRESOURCES_ENDPOINT='http://host.docker.internal:4000/scrape' \
-e WEBRESOURCES_REQUEST_TIMEOUT='10000'

触发机制

当 AI 服务收到以下请求时,会调用 scrape endpoint (WEBRESOURCES_ENDPOINT):

POST /v1/conversations/{id}/web-resources
Content-Type: application/json

{ "url": "https://example.com/page-to-fetch" }

当用户在 Chat sidebar 中添加链接作为源(点击 Add context source 按钮,然后选择 Link),或者选择一个解析为 URL 的集成方提供的源(参见 tinymceai_chat_fetch_sources)时,TinyMCE 编辑器会发送此请求。直接在聊天消息中输入 URL 不会触发获取操作。自定义集成必须显式调用此 endpoint 以触发页面获取。

响应会存储在对应对话中。scrape 响应中的 type 字段必须是 text/html 或 text/markdown,且 data 不能为空。其他 MIME 类型(例如 application/pdf)和空的 data 字段会被拒绝,并返回 422 web-resource-download-error。

Endpoint contract

方向 Payload
Request 包含 url 字段(要获取的页面)的 JSON 对象。
Response 包含 type(text/html 或 text/markdown)和 data(正文内容)的 JSON 对象。

请求体:

{ "url": "https://example.com/article" }

响应体:

{ "type": "text/html", "data": "<html><body><p>Example page body</p></body></html>" }

实现示例 (Playwright)

// scraper-service.js
const { chromium } = require('playwright');
const express = require('express');
const app = express();
app.use(express.json());

app.post('/scrape', async (req, res) => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto(req.body.url, { waitUntil: 'networkidle' });
  const content = await page.content();
  await browser.close();
  res.json({ type: 'text/html', data: content });
});

app.listen(4000);

SSE 事件

自定义流式 UI 集成可以使用以下 Server-Sent Events (SSE) 来渲染工具调用进度和搜索结果。AI 服务在对话期间发出这些事件:

事件名称 描述
mcp-tool-result 当 MCP 工具调用完成时发出。包含工具结果。没有预调用事件;客户端在工具调用结束之前不会收到任何信号。
web-search 当执行网络搜索时发送。载荷是一个空对象,并且当搜索后端失败时也会发送此事件(参见故障排除)。
source 随模型响应中的源引用一起发出。

有关每个事件及其载荷的详细信息,请参阅 API 参考文档。

Kubernetes 部署

在 Kubernetes 中,extra_hosts: host-gateway Docker 模式不适用。请将 MCP 服务器和网络集成端点作为同级 Deployment 部署在同一命名空间中,并使用 ClusterIP Services。通过集群 DNS 引用它们:

-e MCP_SERVERS='{
  "knowledge-hub": {
    "url": "http://mcp-knowledge.tinymce-ai.svc.cluster.local:3001/mcp",
    "options": { "callToolTimeout": 30 }
  }
}'
-e WEBRESOURCES_ENDPOINT='http://web-scrape.tinymce-ai.svc.cluster.local:4000/scrape'
-e WEBSEARCH_ENDPOINT='http://web-search.tinymce-ai.svc.cluster.local:4001/search'

将 MCP_SERVERS 和 WEBSEARCH_HEADERS 存储在 Kubernetes Secret 中,并将其作为环境变量挂载到 AI 服务的 Deployment 中。这避免了在 Deployment 清单中暴露凭据,并允许在不重新部署的情况下进行轮换。

对于生产集群,MCP 服务器 Deployment 应具有独立的资源请求、存活探针和副本数,不依赖于 AI 服务。有关通用的 Kubernetes 模式,请参阅生产环境部署。

故障排除

症状 解决方法
Web 搜索或 Web 抓取功能完全未显示 WEBSEARCH_ENABLED 和 WEBRESOURCES_ENABLED 默认值均为 false。请在 AI 服务环境中将它们设置为 true,并提供相应的 _ENDPOINT 值。如果未启用这些标志,无论 JWT 权限或 MODELS 配置如何,AI 服务都会禁用所有 Web 集成功能。
编辑器中的 Web 搜索开关呈灰色(不可用) JWT 中缺少 ai:conversations:webSearch 权限。请将其添加到 token 的 auth.ai.permissions 数组中(或使用通配符 ai:conversations:*)。请参阅 JWT 权限部分。
已开启 Web 搜索但模型从未使用它 每条消息的请求体中缺少 "capabilities": {"webSearch": {}}。当开关激活时,TinyMCE 编辑器会发送此字段。自定义集成必须在每个请求体中包含它。请参阅按消息激活(自定义集成)部分。
与 Web 搜索相关的 AI 服务日志中出现 ERR_INVALID_HTTP_TOKEN WEBSEARCH_HEADERS 被设置为 JSON 对象。该服务期望的是冒号分隔的 CSV 格式:Header-Name: value, Another: value。
连接 MCP 服务器时出现 ECONNREFUSED MCP 服务器绑定到了 127.0.0.1。请改为绑定到 0.0.0.0,或将 MCP 服务器作为同级容器运行在同一个 Docker 网络(或 Kubernetes namespace)上。
大约每 60 秒出现一次 [WARN] MCP client health check ping failed, evicting 非功能性问题。AI 服务在每次驱逐后会重新与 MCP 服务器进行握手。工具调用继续正常工作。这种日志量在稳态下是预期的,并不表示存在问题。
Web 搜索返回“无结果”,但搜索后端正在运行 检查 AI 服务容器日志中是否有 [WARN] Web search request failed。当 WEBSEARCH_ENDPOINT 返回 5xx 错误时,服务会记录警告,但向客户端发出空的 event: web-search,且不包含错误载荷。模型会继续执行,就像返回了零个结果一样。
来自 web-resources 端点的 422 web-resource-download-error 这个单一的错误代码涵盖了多种失败模式:scrape 端点返回 5xx、返回非 JSON、返回空的 data 字段,或返回不支持的 type(除 text/html 或 text/markdown 以外的任何类型)。请检查 AI 服务容器日志以查找根本原因。
来自 complete 端点的 mcp-oauth-invalid-state 错误 授权会话已过期。调用 initialize 后,会话有效期为十分钟。请从 POST /v1/mcp/oauth/{serverName}/initialize 重新开始流程。
配置 OAuth 后,用户看不到 MCP 工具 用户尚未完成授权流程。OAuth 连接是针对每个用户的——每个用户必须通过 initialize 和 complete 独立进行授权。请使用 GET /v1/mcp/oauth/status 检查连接状态。
initializeMcpOAuth 挂起超过 60 秒且无响应 MCP_SERVERS 中的 MCP 服务器 url 未返回 OAuth 资源发现元数据 (RFC 9728)。AI 服务向该 URL 发送未经身份验证的请求,并期望收到一个带有 resource_metadata 链接的 WWW-Authenticate 头的 401 响应。如果缺少该头,服务将无限期挂起。请使用以下命令验证正确的端点:curl -sI -X POST https://mcp.example.com/endpoint -H "Content-Type: application/json",并检查 WWW-Authenticate 头中是否包含 resource_metadata。某些 MCP 服务器为经过身份验证的访问和受 OAuth 保护的访问暴露了单独的 URL。请参阅用于 OAuth 的 MCP 服务器 URL 部分。

另请参阅

  • LLM 提供商:提供商配置和 MODELS 目录
  • 参考:完整的环境变量参考,包括 MCP_SERVERS、WEBRESOURCES_* 和 WEBSEARCH_*
  • 故障排除:一般故障排除