Skip to content

MCP getTools fallback 到 SSE 导致 405,但 runTool 可正常调用 Streamable HTTP MCP #7047

@Mrxia7757

Description

@Mrxia7757

例行检查

  • 我已确认目前没有类似 issue
  • 我已完整查看过项目 README,以及项目文档
  • 我使用了自己的 key,并确认 key 可正常使用
  • 我理解并愿意跟进此 issue,协助测试和提供反馈
  • 我理解并认可上述内容,并理解项目维护者精力有限

你的版本

  • 公有云版本
  • 私有部署版本,版本号:V4.14.9

问题描述

我们在 FastGPT 私有化环境中接入 Streamable HTTP MCP endpoint 时,发现 runTool 可以正常执行工具并返回 200,但 getTools 解析/刷新工具列表时失败。

后端日志显示:getTools 阶段先尝试 StreamableHTTP,失败后 fallback 到 SSE;由于该 MCP endpoint 不支持 SSE GET,最终报 405。

[POST] /api/core/app/mcpTools/getTools
StreamableHTTP connect failed, falling back to SSE
SSE error: Non-200 status code (405)
[POST] /api/core/app/mcpTools/getTools - 500

但同一个 MCP endpoint 执行工具时可以成功:

[POST] /api/core/app/mcpTools/runTool
MCP client calling tool
[POST] /api/core/app/mcpTools/runTool - 200

我们单独测试 MCP endpoint,结果是:

POST initialize:成功
POST tools/list:成功
GET:405
SSE GET:405

因此该 MCP 服务本身可用,问题集中在 FastGPT 的 getTools 链路:getTools 失败后 fallback 到 SSE,而该 endpoint 不是 SSE endpoint。

最小复现 MCP 服务

from fastapi import FastAPI, Request, Response
from fastapi.responses import JSONResponse
import uvicorn, json

app = FastAPI()
TOKEN = "demo-token"

def ok_auth(req: Request):
    return req.headers.get("authorization") == f"Bearer {TOKEN}"

def err(i, code, msg, status=200):
    return JSONResponse(status_code=status, content={"jsonrpc":"2.0","id":i,"error":{"code":code,"message":msg}})

@app.get("/services/mcp")
async def get_mcp(req: Request):
    return JSONResponse(status_code=405, content={"message":"Method not allowed"})

@app.get("/services/mcp/sse")
async def get_sse(req: Request):
    return JSONResponse(status_code=405, content={"message":"Method not allowed"})

@app.post("/services/mcp")
async def post_mcp(req: Request):
    body = await req.json()
    i = body.get("id")
    m = body.get("method")
    if not ok_auth(req):
        return err(i, -32600, "Authentication failed: No bearer token provided", 401)
    if m == "initialize":
        return {"jsonrpc":"2.0","id":i,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"mock-mcp","version":"1.0.0"}}}
    if m == "notifications/initialized":
        return Response(status_code=200)
    if m == "tools/list":
        return {"jsonrpc":"2.0","id":i,"result":{"tools":[{"name":"demo_get_info","description":"demo tool","inputSchema":{"type":"object","properties":{}}}]}}
    if m == "tools/call":
        result = {"status":"ok","message":"tool call success"}
        return {"jsonrpc":"2.0","id":i,"result":{"content":[{"type":"text","text":json.dumps(result)}],"structuredContent":result}}
    return err(i, -32601, f"Method {m} not found")

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=18089)

启动:

pip install fastapi uvicorn
python mock_mcp_server.py

FastGPT 中配置:

MCP 地址:http://<server-ip>:18089/services/mcp
鉴权 Header:Authorization: Bearer demo-token

复现步骤

  1. 在 FastGPT 中添加上述 MCP 地址。
  2. 配置 Header:Authorization: Bearer demo-token
  3. 点击解析/刷新工具列表。
  4. 观察 FastGPT 后端日志。
  5. 如果 getTools 失败后 fallback 到 SSE,会出现 SSE error: Non-200 status code (405)
  6. 执行已存在工具时,runTool 可以正常返回 200。

预期结果

对于 Streamable HTTP MCP endpoint:

  • getTools 使用 Streamable HTTP / POST JSON-RPC 获取工具列表;
  • runTool 使用 Streamable HTTP / POST JSON-RPC 执行工具;
  • getToolsrunTool 调用逻辑保持一致;
  • 如果 StreamableHTTP 失败,建议不要默认 fallback 到 SSE,或提供关闭 SSE fallback 的配置。

实际结果

runTool 可以成功,但 getTools 阶段失败后 fallback 到 SSE,最终触发 405。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions