stella-mcp

Servidor MCP para crear y manipular modelos de dinámica de sistemas Stella (archivos .stmx en formato XMILE)

Documentación

Servidor Stella MCP

Un servidor Model Context Protocol (MCP) neutral respecto al proveedor para crear y manipular modelos de dinámica de sistemas Stella. Cualquier cliente MCP compatible puede construir, leer, validar y guardar archivos .stmx en formato XMILE; las características opcionales del host aún varían.

¿Para qué sirve esto?

Stella es una herramienta de modelado de dinámica de sistemas utilizada para simular sistemas complejos en campos como ecología, biogeoquímica, economía e ingeniería. Este servidor MCP permite a los asistentes de IA:

  • Crear modelos desde cero - Construir diagramas de stock-y-flujo programáticamente
  • Leer modelos existentes - Analizar y comprender archivos .stmx
  • Validar modelos - Verificar errores como variables indefinidas o conexiones faltantes
  • Modificar modelos - Agregar stocks, flujos, auxiliares y conectores
  • Guardar modelos - Exportar archivos XMILE válidos que se abren en Stella Professional

Esto es particularmente útil para:

  • Enseñar modelado de dinámica de sistemas
  • Prototipado rápido de modelos mediante lenguaje natural
  • Creación o modificación por lotes de modelos
  • Documentar y explicar modelos existentes

Instalación

Desde PyPI

pip install stella-mcp

Desde el código fuente

git clone https://github.com/bradleylab/stella-mcp.git
cd stella-mcp
pip install -e .

Requisitos

  • Python 3.10+
  • mcp>=2.0.0,<3

Configuración

Mediante uvx (sin instalación requerida)

Si tiene uv instalado, la configuración de menor fricción ejecuta el paquete publicado directamente:

{
  "mcpServers": {
    "stella": {
      "command": "uvx",
      "args": ["stella-mcp"]
    }
  }
}

Claude Desktop

Agregue a su claude_desktop_config.json:

{
  "mcpServers": {
    "stella": {
      "command": "stella-mcp"
    }
  }
}

Claude Code

Agregue a su .claude/settings.json:

{
  "mcpServers": {
    "stella": {
      "command": "stella-mcp"
    }
  }
}

Modo de desarrollo

Si se ejecuta desde el código fuente:

{
  "mcpServers": {
    "stella": {
      "command": "python",
      "args": ["-m", "stella_mcp.server"],
      "cwd": "/path/to/stella-mcp"
    }
  }
}

Flujo de trabajo recomendado para agentes

Para un modelo nuevo:

  1. En MCP 2026-07-28, llame a create_workspace y conserve el workspace_id devuelto a través de llamadas con estado. Los clientes stdio heredados pueden omitirlo.
  2. build_model con un model_id estable y el conjunto completo de stocks, auxiliares y flujos en una sola llamada (la sincronización de conectores y la validación se ejecutan por defecto, por lo que la respuesta sirve también como inspección).
  3. Corrija errores de validación con update_*, rename_variable o delete_variable.
  4. Extienda incrementalmente con add_variables (por lotes) o las herramientas de adición individual.
  5. simulate para verificar el comportamiento (requiere el extra sim).
  6. Guarde con save_model.

Para modelos importados:

  1. read_model con compat_mode="permissive" para inspeccionar advertencias.
  2. Ejecute inspect_model para comprender la estructura del modelo.
  3. Use compat_mode="strict" antes del guardado final cuando la fidelidad de ida y vuelta sea importante.

Herramientas disponibles

Creación de modelos y E/S

HerramientaDescripción
create_modelCrear un nuevo modelo con nombre y configuración de tiempo (inicio, fin, dt, método)
set_sim_specsActualizar la configuración de tiempo de simulación en un modelo existente
read_modelCargar un archivo .stmx existente
save_modelGuardar el modelo en un archivo .stmx
delete_modelEliminar un modelo del espacio de trabajo (los archivos guardados no se modifican)

Plantillas

HerramientaDescripción
list_templatesListar plantillas integradas y definidas por el usuario (admite filtros de fuente/consulta/etiqueta)
get_template_infoObtener metadatos detallados de una plantilla
load_templateCargar una plantilla como modelo en el espacio de trabajo actual
save_as_templateGuardar el modelo actual como plantilla de usuario reutilizable (descripción/etiquetas opcionales)

Construcción de modelos

