stella-mcp

Servidor MCP para criar e manipular modelos de dinâmica de sistemas Stella (arquivos .stmx no formato XMILE)

Documentação

Servidor Stella MCP

Um servidor Model Context Protocol (MCP) neutro em relação a fornecedores para criar e manipular modelos de dinâmica de sistemas Stella. Qualquer cliente MCP compatível pode construir, ler, validar e salvar arquivos .stmx no formato XMILE; recursos opcionais do host ainda variam.

Para que serve?

Stella é uma ferramenta de modelagem de dinâmica de sistemas usada para simular sistemas complexos em áreas como ecologia, biogeoquímica, economia e engenharia. Este servidor MCP permite que assistentes de IA possam:

  • Criar modelos do zero - Construir diagramas de estoque-e-fluxo programaticamente
  • Ler modelos existentes - Analisar e compreender arquivos .stmx
  • Validar modelos - Verificar erros como variáveis indefinidas ou conexões ausentes
  • Modificar modelos - Adicionar estoques, fluxos, auxiliares e conectores
  • Salvar modelos - Exportar arquivos XMILE válidos que abrem no Stella Professional

Isso é particularmente útil para:

  • Ensinar modelagem de dinâmica de sistemas
  • Prototipagem rápida de modelos por meio de linguagem natural
  • Criação ou modificação em lote de modelos
  • Documentar e explicar modelos existentes

Instalação

Via PyPI

pip install stella-mcp

Via código-fonte

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

Requisitos

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

Configuração

Via uvx (sem necessidade de instalação)

Se você tiver o uv instalado, a configuração de menor atrito executa o pacote publicado diretamente:

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

Claude Desktop

Adicione ao seu claude_desktop_config.json:

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

Claude Code

Adicione ao seu .claude/settings.json:

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

Modo de desenvolvimento

Se estiver executando a partir do código-fonte:

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

Fluxo de Trabalho Recomendado para Agentes

Para um novo modelo:

  1. Em MCP 2026-07-28, chame create_workspace e carregue o workspace_id retornado nas chamadas com estado. Clientes stdio legados podem omiti-lo.
  2. build_model com um model_id estável e o conjunto completo de estoques, auxiliares e fluxos em uma única chamada (sincronização de conectores e validação são executadas por padrão, então a resposta serve também como inspeção).
  3. Corrija erros de validação com update_*, rename_variable ou delete_variable.
  4. Estenda incrementalmente com add_variables (em lote) ou as ferramentas de adição individual.
  5. simulate para verificar o comportamento (requer o extra sim).
  6. Salve com save_model.

Para modelos importados:

  1. read_model com compat_mode="permissive" para inspecionar avisos.
  2. Execute inspect_model para entender a estrutura do modelo.
  3. Use compat_mode="strict" antes do salvamento final quando a fidelidade de ida-e-volta for importante.

Ferramentas Disponíveis

Criação de Modelos e E/S

FerramentaDescrição
create_modelCriar um novo modelo com nome e configurações de tempo (início, fim, dt, método)
set_sim_specsAtualizar configurações de tempo de simulação em um modelo existente
read_modelCarregar um arquivo .stmx existente
save_modelSalvar modelo em um arquivo .stmx
delete_modelRemover um modelo do espaço de trabalho (arquivos salvos não são alterados)

Modelos Prontos (Templates)

FerramentaDescrição
list_templatesListar modelos prontos integrados e definidos pelo usuário (suporta filtros de origem/consulta/tag)
get_template_infoObter metadados detalhados de um modelo pronto
load_templateCarregar um modelo pronto como modelo no espaço de trabalho atual
save_as_templateSalvar o modelo atual como um modelo pronto reutilizável do usuário (descrição/tags opcionais)

Construção de Modelos

