Skip to main content

MCP server for creating and manipulating Stella system dynamics models (.stmx files)

Project description

Stella MCP Server

A Model Context Protocol (MCP) server for creating and manipulating Stella system dynamics models. This enables AI assistants like Claude to programmatically build, read, validate, and save .stmx files in the XMILE format.

What is this for?

Stella is a system dynamics modeling tool used for simulating complex systems in fields like ecology, biogeochemistry, economics, and engineering. This MCP server allows AI assistants to:

  • Create models from scratch - Build stock-and-flow diagrams programmatically
  • Read existing models - Parse and understand .stmx files
  • Validate models - Check for errors like undefined variables or missing connections
  • Modify models - Add stocks, flows, auxiliaries, and connectors
  • Save models - Export valid XMILE files that open in Stella Professional

This is particularly useful for:

  • Teaching system dynamics modeling
  • Rapid prototyping of models through natural language
  • Batch creation or modification of models
  • Documenting and explaining existing models

Installation

From PyPI

pip install stella-mcp

From source

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

Requirements

  • Python 3.10+
  • mcp>=1.0.0

Configuration

Claude Desktop

Add to your claude_desktop_config.json:

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

Claude Code

Add to your .claude/settings.json:

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

Development mode

If running from source:

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

Recommended Agent Workflow

For a new model:

  1. create_model with a stable model_id.
  2. Add stocks, flows, and auxiliaries.
  3. Run sync_connectors_from_equations.
  4. Run inspect_model with include_validation=true.
  5. Fix validation errors with update_*, rename_variable, or delete_variable.
  6. Save with save_model.

For imported models:

  1. read_model with compat_mode="permissive" to inspect warnings.
  2. Run inspect_model to understand model structure.
  3. Use compat_mode="strict" before final save when round-trip fidelity matters.

Available Tools

Model Creation & I/O

Tool Description
create_model Create a new model with name and time settings (start, stop, dt, method)
set_sim_specs Update simulation time settings on an existing model
read_model Load an existing .stmx file
save_model Save model to a .stmx file

Templates

Tool Description
list_templates List built-in and user-defined templates (supports source/query/tag filters)
get_template_info Get detailed metadata for one template
load_template Load a template as a model in the current session
save_as_template Save the current model as a reusable user template (optional description/tags)

Model Building

Tool Description
add_stock Add a stock (reservoir) with initial value and units
add_flow Add a flow between stocks with an equation
add_aux Add an auxiliary variable (parameter or calculation)
update_stock Update stock fields while preserving relationships
update_flow Update flow fields while preserving stock links
update_aux Update auxiliary variable fields
add_connector Add a dependency connector between variables
sync_connectors_from_equations Add missing dependency connectors inferred from equations
set_connector_routing Set connector angle and explicit waypoint routing metadata
rename_variable Rename a stock/flow/aux and update references in equations/connectors/modules
delete_variable Delete a stock/flow/aux with consistency checks and cleanup
create_module Create a logical module/group of variables
add_to_module Add variables to an existing module/group
remove_from_module Remove variables from a module/group
rename_module Rename a module/group
delete_module Delete a module/group
set_module_view Set explicit module box position/size on the diagram
set_module_style Set module box style (border/background/font/label side) on the diagram
auto_place_module_boxes Auto-place module boxes around their members

Notes:

  • Tools accept optional model_id so one MCP session can manage multiple models safely.
  • create_model and read_model set the session's current model_id and return it.
  • add_flow and add_aux support optional graphical_function payloads (ypts plus exactly one of xscale or xpts).
  • add_stock/add_flow/add_aux reject duplicate variable names across variable types; add_connector requires both variables to exist.
  • set_connector_routing can target a connector by connector_uid or by from_var + to_var.
  • save_model and get_model_xml accept auto_layout (default true) and resolve_layout_violations (default false).
  • read_model, save_model, and get_model_xml accept compat_mode:
    • permissive (default): continue with warnings
    • strict: fail on compatibility issues
  • set_module_style updates module view styling and persists those attributes in XMILE view <group .../> elements.
  • save_as_template writes user templates to ~/.stella-mcp/templates by default (override via STELLA_MCP_TEMPLATE_DIR) and stores metadata in a .meta.json sidecar.
  • Tool failures return structured MCP errors with error.code, error.category, and error.message.

Model Inspection