HerramientaDescripción
build_modelCrear y poblar un modelo en una sola llamada (lote atómico)
add_variablesAgregar múltiples variables/conectores/módulos a un modelo existente (lote atómico)
add_stockAgregar un stock (reservorio) con valor inicial y unidades
add_flowAgregar un flujo entre stocks con una ecuación
add_auxAgregar una variable auxiliar (parámetro o cálculo)
update_stockActualizar campos de stock preservando relaciones
update_flowActualizar campos de flujo preservando enlaces de stock
update_auxActualizar campos de variable auxiliar
add_connectorAgregar un conector de dependencia entre variables
sync_connectors_from_equationsAgregar conectores de dependencia faltantes inferidos de ecuaciones
set_connector_routingEstablecer ángulo de conector y metadatos explícitos de enrutamiento de puntos de paso
rename_variableRenombrar un stock/flujo/auxiliar y actualizar referencias en ecuaciones/conectores/módulos
delete_variableEliminar un stock/flujo/auxiliar con verificaciones de consistencia y limpieza
create_moduleCrear un módulo/grupo lógico de variables
add_to_moduleAgregar variables a un módulo/grupo existente
remove_from_moduleEliminar variables de un módulo/grupo
rename_moduleRenombrar un módulo/grupo
delete_moduleEliminar un módulo/grupo
set_module_viewEstablecer posición/tamaño explícito del cuadro del módulo en el diagrama
set_module_styleEstablecer estilo del cuadro del módulo (borde/fondo/fuente/lado de etiqueta) en el diagrama
auto_place_module_boxesColocar automáticamente los cuadros de módulos alrededor de sus miembros

Notas:

  • Los clientes MCP 2026-07-28 llaman a create_workspace una vez e incluyen su workspace_id devuelto en llamadas con estado. El descubrimiento moderno de herramientas marca ese campo como requerido en herramientas con estado. El ID enruta el estado de la aplicación; no es una credencial de autorización.
  • Los clientes stdio heredados compatibles pueden omitir workspace_id y usar un espacio de trabajo de compatibilidad local al proceso; el descubrimiento heredado mantiene el campo opcional.
  • Las herramientas aceptan model_id opcional para que un espacio de trabajo pueda gestionar múltiples modelos de forma segura.
  • create_model y read_model establecen el model_id actual del espacio de trabajo y lo devuelven.
  • add_flow y add_aux admiten cargas útiles graphical_function opcionales (ypts más exactamente uno de xscale o xpts).
  • add_stock/add_flow/add_aux rechazan nombres de variables duplicados entre tipos de variables; add_connector requiere que ambas variables existan.
  • set_connector_routing puede apuntar a un conector por connector_uid o por from_var + to_var.
  • save_model y get_model_xml aceptan auto_layout (por defecto true) y resolve_layout_violations (por defecto false).
  • save_model, get_model_xml y render_diagram devuelven la vista de diseño más reciente, métricas y advertencias en contenido estructurado. Sus resultados de texto nombran cualquier código de advertencia de diseño no limpio.
  • read_model, save_model y get_model_xml aceptan compat_mode:
    • permissive (por defecto): continuar con advertencias
    • strict: fallar en problemas de compatibilidad
  • set_module_style actualiza el estilo de vista del módulo y persiste esos atributos en elementos <group .../> de vista XMILE.
  • save_as_template escribe plantillas de usuario en ~/.stella-mcp/templates por defecto (anulable mediante STELLA_MCP_TEMPLATE_DIR) y almacena metadatos en un archivo secundario .meta.json.
  • Las fallas de herramientas devuelven errores MCP estructurados con error.code, error.category y error.message.
  • Cada resultado exitoso de herramienta conserva texto legible y proporciona structuredContent validado por esquema descrito por su outputSchema JSON Schema 2020-12.

Ciclo de vida del espacio de trabajo

HerramientaDescripción
create_workspaceCrear un espacio de trabajo aislado, opcionalmente con una vida útil seleccionada por el llamador
revoke_workspaceRevocar un espacio de trabajo y descartar sus modelos en memoria

Inspección de modelos