FerramentaDescrição
build_modelCriar e popular um modelo em uma única chamada (lote atômico)
add_variablesAdicionar múltiplas variáveis/conectores/módulos a um modelo existente (lote atômico)
add_stockAdicionar um estoque (reservatório) com valor inicial e unidades
add_flowAdicionar um fluxo entre estoques com uma equação
add_auxAdicionar uma variável auxiliar (parâmetro ou cálculo)
update_stockAtualizar campos de estoque preservando relacionamentos
update_flowAtualizar campos de fluxo preservando vínculos de estoque
update_auxAtualizar campos de variável auxiliar
add_connectorAdicionar um conector de dependência entre variáveis
sync_connectors_from_equationsAdicionar conectores de dependência ausentes inferidos de equações
set_connector_routingDefinir ângulo do conector e metadados explícitos de roteamento de waypoint
rename_variableRenomear um estoque/fluxo/auxiliar e atualizar referências em equações/conectores/módulos
delete_variableExcluir um estoque/fluxo/auxiliar com verificações de consistência e limpeza
create_moduleCriar um módulo/grupo lógico de variáveis
add_to_moduleAdicionar variáveis a um módulo/grupo existente
remove_from_moduleRemover variáveis de um módulo/grupo
rename_moduleRenomear um módulo/grupo
delete_moduleExcluir um módulo/grupo
set_module_viewDefinir posição/tamanho explícito da caixa do módulo no diagrama
set_module_styleDefinir estilo da caixa do módulo (borda/fundo/fonte/lado do rótulo) no diagrama
auto_place_module_boxesPosicionar automaticamente as caixas dos módulos ao redor de seus membros

Notas:

  • Clientes MCP 2026-07-28 chamam create_workspace uma vez e incluem seu workspace_id retornado nas chamadas com estado. A descoberta moderna de ferramentas marca esse campo como obrigatório nas ferramentas com estado. O ID roteia o estado da aplicação; não é uma credencial de autorização.
  • Clientes stdio legados suportados podem omitir workspace_id e usar um espaço de trabalho de compatibilidade local ao processo; a descoberta legada mantém o campo opcional.
  • As ferramentas aceitam model_id opcional para que um espaço de trabalho possa gerenciar múltiplos modelos com segurança.
  • create_model e read_model definem o model_id atual do espaço de trabalho e o retornam.
  • add_flow e add_aux suportam cargas graphical_function opcionais (ypts mais exatamente um de xscale ou xpts).
  • add_stock/add_flow/add_aux rejeitam nomes de variáveis duplicados entre tipos de variáveis; add_connector exige que ambas as variáveis existam.
  • set_connector_routing pode direcionar um conector por connector_uid ou por from_var + to_var.
  • save_model e get_model_xml aceitam auto_layout (padrão true) e resolve_layout_violations (padrão false).
  • save_model, get_model_xml e render_diagram retornam o viewport de layout mais recente, métricas e avisos em conteúdo estruturado. Seus resultados em texto nomeiam quaisquer códigos de aviso de layout não limpos.
  • read_model, save_model e get_model_xml aceitam compat_mode:
    • permissive (padrão): continuar com avisos
    • strict: falhar em problemas de compatibilidade
  • set_module_style atualiza o estilo da visualização do módulo e persiste esses atributos nos elementos <group .../> da visualização XMILE.
  • save_as_template grava modelos prontos do usuário em ~/.stella-mcp/templates por padrão (substituível via STELLA_MCP_TEMPLATE_DIR) e armazena metadados em um sidecar .meta.json.
  • Falhas de ferramentas retornam erros MCP estruturados com error.code, error.category e error.message.
  • Todo resultado bem-sucedido de ferramenta mantém texto legível e fornece structuredContent validado por esquema, descrito pelo seu outputSchema JSON Schema 2020-12.

Ciclo de Vida do Espaço de Trabalho

FerramentaDescrição
create_workspaceCriar um espaço de trabalho isolado, opcionalmente com tempo de vida selecionado pelo chamador
revoke_workspaceRevogar um espaço de trabalho e descartar seus modelos em memória

Inspeção de Modelos

FerramentaDescrição
list_modelsListar IDs de modelos disponíveis no espaço de trabalho e indicar o modelo atual
inspect_modelRetornar um resumo estruturado do modelo para inspeção do agente
list_modulesListar módulos/grupos no modelo atual
list_connectorsListar IDs de conectores, endpoints, ângulos e metadados de roteamento
list_variablesListar todos os estoques, fluxos e auxiliares
validate_modelVerificar erros (variáveis indefinidas, conexões ausentes, etc.)
get_model_xmlVisualizar a saída XML XMILE
render_diagramRenderizar o modelo como um diagrama SVG de estoque-e-fluxo
simulateExecutar o modelo via PySD e retornar séries temporais + resumos (extra sim)
compare_scenariosExecutar conjuntos nomeados de overrides "e se" contra uma linha de base e relatar deltas (extra sim)
sensitivity_analysisVarrer parâmetros um por vez e classificar seu efeito em uma métrica de saída (extra sim)
calibrateAjustar parâmetros constantes a uma série temporal observada (inverso de simular) (extra sim)

