Skip to main content
Glama
hyunjae-labs

xlwings Excel MCP Server

read_data_from_excel

Extract data from Excel worksheets with cell metadata and validation rules for analysis or processing in corporate environments.

Instructions

Read data from Excel worksheet with cell metadata including validation rules.

Args:
    session_id: Session ID from open_workbook (required)
    sheet_name: Name of worksheet
    start_cell: Starting cell (default A1)
    end_cell: Ending cell (optional, auto-expands if not provided)
    preview_only: Whether to return preview only

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes
sheet_nameYes
start_cellNo
end_cellNo
preview_onlyNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • MCP tool handler for 'read_data_from_excel'. Validates the session, locks it for thread-safety, imports and calls the xlwings implementation function.
    def read_data_from_excel(
        session_id: str,
        sheet_name: str,
        start_cell: Optional[str] = None,
        end_cell: Optional[str] = None,
        preview_only: bool = False
    ) -> str:
        """
        Read data from Excel worksheet with cell metadata including validation rules.
        
        Args:
            session_id: Session ID from open_workbook (required)
            sheet_name: Name of worksheet
            start_cell: Starting cell (default A1)
            end_cell: Ending cell (optional, auto-expands if not provided)
            preview_only: Whether to return preview only
        """
        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.data_xlw import read_data_from_excel_xlw_with_wb
                return read_data_from_excel_xlw_with_wb(session.workbook, sheet_name, start_cell, end_cell, preview_only)
            
        except (ValidationError, DataError) as e:
            return f"Error: {str(e)}"
        except Exception as e:
            logger.error(f"Error reading data: {e}")
            raise
  • Core helper function that performs the actual Excel data reading using xlwings. Handles range expansion, data extraction, and JSON serialization with cell metadata.
    def read_data_from_excel_xlw_with_wb(
        wb,
        sheet_name: str,
        start_cell: str = "A1",
        end_cell: Optional[str] = None,
        preview_only: bool = False
    ) -> str:
        """xlwings 세션 기반 데이터 읽기
        
        Args:
            wb: 워크북 객체 (세션에서 전달)
            sheet_name: 시트명
            start_cell: 시작 셀 (기본값: A1)
            end_cell: 종료 셀 (선택사항, 자동 확장)
            preview_only: 미리보기 모드 (현재 미사용)
            
        Returns:
            JSON 형식의 문자열 - 셀 메타데이터와 함께 구조화된 데이터
        """
        try:
            # 시트 존재 확인
            if sheet_name not in [s.name for s in wb.sheets]:
                return json.dumps({"error": f"Sheet '{sheet_name}' not found"}, indent=2)
            
            ws = wb.sheets[sheet_name]
            
            # Set default start_cell if not provided
            if not start_cell:
                # Find first non-empty cell or default to A1
                used_range = ws.used_range
                if used_range:
                    start_cell = used_range.address.split(":")[0].replace("$", "")
                else:
                    start_cell = "A1"
            
            # 범위 결정
            if end_cell:
                # 명시적 범위 사용
                data_range = ws.range(f"{start_cell}:{end_cell}")
            else:
                # 시작 셀부터 자동 확장
                try:
                    data_range = ws.range(start_cell).expand()
                except Exception:
                    # 빈 시트이거나 단일 셀인 경우
                    data_range = ws.range(start_cell)
            
            # 데이터 읽기
            values = data_range.value
            
            # 결과 구조 생성
            result = {
                "range": str(data_range.address),
                "sheet_name": sheet_name,
                "cells": []
            }
            
            # 셀별 데이터 변환
            if values is None:
                # 단일 빈 셀
                result["cells"].append({
                    "address": data_range.address,
                    "value": None,
                    "row": data_range.row,
                    "column": data_range.column
                })
            elif isinstance(values, list):
                # 다차원 배열
                for i, row in enumerate(values):
                    if isinstance(row, list):
                        for j, val in enumerate(row):
                            cell_range = data_range.offset(i, j).resize(1, 1)
                            result["cells"].append({
                                "address": cell_range.address,
                                "value": val,
                                "row": cell_range.row,
                                "column": cell_range.column
                            })
                    else:
                        # 단일 열의 경우
                        cell_range = data_range.offset(i, 0).resize(1, 1)
                        result["cells"].append({
                            "address": cell_range.address,
                            "value": row,
                            "row": cell_range.row,
                            "column": cell_range.column
                        })
            else:
                # 단일 값
                result["cells"].append({
                    "address": data_range.address,
                    "value": values,
                    "row": data_range.row,
                    "column": data_range.column
                })
            
            return json.dumps(result, indent=2, default=str, ensure_ascii=False)
            
        except Exception as e:
            logger.error(f"xlwings 데이터 읽기 실패: {e}")
            return json.dumps({"error": f"Failed to read data: {str(e)}"}, indent=2)
  • The @mcp.tool() decorator registers this function as an MCP tool named 'read_data_from_excel'.
    def read_data_from_excel(
  • Legacy helper function for reading data without pre-opened workbook (opens Excel app and workbook).
    def read_data_from_excel_xlw(
        filepath: str,
        sheet_name: str,
        start_cell: str = "A1",
        end_cell: Optional[str] = None,
        preview_only: bool = False
    ) -> str:
        """xlwings를 사용한 데이터 읽기
    
        Args:
            filepath: Excel 파일 경로
            sheet_name: 시트명
            start_cell: 시작 셀 (기본값: A1)
            end_cell: 종료 셀 (선택사항, 자동 확장)
            preview_only: 미리보기 모드 (현재 미사용)
    
        Returns:
            JSON 형식의 문자열 - 셀 메타데이터와 함께 구조화된 데이터
        """
        app = None
        wb = None
    
        # Initialize COM for thread safety (Windows)
        _com_initialize()
    
        try:
            # Excel 앱 시작 (백그라운드에서)
            app = xw.App(visible=False, add_book=False)
            
            # 파일 경로 검증
            if not os.path.exists(filepath):
                return json.dumps({"error": f"File not found: {filepath}"}, indent=2)
            
            # 워크북 열기
            wb = app.books.open(filepath)
            
            # 시트 존재 확인
            if sheet_name not in [s.name for s in wb.sheets]:
                return json.dumps({"error": f"Sheet '{sheet_name}' not found"}, indent=2)
            
            ws = wb.sheets[sheet_name]
            
            # Set default start_cell if not provided
            if not start_cell:
                # Find first non-empty cell or default to A1
                used_range = ws.used_range
                if used_range:
                    start_cell = used_range.address.split(":")[0].replace("$", "")
                else:
                    start_cell = "A1"
            
            # 범위 결정
            if end_cell:
                # 명시적 범위 사용
                data_range = ws.range(f"{start_cell}:{end_cell}")
            else:
                # 시작 셀부터 자동 확장
                try:
                    data_range = ws.range(start_cell).expand()
                except Exception:
                    # 빈 시트이거나 단일 셀인 경우
                    data_range = ws.range(start_cell)
            
            # 데이터 읽기
            values = data_range.value
            
            # 결과 구조 생성
            result = {
                "range": str(data_range.address),
                "sheet_name": sheet_name,
                "cells": []
            }
            
            # 셀별 데이터 변환
            if values is None:
                # 단일 빈 셀
                result["cells"].append({
                    "address": data_range.address,
                    "value": None,
                    "row": data_range.row,
                    "column": data_range.column
                })
            elif isinstance(values, list):
                # 다차원 배열
                for i, row in enumerate(values):
                    if isinstance(row, list):
                        for j, val in enumerate(row):
                            cell_range = data_range.offset(i, j).resize(1, 1)
                            result["cells"].append({
                                "address": cell_range.address,
                                "value": val,
                                "row": cell_range.row,
                                "column": cell_range.column
                            })
                    else:
                        # 단일 열의 경우
                        cell_range = data_range.offset(i, 0).resize(1, 1)
                        result["cells"].append({
                            "address": cell_range.address,
                            "value": row,
                            "row": cell_range.row,
                            "column": cell_range.column
                        })
            else:
                # 단일 값
                result["cells"].append({
                    "address": data_range.address,
                    "value": values,
                    "row": data_range.row,
                    "column": data_range.column
                })
            
            return json.dumps(result, indent=2, default=str, ensure_ascii=False)
            
        except Exception as e:
            logger.error(f"xlwings 데이터 읽기 실패: {e}")
            return json.dumps({"error": f"Failed to read data: {str(e)}"}, indent=2)
            
        finally:
            # 리소스 정리
            if wb:
                try:
                    wb.close()
                except Exception as e:
                    logger.warning(f"워크북 닫기 실패: {e}")
            
            if app:
                try:
                    app.quit()
                except Exception as e:
                    logger.warning(f"Excel 앱 종료 실패: {e}")
Behavior2/5

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

With no annotations provided, the description carries full burden but offers minimal behavioral disclosure. It mentions 'cell metadata including validation rules' which adds some context about what data is returned, but doesn't cover important aspects like: whether this is a read-only operation, performance implications for large ranges, error handling, or what 'preview_only' actually means in practice.

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 appropriately sized with a clear purpose statement followed by a structured Args section. Every sentence earns its place, though the purpose statement could be slightly more front-loaded. No wasted words, but the formatting with quotes and line breaks is slightly verbose.

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

Completeness3/5

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

Given the tool's moderate complexity (5 parameters, Excel operations) and the presence of an output schema, the description is adequate but has gaps. It covers parameters well but lacks behavioral context about the read operation's scope, limitations, or relationship to other tools. The output schema existence reduces the need to describe return values, but more operational guidance would help.

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

Parameters4/5

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

With 0% schema description coverage, the description compensates well by explaining all 5 parameters in the Args section. It clarifies that session_id is 'required' and from 'open_workbook', specifies defaults for start_cell and preview_only, and explains end_cell's auto-expansion behavior. This adds significant value beyond the bare schema.

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

Purpose4/5

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

The description clearly states the verb ('Read') and resource ('data from Excel worksheet') with specific scope ('with cell metadata including validation rules'). It distinguishes from siblings like 'write_data_to_excel' by specifying reading vs writing, but doesn't explicitly differentiate from other read-like operations that might exist.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention sibling tools like 'get_workbook_metadata' or 'get_data_validation_info' that might overlap, nor does it specify prerequisites (e.g., requires an open workbook session). Usage context is implied but not explicit.

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

Install Server

Other Tools

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