HerramientaDescripción
list_modelsListar IDs de modelos disponibles en el espacio de trabajo e indicar el modelo actual
inspect_modelDevolver un resumen estructurado del modelo para inspección del agente
list_modulesListar módulos/grupos en el modelo actual
list_connectorsListar IDs de conectores, extremos, ángulos y metadatos de enrutamiento
list_variablesListar todos los stocks, flujos y auxiliares
validate_modelVerificar errores (variables indefinidas, conexiones faltantes, etc.)
get_model_xmlPrevisualizar la salida XML XMILE
render_diagramRenderizar el modelo como diagrama SVG de stock-y-flujo
simulateEjecutar el modelo mediante PySD y devolver series temporales + resúmenes (extra sim)
compare_scenariosEjecutar conjuntos de sobrescritura "qué pasaría si" con nombre contra una línea base e informar deltas (extra sim)
sensitivity_analysisBarrer parámetros uno a la vez y clasificar su efecto en una métrica de salida (extra sim)
calibrateAjustar parámetros constantes a una serie temporal observada (inverso de simular) (extra sim)

Construcción por lotes

build_model crea y puebla un modelo en una sola llamada. Los elementos se aplican en el orden stocks → auxiliares → flujos → conectores → módulos; todo el lote es todo-o-nada, y en caso de fallo el error nombra el elemento fallido (error.stage + error.index). Los mismos arreglos de elementos funcionan en un modelo existente mediante add_variables.

{
  "name": "build_model",
  "arguments": {
    "name": "SIR",
    "model_id": "sir",
    "sim_specs": {"start": 0, "stop": 100, "dt": 0.125, "time_units": "Days"},
    "stocks": [
      {"name": "Susceptible", "initial_value": "9999", "units": "people"},
      {"name": "Infected", "initial_value": "1", "units": "people"},
      {"name": "Recovered", "initial_value": "0", "units": "people"}
    ],
    "auxs": [
      {"name": "contact_rate", "equation": "6"},
      {"name": "infectivity", "equation": "0.25"},
      {"name": "recovery_time", "equation": "2", "units": "days"},
      {"name": "total_population", "equation": "Susceptible + Infected + Recovered"}
    ],
    "flows": [
      {"name": "infection", "equation": "Susceptible * contact_rate * infectivity * Infected / total_population", "from_stock": "Susceptible", "to_stock": "Infected"},
      {"name": "recovery", "equation": "Infected / recovery_time", "from_stock": "Infected", "to_stock": "Recovered"}
    ],
    "modules": [
      {"name": "Disease Dynamics", "members": ["Susceptible", "Infected", "Recovered"]}
    ]
  }
}

La sincronización de conectores y la validación se ejecutan por defecto (deshabilitables con "sync_connectors": false / "validate": false); la respuesta incluye el resumen estructurado completo del modelo, por lo que no se necesita una llamada de seguimiento inspect_model.

Ejemplos de cargas útiles de herramientas

Crear y cambiar entre modelos de espacio de trabajo:

{"name":"create_model","arguments":{"name":"Population","model_id":"pop_v1"}}
{"name":"create_model","arguments":{"name":"Carbon","model_id":"carbon_v1"}}
{"name":"list_models","arguments":{}}
{"name":"delete_model","arguments":{"model_id":"pop_v1"}}
{"name":"inspect_model","arguments":{"model_id":"sir_baseline","include_validation":true}}

Listar y cargar plantillas:

{"name":"list_templates","arguments":{}}
{"name":"list_templates","arguments":{"source":"builtin","query":"epidem","tags":["epidemiology"]}}
{"name":"get_template_info","arguments":{"template_name":"sir"}}
{"name":"load_template","arguments":{"template_name":"sir","model_id":"sir_baseline"}}

Guardar el modelo actual como plantilla de usuario:

{"name":"save_as_template","arguments":{"model_id":"pop_v1","template_name":"my_population_template","description":"Baseline single-stock growth starter","tags":["intro","population"]}}

Crear y gestionar módulos:

{"name":"create_module","arguments":{"model_id":"sir_baseline","name":"Disease Dynamics","members":["Susceptible","Infected","Recovered"]}}
{"name":"add_to_module","arguments":{"model_id":"sir_baseline","module_name":"Disease Dynamics","members":["infection","recovery"]}}
{"name":"list_modules","arguments":{"model_id":"sir_baseline"}}
{"name":"remove_from_module","arguments":{"model_id":"sir_baseline","module_name":"Disease Dynamics","members":["recovery"]}}
{"name":"rename_module","arguments":{"model_id":"sir_baseline","module_name":"Disease Dynamics","new_name":"Disease Core"}}
{"name":"delete_module","arguments":{"model_id":"sir_baseline","module_name":"Disease Core"}}

