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.
AI Assistant (Claude/Super Assistant)
β (MCP Protocol)
External Python MCP Server
β (subprocess calls)
LibreOffice --headless
β (file operations)
Documents
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
- 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
- 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
- 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
- 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
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
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
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
# 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 metadataimport 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)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)
}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
passimport 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 | 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) |
- Create basic extension structure
- Implement UNO bridge for core operations
- Embed simplified MCP server
- Add HTTP interface for external connections
- Port all existing MCP tools to use UNO API
- Implement live document manipulation
- Add advanced formatting capabilities
- Create installation packages (.oxt)
- Add real-time collaborative editing
- Implement advanced document analysis
- Create custom UI elements
- Add event-driven automation
- Optimize for various AI assistants
- Add intelligent document suggestions
- Implement context-aware operations
- Create AI-powered document templates
<!-- 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>- Extension Manager: Direct install through LibreOffice
- Command Line:
unopkg add extension.oxt - Automated Deployment: Enterprise distribution
- Online Repository: LibreOffice Extensions marketplace
Redesigning as a LibreOffice plugin would provide:
- 10x Performance Improvement: Direct UNO API access vs subprocess calls
- Rich Feature Set: Access to all LibreOffice capabilities
- Better User Experience: Native integration and real-time updates
- Future-Proof Architecture: Extensible for advanced AI features
- 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.