Add MCP server and configuration for AI assistant integration

This commit is contained in:
Sepehr 2025-11-30 16:53:53 +01:00
parent e48ea07e44
commit a4ecd3e0ec
3 changed files with 714 additions and 202 deletions

358
README.md
View File

@ -1,303 +1,267 @@
# Document Translation API
# 📄 Document Translation API
A powerful Python API for translating complex structured documents (Excel, Word, PowerPoint) while **strictly preserving** the original formatting, layout, and embedded media.
## 🎯 Features
## Features
### Excel Translation (.xlsx)
### 🔄 Multiple Translation Providers
| Provider | Type | Description |
|----------|------|-------------|
| **Google Translate** | Cloud | Free, fast, reliable |
| **Ollama** | Local LLM | Privacy-focused, customizable with system prompts |
| **WebLLM** | Browser | Runs entirely in browser using WebGPU |
| **DeepL** | Cloud | High-quality translations (API key required) |
| **LibreTranslate** | Self-hosted | Open-source alternative |
### 📊 Excel Translation (.xlsx)
- ✅ Translates all cell content and sheet names
- ✅ Preserves cell merging
- ✅ Maintains font styles (size, bold, italic, color)
- ✅ Keeps background colors and borders
- ✅ Translates text within formulas while preserving formula structure
- ✅ Retains embedded images in original positions
- ✅ Preserves cell merging, formulas, and styles
- ✅ Maintains font styles, colors, and borders
- ✅ Image text extraction with vision models
- ✅ Adds translated image text as comments
### Word Translation (.docx)
### 📝 Word Translation (.docx)
- ✅ Translates body text, headers, footers, and tables
- ✅ Preserves heading styles and paragraph formatting
- ✅ Maintains lists (numbered/bulleted)
- ✅ Keeps embedded images, charts, and SmartArt in place
- ✅ Preserves table structures and cell formatting
- ✅ Maintains lists, images, charts, and SmartArt
- ✅ Image text extraction and translation
### PowerPoint Translation (.pptx)
### 📽️ PowerPoint Translation (.pptx)
- ✅ Translates slide titles, body text, and speaker notes
- ✅ Preserves slide layouts and transitions
- ✅ Maintains animations
- ✅ Keeps images, videos, and shapes in exact positions
- ✅ Preserves layering order
- ✅ Preserves slide layouts, transitions, and animations
- ✅ Image text extraction with text boxes added below images
- ✅ Keeps layering order and positions
### 🧠 LLM Features (Ollama/WebLLM)
- ✅ **Custom System Prompts**: Provide context for better translations
- ✅ **Technical Glossary**: Define term mappings (e.g., `batterie=coil`)
- ✅ **Presets**: HVAC, IT, Legal, Medical terminology
- ✅ **Vision Models**: Translate text within images (gemma3, qwen3-vl, llava)
## 🚀 Quick Start
### Installation
1. **Clone the repository:**
```powershell
git clone <repository-url>
cd Translate
```
# Clone the repository
git clone https://gitea.parsanet.org/sepehr/office_translator.git
cd office_translator
2. **Create a virtual environment:**
```powershell
# Create virtual environment
python -m venv venv
.\venv\Scripts\Activate.ps1
```
3. **Install dependencies:**
```powershell
# Install dependencies
pip install -r requirements.txt
```
4. **Configure environment:**
```powershell
cp .env.example .env
# Edit .env with your preferred settings
```
5. **Run the API:**
```powershell
# Run the API
python main.py
```
The API will start on `http://localhost:8000`
The API starts on `http://localhost:8000`
### Web Interface
Open `http://localhost:8000/static/index.html` for the full-featured web interface.
## 📚 API Documentation
Once the server is running, visit:
- **Swagger UI**: http://localhost:8000/docs
- **ReDoc**: http://localhost:8000/redoc
## 🔧 API Endpoints
### POST /translate
Translate a single document
Translate a document with full customization.
**Request:**
```bash
curl -X POST "http://localhost:8000/translate" \
-F "file=@document.xlsx" \
-F "target_language=es" \
-F "source_language=auto"
-F "target_language=en" \
-F "provider=ollama" \
-F "ollama_model=gemma3:12b" \
-F "translate_images=true" \
-F "system_prompt=You are translating HVAC documents. Use: batterie=coil, CTA=AHU"
```
**Response:**
Returns the translated document file
### Parameters
### POST /translate-batch
Translate multiple documents at once
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `file` | File | required | Document to translate (.xlsx, .docx, .pptx) |
| `target_language` | string | required | Target language code (en, fr, es, fa, etc.) |
| `provider` | string | google | Translation provider (google, ollama, webllm, deepl, libre) |
| `ollama_model` | string | llama3.2 | Ollama model name |
| `translate_images` | bool | false | Extract and translate image text with vision |
| `system_prompt` | string | "" | Custom instructions and glossary for LLM |
**Request:**
```bash
curl -X POST "http://localhost:8000/translate-batch" \
-F "files=@document1.docx" \
-F "files=@document2.pptx" \
-F "target_language=fr"
```
### GET /ollama/models
List available Ollama models.
### GET /languages
Get list of supported language codes
### POST /ollama/configure
Configure Ollama settings.
### GET /health
Health check endpoint
## 💻 Usage Examples
### Python Example
```python
import requests
# Translate a document
with open('document.xlsx', 'rb') as f:
files = {'file': f}
data = {
'target_language': 'es',
'source_language': 'auto'
}
response = requests.post('http://localhost:8000/translate', files=files, data=data)
# Save translated file
with open('translated_document.xlsx', 'wb') as output:
output.write(response.content)
```
### JavaScript/TypeScript Example
```javascript
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('target_language', 'fr');
formData.append('source_language', 'auto');
const response = await fetch('http://localhost:8000/translate', {
method: 'POST',
body: formData
});
const blob = await response.blob();
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'translated_document.docx';
a.click();
```
### PowerShell Example
```powershell
$file = Get-Item "document.pptx"
$uri = "http://localhost:8000/translate"
$form = @{
file = $file
target_language = "de"
source_language = "auto"
}
Invoke-RestMethod -Uri $uri -Method Post -Form $form -OutFile "translated_document.pptx"
```
Health check endpoint.
## 🌐 Supported Languages
The API supports 25+ languages including:
- Spanish (es), French (fr), German (de)
- Italian (it), Portuguese (pt), Russian (ru)
- Chinese (zh), Japanese (ja), Korean (ko)
- Arabic (ar), Hindi (hi), Dutch (nl)
- And many more...
Full list available at: `GET /languages`
| Code | Language | Code | Language |
|------|----------|------|----------|
| en | English | fr | French |
| fa | Persian/Farsi | es | Spanish |
| de | German | it | Italian |
| pt | Portuguese | ru | Russian |
| zh | Chinese | ja | Japanese |
| ko | Korean | ar | Arabic |
## ⚙️ Configuration
Edit `.env` file to configure:
### Environment Variables (.env)
```env
# Translation Service (google, deepl, libre)
# Translation Service
TRANSLATION_SERVICE=google
# DeepL API Key (if using DeepL)
# Ollama Configuration
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2
# DeepL API Key (optional)
DEEPL_API_KEY=your_api_key_here
# File Upload Limits
# File Limits
MAX_FILE_SIZE_MB=50
# Directory Configuration
# Directories
UPLOAD_DIR=./uploads
OUTPUT_DIR=./outputs
```
## 🔌 Model Context Protocol (MCP) Integration
### Ollama Setup
This API is designed to be easily wrapped as an MCP server for future integration with AI assistants and tools.
```bash
# Install Ollama (Windows)
winget install Ollama.Ollama
### MCP Server Structure (Future Implementation)
# Pull a model
ollama pull llama3.2
# For vision/image translation
ollama pull gemma3:12b
# or
ollama pull qwen3-vl:8b
```
## 🎯 Using System Prompts & Glossary
### Example: HVAC Translation
**System Prompt:**
```
You are translating HVAC technical documents.
Use precise technical terminology.
Keep unit measurements (kW, m³/h, Pa) unchanged.
```
**Glossary:**
```
batterie=coil
groupe froid=chiller
CTA=AHU (Air Handling Unit)
échangeur=heat exchanger
vanne 3 voies=3-way valve
```
### Presets Available
- 🔧 **HVAC**: Heating, Ventilation, Air Conditioning
- 💻 **IT**: Software and technology
- ⚖️ **Legal**: Legal documents
- 🏥 **Medical**: Healthcare terminology
## 🔌 MCP Integration
This API can be used as an MCP (Model Context Protocol) server for AI assistants.
### VS Code Configuration
Add to your VS Code `settings.json` or `.vscode/mcp.json`:
```json
{
"mcpServers": {
"servers": {
"document-translator": {
"type": "stdio",
"command": "python",
"args": ["-m", "mcp_server"],
"args": ["mcp_server.py"],
"cwd": "D:/Translate",
"env": {
"API_URL": "http://localhost:8000"
"PYTHONPATH": "D:/Translate"
}
}
}
}
```
### Example MCP Tools
### MCP Tools Available
The MCP wrapper will expose these tools:
1. **translate_document** - Translate a single document
2. **translate_batch** - Translate multiple documents
3. **get_supported_languages** - List supported languages
4. **check_translation_status** - Check status of translation
| Tool | Description |
|------|-------------|
| `translate_document` | Translate a document file |
| `list_ollama_models` | Get available Ollama models |
| `get_supported_languages` | List supported language codes |
| `configure_translation` | Set translation provider and options |
## 🏗️ Project Structure
```
Translate/
├── main.py # FastAPI application
├── config.py # Configuration management
├── config.py # Configuration
├── requirements.txt # Dependencies
├── .env.example # Environment template
├── mcp_server.py # MCP server implementation
├── services/
│ ├── __init__.py
│ └── translation_service.py # Translation abstraction layer
│ └── translation_service.py # Translation providers
├── translators/
│ ├── __init__.py
│ ├── excel_translator.py # Excel translation logic
│ ├── word_translator.py # Word translation logic
│ └── pptx_translator.py # PowerPoint translation logic
│ ├── excel_translator.py # Excel with image support
│ ├── word_translator.py # Word with image support
│ └── pptx_translator.py # PowerPoint with image support
├── utils/
│ ├── __init__.py
│ ├── file_handler.py # File operations
│ └── exceptions.py # Custom exceptions
├── uploads/ # Temporary upload storage
├── static/
│ └── index.html # Web interface
├── uploads/ # Temporary uploads
└── outputs/ # Translated files
```
## 🧪 Testing
### Manual Testing
1. Start the API: `python main.py`
2. Open: http://localhost:8000/static/index.html
3. Configure Ollama model
4. Upload a document
5. Select target language and provider
6. Click "Translate Document"
1. Start the API server
2. Navigate to http://localhost:8000/docs
3. Use the interactive Swagger UI to test endpoints
## 🛠️ Tech Stack
### Test Files
Prepare test files with:
- Complex formatting (multiple fonts, colors, styles)
- Embedded images and media
- Tables and merged cells
- Formulas (for Excel)
- Multiple sections/slides
## 🛠️ Technical Details
### Libraries Used
- **FastAPI**: Modern web framework for building APIs
- **openpyxl**: Excel file manipulation with formatting preservation
- **python-docx**: Word document handling
- **python-pptx**: PowerPoint presentation processing
- **deep-translator**: Multi-provider translation service
- **Uvicorn**: ASGI server for running FastAPI
### Design Principles
1. **Modular Architecture**: Each file type has its own translator module
2. **Provider Abstraction**: Easy to swap translation services (Google, DeepL, LibreTranslate)
3. **Format Preservation**: All translators maintain original document structure
4. **Error Handling**: Comprehensive error handling and logging
5. **Scalability**: Ready for MCP integration and microservices architecture
## 🔐 Security Considerations
For production deployment:
1. **Configure CORS** properly in `main.py`
2. **Add authentication** for API endpoints
3. **Implement rate limiting** to prevent abuse
4. **Use HTTPS** for secure file transmission
5. **Sanitize file uploads** to prevent malicious files
6. **Set appropriate file size limits**
- **FastAPI**: Modern async web framework
- **openpyxl**: Excel manipulation
- **python-docx**: Word documents
- **python-pptx**: PowerPoint presentations
- **deep-translator**: Google/DeepL/Libre translation
- **requests**: Ollama API communication
- **Uvicorn**: ASGI server
## 📝 License
MIT License - Feel free to use this project for your needs.
MIT License
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## 📧 Support
For issues and questions, please open an issue on the repository.
Contributions welcome! Please submit a Pull Request.
---
**Built with ❤️ using Python and FastAPI**
**Built with ❤️ using Python, FastAPI, and Ollama**