Renombrar y eliminar variables de forma segura:

{"name":"rename_variable","arguments":{"model_id":"sir_baseline","old_name":"population_total","new_name":"total_population"}}
{"name":"delete_variable","arguments":{"model_id":"sir_baseline","name":"recovery"}}
{"name":"delete_variable","arguments":{"model_id":"sir_baseline","name":"Susceptible","force":true}}

Actualizar una variable existente:

{"name":"update_flow","arguments":{"model_id":"pop_v1","name":"growth","equation":"Population * growth_rate * stress_modifier"}}

Inferir conectores faltantes a partir de ecuaciones:

{"name":"sync_connectors_from_equations","arguments":{"model_id":"pop_v1"}}

Establecer geometría de vista de módulo directamente:

{"name":"set_module_view","arguments":{"model_id":"sir_baseline","module_name":"Disease Dynamics","x":420,"y":280,"width":420,"height":240}}

Establecer estilo de vista de módulo:

{"name":"set_module_style","arguments":{"model_id":"sir_baseline","module_name":"Disease Dynamics","border_color":"#666666","background":"#FFF7E6","font_color":"#333333","font_size":"10pt","label_side":"top"}}

Colocar automáticamente cuadros de módulos desde posiciones actuales de miembros:

{"name":"auto_place_module_boxes","arguments":{"model_id":"sir_baseline","padding":40,"only_missing":true}}

Apuntar a un modelo específico en llamadas posteriores:

{"name":"add_stock","arguments":{"model_id":"pop_v1","name":"Population","initial_value":"100"}}

Leer con verificaciones estrictas de compatibilidad:

{"name":"read_model","arguments":{"filepath":"./external_model.stmx","model_id":"imported","compat_mode":"strict"}}

Previsualizar XML en modo permisivo (por defecto) y devolver advertencias de compatibilidad cuando estén presentes:

{"name":"get_model_xml","arguments":{"model_id":"imported","compat_mode":"permissive"}}

Carga útil válida de función gráfica:

{
  "name": "add_aux",
  "arguments": {
    "model_id": "pop_v1",
    "name": "lookup_rate",
    "equation": "GRAPH(Time)",
    "graphical_function": {
      "xscale": {"min": 0, "max": 100},
      "ypts": [0.1, 0.2, 0.4, 0.6],
      "type": "continuous"
    }
  }
}

Carga útil inválida de función gráfica (rechazada):

{
  "name": "add_aux",
  "arguments": {
    "name": "bad_lookup",
    "equation": "GRAPH(Time)",
    "graphical_function": {
      "xscale": {"min": 0, "max": 100},
      "xpts": [0, 10, 20, 30],
      "ypts": [0.1, 0.2, 0.4, 0.6]
    }
  }
}

Ejemplo de uso

Crear un modelo simple de población

User: Create a simple exponential growth model with a population starting at 100
      and a growth rate of 0.1 per year

Claude: [Uses create_model, add_stock, add_aux, add_flow, add_connector, save_model]
        Creates population_growth.stmx with:
        - Stock: Population (initial=100)
        - Aux: growth_rate (0.1)
        - Flow: growth (Population * growth_rate) into Population

Leer y analizar un modelo existente

User: Read the carbon cycle model and explain what it does

Claude: [Uses read_model, list_variables]
        This model has 3 stocks (Atmosphere, Land Biota, Soil) and 6 flows
        representing carbon exchange through photosynthesis, respiration...

Construir un modelo biogeoquímico

User: Create a two-box ocean model with surface and deep nutrients

Claude: [Uses create_model, add_stock (x4), add_aux (x8), add_flow (x6), save_model]
        Creates a model with nutrient cycling between surface and deep ocean
        including upwelling, downwelling, biological uptake, and remineralization

Vista previa del diagrama

La herramienta render_diagram renderiza el modelo como un diagrama SVG de stock-y-flujo — stocks como rectángulos, auxiliares como círculos, flujos como tuberías con válvulas (las nubes marcan fuentes/sumideros) y conectores de dependencia como polilíneas enrutadas. El SVG se devuelve en línea para que un agente pueda inspeccionar el diseño y, opcionalmente, se escribe en un archivo que puede abrir en cualquier navegador. Ejecuta el auto-diseño primero por defecto, por lo que un modelo recién construido se renderiza sin posicionamiento manual.

