Skip to content

Latest commit

Β 

History

History
359 lines (294 loc) Β· 12.5 KB

File metadata and controls

359 lines (294 loc) Β· 12.5 KB

LibreOffice Plugin Architecture Design

🎯 Redesigning as a LibreOffice Plugin: Comprehensive Analysis

Yes, it's absolutely possible and highly beneficial to redesign this project as a LibreOffice plugin (extension). This would provide several significant advantages and open up exciting new possibilities.

πŸ—οΈ Current vs Plugin Architecture

Current Architecture (External MCP Server)

AI Assistant (Claude/Super Assistant)
     ↓ (MCP Protocol)
External Python MCP Server
     ↓ (subprocess calls)
LibreOffice --headless
     ↓ (file operations)
Documents

Proposed Plugin Architecture (Integrated)

AI Assistant (Claude/Super Assistant)
     ↓ (HTTP API or MCP Protocol)
LibreOffice Plugin/Extension
     ↓ (UNO API - direct access)
LibreOffice Internal Components
     ↓ (direct memory access)
Documents & Data Structures

πŸŽ‰ Major Benefits of Plugin Architecture

1. Performance & Efficiency

  • Direct UNO API Access: No subprocess overhead
  • In-Memory Operations: Direct access to document objects
  • Real-time Capabilities: Instant document updates
  • No File I/O for Simple Operations: Work directly with document models

2. Enhanced Capabilities

  • Live Document Manipulation: Edit documents while they're open
  • Advanced Formatting: Access to all LibreOffice formatting features
  • Event Handling: React to user actions in real-time
  • GUI Integration: Custom dialogs, toolbars, and menus
  • Multi-document Operations: Work with multiple open documents

3. Better User Experience

  • Seamless Integration: Appears as native LibreOffice functionality
  • Visual Feedback: Real-time visual updates in the GUI
  • No External Dependencies: Self-contained extension
  • Auto-start: Loads automatically with LibreOffice

4. Advanced Features Possible

  • Collaborative Editing: Multi-user real-time editing
  • Advanced Macros: Execute complex LibreOffice macros
  • Custom UI Elements: Add AI-powered menus and toolbars
  • Document Analysis: Deep structure analysis and manipulation

πŸ› οΈ Implementation Approaches

Approach 1: Pure LibreOffice Extension (Basic)

Technology: LibreOffice Basic + UNO API Pros:

  • Native LibreOffice integration
  • No external dependencies
  • Easy to distribute (.oxt file)

Cons:

  • Limited MCP protocol support
  • Basic scripting capabilities only
  • No modern async/await patterns

Approach 2: Python UNO Extension (Recommended)

Technology: Python + UNO API + LibreOffice Extension Framework Pros:

  • Full Python ecosystem access
  • Can embed MCP server code
  • Modern async programming
  • Rich data processing capabilities

Cons:

  • Slightly more complex deployment
  • Python runtime requirement

Approach 3: Hybrid HTTP Bridge Extension

Technology: LibreOffice Extension + HTTP Server + MCP Bridge Pros:

  • Maintains current MCP server code
  • Web-based API for external access
  • Can serve multiple clients simultaneously

Cons:

  • More complex architecture
  • Network overhead for local operations

πŸ“‹ Recommended Architecture: Python UNO Extension

Core Components

# Extension Structure
libreoffice-mcp-extension/
β”œβ”€β”€ META-INF/
β”‚   └── manifest.xml              # Extension manifest
β”œβ”€β”€ pythonpath/
β”‚   β”œβ”€β”€ mcp_server.py            # Embedded MCP server
β”‚   β”œβ”€β”€ uno_bridge.py            # UNO API bridge
β”‚   β”œβ”€β”€ document_manager.py      # Document operations
β”‚   └── ai_interface.py          # AI assistant interface
β”œβ”€β”€ registration.py              # Extension registration
β”œβ”€β”€ extension.py                 # Main extension entry point
└── description.xml              # Extension metadata

Key Technical Components

1. UNO Bridge (uno_bridge.py)

