XLSX Tools MCP
Un servidor MCP para leer, analizar y editar con precisión libros de Excel (.xlsx) preservando la estructura existente, los estilos, las fórmulas y la integridad de los datos. Admite operaciones de celdas, gestión de hojas y filas/columnas, formato, agregación de datos, recálculo de fórmulas y acceso seguro a archivos concurrente.
Documentación
xlsx-tools-mcp
Un servidor MCP para leer y escribir archivos Excel (.xlsx) con alta precisión, preservando la estructura, los estilos y las fórmulas existentes del archivo.
Descripción general
xlsx-tools-mcp expone 29 herramientas del Protocolo de Contexto de Modelos (MCP) que brindan a un agente LLM acceso preciso de lectura y escritura que preserva la estructura a archivos Excel .xlsx. Se ejecuta como un servidor MCP estándar de stdio: lo instalas y lo registras con un cliente MCP (Claude Code, OpenCode, etc.), y el agente del cliente puede listar hojas, leer rangos de celdas, buscar valores, agregar datos, escribir celdas/fórmulas, gestionar hojas/filas/columnas, aplicar estilos y forzar el recálculo de fórmulas.
Está construido sobre el principio de que editar un libro de trabajo existente no debe destruir lo que no toca.
Características
- Escrituras que preservan la estructura mediante openpyxl — las escrituras cargan el libro de trabajo existente y lo guardan de nuevo, preservando estilos, celdas combinadas, comentarios y cualquier aspecto que la edición no toque.
- Resultados de fórmulas nunca obsoletos mediante recálculo con LibreOffice — openpyxl escribe cadenas de fórmulas pero nunca las evalúa. Después de cada escritura de valor/fórmula, el servidor ejecuta una pasada de LibreOffice sin interfaz para recalcular resultados reales y luego devuelve
errors_found— cualquier valor de error de Excel (#REF!,#DIV/0!,#N/A, …) producido por el recálculo. - Lecturas rápidas mediante python-calamine — un analizador basado en Rust para una inferencia de tipos precisa y rápida, con una alternativa automática de openpyxl cuando necesitas fórmulas/estilos/comentarios o cuando calamine no puede analizar el archivo.
- Agrupación/agregación y consultas basadas en pandas —
aggregate_sheetyquery_sheetrealizan operaciones sin destruir la estructura de origen, equipadas con validación de expresiones AST para bloquear la inyección de código. - Objetos nativos de Excel — crea Tablas formales de Excel (
create_table) con autofiltro y estilos, y gráficos nativos (create_chartpara barras, líneas, circulares, dispersión). - Ciclo de vida y formato de hojas — renombra hojas (
rename_sheet), duplica hojas con estilos intactos (copy_sheet), limpia rangos (clear_range) y ajusta automáticamente los anchos de columna (autofit_columns). - Fiabilidad multiplataforma (Windows, macOS, Linux) — confinamiento de rutas sin distinción de mayúsculas, delimitadores de entorno
;con coma o punto y coma, reemplazo atómico seguro de archivos con reintento de bloqueo transitorio (defensa contraWinError 32/ antivirus) y recálculo silencioso sin parpadeo de ventana. - Bloqueo por archivo — las llamadas de herramientas concurrentes (u otros procesos) que tocan el mismo libro de trabajo se serializan mediante un archivo
<path>.lockhermano (filelock), de modo que las escrituras nunca se intercalan y corrompen el archivo. - Confinamiento de rutas —
XLSX_MCP_ALLOWED_DIRS(separado por comas o punto y coma) restringe todas las lecturas y escrituras a directorios específicos. Si se establece, cualquier intento de acceder a un archivo fuera de estos límites generaAccessDeniedError. Se admiten comparaciones de rutas sin distinción de mayúsculas y rutas de múltiples unidades en Windows. - Copia de seguridad y restauración automáticas — las herramientas de escritura crean automáticamente un archivo
.bakhermano antes de modificar el libro de trabajo sibackup=True(que por defecto esXLSX_MCP_AUTO_BACKUP=true). Usarestore_backuppara revertir cambios de forma atómica. - Protección contra inyección de fórmulas —
write_cellsyappend_rowsrechazan fórmulas que contenganWEBSERVICE,HYPERLINK,INDIRECT,RTD,CALL,REGISTERo comandos DDE (|) por defecto para prevenir la exfiltración de datos o enlaces maliciosos. Pasaallow_external_formulas=Truepara omitir esta verificación. - Protección contra bombas XML — el paquete
defusedxmles una dependencia automática; openpyxl lo detecta y usa su analizador XML endurecido, de modo que el XMLxlsxhostil no puede expandirse hasta agotar los recursos. - Precarga de archivos al inicio — establece
XLSX_MCP_FILESpara precargar uno o más libros de trabajo (separados por comas o punto y coma); las herramientas pueden llamarse entonces conpathomitido o con un alias corto en lugar de una ruta completa del sistema de archivos.
Estadísticas de descargas
En vivo a través de pypistats.org, descargas sin espejos. Estas cuentan eventos de descarga, no usuarios únicos o instalaciones — un usuario puede generar muchas descargas (CI, reinstalaciones, reconstrucciones de Docker, espejos).
Arquitectura
┌──────────────────────── Supervisor (MCP transport, stdio)
│ src/xlsx_tools_mcp/server.py 29 MCP tools + instructions
│ src/xlsx_tools_mcp/settings.py env vars, preloaded files, path resolution
│ src/xlsx_tools_mcp/locking.py per-file <path>.lock serialization
│ src/xlsx_tools_mcp/errors.py domain error types
│ src/xlsx_tools_mcp/recalc.py LibreOffice headless recalc + error scanning
│
├─ Read path
│ src/xlsx_tools_mcp/io/reader.py calamine primary → openpyxl fallback
│ src/xlsx_tools_mcp/io/transform.py pandas aggregation on read results
│
└─ Write path
src/xlsx_tools_mcp/io/writer.py openpyxl → LibreOffice recalc → scan errors
La capa de E/S (io/) está deliberadamente desacoplada del transporte MCP (server.py). Cada herramienta MCP es un envoltorio delgado que resuelve la ruta de destino, toma el bloqueo por archivo y llama a una función de la capa de E/S. Esto mantiene la lógica central independiente de MCP, de modo que puede probarse directamente (ver tests/).
La compensación del recálculo
Después de una escritura que toca valores de celdas o fórmulas, el servidor ejecuta soffice --headless --convert-to xlsx en el archivo para que cada fórmula obtenga un valor calculado real. Este ciclo de ida y vuelta recalcula fórmulas pero re-exporta todo el libro de trabajo — es una compensación, no una garantía de preservación bit a bit. Las características que openpyxl de otro modo preservaría pueden no sobrevivir de forma idéntica: tablas dinámicas, gráficos, validación de datos, algunos formatos y algunos nombres definidos.
Si estás trabajando en un libro de trabajo estructuralmente complejo donde ese riesgo importa, puedes pasar recalculate=False en las herramientas de escritura de valores/fórmulas (write_cells, append_rows, insert_rows, delete_rows, insert_columns, delete_columns) para guardar solo con openpyxl y omitir el ciclo de ida y vuelta por completo.
Requisitos
- Python ≥ 3.10
- LibreOffice — opcional pero recomendado. Solo se necesita para el recálculo de fórmulas. Sin él, las escrituras aún tienen éxito (guardadas mediante openpyxl) pero las fórmulas no se recalculan y se devuelve una advertencia en el campo
message.
Instala LibreOffice:
# macOS
brew install --cask libreoffice
# Debian / Ubuntu
sudo apt-get install -y libreoffice-calc
# Windows
winget install TheDocumentFoundation.LibreOffice
El servidor encuentra LibreOffice verificando soffice / libreoffice en PATH, la ubicación estándar de instalación de macOS (/Applications/LibreOffice.app/Contents/MacOS/soffice) y las rutas estándar de Windows (%ProgramFiles%\LibreOffice\program\soffice.exe, etc.). En Windows, el recálculo sin interfaz se ejecuta silenciosamente sin parpadeo de ventana (CREATE_NO_WINDOW) y con perfiles de usuario aislados.
Instalación
El servidor habla transporte stdio (MCP estándar): después de la instalación espera a que un cliente MCP se conecte y llame a las herramientas. Normalmente no lo ejecutas tú mismo; lo registras con un cliente.
1. Desde PyPI mediante uvx (recomendado — sin clonar)
uvx xlsx-tools-mcp
uvx obtiene y ejecuta el paquete publicado sin contaminar tu proyecto. Esta es la forma más sencilla de activar un cliente MCP (ver fragmentos de configuración a continuación).
2. Desde el código fuente
git clone https://github.com/ruriazz/xlsx-tools-mcp.git
cd xlsx-tools-mcp
uv sync
# run the server (useful for local dev / debugging):
uv run xlsx-tools-mcp
3. Mediante pip
pip install xlsx-tools-mcp
Esto instala el punto de entrada de consola, de modo que puedes ejecutar el servidor directamente:
xlsx-tools-mcp
Configuración para clientes MCP
El registro más simple para cada cliente usa uvx xlsx-tools-mcp (sin clonar, siempre la versión publicada).
Consejo para Windows: En los archivos de configuración JSON del cliente (
.mcp.json,opencode.json), usa barras diagonales (p. ej.,"C:/path/to/data.xlsx") o barras invertidas escapadas (p. ej.,"C:\\\\path\\\\to\\\\data.xlsx") para evitar errores de secuencias de escape JSON.
Claude Code
claude mcp add xlsx-tools-mcp -- uvx xlsx-tools-mcp
O mediante .mcp.json en tu proyecto:
{
"mcpServers": {
"xlsx-tools-mcp": { "command": "uvx", "args": ["xlsx-tools-mcp"] }
}
}
OpenCode
En opencode.json (proyecto) o ~/.config/opencode/opencode.json (global):
{
"mcp": {
"xlsx-tools-mcp": { "type": "local", "command": ["uvx", "xlsx-tools-mcp"], "enabled": true }
}
}
Cuando se ejecuta desde un clon del código fuente
Si clonaste el repositorio en lugar de instalarlo desde PyPI, apunta el cliente a tu copia local intercambiando uvx xlsx-tools-mcp por la forma dinámica uv run (usa la ruta absoluta al clon):
Claude Code .mcp.json:
{
"mcpServers": {
"xlsx-tools-mcp": {
"command": "uv",
"args": ["--directory", "/absolute/path/to/xlsx-reader", "run", "xlsx-tools-mcp"]
}
}
}
OpenCode:
{
"mcp": {
"xlsx-tools-mcp": {
"type": "local",
"command": ["uv", "--directory", "/absolute/path/to/xlsx-reader", "run", "xlsx-tools-mcp"],
"enabled": true
}
}
}
Reemplaza /absolute/path/to/xlsx-reader con la ubicación real de tu clon.
Precarga de archivos (XLSX_MCP_FILES)
Establece la variable de entorno XLSX_MCP_FILES en la sección env de la configuración del servidor MCP (no en tu shell interactivo — el servidor lo lanza el cliente) para precargar libros de trabajo al inicio. Formato: entradas alias=absolute/path separadas por comas o punto y coma, o rutas absolutas simples:
XLSX_MCP_FILES=name=/abs/path/to/name.xlsx,report=/data/report.xlsx
Las rutas simples obtienen un alias que por defecto es el nombre del archivo:
XLSX_MCP_FILES=/abs/path/to/sales.xlsx
Con alias/filename como alias:
- Un archivo configurado → cada herramienta puede llamarse con
pathomitido por completo. - Múltiples archivos configurados → pasa el alias (o nombre de archivo) como
path. list_configured_files()devuelve el mapeo alias → ruta absoluta.- Las rutas absolutas y relativas sin procesar aún funcionan para archivos que no precargaste.
Claude Code — .mcp.json con precarga:
{
"mcpServers": {
"xlsx-tools-mcp": {
"command": "uvx",
"args": ["xlsx-tools-mcp"],
"env": {
"XLSX_MCP_FILES": "report=/data/report.xlsx,sales=/data/sales.xlsx"
}
}
}
}
OpenCode con precarga:
{
"mcp": {
"xlsx-tools-mcp": {
"type": "local",
"command": ["uvx", "xlsx-tools-mcp"],
"env": { "XLSX_MCP_FILES": "report=/data/report.xlsx,sales=/data/sales.xlsx" },
"enabled": true
}
}
}
Referencia de herramientas
Las 29 herramientas. Salvo que se indique, path acepta una ruta del sistema de archivos, un alias/nombre de archivo precargado, o puede omitirse cuando exactamente un archivo está precargado. create_workbook es la excepción — su path es obligatorio porque un archivo nuevo nunca está precargado.
Forma de respuesta (todas las herramientas de escritura): cada herramienta de escritura devuelve
{"saved": bool, "recalculated": bool, "errors_found": list, "message": str}. Cuando no está vacío,errors_foundes una lista de{"sheet": "...", "cell": "B2", "error": "#DIV/0!"}.
Inspeccionar / Leer
| Herramienta | Descripción |
|---|---|
list_configured_files() | Lista los archivos precargados al inicio mediante XLSX_MCP_FILES, como un mapa alias → ruta absoluta. Llama a esto primero si no estás seguro de qué está disponible. |
list_sheets(path?) | Lista cada hoja del libro de trabajo con recuentos aproximados de filas/columnas (calamine). |
get_workbook_info(path?) | Metadatos a nivel de libro de trabajo: dimensiones exactas por hoja, max_row/max_column, estado de la hoja, la hoja activa y nombres definidos. |
read_sheet(sheet, cell_range?, max_rows?, offset_row?, format?, path?) | Lee valores de celdas. cell_range limita el área de lectura. max_rows limita las filas. offset_row omite un número de filas para paginación. format puede ser "array" (lista 2D), "records" (lista de diccionarios usando la primera fila como claves) o "markdown" (cadena de tabla). |
get_cell(sheet, cell, path?) | Detalle completo de una sola celda: valor (calculado en caché), fórmula, formato de número, fuente (negrita/cursiva/tamaño/color), color de relleno, estado de combinación, comentario. |
search_workbook(query, sheet?, match_case?, limit?, path?) | Búsqueda de subcadenas en una o todas las hojas. sheet restringe a una hoja; match_case=True la hace sensible a mayúsculas; limit limita las coincidencias. Devuelve {"sheet", "cell", "value"}. |
aggregate_sheet(sheet, group_by, agg, cell_range?, has_header?, path?) | Agrupa y agrega con pandas. group_by es una lista de nombres de columnas (tomados de la fila de encabezado); agg mapea nombre de columna → función de agregación, p. ej., {"amount": "sum"}. has_header=True (por defecto) lee los nombres de columna de la primera fila. Devuelve {columns, records, row_count}. |
profile_sheet(sheet, sample_rows?, path?) | Perfila metadatos de la hoja: tipos inferidos, recuentos de nulos, mín/máx, valores de muestra. |
query_sheet(sheet, filter_query, columns?, max_rows?, cell_range?, path?) | Filtra datos de la hoja usando expresiones pandas con defensa de inyección de código endurecida por AST. |
Escritura
| Herramienta | Descripción |
|---|---|
create_workbook(path, sheets?, overwrite?) | Crear un nuevo libro de trabajo .xlsx/.xlsm. sheets por defecto es ["Sheet1"]. overwrite=True reemplaza un archivo existente. path es obligatorio (los archivos nuevos nunca se precargan). |
write_cells(sheet, cells, create_sheet_if_missing?, recalculate?, allow_external_formulas?, backup?, path?) | Escribir valores y/o fórmulas en celdas específicas. cells es una lista de {"cell": "A1", "value": ...} o {"cell": "B1", "formula": "=A1*2"}. Opcionalmente, crea la hoja primero; recalculate=True (por defecto) ejecuta el recálculo de LibreOffice. |
append_rows(sheet, rows, create_sheet_if_missing?, recalculate?, allow_external_formulas?, backup?, path?) | Añadir filas después de la última fila utilizada. rows es una lista de filas, cada una con una lista de valores de celda en orden de columna. |
create_sheet(sheet, index?, path?) | Añadir una nueva hoja vacía. index es una posición de inserción basada en cero; omítelo para añadir al final. |
delete_sheet(sheet, path?) | Eliminar una hoja. Falla si es la única hoja restante. |
rename_sheet(old_name, new_name, path?) | Renombrar una hoja existente. |
copy_sheet(source_sheet, target_sheet, path?) | Duplicar una hoja incluyendo su contenido, fórmulas y estilos. |
insert_rows(sheet, start_row, count?, recalculate?, path?) | Insertar filas en blanco antes de start_row (basado en 1), desplazando las filas existentes hacia abajo. count por defecto es 1. |
delete_rows(sheet, start_row, count?, recalculate?, path?) | Eliminar filas comenzando en start_row (basado en 1), desplazando las filas inferiores hacia arriba. count por defecto es 1. |
insert_columns(sheet, start_column, count?, recalculate?, path?) | Insertar columnas en blanco antes de start_column (basado en 1), desplazando las columnas existentes hacia la derecha. count por defecto es 1. |
delete_columns(sheet, start_column, count?, recalculate?, path?) | Eliminar columnas comenzando en start_column (basado en 1), desplazando las columnas a la derecha hacia la izquierda. count por defecto es 1. |
merge_cells(sheet, cell_range, path?) | Fusionar un rango rectangular (p. ej., "A1:C1") en una sola celda. |
unmerge_cells(sheet, cell_range, path?) | Deshacer una fusión en un rango previamente fusionado. |
set_cell_style(sheet, cell_range, style, path?) | Aplicar formato a un rango (p. ej., "A1:D1"). Claves de style: bold, italic, font_size, font_color (RGB hexadecimal, p. ej., "FF0000"), bg_color (RGB hexadecimal), horizontal, vertical (alineación), border ("thin", "medium", "thick", …), number_format (p. ej., "#,##0.00"). |
autofit_columns(sheet, min_width?, max_width?, padding?, path?) | Ajustar automáticamente los anchos de columna según la longitud máxima del texto para evitar recortes. |
clear_range(sheet, cell_range, clear_values?, clear_styles?, path?) | Limpiar valores de celda y/o estilos dentro de un rango especificado sin eliminar filas ni columnas. |
create_table(sheet, cell_range, table_name, style_name?, show_filter?, show_row_stripes?, path?) | Crear una tabla formal de Excel sobre un rango. |
create_chart(sheet, chart_type, data_range, categories_range?, title?, target_cell?, path?) | Añadir un gráfico nativo de Excel (barras, líneas, circular, dispersión). |
recalculate_workbook(path?) | Forzar un pase de recálculo sin interfaz de LibreOffice e informar cualquier error de fórmula encontrado. |
restore_backup(backup_path, target_path) | Restaurar un archivo de respaldo .bak sobre un libro de trabajo objetivo de forma atómica. |
Ejemplo de carga útil — write_cells
Una llamada que escribe una fórmula y un valor:
{
"sheet": "Sheet1",
"cells": [
{ "cell": "A1", "value": 100 },
{ "cell": "B1", "formula": "=A1*2" }
],
"recalculate": true,
"path": "/data/budget.xlsx"
}
Respuesta correspondiente:
{
"saved": true,
"recalculated": true,
"errors_found": [],
"message": "Recalculated with LibreOffice headless."
}
Si una fórmula afectada produjo un error, errors_found se vería así:
{
"saved": true,
"recalculated": true,
"errors_found": [
{ "sheet": "Sheet1", "cell": "C5", "error": "#DIV/0!" }
],
"message": "Recalculated with LibreOffice headless."
}
Ejemplo de carga útil — query_sheet
{
"sheet": "Sales",
"filter_query": "Revenue > 500 and Status == 'PAID'",
"columns": ["Customer", "Revenue"],
"max_rows": 10
}
Ejemplo de carga útil — create_table y create_chart
{
"sheet": "Summary",
"cell_range": "A1:D10",
"table_name": "SalesTable",
"style_name": "TableStyleMedium9"
}
{
"sheet": "Summary",
"chart_type": "bar",
"data_range": "B1:B10",
"categories_range": "A2:A10",
"title": "Monthly Revenue",
"target_cell": "F2"
}
Variables de entorno
| Variable | Predeterminado | Descripción |
|---|---|---|
XLSX_MCP_FILES | vacío | Lista separada por comas o punto y coma de alias=path o path para precargar al inicio. |
XLSX_MCP_ALLOWED_DIRS | vacío | Directorios separados por comas o punto y coma para limitar el acceso a archivos (las rutas fuera generan AccessDeniedError). Admite distinción de mayúsculas y minúsculas en Windows. |
XLSX_MCP_AUTO_BACKUP | true | Crear automáticamente una copia .bak antes de modificar un libro de trabajo. |
XLSX_MCP_BACKUP_DIR | vacío | Directorio personalizado para archivos de respaldo (por defecto, junto al archivo objetivo). |
XLSX_MCP_RECALC_TIMEOUT | 60 | Tiempo de espera en segundos para el recálculo de fórmulas de LibreOffice sin interfaz. |
XLSX_MCP_LOCK_TIMEOUT | 10 | Tiempo de espera en segundos para adquirir el bloqueo por archivo antes de fallar. |
Seguridad y concurrencia
- Limitación de rutas —
XLSX_MCP_ALLOWED_DIRS(separado por comas o punto y coma) restringe todas las lecturas y escrituras a directorios específicos. Si se establece, cualquier intento de acceder a un archivo fuera de estos límites generaAccessDeniedError. Se admiten comparaciones de rutas sin distinción de mayúsculas y minúsculas y rutas de múltiples unidades en Windows. - Respaldo automático y restauración — Las herramientas de escritura crearán automáticamente un archivo hermano
.bakantes de modificar el libro de trabajo sibackup=True(que por defecto esXLSX_MCP_AUTO_BACKUP=true). UsaXLSX_MCP_BACKUP_DIRpara guardar respaldos en una carpeta específica. Usarestore_backuppara revertir cambios de forma atómica. - Protección contra inyección de fórmulas —
write_cellsyappend_rowsrechazan fórmulas que contenganWEBSERVICE,HYPERLINK,INDIRECT,RTD,CALL,REGISTERo comandos DDE (|) por defecto para prevenir la exfiltración de datos o la ejecución de comandos. Pasaallow_external_formulas=Truepara omitir esta verificación. - Validación segura de consultas AST —
query_sheetusa un analizador AST para permitir estrictamente solo comparaciones, lógica booleana y operadores seguros, bloqueando búsquedas de variables@, llamadas de ejecución de código y atributos dunder privados. - Protección contra bombas XML —
defusedxmles una dependencia automática de este paquete. openpyxl lo detecta automáticamente y usa su analizador XML endurecido, por lo que un.xlsxmalicioso (un zip de XML) no puede provocar agotamiento de recursos por expansión de entidades. No se necesita configuración. - Bloqueo por archivo — cada lectura/escritura adquiere un archivo hermano
<path>.lock(a través defilelock). Las llamadas de herramientas concurrentes u otros procesos que toquen el mismo libro de trabajo se serializan para que las escrituras nunca se intercalen y corrompan el archivo. - Resiliencia ante bloqueos transitorios — en Windows NTFS, los intercambios atómicos de archivos pueden encontrar temporalmente violaciones de uso compartido (
WinError 32/33) mientras los escáneres antivirus o indexadores de búsqueda inspeccionan archivos recién guardados. El servidor realiza un reintento con retroceso exponencial para tener éxito de forma transparente una vez liberado, o proporciona un mensaje de orientación claro si el archivo está abierto permanentemente en Microsoft Excel. - Tiempo de espera de recálculo —
XLSX_MCP_RECALC_TIMEOUT(segundos, por defecto60) limita cuánto tiempo puede ejecutarse el pase de recálculo de LibreOffice. - Tiempo de espera de bloqueo —
XLSX_MCP_LOCK_TIMEOUT(segundos, por defecto10) limita cuánto tiempo esperará una herramienta para adquirir el bloqueo por archivo antes de fallar.
Solución de problemas
errors_foundestá vacío aunque mi fórmula está rota — probablemente el recálculo no se ejecutó. Verifica el campomessage: si dice que no se encontró LibreOffice, el archivo se guardó a través de openpyxl tal cual y las fórmulas no se recalcularon (los valores en caché pueden estar desactualizados). Instala LibreOffice (consulta Requisitos).- El recálculo es lento o agota el tiempo — aumenta
XLSX_MCP_RECALC_TIMEOUT(por defecto 60s). En caso de tiempo de espera agotado, el archivo aún se guarda, perorecalculatedseráfalseymessageindica que el recálculo agotó el tiempo. LockTimeoutErroren acceso concurrente — otra operación mantiene el bloqueo. AumentaXLSX_MCP_LOCK_TIMEOUT(por defecto 10s), o reintenta cuando la otra operación termine.Workbook is locked by another process/WinError 32— en Windows, Microsoft Excel y algunas aplicaciones bloquean archivos abiertos de forma exclusiva. Cierra el libro de trabajo en Excel y reintenta. Los bloqueos transitorios de escáneres antivirus o indexadores de búsqueda se reintentan automáticamente por el servidor antes de fallar.- "Hoja no encontrada" — el mensaje de error lista los nombres de hojas disponibles, para que puedas elegir la correcta.
pathrequerido / no hay archivo configurado — llamaste a una herramienta sinpathpero no hay (o hay múltiples) archivos precargados. Precarga un archivo a través deXLSX_MCP_FILES, pasa un alias explícito o pasa una ruta directa.
Desarrollo / Contribución
Consulta CONTRIBUTING.md. Ejecuta la suite de pruebas con:
uv run pytest