使用说明
文件提取服务
通过REST API和模型上下文协议(MCP)从文件(PDF、Office文档、图像、URL)中提取文本和数据作为LLM就绪上下文。
此服务将文档转换为干净的Markdown,您可以将其输入LLM管道 (RAG,与您的文档、代理上下文聊天)。它处理了混乱的摄入层,因此 您不必:格式检测、扫描页面的OCR、结构化输出 每页元数据和令牌计数、分块、缓存和SSRF保护的URL获取。
它建立在一个小型动态工具框架之上( .py 文件在 tools/ 它是
通过两个接口公开),因此您可以使用自己的提取器对其进行扩展。
它做什么
- File → 标记语言 通过 MarkItDown 库:PDF、DOCX、XLSX、PPTX、HTML、图像等。
- 扫描PDF和图像的OCR回退 --传统OCR(Tesseract)首先运行,需要 没有API密钥;可选的LLM视觉模型是硬页面的二级回退。
- LLM就绪的结构化输出 --Markdown加每页文本、标记估计、提取方法标签和可选的基于字符的重叠块。
- URL摄取 --以Markdown格式获取网页,或获取远程文档并提取它,并防止对内部/私有地址(SSRF)的请求。
- 缓存 --相同的文件被提取一次,并从内容哈希缓存中提供(没有重复的OCR/视觉成本)。
- 双界面 --同样的工具可用作REST端点和LLM客户端的MCP工具。
🎯 项目目标
在不受信任的文档和下游LLM上下文之间提供可靠的摄取边界。
该服务被组织为一组自包含的工具 tools/:
file_converter--核心文件/URL→ Markdown提取器(带OCR)。url_fetcher--以Markdown格式获取网页/文件,SSRF保护。text_processor--小型文本工具(clean、case、strip HTML、提取电子邮件)。
添加自己的提取器 tools/your_tool.py (参见“添加自己的工具”);它会被自动发现并在两个界面上公开。
🏗️ 架构概述
fastapi-mcp-template/
├── fastapi_mcp_template/ # Core MCP server package
│ ├── __about__.py # Version information
│ ├── __init__.py # Package initialization
│ ├── config.py # Configuration management
│ ├── main.py # Application entry point
│ ├── requirements.txt # Core dependencies only
│ ├── api/ # REST API endpoints
│ │ ├── __init__.py
│ │ └── routes.py # API route definitions
│ ├── core/ # MCP core functionality
│ │ ├── __init__.py
│ │ ├── tool_base.py # Base tool infrastructure
│ │ ├── tool_definition.py # Tool interface definitions
│ │ └── tool_manager.py # Dynamic tool loading
│ └── core_test/ # Core functionality tests
│ ├── __init__.py
│ ├── requirements.txt # Test dependencies
│ ├── test_base.py
│ ├── test_core.py
│ └── test_manager.py
├── tools/ # Self-contained tools (your custom tools go here!)
│ ├── file_converter.py # Example: File-to-Markdown converter with OCR
│ ├── text_processor.py # Example: Text processing operations
│ ├── url_fetcher.py # Example: URL content fetcher
│ └── requirements/ # Tool-specific dependencies
│ ├── file_converter.txt # Dependencies for file_converter (markitdown, openai, PyMuPDF)
│ ├── text_processor.txt # Dependencies for text_processor
│ └── url_fetcher.txt # Dependencies for url_fetcher
├── tests/ # Tool tests
│ ├── __init__.py
│ └── test_tools.py
├── data/ # Data directory for file storage
├── docker-compose.yml # Container orchestration
├── Dockerfile # Container definition with dynamic deps
├── .env.example # Environment configuration template
└── README.md # This file
🚀 主要特点
动态工具加载
- 零配置:将Python文件放入
tools/它们会被自动发现 - 热重新加载:开发模式更改后会自动重新加载工具
- 依赖隔离:每个工具通过以下方式管理自己的依赖关系
requirements/{toolname}.txt - 独立:工具不依赖于核心包
- 动态工具类型:工具可以定义任何自定义类型,而无需修改核心
双接口架构
- MCP协议:与LLM应用程序(Claude等)的本地集成
- REST API:web应用程序的标准HTTP端点
- 统一工具访问:两个界面都提供相同的工具
- 交互式文档:上的自动生成API文档
/docs
生产就绪部署
- Docker支持:通过多阶段构建完成集装箱化
- 动态依赖:仅在启用工具时安装工具依赖项
- 健康检查:内置监测和健康端点
- 环境配置:通过环境变量灵活配置
开发者体验
- FastAPI基金会:具有自动验证功能的现代Python web框架
- 类型安全:完整类型提示和Pydantic模型
- 错误处理:全面的错误处理和记录
- 测试就绪:结构支持简单的单元和集成测试
📋 MCP协议合规性
此模板实现了 模型上下文协议(MCP)2024-11-05 完全符合规范,以确保与Claude Desktop、Cline和其他LLM应用程序等MCP客户端的无缝集成。
协议标准遵守情况
JSON-RPC 2.0基础
- ✅ 完全符合JSON-RPC 2.0标准 具有适当的消息结构
- ✅ 唯一请求ID 在会话中永远不会重复使用
- ✅ 正确的错误代码 遵循JSON-RPC标准(-32000至-32099范围)
- ✅ 结构化错误响应 带有代码、消息和可选数据字段
MCP生命周期管理
- ✅ 正确的初始化握手 通过能力谈判
- ✅ 会话管理 具有基于UUID的会话ID
- ✅ 协议版本协商 (支持2024-11-05)
- ✅ 优雅的错误处理 不支持的协议版本
核心MCP方法
{
"initialize": "✅ Capability negotiation with tool listing support",
"notifications/initialized": "✅ Post-initialization state management",
"tools/list": "✅ Dynamic tool discovery and enumeration",
"tools/call": "✅ Tool execution with parameter validation",
"ping": "✅ Connection liveness verification"
}
能力声明
服务器在初始化过程中正确声明了其功能:
{
"capabilities": {
"tools": {
"listChanged": true
}
},
"serverInfo": {
"name": "fastapi_mcp_template",
"version": "1.0.0"
}
}
主要合规特征:
- 工具能力:声明支持工具列表和执行
- 动态更新:支持
listChanged工具修改通知 - 服务器标识:正确的服务器信息,包括名称和版本
- 协议版本:显式协议版本支持声明
工具架构合规性
工具遵循MCP工具规范,并进行适当的JSON模式验证:
{
"name": "file_to_markdown",
"description": "Convert files to Markdown format",
"inputSchema": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "Name of the file to convert"
},
"base64_content": {
"type": "string",
"description": "Base64 encoded file content"
}
},
"required": ["filename", "base64_content"]
}
}
错误处理标准
协议级错误
- -32601:找不到方法(不支持的MCP方法)
- -32602:无效参数(请求格式错误、工具未知)
- -32603:内部错误(服务器端故障)
- -32002:服务器未初始化(会话/功能问题)
工具执行错误
使用以下命令在成功的JSON-RPC响应中报告工具错误 isError 标志:
{
"jsonrpc": "2.0",
"id": 123,
"result": {
"content": [
{
"type": "text",
"text": "Tool execution failed: File format not supported"
}
],
"isError": true
}
}
会话管理
会话生命周期
- 初始化:客户端发送
initialize请求 - 能力协商:服务器使用支持的功能进行响应
- 就绪状态:客户端发送
notifications/initialized - 活动会话:可以列出并调用工具
- 会话保持:会话跨请求维护状态
会话安全
- 基于UUID的会话ID:加密安全会话标识符
- 会话验证:根据活动会话验证所有请求
- 会话超时:自动清理非活动会话
- 基于标头的身份验证:会话ID通过传递
Mcp-Session-Id头球
传输层合规性
HTTP传输支持
- ✅ 内容类型:
application/json对于所有请求/响应 - ✅ CORS支持:为web客户端提供适当的跨源标头
- ✅ 会话标头:
Mcp-Session-Id标题处理 - ✅ 状态代码:适当的HTTP状态代码(200、202、400、500)
端点结构
POST /mcp # Main MCP protocol endpoint
POST / # Fallback MCP endpoint
GET /mcp/session # Session creation helper
OPTIONS /mcp # CORS preflight support
测试与验证
MCP检查器兼容性
服务器与官方MCP Inspector工具完全兼容:
# Test with MCP Inspector
npx @modelcontextprotocol/inspector
# Connect to: http://localhost:8000/mcp
方案验证测试
- ✅ 初始化流程:完整的握手序列
- ✅ 工具发现:列出并验证所有可用工具
- ✅ 工具执行:参数验证和结果格式化
- ✅ 错误场景:正确的错误代码和消息处理
- ✅ 会话管理:会话创建、验证和清理
互操作性
客户端兼容性
通过以下方式进行测试和验证:
- ✅ 克劳德桌面版:全面集成支持
- ✅ MCP检查员:官方测试工具兼容性
- ✅ 自定义客户端:Java、TypeScript、Python客户端库
- ✅ Web客户端:基于浏览器的MCP应用程序
标准符合性
- 📋 MCP规范2024-11-05:完全合规
- 📋 JSON-RPC 2.0:完成实施
- 📋 JSON 模式:工具参数验证
- 📋 HTTP/1.1:标准网络兼容性
- 📋 跨域资源共享:跨来源资源共享支持
这种全面的合规性确保了任何MCP客户端都可以无缝连接到您的服务器并与之交互,为LLM集成提供了可靠的基础。
🛠️ 示例用例
此模板可以适用于任何MCP服务器用例:
- 📄 文档处理:使用LLM增强的OCR转换、分析或转换文档
- 🔗 API集成:连接到外部服务和API
- 📊 数据分析:处理和分析数据集
- 🎨 内容生成:在人工智能的帮助下创建或转换内容
- 🔍 信息检索:从各种来源搜索和获取信息
- 🧮 计算:执行复杂的计算或模拟
- 📈 监控:收集指标或监控系统
- 🖼️ 图像分析:使用具有视觉能力的LLM从图像中提取文本和描述
📦 安装和设置
选项1:Docker(推荐)
快速入门-启用所有工具:
# Clone the template
git clone https://github.com/SteffenHebestreit/fastapi-mcp-template.git
cd fastapi-mcp-template
# Start with default configuration
docker-compose up --build
自定义工具选择:
# Copy environment template
cp .env.example .env
# Edit .env to specify which tools to enable
# ENABLED_TOOLS=file_converter,text_processor
# Build with custom tools
docker-compose up --build
Docker高级用法:
# Build with specific tools only
docker-compose build --build-arg ENABLED_TOOLS=file_converter,text_processor
# Run in background
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
选项2:直接安装
对于开发或自定义部署:
# 1. Clone and navigate
git clone https://github.com/SteffenHebestreit/fastapi-mcp-template.git
cd fastapi-mcp-template
# 2. (recommended) create a virtualenv
python -m venv .venv && . .venv/Scripts/activate # Windows
# python -m venv .venv && source .venv/bin/activate # macOS/Linux
# 3. Install core dependencies
pip install -r fastapi_mcp_template/requirements.txt
# 4. Install tool dependencies (choose what you need)
pip install -r tools/requirements/file_converter.txt # File conversion + OCR
pip install -r tools/requirements/url_fetcher.txt # URL fetching
# text_processor has no additional dependencies
# 5. Additional OCR setup (for the traditional OCR fallback)
# Install the Tesseract OCR engine:
# - Windows: https://github.com/UB-Mannheim/tesseract/wiki
# - Ubuntu/Debian: sudo apt install tesseract-ocr
# - macOS: brew install tesseract
# 6. Run the server (config comes from FTMD_* env vars / .env — no CLI flags)
# PYTHONPATH must include the repo root so the package is importable.
PYTHONPATH=. python -m fastapi_mcp_template.main
# Custom configuration is via environment variables, e.g.:
FTMD_PORT=8080 FTMD_DEBUG=true PYTHONPATH=. python -m fastapi_mcp_template.main
🔧 配置
环境变量
通过环境变量配置服务器行为:
所有运行时设置都使用 FTMD_ 前缀(请参见 .env.example 对于完整
列表)。一个没有前缀的流浪汉 PORT=... 被忽略--使用 FTMD_PORT.
# Core
FTMD_HOST=0.0.0.0 # Server host
FTMD_PORT=8000 # Server port
FTMD_DEBUG=false # Debug mode (also exposes /tests/* endpoints)
FTMD_RELOAD=false # uvicorn auto-reload (dev only)
FTMD_LOG_LEVEL=INFO # Logging level
# Tool loading
FTMD_ENABLED_TOOLS=file_converter,text_processor,url_fetcher # empty = all
# FTMD_TOOLS_DIRECTORY=/app/tools # auto-detected; override only if needed
# Security
FTMD_API_KEY= # if set, X-API-Key required on tool/admin endpoints
FTMD_CORS_ORIGINS=* # "*" (no credentials) or comma-separated origins
# Extraction limits
FTMD_MAX_UPLOAD_BYTES=52428800 # 50 MiB
FTMD_OCR_MAX_PAGES=50 # 0 = no limit
FTMD_OCR_LANGUAGES=eng # tesseract lang(s), e.g. eng+deu
# URL fetching / SSRF
FTMD_BLOCK_PRIVATE_URLS=true # block internal/private/metadata addresses
OpenAI集成配置
启用OpenAI集成以增强图像处理和内容分析:
基本OpenAI设置
# Enable LLM features for enhanced file conversion
FTMD_MARKITDOWN_ENABLE_LLM=true
# Your OpenAI API key
FTMD_OPENAI_API_KEY=sk-proj-your-api-key-here
# Model to use (default: gpt-4o)
FTMD_OPENAI_MODEL=gpt-4o
Azure OpenAI设置
# Enable LLM features
FTMD_MARKITDOWN_ENABLE_LLM=true
# Azure OpenAI endpoint
FTMD_OPENAI_BASE_URL=https://your-resource.openai.azure.com/
# Azure API key
FTMD_OPENAI_API_KEY=your-azure-api-key
# Model deployment name
FTMD_OPENAI_MODEL=gpt-4o
自定义OpenAI兼容端点
# Enable LLM features
FTMD_MARKITDOWN_ENABLE_LLM=true
# Custom endpoint
FTMD_OPENAI_BASE_URL=https://your-custom-endpoint.com/v1
# API key for custom endpoint
FTMD_OPENAI_API_KEY=your-custom-api-key
# Model name
FTMD_OPENAI_MODEL=your-model-name
支持的型号
与MarkItDown配合良好的常见OpenAI模型:
gpt-4o(推荐)gpt-4o-mini(成本效益)gpt-4-turbogpt-4
LLM集成增强了功能
启用LLM集成时,文件转换器提供:
- 增强图像处理:生成图像、图表和示意图的详细描述
- 用于扫描PDF的OCR:使用支持视觉的LLM自动将PDF页面转换为图像并提取文本
- 更好的内容分析:更好地理解文件结构和内容
- 智能格式化:更智能的Markdown格式决策
增强的OCR回退过程: 文件转换器现在对扫描的PDF使用复杂的三级回退系统:
-
传统OCR(初级):使用pytesseract或easyocr快速且经济高效地提取文本
- 使用传统OCR算法处理文档图像
- 非常适合清晰、标准的字体和简单的布局
- 无API成本,离线工作
-
LLM视觉分析(二级):复杂内容的高级分析
- 当传统OCR产生的结果不足(<50个字符)时使用
- 处理手写、复杂布局和低质量扫描
- 使用具有视觉能力的LLM,实现卓越的精度
-
智能选择(三级):结合最佳结果
- 自动选择最全面的输出
- 如果足够,更喜欢传统的OCR,如果需要,更喜欢LLM
- 优化成本和准确性
流程详细信息:
- 自动检测扫描的PDF(空文本内容)
- 将PDF页面转换为高分辨率图像(2倍缩放)
- 每份文档最多处理5页以管理成本
- 在Markdown输出中保持原始格式和结构
Docker配置
docker-compose.yml 支持:
- 通过构建参数选择工具
- 环境文件挂载
- 批量安装用于开发
- 端口配置
- 健康检查
Dockerfile 特征:
- 多阶段构建以实现优化
- 基于已启用工具的动态依赖关系安装
- 安全强化容器(非root用户)
- 健康检查端点
🎯 添加您自己的工具
动态刀具类型系统
该模板使用灵活的动态工具类型系统,允许您在不修改核心代码的情况下定义任何自定义工具类型。
运作原理
工具使用简单的字符串作为类型,而不是硬编码的枚举:
# Define any tool type you want
tool_type = "converter" # Built-in type
tool_type = "analyzer" # Custom type
tool_type = "my_special_ai" # Your unique type
可用的内置类型
为方便起见,提供了常见的工具类型:
"converter"-文件格式转换器"processor"-文本/数据处理器"fetcher"-内容/数据提取器"utility"-通用工具
自定义类型
您可以创建任何自定义类型:
def get_definition(self):
return ToolDefinition(
name="sentiment_analyzer",
description="AI-powered sentiment analysis",
endpoint="/sentiment",
tool_type="ai_analyzer", # Custom type!
version="1.0.0"
)
加载工具时,系统会自动发现并跟踪所有工具类型。
步骤1:创建工具文件
在中创建一个新的Python文件 tools/ 目录:
# tools/my_custom_tool.py
from typing import Dict, Any
class ToolInterface:
"""Interface that tools must implement."""
def get_definition(self): raise NotImplementedError
def get_schema(self): raise NotImplementedError
async def execute(self, **kwargs) -> Dict[str, Any]: raise NotImplementedError
class ToolDefinition:
def __init__(self, name: str, description: str, endpoint: str, tool_type: str, version: str = "1.0.0"):
self.name = name
self.description = description
self.endpoint = endpoint
self.tool_type = tool_type
self.version = version
class ToolSchema:
def __init__(self, properties: Dict[str, Any], required: list = None):
self.properties = properties
self.required = required or []
class MyCustomTool(ToolInterface):
def __init__(self, tool_base):
self.tool_base = tool_base
def get_definition(self) -> ToolDefinition:
return ToolDefinition(
name="my_custom_tool",
description="Description of what my tool does",
endpoint="/my-endpoint",
tool_type="my_analyzer", # Any string you want!
version="1.0.0"
)
def get_schema(self) -> ToolSchema:
return ToolSchema(
properties={
"input_param": {
"type": "string",
"description": "Description of the parameter"
}
},
required=["input_param"]
)
async def execute(self, **kwargs) -> Dict[str, Any]:
input_param = kwargs.get("input_param")
try:
# Your tool logic here
result = f"Processed: {input_param}"
self.tool_base.log_info(f"Tool executed successfully")
return {
"success": True,
"result": result
}
except Exception as e:
self.tool_base.log_error(f"Tool execution failed: {str(e)}")
return {
"success": False,
"error": str(e)
}
def setup_tool(tool_base):
"""Setup function called by the core service."""
return MyCustomTool(tool_base)
步骤2:添加依赖关系(如果需要)
如果您的工具需要其他软件包:
# Create tools/requirements/my_custom_tool.txt
mkdir -p tools/requirements
echo "requests>=2.28.0" > tools/requirements/my_custom_tool.txt
echo "beautifulsoup4>=4.11.0" >> tools/requirements/my_custom_tool.txt
步骤3:启用您的工具
将您的工具添加到已启用的工具列表中:
# In .env file or environment
ENABLED_TOOLS=file_converter,text_processor,url_fetcher,my_custom_tool
步骤4:部署
# Rebuild and restart
docker-compose up --build
就是这样!您的工具现在可以通过MCP和REST API接口使用。
🌐 API终点
运行后,服务器提供多个接口:
MCP协议端点
POST /mcp-主MCP协议端点(处理所有MCP方法)GET /mcp/session-会话创建辅助端点
REST API端点
GET /health,GET /api/health-健康检查GET /tools-列出所有可用工具及其模式GET /api/tools/{tool_name}/schema-获取工具的参数模式POST /api/tools/{tool_name}-通过以下方式执行工具 多部分 (file上传+paramsJSON字符串)POST /mcp/tools/{tool_name}-通过执行工具 JSON正文 (参数作为顶级键)GET /metrics,GET /api/metrics-进程中计数器(提取、错误、视觉调用+估计成本)GET /docs-交互式API文档
后台作业(用于慢速OCR)
长OCR/视觉提取可以作为后台作业运行,因此请求返回 立即。作业正在处理中(在重新启动后不持久)。
POST /api/jobs/{tool_name}-提交作业(多部分输入与/api/tools/{name});退货202带着一个job_idGET /api/jobs/{job_id}-投票状态(pending/running/completed/failed)并获取结果GET /api/jobs-列出最近的工作
# Submit, then poll
JID=$(curl -s -X POST http://localhost:8000/api/jobs/file_to_markdown \
-F "file=@big-scan.pdf" | python -c "import sys,json;print(json.load(sys.stdin)['job_id'])")
curl http://localhost:8000/api/jobs/$JID
MCP协议说明
这 /mcp 端点使用JSON-RPC 2.0并支持 批量请求 (发送
数组),协商 protocolVersion (在支持时,与客户的相呼应: 2024-11-05
或 2025-03-26),并宣布 tools.listChanged: false (没有服务器→客户
推流)。 GET /mcp 回报 405 (SSE流未实现;使用POST)。
认证: 如果
FTMD_API_KEY已设置,工具执行和管理端点需要X-API-Key头球如果未设置(默认),则禁用auth——不要公开 无需设置密钥即可公开服务。
可用工具
file_to_markdown-使用OCR回退、分块和缓存将文件/URL提取到Markdowntext_processor-处理和转换文本内容url_fetcher-以Markdown格式获取网页/文件(SSRF保护)
示例用法
通过REST——JSON body(base64),使用 /mcp/tools/{name} 端点:
# List available tools
curl http://localhost:8000/tools
# Extract a file from base64 content
curl -X POST http://localhost:8000/mcp/tools/file_to_markdown \
-H "Content-Type: application/json" \
-d '{"filename": "document.pdf", "base64_content": "JVBERi0xLjQK..."}'
# Extract a remote document by URL (fetched with SSRF protection)
curl -X POST http://localhost:8000/mcp/tools/file_to_markdown \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/report.pdf", "chunk_size": 2000}'
# Process text
curl -X POST http://localhost:8000/mcp/tools/text_processor \
-H "Content-Type: application/json" \
-d '{"text": "Hello World", "operation": "uppercase"}'
# Fetch a URL as Markdown
curl -X POST http://localhost:8000/mcp/tools/url_fetcher \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
通过REST——多部分文件上传,使用 /api/tools/{name}:
# 'file' is the upload; 'params' is a JSON string of extra arguments
curl -X POST http://localhost:8000/api/tools/file_to_markdown \
-F "file=@document.pdf" \
-F 'params={"chunk_size": 2000}'
如果
FTMD_API_KEY已设置,添加-H "X-API-Key: <your-key>"对于上述呼吁。
通过MCP协议:
# Initialize MCP session
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "test-client", "version": "1.0.0"}
}
}'
# List tools (after initialization)
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <session-id-from-initialize>" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
# Call tool
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <session-id>" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "file_to_markdown",
"arguments": {"filename": "test.pdf", "base64_content": "..."}
}
}'
🔍 监测与健康
- 健康检查:
GET /api/health - 指标:内置日志记录和指标收集
- Docker健康状况:已配置容器健康检查
- API文档:互动文档
/docs
🧪 开发与测试
发展模式
# Run with hot reloading
python fastapi_mcp_template/main.py --reload
# Or with Docker in development mode
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
测试MCP服务器
使用MCP检查器(推荐)
-
确保fastapi-mcp模板服务器正在运行:
docker-compose up -d -
运行MCP检查器以测试服务器:
npx @modelcontextprotocol/inspector -
在MCP检查器UI中:
- 将传输设置为“可流式传输http”
- 将服务器URL设置为“http://localhost:8000/mcp"
- 点击“连接”
使用curl进行手动测试
测试初始化终结点:
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {
"name": "test-client",
"version": "1.0.0"
}
}
}'
测试工具/列表端点(初始化后):
curl -X POST http://localhost:8000/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <session-id-from-initialize>" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
预期行为
- 初始化应返回会话ID和服务器信息
- 初始化的通知应自动发送
- 工具/列表应在正确初始化后返回可用工具
- 服务器不应返回“服务器未初始化”错误
调试
- 检查Docker日志:
docker compose logs file-extraction-service - 检查端口8000是否可访问:
curl http://localhost:8000/health - 使用MCP检查器的调试功能查看完整的请求/响应流
测试OCR/扫描文档提取
传统OCR(Tesseract)运行 没有任何API密钥LLM视觉模型是
仅启用二级回退 FTMD_MARKITDOWN_ENABLE_LLM=true 和a
OpenAI密钥。
提取扫描图像(OCR):
curl -X POST "http://localhost:8000/mcp/tools/file_to_markdown" \
-H "Content-Type: application/json" \
-d '{
"filename": "chart.png",
"base64_content": "iVBORw0KGgoAAAANSUhEUgAA..."
}'
提取扫描的PDF(OCR回退,每页输出):
curl -X POST "http://localhost:8000/mcp/tools/file_to_markdown" \
-H "Content-Type: application/json" \
-d '{
"filename": "scanned_document.pdf",
"base64_content": "JVBERi0xLjYNJeLjz9MN..."
}'
提取行为:
- 文本PDF/Office文档:直接提取MarkItDown。
- 扫描的PDF和图像:Tesseract OCR(免费);响应包括
pages[]和aextraction_method的ocr(或ocr+vision当使用LLM回退时)。 - 响应报告
success: false如果无法提取文本,则会发出警告——它从不报告空输出的成功。
LLM集成故障排除:
- PyMuPDF不可用:安装
pip install PyMuPDF>=1.24.0用于OCR功能 - OpenAI库不可用:安装依赖项
pip install openai>=1.0.0 - API关键问题:
- 确保您的API密钥有效并且有足够的信用
- 检查Azure OpenAI或自定义终结点的基本URL是否正确
- 验证环境变量名称是否使用
FTMD_前缀
- 未找到型号:
- 确保模型名称对于您的OpenAI设置是正确的
- 对于Azure OpenAI,使用您的部署名称,而不是基本模型名称
- 验证模型是否支持OCR功能的视觉功能
- OCR不工作:
- 检查一下
FTMD_MARKITDOWN_ENABLE_LLM=true已设置 - 验证PDF实际上不包含可提取文本(扫描文档)
- 在日志中查找“正在尝试增强OCR回退”消息
- 检查一下
- 传统OCR问题:
- Pytesseract:确保系统上安装了Tesseract OCR引擎
- EasyOCR:可能需要额外的GPU设置才能获得最佳性能
- 低质量结果:工具将自动回退到LLM视觉分析
- OCR性能:
- 传统的OCR优先考虑成本效益(无API成本)
- 当OCR产生<50个字符时,LLM视觉分析激活
- 每个PDF仅处理5页以管理成本
安全注意事项:
- 永远不要将API密钥提交到版本控制
- 使用环境变量或安全密钥管理
- 定期旋转API键
- 监视API使用情况以发现意外活动
成本考虑:
- LLM集成会根据使用情况产生API成本
- OCR处理(扫描的PDF)比标准文本提取使用更多的标记
- 图像处理通常比纯文本操作使用更多的令牌
- 考虑使用
gpt-4o-mini为了实现经济高效的加工 - OCR处理限制为每个PDF 5页,以管理成本
- 通过OpenAI仪表板监控您的使用情况
测试结构
该项目使用了一种分离的测试方法,反映了核心功能和工具之间的分离。
测试组织
1.核心测试(fastapi_mcp_template/core_test/)
- 目的:核心MCP模板服务器功能测试
- 位置:模板服务包内部
- 封面:工具管理器、配置加载、API路由、核心应用程序逻辑
2.工具测试(tests/)
- 目的:专门针对单个工具的测试
- 位置:根级测试目录
- 封面:单个工具加载和执行、工具特定功能、工具要求验证
运行测试
建议:使用pytest运行套件(从repo根目录)。
pip install pytest pytest-asyncio
# pytest.ini sets asyncio_mode=auto and the test paths.
PYTHONPATH=. pytest
这将在中运行工具测试 tests/ (真实提取、分块、缓存、SSRF)
框架测试 fastapi_mcp_template/core_test/.
通过应用内测试运行器(仅限开发容器)。 测试端点已暴露
只有当 FTMD_DEBUG=true,并要求 X-API-Key 当配置密钥时:
# Start the dev service (debug + tests enabled)
docker compose --profile dev up file-extraction-service-dev # dev is on :8001
curl http://localhost:8001/tests/status
curl -X POST http://localhost:8001/tests/run-all
curl -X POST http://localhost:8001/tests/run/test_tools
测试API端点
启用测试时(ENABLE_TESTS=true),以下端点可用:
GET /tests/status-检查是否启用了测试GET /tests-列出所有可用的测试POST /tests/run/{test_name}-运行特定的测试文件POST /tests/run-all-运行所有测试
添加新测试
对于核心功能: 将测试文件添加到 fastapi_mcp_template/core_test/ 遵循模式 test_*.py
对于工具: 将测试文件添加到 tests/ 遵循模式 test_*.py
为了保持一致性,这两种类型都使用相同的基础测试类。
工具开发技巧
- 保持工具自给自足:不从核心包中导入
- 优雅地处理错误:始终返回结构化错误响应
- 使用类型提示:利用Python的类型系统获得更好的开发体验
- 日志操作:使用
tool_base.log_info()和tool_base.log_error() - 验证输入:在工具中实施适当的输入验证
📝 许可证
此作品根据 知识共享署名-非商业4.0国际许可.
这意味着:
- ✅ 需要归因:您必须对原始创建者给予适当的赞扬
- ✅ 非商业用途:您可以出于非商业目的使用、修改和分发
- ✅ 混音与改编:您可以构建和修改材质
- ❌ 商业用途:商业使用需要单独的许可协议
版权所有(c)2025 Steffen Hebestreit
有关完整的许可证文本,请访问: https://creativecommons.org/licenses/by-nc/4.0/
用于商业许可,请联系作者。
🚀 入门指南
准备好构建MCP服务器了吗?
- 分叉此模板
- 克隆你的叉子
git clone https://github.com/yourusername/fastapi-mcp-template.git cd fastapi-mcp-template - 添加自定义工具 到
tools/目录 - 配置 通过
.env文件 - 部署 与
docker-compose up --build
您的MCP服务器将准备好与LLM应用程序集成,并提供对您的工具的MCP和REST API访问!
快乐建筑! 🛠️