{"name":"render_diagram","arguments":{"model_id":"sir_baseline","filepath":"./sir.svg"}}

El diagrama siguiente es la plantilla integrada sir renderizada por render_diagram (sin posicionamiento manual):

SIR model rendered by render_diagram

Simulación

La herramienta simulate ejecuta el modelo actual y devuelve series temporales reducidas en muestreo más resúmenes por variable (inicial/final/mín/máx), cerrando el bucle construir→verificar sin abrir Stella. Requiere la dependencia opcional PySD:

pip install 'stella-mcp[sim]'
{"name":"simulate","arguments":{"model_id":"pop_v1","overrides":{"growth_rate":0.05},"include":["Population"],"max_points":50}}

Notas y advertencias:

  • PySD se integra solo con Euler — los modelos cuyo method es RK4 simulan con Euler y la respuesta lleva una advertencia. Cada respuesta respaldada por PySD identifica la versión instalada de PySD, el método real, el método declarado, la verificación previa de funciones no compatibles y las advertencias.
  • Los arreglos, las instancias de módulos composicionales y los modelos adicionales de nivel superior se conservan únicamente en 0.14. Fallan antes de PySD con un error estructurado unsupported_model_feature en lugar de ser escalarizados o aplanados silenciosamente.
  • PySD y Stella no tienen semántica de salida idéntica en todos los casos escalares compatibles. En el fixture conservado de Lotka-Volterra, Stella limita un flujo de salida para imponer un stock no negativo, mientras que PySD reporta la ecuación de flujo sin límite. Las trayectorias de los stocks aún llegan a cero juntas en el siguiente tiempo del modelo.
  • overrides acepta nombres de variables en forma de visualización ("growth rate") o de guion bajo (growth_rate) y reemplaza la variable con una constante.
  • save_results_csv escribe la tabla de resultados de resolución completa con una columna time.
  • El modelo del espacio de trabajo nunca se modifica mediante simulación (la ejecución utiliza una copia desechable).

Comparación de Escenarios

La herramienta compare_scenarios responde "¿qué sucede bajo estas suposiciones alternativas?" — ejecuta varios conjuntos de anulaciones nombradas contra una línea base (el modelo sin modificar por defecto) e informa cómo diverge cada uno. También requiere el extra sim.

{"name":"compare_scenarios","arguments":{"model_id":"pop_v1","include":["Population"],"scenarios":[{"name":"low growth","overrides":{"growth_rate":0.02}},{"name":"high growth","overrides":{"growth_rate":0.08}}]}}

Cada escenario informa su propia serie submuestreada más delta_vs_baseline por variable: final_abs, final_pct (cambio porcentual del valor final), y max_abs. Notas:

  • Cada nombre de anulación en todos los escenarios se valida antes de cualquier ejecución, por lo que un error tipográfico falla rápidamente y de forma atómica — ningún escenario se ejecuta a medias.
  • Un escenario cuya ejecución produce NaN/inf informa la advertencia en el warnings de ese escenario sin abortar los demás; final_pct es null cuando el final de la línea base es cero (sin división por cero).
  • baseline es opcional — pase un conjunto de anulaciones para medir deltas contra él, u omítalo para comparar contra el modelo sin modificar.
  • save_comparison_csv escribe una tabla ancha con una columna por variable__scenario (y variable__baseline).
  • El modelo compilado se reutiliza en cada escenario en una sola llamada, por lo que una comparación es aproximadamente tan costosa como una sola simulación más una ejecución por escenario.

Análisis de Sensibilidad

La herramienta sensitivity_analysis responde "¿qué parámetros realmente mueven el resultado?" — barre cada parámetro uno a la vez a través de un rango (manteniendo los demás en su línea base) e informa cómo responde una única métrica de salida elegida. También requiere el extra sim.

{"name":"sensitivity_analysis","arguments":{"model_id":"pop_v1","parameters":[{"name":"growth_rate","start":0.02,"stop":0.08,"steps":7}],"output":{"variable":"Population","metric":"final"}}}