Construção em Lote

build_model cria e popula um modelo em uma única chamada. Os itens são aplicados na ordem estoques → auxiliares → fluxos → conectores → módulos; todo o lote é tudo-ou-nada, e em caso de falha o erro nomeia o item com falha (error.stage + error.index). Os mesmos arrays de itens funcionam em um modelo existente via 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"]}
    ]
  }
}

Sincronização de conectores e validação são executadas por padrão (desative com "sync_connectors": false / "validate": false); a resposta inclui o resumo estruturado completo do modelo, então nenhuma chamada de acompanhamento inspect_model é necessária.

Exemplos de Cargas de Ferramentas

Criar e alternar entre modelos no espaço de trabalho:

{"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 e carregar modelos prontos:

{"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"}}

Salvar o modelo atual como um modelo pronto do usuário:

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

Criar e gerenciar 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"}}

Renomear e excluir variáveis com segurança:

{"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}}

Atualizar uma variável existente:

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

Inferir conectores ausentes de equações:

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

Definir geometria da visualização do módulo diretamente:

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

Definir estilo da visualização do 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"}}

Posicionar automaticamente caixas de módulos a partir das posições atuais dos membros:

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

Direcionar um modelo específico em chamadas posteriores:

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

Ler com verificações estritas de compatibilidade:

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

Visualizar XML em modo permissivo (padrão) e retornar avisos de compatibilidade quando presentes:

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

Carga válida de função 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 inválida de função gráfica (rejeitada):

{
  "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]
    }
  }
}

Exemplo de Uso

Criando um modelo populacional simples

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

Lendo e analisando um 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...

Construindo um 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

Visualização do Diagrama

A ferramenta render_diagram renderiza o modelo como um diagrama SVG de estoque-e-fluxo — estoques como retângulos, auxiliares como círculos, fluxos como tubos com válvulas (nuvens marcam fontes/destinos) e conectores de dependência como polilinhas roteadas. O SVG é retornado inline para que um agente possa inspecionar o layout e, opcionalmente, gravado em um arquivo que você pode abrir em qualquer navegador. Ele executa auto-layout primeiro por padrão, então um modelo recém-construído é renderizado sem posicionamento manual.

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

O diagrama abaixo é o modelo pronto integrado sir renderizado por render_diagram (sem posicionamento manual):

SIR model rendered by render_diagram

Simulação

A ferramenta simulate executa o modelo atual e retorna séries temporais reduzidas por amostragem, além de resumos por variável (inicial/final/mín/máx), fechando o ciclo construir→verificar sem abrir o Stella. Ela requer a dependência 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 e ressalvas:

  • O PySD integra-se somente com Euler — modelos cujo method é RK4 simulam com Euler e a resposta carrega um aviso. Toda resposta apoiada pelo PySD identifica a versão instalada do PySD, o método real, o método declarado, a pré-verificação de recursos não suportados e avisos.
  • Arrays, instâncias de módulos composicionais e modelos adicionais de nível superior são apenas preservados na versão 0.14. Eles falham antes do PySD com um erro estruturado unsupported_model_feature em vez de serem silenciosamente escalarizados ou achatados.
  • PySD e Stella não têm semântica de saída idêntica em todos os casos escalares suportados. No fixture Lotka-Volterra mantido, Stella limita uma saída para impor um estoque não negativo, enquanto o PySD relata a equação de fluxo sem limite. As trajetórias de estoque ainda chegam a zero juntas no próximo tempo do modelo.
  • overrides aceita nomes de variáveis na forma de exibição ("growth rate") ou sublinhado (growth_rate) e substitui a variável por uma constante.
  • save_results_csv escreve a tabela de resultados em resolução completa com uma coluna time.
  • O modelo do workspace nunca é modificado pela simulação (a execução usa uma cópia descartável).

Comparação de Cenários

