文件提取服务

该服务通过REST API和MCP协议从PDF、Office文档、图像和URL中提取文本和数据,转换为LLM可用的Markdown格式,支持OCR和结构化输出。

  • by SteffenHebestreit
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 SteffenHebestreit/fastapi_mcp_template

使用说明

文件提取服务

通过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
  }
}

会话管理

会话生命周期

  1. 初始化:客户端发送 initialize 请求
  2. 能力协商:服务器使用支持的功能进行响应
  3. 就绪状态:客户端发送 notifications/initialized
  4. 活动会话:可以列出并调用工具
  5. 会话保持:会话跨请求维护状态

会话安全

  • 基于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-turbo
  • gpt-4

LLM集成增强了功能

启用LLM集成时,文件转换器提供:

  1. 增强图像处理:生成图像、图表和示意图的详细描述
  2. 用于扫描PDF的OCR:使用支持视觉的LLM自动将PDF页面转换为图像并提取文本
  3. 更好的内容分析:更好地理解文件结构和内容
  4. 智能格式化:更智能的Markdown格式决策

增强的OCR回退过程: 文件转换器现在对扫描的PDF使用复杂的三级回退系统:

  1. 传统OCR(初级):使用pytesseract或easyocr快速且经济高效地提取文本

    • 使用传统OCR算法处理文档图像
    • 非常适合清晰、标准的字体和简单的布局
    • 无API成本,离线工作
  2. LLM视觉分析(二级):复杂内容的高级分析

    • 当传统OCR产生的结果不足(<50个字符)时使用
    • 处理手写、复杂布局和低质量扫描
    • 使用具有视觉能力的LLM,实现卓越的精度
  3. 智能选择(三级):结合最佳结果

    • 自动选择最全面的输出
    • 如果足够,更喜欢传统的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 上传+ params JSON字符串)
  • 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_id
  • GET /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提取到Markdown
  • text_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检查器(推荐)

  1. 确保fastapi-mcp模板服务器正在运行:

    docker-compose up -d
    
  2. 运行MCP检查器以测试服务器:

    npx @modelcontextprotocol/inspector
    
  3. 在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": {}
  }'

预期行为

  1. 初始化应返回会话ID和服务器信息
  2. 初始化的通知应自动发送
  3. 工具/列表应在正确初始化后返回可用工具
  4. 服务器不应返回“服务器未初始化”错误

调试

  • 检查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[] 和a extraction_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

为了保持一致性,这两种类型都使用相同的基础测试类。

工具开发技巧

  1. 保持工具自给自足:不从核心包中导入
  2. 优雅地处理错误:始终返回结构化错误响应
  3. 使用类型提示:利用Python的类型系统获得更好的开发体验
  4. 日志操作:使用 tool_base.log_info() 和 tool_base.log_error()
  5. 验证输入:在工具中实施适当的输入验证

📝 许可证

此作品根据 知识共享署名-非商业4.0国际许可.

这意味着:

  • ✅ 需要归因:您必须对原始创建者给予适当的赞扬
  • ✅ 非商业用途:您可以出于非商业目的使用、修改和分发
  • ✅ 混音与改编:您可以构建和修改材质
  • ❌ 商业用途:商业使用需要单独的许可协议

版权所有(c)2025 Steffen Hebestreit

有关完整的许可证文本,请访问: https://creativecommons.org/licenses/by-nc/4.0/

用于商业许可,请联系作者。

🚀 入门指南

准备好构建MCP服务器了吗?

  1. 分叉此模板
  2. 克隆你的叉子
    git clone https://github.com/yourusername/fastapi-mcp-template.git
    cd fastapi-mcp-template
    
  3. 添加自定义工具 到 tools/ 目录
  4. 配置 通过 .env 文件
  5. 部署 与 docker-compose up --build

您的MCP服务器将准备好与LLM应用程序集成,并提供对您的工具的MCP和REST API访问!


快乐建筑! 🛠️