Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

by hyunjae-labs

close_workbook

Closes an Excel workbook session in xlwings Excel MCP Server, optionally saving changes before termination to ensure data integrity.

Instructions

Close a workbook session.

Args:
    session_id: Session ID from open_workbook
    save: Whether to save changes (default: True)
    
Returns:
    Success message

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes
saveNo

Implementation Reference

  • MCP tool handler for 'close_workbook'. Calls SESSION_MANAGER.close_workbook and handles errors.
    @mcp.tool()
    def close_workbook(
        session_id: str,
        save: bool = True
    ) -> str:
        """
        Close a workbook session.
        
        Args:
            session_id: Session ID from open_workbook
            save: Whether to save changes (default: True)
            
        Returns:
            Success message
        """
        try:
            success = SESSION_MANAGER.close_workbook(session_id, save)
            if not success:
                raise WorkbookError(f"Session {session_id} not found")
            
            return f"Workbook session {session_id} closed successfully"
            
        except Exception as e:
            logger.error(f"Error closing workbook: {e}")
            raise WorkbookError(f"Failed to close workbook: {str(e)}")
  • Core implementation of closing workbook session in ExcelSessionManager. Handles cleanup, saving, and session removal.
    def close_workbook(self, session_id: str, save: bool = True) -> bool:
        """Close a workbook and remove session"""
        # Ensure COM is initialized for this thread
        _com_initialize()
    
        with self._sessions_lock:
            # Handle redirect mapping if exists
            actual_session_id = self._session_redirects.get(session_id, session_id)
            
            session = self._sessions.get(actual_session_id)
            if not session:
                logger.warning(f"Cannot close: session {session_id} not found")
                return False
            
            try:
                with session.lock:
                    logger.debug(f"Closing session {session_id} (actual: {actual_session_id})")
                    
                    # Save and close workbook
                    if session.workbook:
                        if save and not session.read_only:
                            session.workbook.save()
                        session.workbook.close()
                    
                    # Quit Excel app
                    if session.app:
                        session.app.quit()
                    
                    # Remove from sessions
                    del self._sessions[actual_session_id]
                    
                    # Clean up auto-recovery related data
                    if session_id in self._expired_sessions:
                        del self._expired_sessions[session_id]
                    
                    # Clean up redirect mappings
                    redirect_keys_to_remove = []
                    for k, v in self._session_redirects.items():
                        if k == session_id or v == actual_session_id:
                            redirect_keys_to_remove.append(k)
                    
                    for key in redirect_keys_to_remove:
                        del self._session_redirects[key]
                    
                    logger.info(f"Session {session_id} closed permanently (remaining sessions: {len(self._sessions)})")
                    return True
                    
            except Exception as e:
                logger.error(f"Error closing session {session_id}: {e}")
                # Force remove from sessions even on error
                if actual_session_id in self._sessions:
                    del self._sessions[actual_session_id]
                    
                # Clean up recovery data on error too
                if session_id in self._expired_sessions:
                    del self._expired_sessions[session_id]
                if session_id in self._session_redirects:
                    del self._session_redirects[session_id]
                    
                return False
  • Helper function for force closing workbook by path, used in error handling.
    def force_close_workbook_by_path(filepath: str) -> Dict[str, Any]:
        """
        Force close a specific workbook from any running Excel process.
        
        Args:
            filepath: Absolute path to the workbook to close
            
        Returns:
            Dictionary with 'closed' (bool) and 'message' (str)
        """
        
        if not PYWIN32_AVAILABLE:
            return {
                "closed": False,
                "message": "Force close not available (pywin32 not installed or not on Windows)"
            }
        
        # Normalize the file path
        target_path = os.path.abspath(filepath).lower()
        
        try:
            # Initialize COM for this thread
            pythoncom.CoInitialize()
            
            found = False
            closed = False
            
            try:
                # Try to connect to running Excel instance
                xl = win32com.client.GetObject(Class="Excel.Application")
                
                # Check all open workbooks
                for wb in xl.Workbooks:
                    try:
                        # Compare full paths (case-insensitive on Windows)
                        wb_path = os.path.abspath(wb.FullName).lower()
                        
                        if wb_path == target_path:
                            logger.info(f"Found workbook to force close: {wb.FullName}")
                            found = True
                            
                            # Force close without saving
                            wb.Close(SaveChanges=False)
                            closed = True
                            logger.info(f"Successfully force closed: {filepath}")
                            break
                            
                    except Exception as e:
                        logger.warning(f"Error checking/closing workbook: {e}")
                        continue
                
                # If no workbooks remain, optionally quit Excel
                if closed and xl.Workbooks.Count == 0:
                    try:
                        xl.Quit()
                        logger.info("Excel application quit (no remaining workbooks)")
                    except:
                        pass
                        
            except Exception as e:
                # No Excel instance running or other COM error
                logger.debug(f"Could not connect to Excel: {e}")
                return {
                    "closed": False,
                    "message": f"No Excel instance found or cannot connect: {str(e)}"
                }
            
            finally:
                # Uninitialize COM
                pythoncom.CoUninitialize()
            
            if not found:
                return {
                    "closed": False,
                    "message": f"Workbook not found in any Excel instance: {filepath}"
                }
            
            return {
                "closed": closed,
                "message": f"Successfully force closed workbook: {filepath}"
            }
            
        except Exception as e:
            logger.error(f"Force close failed for {filepath}: {e}")
            return {
                "closed": False,
                "message": f"Force close failed: {str(e)}"
            }
  • The @mcp.tool() decorator registers this function as the MCP tool named 'close_workbook'.
    @mcp.tool()
    def close_workbook(
        session_id: str,
        save: bool = True
    ) -> str:
        """
        Close a workbook session.
        
        Args:
            session_id: Session ID from open_workbook
            save: Whether to save changes (default: True)
            
        Returns:
            Success message
        """
        try:
            success = SESSION_MANAGER.close_workbook(session_id, save)
            if not success:
                raise WorkbookError(f"Session {session_id} not found")
            
            return f"Workbook session {session_id} closed successfully"
            
        except Exception as e:
            logger.error(f"Error closing workbook: {e}")
            raise WorkbookError(f"Failed to close workbook: {str(e)}")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hyunjae-labs/xlwings-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server