A ferramenta compare_scenarios responde "o que acontece sob estas suposições alternativas?" — ela executa vários conjuntos de substituições nomeadas contra uma linha de base (o modelo não modificado por padrão) e relata como cada uma diverge. Também requer o 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 cenário relata sua própria série reduzida, além de delta_vs_baseline por variável: final_abs, final_pct (mudança percentual do valor final) e max_abs. Notas:

  • Cada nome de substituição em todos os cenários é validado antes de qualquer execução, então um erro de digitação falha rapidamente e atomicamente — nenhum cenário é executado pela metade.
  • Um cenário cuja execução produz NaN/inf relata o aviso no warnings desse cenário sem abortar os outros; final_pct é null quando o final da linha de base é zero (sem divisão por zero).
  • baseline é opcional — passe um conjunto de substituições para medir deltas contra, ou omita-o para comparar com o modelo não modificado.
  • save_comparison_csv escreve uma tabela larga com uma coluna por variable__scenario (e variable__baseline).
  • O modelo compilado é reutilizado em todos os cenários em uma única chamada, então uma comparação é aproximadamente tão barata quanto uma única simulação mais uma execução por cenário.

Análise de Sensibilidade

A ferramenta sensitivity_analysis responde "quais parâmetros realmente movem o resultado?" — ela varre cada parâmetro um de cada vez em um intervalo (mantendo os outros em sua linha de base) e relata como uma única métrica de saída escolhida responde. Também requer o 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, ela retorna a métrica em cada valor varrido, um range_sensitivity (a inclinação média da métrica no intervalo varrido) e um elasticity normalizado pela linha de base (≈ Δsaída% / Δparâmetro%) para que os parâmetros possam ser classificados por influência. Notas:

  • Somente um de cada vez. mode aceita "oat"; fatorial completo (grid) e amostragem Monte-Carlo são reservados para uma versão futura.
  • metric é um de final, max, min, mean ou time_to_threshold (que precisa de um output.threshold e relata o primeiro momento em que a série o cruza). max/min/média cobrem apenas valores finitos; uma execução não finita ou que nunca cruza relata null para esse ponto com um aviso.
  • Uma especificação de parâmetro é start/stop/steps (espaçado uniformemente, steps ≥ 2) ou uma lista explícita de values (≥ 2 entradas).
  • max_runs (padrão 200) limita o total de execuções varridas; uma varredura superdimensionada gera erro em vez de truncar silenciosamente. Execuções OAT são uma soma entre parâmetros, não um produto, então o limite só é atingido em varreduras realmente grandes.
  • elasticity é null quando não pode ser definido (um parâmetro não constante, ou uma métrica/parâmetro de linha de base zero); range_sensitivity ainda é relatado.
  • save_sweep_csv escreve uma tabela longa parameter, value, metric.
  • Como na comparação de cenários, o modelo é compilado uma vez e reutilizado em toda a varredura.

Calibração

A ferramenta calibrate é o inverso de simulate: dado uma série temporal observada, ela ajusta parâmetros constantes para que o modelo reproduza os dados. Também requer o 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}]}}

Ela retorna os parâmetros ajustados (cada um com seus limites, um sinalizador at_bound e um std_error linearizado), a trajetória do objetivo ponderado (initial/final weighted_sse e weighted_rmse), métricas de erro em unidades nativas para cada alvo, status/configuração do otimizador e avisos. Notas:

  • Somente auxiliares e fluxos constantes são calibráveis. Estoques são rejeitados: a substituição de parâmetro do PySD fixa um estoque a uma constante para toda a execução em vez de definir seu valor inicial, o que achataria silenciosamente um modelo dinâmico. Ajustar condições iniciais de estoque não é suportado.
  • Dois otimizadores. least_squares (padrão) é local e rápido e relata um std_error; differential_evolution é global, estocástico, com semente para reprodutibilidade, e requer limites min/max em cada parâmetro. Seu limite de gerações maxiter é 100 por padrão.
  • O initial de cada parâmetro é o valor constante atual do modelo por padrão. Limites são opcionais para least_squares, obrigatórios para differential_evolution.
  • std_error é uma aproximação linearizada, não uma posterior: é a covariância σ²·(JᵀJ)⁻¹ e é relatada somente quando há mais observações do que parâmetros, o Jacobiano é bem condicionado e nenhum parâmetro está em um limite; caso contrário, é null com um aviso. differential_evolution retorna null (sem Jacobiano). Sob weights não padrão, a interpretação do erro padrão vale somente para pesos inversos de σ.
  • Alinhamento. O modelo executa em sua janela nativa [start, stop] e a simulação é linearmente interpolada nos tempos de observação. Tempos de observação fora da janela são rejeitados (sem extrapolação). Todos os alvos compartilham uma grade de tempo estritamente crescente; observações são carregadas inline ou de um csv_path (primeira coluna tempo, o restante alvos).
  • weights opcionais por alvo são multiplicadores de resíduo: o otimizador usa weight * (simulated - observed). Valores inversos do desvio padrão de medição dão resíduos normalizados. Como erros ponderados podem misturar unidades, target_metrics relata um SSE e RMSE não ponderados nas unidades nativas de cada alvo; nenhum RMSE agregado em unidades nativas é relatado. save_fit_csv escreve uma tabela longa time, target, observed, fitted; return_fit_series anexa a série de melhor ajuste. O modelo é compilado uma vez e reutilizado em todo o ajuste.