Para cada parámetro devuelve la métrica en cada valor barrido, un range_sensitivity (la pendiente promedio de la métrica a través del rango barrido), y un elasticity normalizado a la línea base (≈ Δsalida% / Δparámetro%) para que los parámetros puedan clasificarse por influencia. Notas:

  • Solo uno a la vez. mode acepta "oat"; el factorial completo (grid) y el muestreo Monte-Carlo están reservados para una versión futura.
  • metric es uno de final, max, min, mean, o time_to_threshold (que necesita un output.threshold e informa la primera vez que la serie lo cruza). max/min/mean cubren solo valores finitos; una ejecución no finita o que nunca cruza informa null para ese punto con una advertencia.
  • Una especificación de parámetro es start/stop/steps (espaciado uniformemente, steps ≥ 2) o una lista explícita de values (≥ 2 entradas).
  • max_runs (por defecto 200) limita el total de ejecuciones barridas; un barrido sobredimensionado genera un error en lugar de truncarse silenciosamente. Las ejecuciones OAT son una suma entre parámetros, no un producto, por lo que el límite solo se activa en barridos genuinamente grandes.
  • elasticity es null cuando no puede definirse (un parámetro no constante, o una métrica/parámetro de línea base cero); range_sensitivity aún se informa.
  • save_sweep_csv escribe una tabla larga de parameter, value, metric.
  • Al igual que la comparación de escenarios, el modelo se compila una vez y se reutiliza en todo el barrido.

Calibración

La herramienta calibrate es la inversa de simulate: dado un serie de tiempo observada, ajusta parámetros constantes para que el modelo reproduzca los datos. También requiere el extra sim.

{"name":"calibrate","arguments":{"model_id":"pop_v1","observations":{"time":[0,2,4,6,8,10],"targets":{"Population":[100,122,149,182,222,271]}},"parameters":[{"name":"growth_rate","initial":0.05,"min":0,"max":0.3}]}}

Devuelve los parámetros ajustados (cada uno con sus límites, un indicador at_bound, y un std_error linealizado), la trayectoria del objetivo ponderado (initial/final weighted_sse y weighted_rmse), métricas de error en unidades nativas para cada objetivo, estado/configuración del optimizador, y advertencias. Notas:

  • Solo los auxiliares y flujos constantes son calibrables. Los stocks son rechazados: la anulación de parámetros de PySD fija un stock a una constante durante toda la ejecución en lugar de establecer su valor inicial, lo que aplanaría silenciosamente un modelo dinámico. Ajustar condiciones iniciales de stocks no es compatible.
  • Dos optimizadores. least_squares (por defecto) es local y rápido e informa un std_error; differential_evolution es global, estocástico, sembrado para reproducibilidad, y requiere límites min/max en cada parámetro. Su límite de generaciones maxiter por defecto es 100.
  • El initial de cada parámetro por defecto es el valor constante actual del modelo. Los límites son opcionales para least_squares, requeridos para differential_evolution.
  • std_error es una aproximación linealizada, no un posterior: es la covarianza σ²·(JᵀJ)⁻¹ y se informa solo cuando hay más observaciones que parámetros, el jacobiano está bien condicionado, y ningún parámetro está en un límite; de lo contrario es null con una advertencia. differential_evolution devuelve null (sin jacobiano). Bajo weights no predeterminado, la interpretación del error estándar se mantiene solo para pesos inversos a σ.
  • Alineación. El modelo se ejecuta sobre su ventana nativa de [start, stop] y la simulación se interpola linealmente en los tiempos de observación. Los tiempos de observación fuera de la ventana se rechazan (sin extrapolación). Todos los objetivos comparten una cuadrícula de tiempo estrictamente creciente; las observaciones se cargan en línea o desde un csv_path (primera columna tiempo, el resto objetivos).
  • Los weights opcionales por objetivo son multiplicadores de residuos: el optimizador usa weight * (simulated - observed). Los valores inversos de desviación estándar de medición dan residuos normalizados. Debido a que los errores ponderados pueden mezclar unidades, target_metrics informa un SSE y RMSE no ponderados en las unidades nativas de cada objetivo; no se informa un RMSE agregado en unidades nativas. save_fit_csv escribe una tabla larga de time, target, observed, fitted; return_fit_series adjunta la serie de mejor ajuste. El modelo se compila una vez y se reutiliza en todo el ajuste.

Recursos y Prompts de MCP

