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. 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 - ✅ Translates all cell content and sheet names
- ✅ Preserves cell merging - ✅ Preserves cell merging, formulas, and styles
- ✅ Maintains font styles (size, bold, italic, color) - ✅ Maintains font styles, colors, and borders
- ✅ Keeps background colors and borders - ✅ Image text extraction with vision models
- ✅ Translates text within formulas while preserving formula structure - ✅ Adds translated image text as comments
- ✅ Retains embedded images in original positions
### Word Translation (.docx) ### 📝 Word Translation (.docx)
- ✅ Translates body text, headers, footers, and tables - ✅ Translates body text, headers, footers, and tables
- ✅ Preserves heading styles and paragraph formatting - ✅ Preserves heading styles and paragraph formatting
- ✅ Maintains lists (numbered/bulleted) - ✅ Maintains lists, images, charts, and SmartArt
- ✅ Keeps embedded images, charts, and SmartArt in place - ✅ Image text extraction and translation
- ✅ Preserves table structures and cell formatting
### PowerPoint Translation (.pptx) ### 📽️ PowerPoint Translation (.pptx)
- ✅ Translates slide titles, body text, and speaker notes - ✅ Translates slide titles, body text, and speaker notes
- ✅ Preserves slide layouts and transitions - ✅ Preserves slide layouts, transitions, and animations
- ✅ Maintains animations - ✅ Image text extraction with text boxes added below images
- ✅ Keeps images, videos, and shapes in exact positions - ✅ Keeps layering order and positions
- ✅ Preserves layering order
### 🧠 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 ## 🚀 Quick Start
### Installation ### Installation
1. **Clone the repository:**
```powershell ```powershell
git clone <repository-url> # Clone the repository
cd Translate git clone https://gitea.parsanet.org/sepehr/office_translator.git
``` cd office_translator
2. **Create a virtual environment:** # Create virtual environment
```powershell
python -m venv venv python -m venv venv
.\venv\Scripts\Activate.ps1 .\venv\Scripts\Activate.ps1
```
3. **Install dependencies:** # Install dependencies
```powershell
pip install -r requirements.txt pip install -r requirements.txt
```
4. **Configure environment:** # Run the API
```powershell
cp .env.example .env
# Edit .env with your preferred settings
```
5. **Run the API:**
```powershell
python main.py 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 ## 📚 API Documentation
Once the server is running, visit:
- **Swagger UI**: http://localhost:8000/docs - **Swagger UI**: http://localhost:8000/docs
- **ReDoc**: http://localhost:8000/redoc - **ReDoc**: http://localhost:8000/redoc
## 🔧 API Endpoints ## 🔧 API Endpoints
### POST /translate ### POST /translate
Translate a single document Translate a document with full customization.
**Request:**
```bash ```bash
curl -X POST "http://localhost:8000/translate" \ curl -X POST "http://localhost:8000/translate" \
-F "file=@document.xlsx" \ -F "file=@document.xlsx" \
-F "target_language=es" \ -F "target_language=en" \
-F "source_language=auto" -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:** ### Parameters
Returns the translated document file
### POST /translate-batch | Parameter | Type | Default | Description |
Translate multiple documents at once |-----------|------|---------|-------------|
| `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:** ### GET /ollama/models
```bash List available Ollama models.
curl -X POST "http://localhost:8000/translate-batch" \
-F "files=@document1.docx" \
-F "files=@document2.pptx" \
-F "target_language=fr"
```
### GET /languages ### POST /ollama/configure
Get list of supported language codes Configure Ollama settings.
### GET /health ### GET /health
Health check endpoint 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"
```
## 🌐 Supported Languages ## 🌐 Supported Languages
The API supports 25+ languages including: | Code | Language | Code | Language |
- Spanish (es), French (fr), German (de) |------|----------|------|----------|
- Italian (it), Portuguese (pt), Russian (ru) | en | English | fr | French |
- Chinese (zh), Japanese (ja), Korean (ko) | fa | Persian/Farsi | es | Spanish |
- Arabic (ar), Hindi (hi), Dutch (nl) | de | German | it | Italian |
- And many more... | pt | Portuguese | ru | Russian |
| zh | Chinese | ja | Japanese |
Full list available at: `GET /languages` | ko | Korean | ar | Arabic |
## ⚙️ Configuration ## ⚙️ Configuration
Edit `.env` file to configure: ### Environment Variables (.env)
```env ```env
# Translation Service (google, deepl, libre) # Translation Service
TRANSLATION_SERVICE=google 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 DEEPL_API_KEY=your_api_key_here
# File Upload Limits # File Limits
MAX_FILE_SIZE_MB=50 MAX_FILE_SIZE_MB=50
# Directory Configuration # Directories
UPLOAD_DIR=./uploads UPLOAD_DIR=./uploads
OUTPUT_DIR=./outputs 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 ```json
{ {
"mcpServers": { "servers": {
"document-translator": { "document-translator": {
"type": "stdio",
"command": "python", "command": "python",
"args": ["-m", "mcp_server"], "args": ["mcp_server.py"],
"cwd": "D:/Translate",
"env": { "env": {
"API_URL": "http://localhost:8000" "PYTHONPATH": "D:/Translate"
} }
} }
} }
} }
``` ```
### Example MCP Tools ### MCP Tools Available
The MCP wrapper will expose these tools: | Tool | Description |
|------|-------------|
1. **translate_document** - Translate a single document | `translate_document` | Translate a document file |
2. **translate_batch** - Translate multiple documents | `list_ollama_models` | Get available Ollama models |
3. **get_supported_languages** - List supported languages | `get_supported_languages` | List supported language codes |
4. **check_translation_status** - Check status of translation | `configure_translation` | Set translation provider and options |
## 🏗️ Project Structure ## 🏗️ Project Structure
``` ```
Translate/ Translate/
├── main.py # FastAPI application ├── main.py # FastAPI application
├── config.py # Configuration management ├── config.py # Configuration
├── requirements.txt # Dependencies ├── requirements.txt # Dependencies
├── .env.example # Environment template ├── mcp_server.py # MCP server implementation
├── services/ ├── services/
│ ├── __init__.py │ └── translation_service.py # Translation providers
│ └── translation_service.py # Translation abstraction layer
├── translators/ ├── translators/
│ ├── __init__.py │ ├── excel_translator.py # Excel with image support
│ ├── excel_translator.py # Excel translation logic │ ├── word_translator.py # Word with image support
│ ├── word_translator.py # Word translation logic │ └── pptx_translator.py # PowerPoint with image support
│ └── pptx_translator.py # PowerPoint translation logic
├── utils/ ├── utils/
│ ├── __init__.py
│ ├── file_handler.py # File operations │ ├── file_handler.py # File operations
│ └── exceptions.py # Custom exceptions │ └── exceptions.py # Custom exceptions
├── uploads/ # Temporary upload storage ├── static/
│ └── index.html # Web interface
├── uploads/ # Temporary uploads
└── outputs/ # Translated files └── outputs/ # Translated files
``` ```
## 🧪 Testing ## 🧪 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 ## 🛠️ Tech Stack
2. Navigate to http://localhost:8000/docs
3. Use the interactive Swagger UI to test endpoints
### Test Files - **FastAPI**: Modern async web framework
- **openpyxl**: Excel manipulation
Prepare test files with: - **python-docx**: Word documents
- Complex formatting (multiple fonts, colors, styles) - **python-pptx**: PowerPoint presentations
- Embedded images and media - **deep-translator**: Google/DeepL/Libre translation
- Tables and merged cells - **requests**: Ollama API communication
- Formulas (for Excel) - **Uvicorn**: ASGI server
- 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**
## 📝 License ## 📝 License
MIT License - Feel free to use this project for your needs. MIT License
## 🤝 Contributing ## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. Contributions welcome! Please submit a Pull Request.
## 📧 Support
For issues and questions, please open an issue on the repository.
--- ---
**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()