Recursos e Prompts MCP

Além das ferramentas, o servidor expõe capacidades nativas do MCP:

  • Anotações de ferramentas. Cada ferramenta carrega dicas (readOnlyHint, destructiveHint, idempotentHint) para que os clientes possam gerenciar permissões e paralelizar chamadas somente leitura. Ferramentas de inspeção (inspect_model, validate_model, list_*, get_model_xml) são somente leitura; delete_* são marcadas como destrutivas.
  • Recursos. Modelos de template e workspace são legíveis como recursos:
    • stella://templates/{name} — o .stmx de um template embutido ou do usuário
    • stella://workspaces/{workspace_id}/models/{model_id} — a exportação XMILE atual de um modelo de workspace explícito
    • stella://models/{model_id} — somente o workspace legado de compatibilidade stdio
  • Prompt. Um prompt build-stella-model (argumento: description) codifica o fluxo de trabalho recomendado construir → validar → simular → renderizar → salvar, então é descobrível dentro de clientes MCP.

Validação

A ferramenta validate_model verifica:

  • Variáveis indefinidas - Referências a variáveis que não existem
  • Problemas de balanço de massa - Estoques sem fluxos, fluxos referenciando estoques inexistentes
  • Conexões ausentes - Equações usando variáveis sem conectores (aviso)
  • Integridade dos pontos finais dos conectores - Conectores apontando para variáveis ausentes (erro)
  • Fluxos órfãos - Fluxos não conectados a nenhum estoque
  • Dependências circulares - Loops infinitos em cálculos auxiliares
  • Integridade do módulo - Módulos vazios (aviso) e módulos referenciando membros ausentes (erro)
  • Unidades presentes - Um estoque ou fluxo sem unidades enquanto outros as definem (aviso)
  • Consistência de unidades - Um fluxo cujas unidades não leem como stock-units/time-unit quando todos os estoques anexados compartilham as mesmas unidades (aviso; conservador — permanece silencioso em fluxos de conversão e qualquer coisa que não possa analisar com confiança)
  • Auxiliares não utilizados - Um auxiliar referenciado por nenhuma equação ou conector (aviso); estoques e fluxos nunca são sinalizados