Más allá de las herramientas, el servidor expone capacidades nativas de MCP:

  • Anotaciones de herramientas. Cada herramienta lleva pistas (readOnlyHint, destructiveHint, idempotentHint) para que los clientes puedan gestionar permisos y paralelizar llamadas de solo lectura. Las herramientas de inspección (inspect_model, validate_model, list_*, get_model_xml) son de solo lectura; delete_* están marcadas como destructivas.
  • Recursos. Las plantillas y los modelos del espacio de trabajo son legibles como recursos:
    • stella://templates/{name} — el .stmx de una plantilla integrada o de usuario
    • stella://workspaces/{workspace_id}/models/{model_id} — una exportación XMILE actual de un modelo explícito del espacio de trabajo
    • stella://models/{model_id} — solo el espacio de trabajo de compatibilidad stdio heredado
  • Prompt. Un prompt de build-stella-model (argumento: description) codifica el flujo de trabajo recomendado construir → validar → simular → renderizar → guardar, por lo que es descubrible dentro de los clientes MCP.

Validación

La herramienta validate_model verifica:

  • Variables indefinidas - Referencias a variables que no existen
  • Problemas de balance de masa - Stocks sin flujos, flujos que referencian stocks inexistentes
  • Conexiones faltantes - Ecuaciones que usan variables sin conectores (advertencia)
  • Integridad de extremos de conectores - Conectores que apuntan a variables faltantes (error)
  • Flujos huérfanos - Flujos no conectados a ningún stock
  • Dependencias circulares - Bucles infinitos en cálculos auxiliares
  • Integridad de módulos - Módulos vacíos (advertencia) y módulos que referencian miembros faltantes (error)
  • Unidades presentes - Un stock o flujo sin unidades mientras otros las definen (advertencia)
  • Consistencia de unidades - Un flujo cuyas unidades no se leen como stock-units/time-unit cuando todos los stocks adjuntos comparten las mismas unidades (advertencia; conservador — permanece en silencio en flujos de conversión y cualquier cosa que no pueda analizar con confianza)
  • Auxiliares no utilizados - Un auxiliar referenciado por ninguna ecuación o conector (advertencia); los stocks y flujos nunca se marcan

Compatibilidad XMILE

  • Los archivos de salida usan el estándar XMILE
  • Compatible con Stella Professional 1.9+ y Stella Architect
  • La importación/exportación de permissive preserva el contenido compatible y los fragmentos XML no compatibles seleccionados cuando es práctico, mientras devuelve advertencias explícitas. Editar variables compatibles no garantiza que las referencias dentro de fragmentos solo preservados se actualicen.
  • La importación/exportación de strict rechaza arreglos, instancias de módulos composicionales, modelos adicionales de nivel superior, e identificadores reservados confirmados de Stella/XMILE. Los arreglos y modelos anidados no son funciones implementadas en 0.14.
  • Nombres reservados como beta y gamma se preservan con advertencias en modo permisivo y se rechazan en modo estricto. La plantilla SIR integrada usa transmission_rate y recovery_rate para que Stella no los renombre al guardar.
  • El auto-diseño utiliza una columna vertebral determinista de flujo de stock dirigido, puertos de stock distintos, rutas de flujo y conector conscientes de obstáculos, verificaciones de colisión de etiquetas, y tamaño de cuadrícula de página a partir de límites visuales completos.
  • Las coordenadas autorizadas, incluidas las coordenadas suministradas a través de herramientas de actualización, y los puntos de ruta bloqueados permanecen fijos. Las coordenadas generadas automáticamente se recalculan en exportaciones posteriores para que los modelos extendidos incrementalmente puedan clasificarse nuevamente en lugar de congelarse después de su primer guardado.
  • Las rutas bloqueadas se reservan antes que las rutas desbloqueadas, las etiquetas se seleccionan en orden de nombre normalizado, y los tamaños de fuente de vista importados controlan la geometría de etiquetas en vistas previas de análisis y SVG.
  • Los conectores de información usan segmentos directos de límite a límite siempre que el diagrama completo los deje sin obstrucciones y sin compartir. Las tuberías de flujo de stock permanecen ortogonales porque Stella reescribe segmentos de flujo diagonales al guardar.
  • Los diseños planos limpios de referencia no tienen cruces de glifos, etiquetas o rutas. Un gráfico que no puede dibujarse limpiamente aún se exporta e informa una advertencia estable de layout.*; no se prometen cruces cero para gráficos no planos arbitrarios.
  • Los nombres de variables con espacios se convierten a guiones bajos internamente
  • El analizador normaliza las referencias de extremos de conectores y flujos de entrada/salida de stock importados
  • La exportación de paso de tiempo evita el redondeo recíproco con pérdida (los recíprocos no exactos se exportan como dt simple)
  • La importación/exportación preserva atributos/elementos desconocidos en secciones compatibles (encabezado, sim_specs, variables, vistas/extras de modelo) para reducir la pérdida de datos en viajes de ida y vuelta
  • Las pruebas de regresión del corpus de compatibilidad viven en tests/fixtures/compat_corpus/. Un subconjunto fijado y atribuido de modelos de prueba de SDXorg vive en tests/fixtures/external_corpus/; ambos se ejecutan sin conexión en CI.
  • Ayudante de mantenimiento: python scripts/sync_compat_corpus_manifest.py --check valida la sincronización del manifiesto del corpus