Tool Description
list_models List available session model IDs and indicate the current model
inspect_model Return a structured model summary for agent inspection
list_modules List modules/groups in the current model
list_connectors List connector IDs, endpoints, angles, and routing metadata
list_variables List all stocks, flows, and auxiliaries
validate_model Check for errors (undefined variables, missing connections, etc.)
get_model_xml Preview the XMILE XML output

Tool Payload Examples

Create and switch between session models:

{"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":"inspect_model","arguments":{"model_id":"sir_baseline","include_validation":true}}

List and load templates:

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

Save current model as a user template:

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

Create and manage modules:

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

Rename and delete variables safely:

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

Update an existing variable:

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

Infer missing connectors from equations:

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

Set module view geometry directly:

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

Set module view style:

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

Auto-place module boxes from current member positions:

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

Target a specific model in later calls:

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

Read with strict compatibility checks:

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

Preview XML in permissive mode (default) and return compatibility warnings when present:

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

Valid graphical function payload:

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

Invalid graphical function payload (rejected):

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

Example Usage

Creating a simple population model

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

Reading and analyzing an existing model

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...

Building a biogeochemical model

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

Validation

The validate_model tool checks for:

  • Undefined variables - References to variables that don't exist
  • Mass balance issues - Stocks without flows, flows referencing non-existent stocks
  • Missing connections - Equations using variables without connectors (warning)
  • Connector endpoint integrity - Connectors pointing at missing variables (error)
  • Orphan flows - Flows not connected to any stock
  • Circular dependencies - Infinite loops in auxiliary calculations
  • Module integrity - Empty modules (warning) and modules referencing missing members (error)

XMILE Compatibility

  • Output files use the XMILE standard
  • Compatible with Stella Professional 1.9+ and Stella Architect
  • Auto-layout positions elements reasonably; adjust manually in Stella if needed
  • Variable names with spaces are converted to underscores internally
  • Parser normalizes imported stock inflow/outflow and connector endpoint references
  • Time-step export avoids lossy reciprocal rounding (non-exact reciprocals are exported as plain dt)
  • Import/export preserves unknown attrs/elements on supported sections (header, sim_specs, variables, views/model extras) to reduce round-trip data loss
  • Compatibility corpus regression tests live in tests/fixtures/compat_corpus/ and run in CI
  • Maintainer helper: python scripts/sync_compat_corpus_manifest.py --check validates corpus manifest sync

Project Structure

stella-mcp/
├── README.md
├── LICENSE
├── pyproject.toml
└── stella_mcp/
    ├── __init__.py
    ├── server.py      # MCP server wiring + schemas
    ├── tool_handlers.py # Tool handler implementations/registration
    ├── tool_schemas.py  # MCP tool schema definitions
    ├── xmile.py       # Core model types + layout logic
    ├── xmile_io.py    # XMILE parsing/export helpers
    └── 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. Update the version in pyproject.toml and stella_mcp/__init__.py.
  2. Merge the release changes to main.
  3. Create and publish a GitHub release with a matching tag, for example v0.5.0.

The GitHub release event builds the source distribution and wheel, then publishes them to PyPI through the configured trusted publisher.

License

MIT License - see LICENSE for details.

Acknowledgments

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

stella_mcp-0.6.0.tar.gz (84.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

stella_mcp-0.6.0-py3-none-any.whl (65.4 kB view details)

Uploaded Python 3

File details

Details for the file stella_mcp-0.6.0.tar.gz.

File metadata

  • Download URL: stella_mcp-0.6.0.tar.gz
  • Upload date:
  • Size: 84.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for stella_mcp-0.6.0.tar.gz
Algorithm Hash digest
SHA256 2fcb171aa4926304acabc6aaadd3d621341356d12c85d54e3b3056b76184312b
MD5 c8a9062a498ef634a79751e87c6669c4
BLAKE2b-256 8f36ef8ec408f05a65c3b73c20a23c8f0e20a13fc9cb6683476cc5ae552968a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for stella_mcp-0.6.0.tar.gz:

Publisher: publish.yml on bradleylab/stella-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file stella_mcp-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: stella_mcp-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 65.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for stella_mcp-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 04af7007d1016ea7b745c2fa047401157aee356cf85c130c5f5523f089fa2fd0
MD5 835885b07ca30ecedd5190815b98f654
BLAKE2b-256 91cc52e6228408b7425a100b30ca3d350b8168f80290aaba90fae753b3f2f69a

See more details on using hashes here.

Provenance

The following attestation bundles were made for stella_mcp-0.6.0-py3-none-any.whl:

Publisher: publish.yml on bradleylab/stella-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page