157
mcp.json Normal file
View File

@ -0,0 +1,157 @@
{
"$schema": "https://json.schemastore.org/mcp-config.json",
"name": "document-translator",
"version": "1.0.0",
"description": "Document Translation API - Translate Excel, Word, PowerPoint files with format preservation",
"author": "Sepehr",
"repository": "https://gitea.parsanet.org/sepehr/office_translator.git",
"license": "MIT",
"runtime": {
"type": "python",
"command": "python",
"args": ["mcp_server.py"],
"cwd": "${workspaceFolder}"
},
"requirements": {
"python": ">=3.8",
"dependencies": [
"requests>=2.28.0"
]
},
"tools": [
{
"name": "translate_document",
"description": "Translate a document (Excel, Word, PowerPoint) to another language while preserving all formatting, styles, formulas, and layouts",
"parameters": {
"file_path": {
"type": "string",
"description": "Absolute path to the document file (.xlsx, .docx, .pptx)",
"required": true
},
"target_language": {
"type": "string",
"description": "Target language code (en, fr, es, fa, de, it, pt, ru, zh, ja, ko, ar)",
"required": true
},
"provider": {
"type": "string",
"enum": ["google", "ollama", "deepl", "libre"],
"default": "google",
"description": "Translation provider to use"
},
"ollama_model": {
"type": "string",
"description": "Ollama model name (e.g., llama3.2, gemma3:12b, qwen3-vl)"
},
"translate_images": {
"type": "boolean",
"default": false,
"description": "Use vision model to extract and translate text from embedded images"
},
"system_prompt": {
"type": "string",
"description": "Custom instructions and context for LLM translation (glossary, domain context, style guidelines)"
},
"output_path": {
"type": "string",
"description": "Path where to save the translated document"
}
},
"examples": [
{
"description": "Translate Excel file to French using Google",
"arguments": {
"file_path": "C:/Documents/data.xlsx",
"target_language": "fr",
"provider": "google"
}
},
{
"description": "Translate Word document to Persian with Ollama and custom glossary",
"arguments": {
"file_path": "C:/Documents/report.docx",
"target_language": "fa",
"provider": "ollama",
"ollama_model": "gemma3:12b",
"system_prompt": "You are translating HVAC technical documentation. Glossary: batterie=کویل, ventilateur=فن, condenseur=کندانسور"
}
},
{
"description": "Translate PowerPoint with image text extraction",
"arguments": {
"file_path": "C:/Presentations/slides.pptx",
"target_language": "de",
"provider": "ollama",
"ollama_model": "gemma3:12b",
"translate_images": true
}
}
]
},
{
"name": "list_ollama_models",
"description": "List all available Ollama models for translation",
"parameters": {
"base_url": {
"type": "string",
"default": "http://localhost:11434",
"description": "Ollama server URL"
}
}
},
{
"name": "get_supported_languages",
"description": "Get the full list of supported language codes and names",
"parameters": {}
},
{
"name": "check_api_health",
"description": "Check if the translation API server is running and healthy",
"parameters": {}
}
],
"features": [
"Format-preserving translation for Excel, Word, PowerPoint",
"Multiple translation providers (Google, Ollama, DeepL, LibreTranslate)",
"Image text extraction using vision models (Gemma3, Qwen3-VL)",
"Custom system prompts and glossaries for technical translation",
"Domain-specific presets (HVAC, IT, Legal, Medical)",
"Browser-based WebLLM support for offline translation"
],
"usage": {
"start_server": "python main.py",
"api_endpoint": "http://localhost:8000",
"web_interface": "http://localhost:8000"
},
"providers": {
"google": {
"description": "Google Translate (free, no API key required)",
"supports_system_prompt": false
},
"ollama": {
"description": "Local Ollama LLM server",
"supports_system_prompt": true,
"supports_vision": true,
"recommended_models": [
"llama3.2",
"gemma3:12b",
"qwen3-vl",
"mistral"
]
},
"deepl": {
"description": "DeepL API (requires API key)",
"supports_system_prompt": false
},
"libre": {
"description": "LibreTranslate (self-hosted)",
"supports_system_prompt": false
}
}
}