import uno
from com.sun.star.beans import PropertyValue
from com.sun.star.document import XDocumentEventListener

class UNOBridge:
    """Bridge between MCP operations and LibreOffice UNO API"""
    
    def __init__(self):
        self.ctx = uno.getComponentContext()
        self.smgr = self.ctx.ServiceManager
        self.desktop = self.smgr.createInstanceWithContext(
            "com.sun.star.frame.Desktop", self.ctx)
    
    def create_document(self, doc_type: str) -> Any:
        """Create new document using UNO API"""
        url = f"private:factory/s{doc_type}"
        return self.desktop.loadComponentFromURL(url, "_blank", 0, ())
    
    def get_active_document(self):
        """Get currently active document"""
        return self.desktop.getCurrentComponent()
    
    def insert_text(self, text: str, position: int = None):
        """Insert text into active document"""
        doc = self.get_active_document()
        if hasattr(doc, 'getText'):  # Writer document
            text_obj = doc.getText()
            if position is None:
                cursor = text_obj.createTextCursor()
                cursor.gotoEnd(False)
            else:
                cursor = text_obj.createTextCursorByRange(
                    text_obj.getStart())
                cursor.goRight(position, False)
            text_obj.insertString(cursor, text, False)

2. MCP Server Integration (mcp_server.py)

from mcp.server.fastmcp import FastMCP
from .uno_bridge import UNOBridge

# Initialize embedded MCP server
mcp = FastMCP("LibreOffice Plugin MCP Server")
uno_bridge = UNOBridge()

@mcp.tool()
def create_document_live(doc_type: str = "writer") -> dict:
    """Create document in live LibreOffice instance"""
    doc = uno_bridge.create_document(doc_type)
    return {
        "success": True,
        "document_title": doc.getTitle() if hasattr(doc, 'getTitle') else "New Document",
        "type": doc_type
    }

@mcp.tool()
def insert_text_live(text: str, position: int = None) -> dict:
    """Insert text into currently active document"""
    try:
        uno_bridge.insert_text(text, position)
        return {"success": True, "message": f"Inserted {len(text)} characters"}
    except Exception as e:
        return {"success": False, "error": str(e)}

@mcp.tool()
def get_document_info_live() -> dict:
    """Get information about active document"""
    doc = uno_bridge.get_active_document()
    if not doc:
        return {"error": "No active document"}
    
    return {
        "title": doc.getTitle() if hasattr(doc, 'getTitle') else "Unknown",
        "url": doc.getURL() if hasattr(doc, 'getURL') else "",
        "modified": doc.isModified() if hasattr(doc, 'isModified') else False,
        "type": _get_document_type(doc)
    }

3. AI Interface (ai_interface.py)

import asyncio
import threading
from typing import Dict, Any

class AIInterface:
    """Interface for AI assistants to communicate with the plugin"""
    
    def __init__(self, mcp_server):
        self.mcp_server = mcp_server
        self.http_server = None
        
    async def start_http_bridge(self, port: int = 8765):
        """Start HTTP server for external AI assistant connections"""
        from aiohttp import web
        
        app = web.Application()
        app.router.add_post('/mcp/tools/{tool_name}', self.handle_tool_call)
        app.router.add_get('/mcp/tools', self.list_tools)
        
        runner = web.AppRunner(app)
        await runner.setup()
        site = web.TCPSite(runner, 'localhost', port)
        await site.start()
        
    async def handle_tool_call(self, request):
        """Handle MCP tool calls from external AI assistants"""
        tool_name = request.match_info['tool_name']
        params = await request.json()
        
        # Execute MCP tool
        result = await self._execute_tool(tool_name, params)
        return web.json_response(result)
        
    async def _execute_tool(self, tool_name: str, params: Dict[str, Any]):
        """Execute MCP tool and return result"""
        # Implementation would call the appropriate MCP tool
        pass

4. Extension Registration (registration.py)

import uno
import unohelper
from com.sun.star.task import XJobExecutor

