
1. FastAPI 项目接入 MCP 的真实痛点Server 能跑Client 却连不上FastAPI 接入 MCP 完整指南要解决的核心问题是把一个已经能跑的 FastAPI 服务稳定地暴露成 MCP Server再让 MCP Client 通过统一 Key 通道调起来。MCP 全称 Model Context Protocol它做的事情可以理解成给大模型装一个标准插座模型不直接碰你的数据库和内部接口而是通过 MCP 工具去调用。FastAPI 负责提供 HTTP 能力MCP 负责把这层能力翻译成模型能理解的工具描述。适合谁已经有 FastAPI 后端、想让 AI IDE 或 Agent 调用自己业务接口的开发者以及正在被 401、local proxy failed 这类报错卡住的同学。我见过太多项目卡在同一个地方Server 端uvicorn起来了浏览器访问/docs正常但 MCP Client 一连接就报错。原因通常不是代码写错而是两端对「地址」和「鉴权」的理解不一致。Server 认为自己监听0.0.0.0:8000就万事大吉Client 却拿着localhost去连容器里的服务或者 Client 发请求时没带 KeyServer 直接返回 401。更隐蔽的是本地代理配置残留导致请求根本没发到你的 FastAPI 上而是被转发到一个不存在的端口于是出现local proxy failed。这篇内容按「先跑通 Server再配通 Client最后统一 Key」的顺序推进。每一步都给可复制的代码和配置重点放在报错排查上。你不需要先理解 MCP 协议的全部细节跟着配置走一遍再回头看协议会清晰很多。下面从环境准备开始把 Server 端两种写法都过一遍然后进入 Client 配置和统一 Key 的验证。2. TaoToken 前置准备统一 Key 与 Base URL 的获取在写 MCP Client 之前先把模型调用通道准备好。MCP 本身只负责工具调用真正生成回答的还是背后的大模型。如果你用 LangChain 这类客户端需要给 LLM 配一个可用的 Base URL 和 API Key。TaoToken 在这里的角色是提供统一的 API 通道让你不用在多个模型供应商之间来回切换配置。你需要拿到两样东西API Key 和 Base URL。API Key 在控制台的 API Keys 页面创建Base URL 统一使用https://taotoken.net/api。注意这个地址不带任何查询参数直接作为 OpenAI 兼容接口的 base_url 使用。创建 Key 的入口在 API Keys文档说明在 接入文档。拿到 Key 之后建议先做一次最小验证确认通道可用再去配 MCP。验证方式很简单用 curl 发一个 chat completions 请求curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: ping}] }如果返回正常的 JSON 结构说明 Key 和 Base URL 都没问题。这一步很关键因为后面 MCP Client 报错时你需要能区分是「模型通道不通」还是「MCP 连接不通」。把这两个问题混在一起排查会浪费大量时间。环境变量建议这样设置避免 Key 硬编码进代码export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/api模型 ID 的选择上MCP 场景里工具调用能力比较重要建议选支持 function calling 的模型。具体可用模型列表可以在 模型对话 页面里试一下确认工具调用返回正常再接入。如果你后面要做长期编码或 Agent 任务可以考虑 Coding Plan额度模型更适合持续调用。3. 可复制配置FastAPI 作为 MCP Server 的两种写法Server 端有两种主流写法选哪种取决于你的现状。第一种是「已有 FastAPI 应用包装成 MCP 工具」适合存量项目第二种是「直接用 FastMCP 写原生 MCP 工具」适合从零开始、不需要 REST API 的场景。先装依赖pip install -qU fastapi-mcp fastapi uvicorn nest_asyncio3.1 包装已有 FastAPI 应用这是最常见的需求。你已经有了一堆app.get接口现在想让 AI 能调用它们。用FastApiMCP包装即可from fastapi import FastAPI from fastapi_mcp import FastApiMCP import nest_asyncio nest_asyncio.apply() app FastAPI() app.get(/users/{user_id}, operation_idget_user_info) async def read_user(user_id: int): return {user_id: user_id, name: test} mcp FastApiMCP( app, nameMy API MCP, describe_all_responsesTrue, describe_full_response_schemaTrue, ) mcp.mount() if __name__ __main__: import uvicorn uvicorn.run(app, host0.0.0.0, port8000)启动后MCP 端点默认挂在/mcp。这里有个容易踩的坑operation_id不显式指定的话会自动生成类似read_user_users__user_id__get的名字模型看到这种名字很难判断用途。所以每个要暴露成工具的接口都建议手动写operation_id、summary和description。3.2 原生 FastMCP 写法如果你不需要 REST API直接用 FastMCP 更干净from fastmcp import FastMCP mcp FastMCP(Logistics) mcp.tool() def estimate_delivery_time(distance_km: float) - str: 根据距离估算送达时间(小时) return f预计送达时间{distance_km / 500:.1f} 小时 if __name__ __main__: mcp.run(transportstreamable-http, host0.0.0.0, port8000)两种写法的区别在于包装式复用现有路由原生式工具描述更可控。如果你的接口参数复杂、需要精细控制模型看到的 schema原生式更合适。3.3 Client 端配置片段标准 MCP Client 配置适用于支持 SSE/HTTP 的客户端{ mcpServers: { my-api-mcp: { url: http://127.0.0.1:8000/mcp, alwaysAllow: [], disabled: false } } }注意这里用127.0.0.1而不是localhost。在某些容器或 WSL 环境里localhost解析会出问题直接写回环 IP 更稳。如果你的 Client 需要走本地代理程序配置长这样{ mcpServers: { my-api-mcp-proxy: { command: /Full/Path/To/mcp-proxy, args: [http://127.0.0.1:8000/mcp] } } }LangChain 客户端接入时把 LLM 的 base_url 指向 TaoTokenfrom langchain_openai import ChatOpenAI import os llm ChatOpenAI( modelgpt-4o-mini, temperature0, api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL) /v1, )这里base_url拼上/v1是因为 OpenAI 兼容接口的路径约定。如果你用的是 Codex 类工具auth.json里对应字段是OPENAI_BASE_URL和OPENAI_API_KEY值分别填https://taotoken.net/api/v1和你的 Key。三件套Base URL Key Model ID缺一不可少任何一个都会在请求阶段失败。4. 验证请求从 Client 发起一次完整工具调用配置写完必须验证。验证分两层先确认 MCP Server 的工具能被列出再确认模型能通过工具拿到结果。先单独测 MCP 端点是否可达curl -N http://127.0.0.1:8000/mcp \ -H Accept: text/event-stream如果返回 SSE 流或握手信息说明 Server 端正常。如果连接被拒绝检查uvicorn是否真的在监听、端口是否被占用。然后用 LangChain 客户端跑一次完整调用import asyncio from langchain_mcp_adapters.client import MultiServerMCPClient from langchain_mcp_adapters.tools import load_mcp_tools from langchain_openai import ChatOpenAI from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain.prompts import ChatPromptTemplate import os client MultiServerMCPClient({ logistics: { url: http://127.0.0.1:8000/mcp, transport: streamable_http, } }) async def main(): async with client.session(logistics) as session: tools await asyncio.wait_for(load_mcp_tools(session), timeout30.0) print(f已加载 {len(tools)} 个工具) for t in tools: print(f - {t.name}: {t.description[:50]}) llm ChatOpenAI( modelgpt-4o-mini, temperature0, api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL) /v1, ) prompt ChatPromptTemplate.from_messages([ (system, 你是物流助手根据用户问题调用合适的工具。), (human, {input}), (placeholder, {agent_scratchpad}), ]) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools, verboseTrue, max_iterations3) result await executor.ainvoke({input: 距离 1200 公里多久能到}) print(result[output]) asyncio.run(main())成功时你会看到工具列表被打印出来然后 Agent 调用工具并返回结果。如果工具列表为空说明 MCP 端点连上了但没解析出工具回去检查operation_id和路由定义。如果工具列表正常但 Agent 报错问题多半在 LLM 通道也就是 Key 或 Base URL。验证通过后建议把这次请求的完整日志留一份。后面换模型、换环境时这份日志是最好的对照基线。5. 常见报错排查401、local proxy failed 与工具加载失败这一节按真实报错来对。你遇到的大部分问题基本都在这几类里。401 Unauthorized。这个最直接Key 没带、带错、或者格式不对。检查三处环境变量是否真的导出成功echo $TAOTOKEN_API_KEY、请求头是否是Authorization: Bearer sk-xxx、Key 是否被复制时带了空格。如果 MCP Server 自己也做了鉴权Client 配置里要额外加 header 字段别只配 url。local proxy failed。这个报错通常和 MCP 无关是本地代理配置残留导致的。请求被转发到一个不存在的本地端口自然失败。排查方法先确认http_proxy、https_proxy环境变量是否为空再确认 Client 配置里没有指向失效的代理程序路径。把代理配置清掉直接用127.0.0.1连多数情况能恢复。reading choices 相关报错。这类错误出现在解析模型响应阶段说明请求发出去了、也返回了但返回结构不符合预期。常见原因是 Base URL 少写或多写了/v1导致请求打到了错误的路径返回了 HTML 或错误页。确认base_url是https://taotoken.net/api/v1不要重复拼/v1/v1。OAuth 相关报错。部分 MCP Client 默认走 OAuth 流程如果你的 Server 没配 OAuth就会卡在授权环节。解决办法是在 Client 配置里显式声明不需要 OAuth或者改用支持静态 header 的传输方式。别在没配 OAuth 的情况下硬走授权流程。工具加载超时。load_mcp_tools超时通常是 Server 端工具描述生成太慢或者网络握手有问题。先单独 curl 测端点再检查describe_full_response_schemaTrue是否让 schema 过大。工具多的时候可以分批暴露。排查顺序建议固定下来先 curl 测 MCP 端点再测 LLM 通道最后跑完整 Agent。这样每次都能定位到具体是哪一层的问题而不是盲目改配置。6. 统一 Key 通道的长期维护与接入建议跑通一次不难难的是长期稳定。统一 Key 通道的价值在于你只需要维护一套 Base URL 和 Key所有 MCP Client、Agent、编码工具都指向同一个入口。换模型时改 Model ID 就行不用动鉴权配置。日常维护上建议把 Key 放在环境变量或密钥管理里不要写进代码仓库。MCP Server 的operation_id和描述要当成接口文档来维护模型能不能正确调用很大程度取决于这些描述写得好不好。工具数量增长后定期清理不再使用的工具避免模型在无关工具上浪费 token。如果你在做长期编码或 Agent 类项目Coding Plan 的额度模式比按次调用更适合。需要调试模型行为时模型对话 页面可以快速验证工具调用是否符合预期。Key 管理和文档分别在 API Keys 和 接入文档。最后留一个实操建议把本文的 Server 代码和 Client 配置存成一个最小可运行仓库每次改配置前先在这个仓库里验证确认没问题再同步到主项目。这样能把「配置问题」和「业务问题」彻底分开排查效率会高很多。