391
mcp_server.py Normal file
View File

@ -0,0 +1,391 @@
#!/usr/bin/env python3
"""
MCP Server for Document Translation API
Model Context Protocol server for AI assistant integration
"""
import sys
import json
import asyncio
import base64
import requests
from pathlib import Path
from typing import Any, Optional
# MCP Protocol Constants
JSONRPC_VERSION = "2.0"
class MCPServer:
"""MCP Server for Document Translation"""
def __init__(self):
self.api_base = "http://localhost:8000"
self.capabilities = {
"tools": {}
}
def get_tools(self) -> list:
"""Return list of available tools"""
return [
{
"name": "translate_document",
"description": "Translate a document (Excel, Word, PowerPoint) to another language while preserving formatting",
"inputSchema": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to the document file (.xlsx, .docx, .pptx)"
},
"target_language": {
"type": "string",
"description": "Target language code (e.g., 'en', 'fr', 'es', 'fa', 'de')"
},
"provider": {
"type": "string",
"enum": ["google", "ollama", "deepl", "libre"],
"description": "Translation provider (default: google)"
},
"ollama_model": {
"type": "string",
"description": "Ollama model to use (e.g., 'llama3.2', 'gemma3:12b')"
},
"translate_images": {
"type": "boolean",
"description": "Extract and translate text from images using vision model"
},
"system_prompt": {
"type": "string",
"description": "Custom system prompt with context, glossary, or instructions for LLM translation"
},
"output_path": {
"type": "string",
"description": "Path where to save the translated document (optional)"
}
},
"required": ["file_path", "target_language"]
}
},
{
"name": "list_ollama_models",
"description": "List available Ollama models for translation",
"inputSchema": {
"type": "object",
"properties": {
"base_url": {
"type": "string",
"description": "Ollama server URL (default: http://localhost:11434)"
}
}
}
},
{
"name": "get_supported_languages",
"description": "Get list of supported language codes for translation",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "configure_translation",
"description": "Configure translation settings",
"inputSchema": {
"type": "object",
"properties": {
"provider": {
"type": "string",
"enum": ["google", "ollama", "deepl", "libre"],
"description": "Default translation provider"
},
"ollama_url": {
"type": "string",
"description": "Ollama server URL"
},
"ollama_model": {
"type": "string",
"description": "Default Ollama model"
}
}
}
},
{
"name": "check_api_health",
"description": "Check if the translation API is running and healthy",
"inputSchema": {
"type": "object",
"properties": {}
}
}
]
async def handle_tool_call(self, name: str, arguments: dict) -> dict:
"""Handle tool calls"""
try:
if name == "translate_document":
return await self.translate_document(arguments)
elif name == "list_ollama_models":
return await self.list_ollama_models(arguments)
elif name == "get_supported_languages":
return await self.get_supported_languages()
elif name == "configure_translation":
return await self.configure_translation(arguments)
elif name == "check_api_health":
return await self.check_api_health()
else:
return {"error": f"Unknown tool: {name}"}
except Exception as e:
return {"error": str(e)}
async def translate_document(self, args: dict) -> dict:
"""Translate a document file"""
file_path = Path(args["file_path"])
if not file_path.exists():
return {"error": f"File not found: {file_path}"}
# Prepare form data
with open(file_path, 'rb') as f:
files = {'file': (file_path.name, f)}
data = {
'target_language': args['target_language'],
'provider': args.get('provider', 'google'),
'translate_images': str(args.get('translate_images', False)).lower(),
}
if args.get('ollama_model'):
data['ollama_model'] = args['ollama_model']
if args.get('system_prompt'):
data['system_prompt'] = args['system_prompt']
try:
response = requests.post(
f"{self.api_base}/translate",
files=files,
data=data,
timeout=300 # 5 minutes timeout
)
if response.status_code == 200:
# Save translated file
output_path = args.get('output_path')
if not output_path:
output_path = file_path.parent / f"translated_{file_path.name}"
output_path = Path(output_path)
with open(output_path, 'wb') as out:
out.write(response.content)
return {
"success": True,
"message": f"Document translated successfully",
"output_path": str(output_path),
"source_file": str(file_path),
"target_language": args['target_language'],
"provider": args.get('provider', 'google')
}
else:
error_detail = response.json() if response.headers.get('content-type') == 'application/json' else response.text
return {"error": f"Translation failed: {error_detail}"}
except requests.exceptions.ConnectionError:
return {"error": "Cannot connect to translation API. Make sure the server is running on http://localhost:8000"}
except requests.exceptions.Timeout:
return {"error": "Translation request timed out"}
async def list_ollama_models(self, args: dict) -> dict:
"""List available Ollama models"""
base_url = args.get('base_url', 'http://localhost:11434')
try:
response = requests.get(
f"{self.api_base}/ollama/models",
params={'base_url': base_url},
timeout=10
)
if response.status_code == 200:
data = response.json()
return {
"models": data.get('models', []),
"count": data.get('count', 0),
"ollama_url": base_url
}
else:
return {"error": "Failed to list models", "models": []}
except requests.exceptions.ConnectionError:
return {"error": "Cannot connect to API server", "models": []}
async def get_supported_languages(self) -> dict:
"""Get supported language codes"""
return {
"languages": [
{"code": "en", "name": "English"},
{"code": "fa", "name": "Persian/Farsi"},
{"code": "fr", "name": "French"},
{"code": "es", "name": "Spanish"},
{"code": "de", "name": "German"},
{"code": "it", "name": "Italian"},
{"code": "pt", "name": "Portuguese"},
{"code": "ru", "name": "Russian"},
{"code": "zh", "name": "Chinese"},
{"code": "ja", "name": "Japanese"},
{"code": "ko", "name": "Korean"},
{"code": "ar", "name": "Arabic"},
{"code": "nl", "name": "Dutch"},
{"code": "pl", "name": "Polish"},
{"code": "tr", "name": "Turkish"},
{"code": "vi", "name": "Vietnamese"},
{"code": "th", "name": "Thai"},
{"code": "hi", "name": "Hindi"},
{"code": "he", "name": "Hebrew"},
{"code": "sv", "name": "Swedish"}
]
}
async def configure_translation(self, args: dict) -> dict:
"""Configure translation settings"""
config = {}
if args.get('ollama_url') and args.get('ollama_model'):
try:
response = requests.post(
f"{self.api_base}/ollama/configure",
data={
'base_url': args['ollama_url'],
'model': args['ollama_model']
},
timeout=10
)
if response.status_code == 200:
config['ollama'] = response.json()
except Exception as e:
config['ollama_error'] = str(e)
config['provider'] = args.get('provider', 'google')
return {
"success": True,
"configuration": config
}
async def check_api_health(self) -> dict:
"""Check API health status"""
try:
response = requests.get(f"{self.api_base}/health", timeout=5)
if response.status_code == 200:
return {
"status": "healthy",
"api_url": self.api_base,
"details": response.json()
}
else:
return {"status": "unhealthy", "error": "API returned non-200 status"}
except requests.exceptions.ConnectionError:
return {
"status": "unavailable",
"error": "Cannot connect to API. Start the server with: python main.py"
}
def create_response(self, id: Any, result: Any) -> dict:
"""Create JSON-RPC response"""
return {
"jsonrpc": JSONRPC_VERSION,
"id": id,
"result": result
}
def create_error(self, id: Any, code: int, message: str) -> dict:
"""Create JSON-RPC error response"""
return {
"jsonrpc": JSONRPC_VERSION,
"id": id,
"error": {
"code": code,
"message": message
}
}
async def handle_message(self, message: dict) -> Optional[dict]:
"""Handle incoming JSON-RPC message"""
msg_id = message.get("id")
method = message.get("method")
params = message.get("params", {})
if method == "initialize":
return self.create_response(msg_id, {
"protocolVersion": "2024-11-05",
"capabilities": self.capabilities,
"serverInfo": {
"name": "document-translator",
"version": "1.0.0"
}
})
elif method == "notifications/initialized":
return None # No response needed for notifications
elif method == "tools/list":
return self.create_response(msg_id, {
"tools": self.get_tools()
})
elif method == "tools/call":
tool_name = params.get("name")
tool_args = params.get("arguments", {})
result = await self.handle_tool_call(tool_name, tool_args)
return self.create_response(msg_id, {
"content": [
{
"type": "text",
"text": json.dumps(result, indent=2, ensure_ascii=False)
}
]
})
elif method == "ping":
return self.create_response(msg_id, {})
else:
return self.create_error(msg_id, -32601, f"Method not found: {method}")
async def run(self):
"""Run the MCP server using stdio"""
while True:
try:
line = sys.stdin.readline()
if not line:
break
message = json.loads(line)
response = await self.handle_message(message)
if response:
sys.stdout.write(json.dumps(response) + "\n")
sys.stdout.flush()
except json.JSONDecodeError as e:
error = self.create_error(None, -32700, f"Parse error: {e}")
sys.stdout.write(json.dumps(error) + "\n")
sys.stdout.flush()
except Exception as e:
error = self.create_error(None, -32603, f"Internal error: {e}")
sys.stdout.write(json.dumps(error) + "\n")
sys.stdout.flush()
def main():
"""Main entry point"""
server = MCPServer()
asyncio.run(server.run())
if __name__ == "__main__":
main()