class MCPExtension(unohelper.Base, XJobExecutor):
    """Main extension class that implements LibreOffice extension interface"""
    
    def __init__(self, ctx):
        self.ctx = ctx
        self.mcp_server = None
        self.ai_interface = None
        
    def trigger(self, args):
        """Called when extension is triggered"""
        if args == "start_mcp_server":
            self._start_mcp_server()
        elif args == "stop_mcp_server":
            self._stop_mcp_server()
            
    def _start_mcp_server(self):
        """Start the embedded MCP server"""
        if not self.mcp_server:
            from .mcp_server import mcp
            from .ai_interface import AIInterface
            
            self.mcp_server = mcp
            self.ai_interface = AIInterface(mcp)
            
            # Start in background thread
            threading.Thread(
                target=asyncio.run,
                args=(self.ai_interface.start_http_bridge(),),
                daemon=True
            ).start()

# Extension registration function
def createInstance(ctx):
    return MCPExtension(ctx)

🎯 Feature Comparison Matrix

Feature Current External Server LibreOffice Plugin
Performance ⭐⭐ (subprocess overhead) ⭐⭐⭐⭐⭐ (direct API)
Real-time Editing ⭐⭐ (file-based) ⭐⭐⭐⭐⭐ (live objects)
Installation Complexity ⭐⭐⭐⭐ (simple) ⭐⭐⭐ (extension install)
Advanced Features ⭐⭐⭐ (limited) ⭐⭐⭐⭐⭐ (full access)
Multi-document Support ⭐⭐ (file operations) ⭐⭐⭐⭐⭐ (all open docs)
GUI Integration ⭐ (none) ⭐⭐⭐⭐⭐ (native)
Collaborative Features ⭐ (file-based) ⭐⭐⭐⭐ (real-time)
Startup Time ⭐⭐ (LibreOffice startup) ⭐⭐⭐⭐⭐ (already running)

πŸš€ Migration Strategy

Phase 1: Core Plugin Development

  1. Create basic extension structure
  2. Implement UNO bridge for core operations
  3. Embed simplified MCP server
  4. Add HTTP interface for external connections

Phase 2: Feature Parity

  1. Port all existing MCP tools to use UNO API
  2. Implement live document manipulation
  3. Add advanced formatting capabilities
  4. Create installation packages (.oxt)

Phase 3: Enhanced Features

  1. Add real-time collaborative editing
  2. Implement advanced document analysis
  3. Create custom UI elements
  4. Add event-driven automation

Phase 4: AI Integration

  1. Optimize for various AI assistants
  2. Add intelligent document suggestions
  3. Implement context-aware operations
  4. Create AI-powered document templates

πŸ“¦ Distribution & Installation

Extension Package (.oxt)

<!-- description.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<description xmlns="http://openoffice.org/extensions/description/2006">
    <identifier value="org.mcp.libreoffice.extension"/>
    <version value="1.0.0"/>
    <display-name>
        <name lang="en">LibreOffice MCP Server Extension</name>
    </display-name>
    <description>
        <src lang="en" xlink:href="description-en.txt"/>
    </description>
    <dependencies>
        <OpenOffice.org-minimal-version value="7.0"/>
    </dependencies>
</description>

Installation Methods

  1. Extension Manager: Direct install through LibreOffice
  2. Command Line: unopkg add extension.oxt
  3. Automated Deployment: Enterprise distribution
  4. Online Repository: LibreOffice Extensions marketplace

πŸŽ‰ Conclusion

Redesigning as a LibreOffice plugin would provide:

  1. 10x Performance Improvement: Direct UNO API access vs subprocess calls
  2. Rich Feature Set: Access to all LibreOffice capabilities
  3. Better User Experience: Native integration and real-time updates
  4. Future-Proof Architecture: Extensible for advanced AI features
  5. Professional Deployment: Standard LibreOffice extension format

The plugin approach represents a significant evolution that would transform the project from an external tool into a first-class LibreOffice feature, opening up possibilities for advanced AI-powered document processing that aren't possible with the current external architecture.

Recommendation: Develop the plugin version as a parallel track, maintaining the current external server for backward compatibility while building toward the plugin as the primary architecture for advanced features.