Compatibilidade XMILE

  • Arquivos de saída usam o padrão XMILE
  • Compatível com Stella Professional 1.9+ e Stella Architect
  • Importação/exportação permissive preserva conteúdo suportado e os fragmentos XML não suportados selecionados quando prático, retornando avisos explícitos. Editar variáveis suportadas não garante que referências dentro de fragmentos apenas preservados sejam atualizadas.
  • Importação/exportação strict rejeita arrays, instâncias de módulos composicionais, modelos adicionais de nível superior e identificadores reservados confirmados de Stella/XMILE. Arrays e modelos aninhados não são recursos implementados na versão 0.14.
  • Nomes reservados como beta e gamma são preservados com avisos no modo permissivo e rejeitados no modo estrito. O template SIR embutido usa transmission_rate e recovery_rate para que Stella não os renomeie ao salvar.
  • Auto-layout usa uma espinha dorsal determinística direcionada de estoque-fluxo, portas de estoque distintas, rotas de fluxo e conector cientes de obstáculos, verificações de colisão de rótulos e dimensionamento de grade de página a partir de limites visuais completos.
  • Coordenadas autorais, incluindo coordenadas fornecidas por ferramentas de atualização, e pontos de rota bloqueados permanecem fixos. Coordenadas geradas automaticamente são recalculadas em exportações posteriores para que modelos estendidos incrementalmente possam ser classificados novamente em vez de congelarem após o primeiro salvamento.
  • Caminhos bloqueados são reservados antes de rotas desbloqueadas, rótulos são selecionados em ordem de nome normalizado, e tamanhos de fonte de visualização importados controlam a geometria dos rótulos em visualizações de análise e SVG.
  • Conectores de informação usam segmentos diretos de limite a limite sempre que o diagrama completo os deixa desobstruídos e não compartilhados. Tubos de estoque-fluxo permanecem ortogonais porque Stella reescreve segmentos de fluxo diagonais ao salvar.
  • Layouts de referência planares limpos não têm cruzamentos de glifos, rótulos ou rotas. Um grafo que não pode ser desenhado limpo ainda é exportado e relata um aviso estável layout.*; zero cruzamentos não são prometidos para grafos não planares arbitrários.
  • Nomes de variáveis com espaços são convertidos para sublinhados internamente
  • O parser normaliza referências de pontos finais de entrada/saída de estoque e conectores importados
  • Exportação de passo de tempo evita arredondamento recíproco com perda (recíprocos não exatos são exportados como dt simples)
  • Importação/exportação preserva atributos/elementos desconhecidos em seções suportadas (cabeçalho, sim_specs, variáveis, visualizações/extras de modelo) para reduzir perda de dados em ida e volta
  • Testes de regressão do corpus de compatibilidade vivem em tests/fixtures/compat_corpus/. Um subconjunto fixado e atribuído de modelos de teste SDXorg vive em tests/fixtures/external_corpus/; ambos rodam offline no CI.
  • Auxiliar de manutenção: python scripts/sync_compat_corpus_manifest.py --check valida a sincronização do manifesto do corpus

Testes

A suíte de testes do repositório cobre o protocolo MCP stdio, isolamento de workspace, construção de modelo, validação, renderização SVG, importação/exportação XMILE, simulação, análise de cenários, análise de sensibilidade, calibração e instalação de pacotes. Execute-a a partir de um checkout da fonte com:

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.

Estrutura do Projeto

Consulte docs/architecture.md para limites de dependência, propriedade de módulos, ciclo de vida do workspace e contratos de compatibilidade.

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

Contribuindo

Contribuições são bem-vindas! Sinta-se à vontade para enviar issues ou pull requests.

Lançamento pelo Mantenedor

A publicação no PyPI é gerenciada por .github/workflows/publish.yml usando PyPI Trusted Publishing. Para lançar uma nova versão:

  1. Sincronize a versão em pyproject.toml, stella_mcp/__init__.py, CITATION.cff e CHANGELOG.md; mantenha as datas de lançamento da citação e do changelog idênticas.
  2. Execute uv lock --check, as suítes de teste de núcleo e simulação, a suíte MCP-floor e o job de pacote. Prepare o rascunho das notas de lançamento do GitHub a partir da entrada correspondente em CHANGELOG.md.
  3. Antes de enviar o branch de lançamento, verifique as regras protegidas de tag main e v*, a política de tag protegida do ambiente pypi e o PyPI Trusted Publisher configurado.
  4. Abra um pull request de rascunho para que todas as verificações críticas de lançamento sejam executadas, exija exatamente essas verificações, obtenha revisão e aprove o merge separadamente.
  5. Aguarde uma nova execução de CI main no commit de merge exato. Se a data de lançamento de Chicago tiver mudado, corrija os metadados por meio de outro pull request revisado antes de continuar.
  6. Com aprovação separada, crie a tag de versão leve nesse commit de merge auditado. Com outra aprovação, crie e inspecione o rascunho do GitHub release a partir do arquivo de notas correspondente.
  7. Com aprovação final de publicação, publique o rascunho. O evento de release compila e valida a distribuição de código-fonte e a wheel sem autoridade OIDC; a política de implantação configurada do job pypi aceita apenas tags que correspondam à política de tag de release protegida v* antes que o Trusted Publishing possa enviar os artefatos verificados.

Criação de tag, criação de rascunho e publicação são portões de aprovação distintos. Não mova ou substitua uma tag pública ou distribuição enviada para reparar um lançamento.

Licença

Licença MIT - consulte LICENSE para detalhes.

Agradecimentos