Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

by hyunjae-labs

get_workbook_metadata

Retrieve workbook structure and content details such as sheets and ranges from Excel files using xlwings Excel MCP Server for data analysis and automation workflows.

Instructions

Get metadata about workbook including sheets, ranges, etc.

Args:
    session_id: Session ID from open_workbook (required)
    include_ranges: Whether to include range information

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes
include_rangesNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Primary MCP handler and registration for the 'get_workbook_metadata' tool. Validates session, locks it, calls the xlwings implementation, serializes result to JSON.
    def get_workbook_metadata(
        session_id: str,
        include_ranges: bool = False
    ) -> str:
        """
        Get metadata about workbook including sheets, ranges, etc.
        
        Args:
            session_id: Session ID from open_workbook (required)
            include_ranges: Whether to include range information
        """
        try:
            # Validate session using centralized helper
            session = get_validated_session(session_id)
            if isinstance(session, str):  # Error message returned
                return session
                
            with session.lock:
                from xlwings_mcp.xlwings_impl.workbook_xlw import get_workbook_metadata_xlw_with_wb
                result = get_workbook_metadata_xlw_with_wb(session.workbook, include_ranges=include_ranges)
            
            if "error" in result:
                return f"Error: {result['error']}"
            import json
            return json.dumps(result, indent=2, default=str, ensure_ascii=False)
                
        except (ValidationError, WorkbookError) as e:
            return f"Error: {str(e)}"
        except Exception as e:
            logger.error(f"Error getting workbook metadata: {e}")
            raise
  • Core helper function implementing workbook metadata extraction using xlwings for session-based workbook objects. Collects sheets, document properties, active sheet, and detailed sheet info if requested.
    def get_workbook_metadata_xlw_with_wb(
        wb,
        include_ranges: bool = False
    ) -> Dict[str, Any]:
        """Session-based version using existing workbook object.
        
        Args:
            wb: Workbook object from session
            include_ranges: 각 시트의 사용 범위 포함 여부
            
        Returns:
            워크북 메타데이터 딕셔너리
        """
        try:
            # 기본 메타데이터 수집
            metadata = {
                "sheets": [sheet.name for sheet in wb.sheets],
                "sheet_count": len(wb.sheets)
            }
            
            # 워크북 속성 추가
            try:
                # COM 객체를 통해 추가 속성 접근 (가능한 경우)
                wb_props = wb.api.BuiltinDocumentProperties
                
                # 작성자 정보
                try:
                    metadata["author"] = wb_props("Author").Value
                except Exception:
                    metadata["author"] = "Unknown"
                
                # 생성 날짜
                try:
                    metadata["created"] = wb_props("Creation Date").Value
                except Exception:
                    metadata["created"] = None
                    
                # 마지막 저장자
                try:
                    metadata["last_saved_by"] = wb_props("Last Save Time").Value
                except Exception:
                    metadata["last_saved_by"] = None
                    
            except Exception as e:
                logger.debug(f"워크북 속성 읽기 부분적 실패: {e}")
            
            # 활성 시트 정보
            if wb.sheets:
                try:
                    # xlwings에서 활성 시트는 첫 번째 시트로 가정
                    metadata["active_sheet"] = wb.sheets[0].name
                except Exception:
                    metadata["active_sheet"] = None
            
            # 시트별 범위 정보 (요청된 경우)
            if include_ranges:
                sheet_info = {}
                for sheet in wb.sheets:
                    try:
                        # 사용된 범위 확인
                        used_range = sheet.used_range
                        if used_range:
                            sheet_info[sheet.name] = {
                                "used_range": str(used_range.address),
                                "rows": used_range.rows.count,
                                "columns": used_range.columns.count,
                                "first_cell": used_range.offset(0, 0).resize(1, 1).address,
                                "last_cell": used_range.offset(
                                    used_range.rows.count - 1,
                                    used_range.columns.count - 1
                                ).resize(1, 1).address
                            }
                        else:
                            # 빈 시트
                            sheet_info[sheet.name] = {
                                "used_range": "Empty",
                                "rows": 0,
                                "columns": 0,
                                "first_cell": "A1",
                                "last_cell": "A1"
                            }
                            
                        # 시트 보호 상태 확인
                        try:
                            sheet_info[sheet.name]["protected"] = sheet.api.ProtectContents
                        except Exception:
                            sheet_info[sheet.name]["protected"] = False
                            
                    except Exception as e:
                        logger.warning(f"시트 '{sheet.name}' 정보 수집 실패: {e}")
                        sheet_info[sheet.name] = {"error": str(e)}
                
                metadata["sheet_info"] = sheet_info
            
            return metadata
        
        except Exception as e:
            logger.error(f"xlwings 워크북 메타데이터 조회 실패: {e}")
            return {"error": f"Failed to get workbook metadata: {str(e)}"}
  • Filepath-based helper function for workbook metadata extraction using xlwings. Opens workbook in context manager, collects metadata. Used in legacy non-session paths.
    def get_workbook_metadata_xlw(
        filepath: str,
        include_ranges: bool = False
    ) -> Dict[str, Any]:
        """xlwings를 사용한 워크북 메타데이터 조회
        
        Args:
            filepath: Excel 파일 경로
            include_ranges: 각 시트의 사용 범위 포함 여부
            
        Returns:
            워크북 메타데이터 딕셔너리
        """
        try:
            # 파일 경로 검증
            file_path = validate_file_path(filepath, must_exist=True)
            
            # Excel context로 워크북 열기
            with excel_context(filepath) as wb:
                # 기본 메타데이터 수집
                metadata = {
                    "filename": file_path.name,
                    "full_path": str(file_path.absolute()),
                    "sheets": [sheet.name for sheet in wb.sheets],
                    "sheet_count": len(wb.sheets),
                    "size": file_path.stat().st_size,
                    "modified": file_path.stat().st_mtime
                }
                
                # 워크북 속성 추가
                try:
                    # COM 객체를 통해 추가 속성 접근 (가능한 경우)
                    wb_props = wb.api.BuiltinDocumentProperties
                    
                    # 작성자 정보
                    try:
                        metadata["author"] = wb_props("Author").Value
                    except Exception:
                        metadata["author"] = "Unknown"
                    
                    # 생성 날짜
                    try:
                        metadata["created"] = wb_props("Creation Date").Value
                    except Exception:
                        metadata["created"] = None
                        
                    # 마지막 저장자
                    try:
                        metadata["last_saved_by"] = wb_props("Last Save Time").Value
                    except Exception:
                        metadata["last_saved_by"] = None
                        
                except Exception as e:
                    logger.debug(f"워크북 속성 읽기 부분적 실패: {e}")
                
                # 활성 시트 정보
                if wb.sheets:
                    try:
                        # xlwings에서 활성 시트는 첫 번째 시트로 가정
                        metadata["active_sheet"] = wb.sheets[0].name
                    except Exception:
                        metadata["active_sheet"] = None
                
                # 시트별 범위 정보 (요청된 경우)
                if include_ranges:
                    sheet_info = {}
                    for sheet in wb.sheets:
                        try:
                            # 사용된 범위 확인
                            used_range = sheet.used_range
                            if used_range:
                                sheet_info[sheet.name] = {
                                    "used_range": str(used_range.address),
                                    "rows": used_range.rows.count,
                                    "columns": used_range.columns.count,
                                    "first_cell": used_range.offset(0, 0).resize(1, 1).address,
                                    "last_cell": used_range.offset(
                                        used_range.rows.count - 1,
                                        used_range.columns.count - 1
                                    ).resize(1, 1).address
                                }
                            else:
                                # 빈 시트
                                sheet_info[sheet.name] = {
                                    "used_range": "Empty",
                                    "rows": 0,
                                    "columns": 0,
                                    "first_cell": "A1",
                                    "last_cell": "A1"
                                }
                                
                            # 시트 보호 상태 확인
                            try:
                                sheet_info[sheet.name]["protected"] = sheet.api.ProtectContents
                            except Exception:
                                sheet_info[sheet.name]["protected"] = False
                                
                        except Exception as e:
                            logger.warning(f"시트 '{sheet.name}' 정보 수집 실패: {e}")
                            sheet_info[sheet.name] = {"error": str(e)}
                    
                    metadata["sheet_info"] = sheet_info
                
                return metadata
            
        except Exception as e:
            logger.error(f"xlwings 워크북 메타데이터 조회 실패: {e}")
            return {"error": f"Failed to get workbook metadata: {str(e)}"}
  • MCP tool registration decorator for get_workbook_metadata.
    def get_workbook_metadata(

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • removedInput schema / properties / filepath
      Removed value: -{
      -  "title": "Filepath",
      -  "type": "string"
      -}
    • addedInput schema / properties / session_id
      Added value: +{
      +  "title": "Session Id",
      +  "type": "string"
      +}
    • changedInput schema / required
      Previous value: -[
      -  "filepath"
      -]New value: +[
      +  "session_id"
      +]
  2. First observed

TDQS

A3.5/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It does not disclose whether the tool is read-only, its side effects (likely none), error behavior, or any prerequisites beyond the session_id. The limited behavioral information is a significant gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very short and uses a clear list for arguments. Every sentence is meaningful, though the structure could be improved by separating the purpose statement from the arguments more formally.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (2 params, no nested objects) and the presence of an output schema (which documents return values), the description is sufficient. It covers the tool's purpose and parameters, leaving details about return structure to the output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must add meaning. It explains session_id as 'Session ID from open_workbook (required)' and include_ranges as 'Whether to include range information', adding context beyond the schema fields. However, it does not specify what range information entails or the format required for session_id.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool gets workbook metadata including sheets and ranges, using specific verb 'Get' and resource 'workbook metadata'. It distinguishes itself from sibling tools (e.g., read_data_from_excel, validate_excel_range) by focusing on overall workbook structure.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by requiring a session_id from open_workbook, but it does not explicitly state when to use this tool versus alternatives, nor does it provide guidance on when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.