Pruebas

La suite de pruebas del repositorio cubre el protocolo stdio de MCP, aislamiento del espacio de trabajo, construcción de modelos, validación, renderizado SVG, importación/exportación XMILE, simulación, análisis de escenarios, análisis de sensibilidad, calibración, e instalación de paquetes. Ejecútela desde una copia de origen con:

uv sync --locked --extra dev --extra sim
uv run python -m pytest

Pinned Stella-saved and external XMILE fixtures live under tests/fixtures/ and run offline in CI. Generated reports, local planning files, and manual review artifacts are intentionally not committed to the source tree.

Project Structure

See docs/architecture.md for dependency boundaries, module ownership, workspace lifecycle, and compatibility contracts.

stella-mcp/
├── CHANGELOG.md
├── CITATION.cff
├── README.md
├── LICENSE
├── pyproject.toml
└── stella_mcp/
    ├── __init__.py
    ├── server.py         # MCP server lifecycle and protocol wiring
    ├── tool_handlers.py  # Compatibility facade for domain handlers
    ├── tool_schemas.py   # Compatibility facade for the tool catalog
    ├── tools/            # Domain schemas and handlers
    ├── mcp_resources.py  # MCP resources and prompts
    ├── session_store.py  # Explicit application workspace state
    ├── simulate.py       # PySD-backed simulation
    ├── analysis.py       # Scenario comparison and sensitivity analysis
    ├── calibrate.py      # Parameter fitting and native-unit error metrics
    ├── render_svg.py     # Stock-and-flow SVG rendering
    ├── model_types.py     # Model records and XMILE constants
    ├── model.py           # StellaModel lifecycle and compatibility delegates
    ├── model_layout.py    # Layout compatibility delegates and stock sizing
    ├── layout_graph.py    # Directed graph ranking and component packing
    ├── layout_router.py   # Boundary ports and obstacle-aware routing
    ├── layout_quality.py  # Geometry analysis, metrics, and warnings
    ├── layout_pipeline.py # Staged deterministic layout orchestration
    ├── xmile.py           # Public model compatibility facade
    ├── xmile_io.py        # XMILE I/O compatibility facade
    ├── xmile_features.py  # XMILE feature classification and typed errors
    ├── xmile_parse.py     # XMILE parser and compatibility warnings
    ├── xmile_export.py    # XMILE serialization and fragment retention
    └── validator.py      # Model validation logic

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Maintainer Release

PyPI publishing is handled by .github/workflows/publish.yml using PyPI Trusted Publishing. To release a new version:

  1. Synchronize the version in pyproject.toml, stella_mcp/__init__.py, CITATION.cff, and CHANGELOG.md; keep the citation and changelog release dates identical.
  2. Run uv lock --check, the core and simulation test suites, the MCP-floor suite, and the package job. Prepare the draft GitHub release notes from the matching CHANGELOG.md entry.
  3. Before pushing the release branch, verify the protected main and v* tag rules, the pypi environment's protected-tag policy, and the configured PyPI Trusted Publisher.
  4. Open a draft pull request so every release-critical check runs, require those exact checks, obtain review, and separately approve the merge.
  5. Wait for a fresh main CI run at the exact merge commit. If the Chicago release date has changed, correct the metadata through another reviewed pull request before continuing.
  6. With separate approval, create the lightweight version tag at that audited merge commit. With another approval, create and inspect the draft GitHub release from the matching notes file.
  7. With final publication approval, publish the draft. The release event builds and validates the source distribution and wheel without OIDC authority; the pypi job's configured deployment policy accepts only tags matching the protected v* release-tag policy before Trusted Publishing can upload the verified artifacts.

Tagging, draft creation, and publication are distinct approval gates. Do not move or replace a public tag or uploaded distribution to repair a release.

License

MIT License - see LICENSE for details.

Acknowledgments