Skip to main content

SimConnect MCP Server

PyPI Python License

An MCP (Model Context Protocol) server that connects AI coding agents to Microsoft Flight Simulator via SimConnect. This server is built for add-on development — full read/write access to SimVars, L-vars, events, calculator code execution, and embedded documentation.

What It Does

  • Read/write any SimVar — altitude, heading, speed, autopilot settings, engine parameters, and 1,080+ more from a comprehensive built-in catalog, with unit selection and honest failures on a rejected write
  • Read/write L-vars — aircraft-specific local variables used by add-on developers (Fenix A320, FlyByWire A32NX, PMDG, etc.), including live enumeration of what the loaded aircraft has actually registered
  • PMDG 777 and 737 NG3 native SDK support — direct access to all aircraft data fields and control events via the PMDG SDK Client Data Areas, plus CDU screen reading with colors/formatting
  • Trigger events — toggle switches, set autopilot modes, control lights, fire custom MobiFlight events
  • Execute RPN calculator code — run arbitrary Reverse Polish Notation code directly in the sim
  • Search and discover variables — searchable catalogs of SimVars, events, and aircraft-specific L-vars with human-readable names and valid values
  • Facilities lookup — nearby airports sorted by distance and detail lookup for a specific airport, waypoint, NDB or VOR by ICAO identifier, read directly from SimConnect's facility subscription
  • Flight and scenario tools — load and save .FLT flights, load a .PLN flight plan, and spawn an AI aircraft or object, for scripting test scenarios instead of setting them up by hand
  • Embedded documentation — SimConnect reference docs served as MCP resources, available offline
  • Aircraft-specific catalogs — pre-built variable databases with panel groupings, display names, and value descriptions. Ships with 1,607 PMDG 777 variables (777-200LR/200F/300ER/F) and 1,861 PMDG 737 NG3 variables (-600/700/800/900 incl. BBJ/BDSF/BCF).
  • HubHop integration — search the MobiFlight HubHop community preset database directly as an MCP tool, or use the built-in client to generate and extend L-var catalogs for any supported aircraft

Prerequisites

  • Microsoft Flight Simulator (MSFS 2020 or 2024) running on the same machine
  • uv — provides uvx, which fetches the server and its Python runtime for you
  • MobiFlight WASM Module (optional, for L-var support) — install in your MSFS Community folder. Download from MobiFlight

Installation

Published on PyPI as simconnect-mcp, and listed in the MCP Registry as io.github.robin24/simconnect-mcp.

Once uv is installed, no separate install step is needed — uvx fetches and runs the server on demand:

uvx simconnect-mcp

That starts the server on stdio, which is what an MCP client does for you. Run it by hand only to check that it starts; press Ctrl+C to stop.

To pin a version, use uvx simconnect-mcp@1.0.1.

From source (for development)

git clone https://github.com/robin24/simconnect-mcp.git
cd simconnect-mcp

# Creates the virtual environment and installs the dev group too
uv sync

Configuring as an MCP Server

Claude Code

Via CLI:

claude mcp add --transport stdio simconnect -- uvx simconnect-mcp

Or to make it available across all projects:

claude mcp add --transport stdio --scope user simconnect -- uvx simconnect-mcp

Via JSON (~/.claude/settings.json or project-level .claude/settings.json):

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

OpenAI Codex CLI

Via CLI:

codex mcp add simconnect -- uvx simconnect-mcp

Via JSON:

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

Gemini CLI

Via CLI:

gemini mcp add --transport stdio simconnect -- uvx simconnect-mcp

Via JSON (~/.gemini/settings.json):

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

MCP Inspector (Interactive Testing)

uv run mcp dev src/simconnect_mcp/server.py

Note: To run a local checkout instead of the published package, replace uvx simconnect-mcp with uv run --directory /path/to/simconnect-mcp simconnect-mcp, using the absolute path to your clone.

Tools (32)

Every tool is prefixed msfs_, carries explicit readOnlyHint/destructiveHint annotations, and returns a typed result or a structured error — never a fabricated success. The tables below are generated from the live server (name, kind, and title come straight from each tool's ToolAnnotations); descriptions are the one-line summary from the tool's own docstring:

uv run python -c "
import asyncio
from simconnect_mcp.server import mcp
async def m():
    for t in sorted(await mcp.list_tools(), key=lambda x: x.name):
        kind = 'read' if t.annotations.readOnlyHint else 'write'
        print(f'| \`{t.name}\` | {kind} | {t.annotations.title} |')
asyncio.run(m())"

Connection (3)

Tool Kind Description
msfs_connect write Establish a SimConnect connection to MSFS
msfs_disconnect write Close the SimConnect connection to MSFS
msfs_get_connection_status read Check connection state, whether the sim is running/paused

SimVar Operations (6)

Tool Kind Description
msfs_get_simvar read Read a SimVar value by name, in the requested unit
msfs_set_simvar write Write a value to a settable SimVar — fails honestly rather than reporting success on a rejected write
msfs_get_simvars_bulk read Read several SimVars in one call; one failing entry doesn't abort the rest
msfs_search_simvars read Search the SimVar catalog by keyword
msfs_list_simvar_categories read List every SimVar category with its variable count
msfs_watch_simvar read Sample a SimVar over time, returning a time series for debugging

Units: msfs_get_simvar (and msfs_set_simvar) accept an optional unit argument and always report the unit actually used in the result. Omit unit and the bundled SimVar catalog supplies a sensible default for that variable; for a variable the catalog doesn't know, the default is "number".

Event Operations (3)

Tool Kind Description
msfs_trigger_event write Fire a SimConnect event, with an optional parameter
msfs_search_events read Search SimConnect events by keyword, optionally filtered by category
msfs_trigger_custom_event write Fire a custom event as a key event through the MobiFlight WASM module

L-Var Operations (6)

Tool Kind Description
msfs_get_lvar read Read an L-var (local variable) value from the current aircraft
msfs_set_lvar write Write a value to an L-var on the current aircraft
msfs_list_lvars read Enumerate the L-vars the currently loaded aircraft has registered
msfs_execute_calculator_code write Execute RPN calculator code in the simulator
msfs_search_lvars read Search known aircraft L-vars by keyword across the bundled catalogs
msfs_browse_lvar_catalog read Browse the aircraft L-var catalogs — list catalogs, the panels in one, or the variables on one panel

msfs_list_lvars asks the MobiFlight WASM module to enumerate what the aircraft has actually registered, live — but the module caps its reply at 1000 names and still reports the list as complete when it truncates. A busy add-on setup (GSX and similar) can crowd the aircraft's own variables out of the response entirely; watch for truncated: true. Treat the catalogs and the live listing as a starting point, not a guaranteed inventory — msfs_get_lvar reads any name you supply, whether or not it surfaced in either one.

Aircraft State (1)

Tool Kind Description
msfs_get_aircraft_snapshot read Read a snapshot of the current aircraft state (position, speed, attitude, and key systems in one call)

Facilities (2)

Tool Kind Description
msfs_get_nearby_airports read List airports near a point, nearest first
msfs_get_facility_info read Look up one airport, waypoint, NDB or VOR by ICAO identifier

Airports are world-wide (SimConnect returns the full 85,249-airport list, cached after the first collection). Waypoints, NDBs and VORs are scoped to wherever the aircraft currently is, so they are re-collected on every call rather than cached — a cached navaid list would keep answering for the aircraft's previous position after a reposition or a flight.

Utilities (2)

Tool Kind Description
msfs_send_sim_text write Display a text overlay message in the simulator (debug feedback)
msfs_set_aircraft_position write Reposition the aircraft (test scenario setup)

PMDG 777 / 737 NG3 (3)

Tool Kind Description
msfs_get_pmdg_var read Read a PMDG aircraft data field by name — switches, MCP values, fuel qty, FMC data (777 or 737 NG3)
msfs_get_pmdg_cdu read Read a PMDG CDU screen as text rows with per-cell color and formatting
msfs_send_pmdg_event write Send a PMDG control event — toggle a switch, press a button, set a selector (777 or 737 NG3)

These tools use the PMDG SDK Client Data Areas for direct binary access to the aircraft state — bypassing the MobiFlight L-var bridge. The right SDK (777 or 737 NG3) is auto-detected from the loaded aircraft, or can be forced with the variant argument. Requires EnableDataBroadcast=1 and EnableCDUBroadcast.N=1 in the aircraft's options.ini (777_Options.ini or 737NG3_Options.ini). The 777 has three CDUs (Capt/Center/F-O); the 737 NG3 has two (Capt/F-O). See PMDG 777 SDK Reference and PMDG 737 NG3 SDK Reference for details.

HubHop (2)

Tool Kind Description
msfs_search_hubhop read Search the MobiFlight HubHop community preset database
msfs_list_hubhop_aircraft read List the aircraft that HubHop has presets for

Unlike every other tool, these two reach HubHop's HTTP API rather than the simulator, so they work with MSFS closed. The first call downloads and caches the full preset database (~17 MB); later calls in the same server process are served from that in-memory cache, which both tools share and which re-fetches on its own every 6 hours. Either tool accepts refresh=true to force an immediate re-fetch.

Flight and Scenario (4)

Tool Kind Description
msfs_load_flight write Load a saved flight, replacing the current one
msfs_save_flight write Save the current flight to a .FLT file — refuses to overwrite an existing file unless overwrite=true is passed explicitly
msfs_load_flight_plan write Load a .PLN flight plan into the aircraft's GPS/FMS, replacing whatever plan is currently active
msfs_create_ai_object write Spawn an AI aircraft or object at a position — reports whether SimConnect accepted the request, which is not the same as the object existing (MSFS ignores an unmatched title silently)

These wrap the underlying SimConnect flight/scenario file operations for scripting test setups (e.g. "load this approach", "save the current state", "spawn traffic nearby") rather than driving them by hand in the sim's own UI. msfs_create_ai_object is confirmed live end-to-end — spawned, verified to answer a targeted SimVar request, then removed again — by tests/live/test_live_flight.py. msfs_save_flight was also confirmed live, including the multi-second post-save SimConnect stall documented in CLAUDE.md's Known Sim Behaviours; its own live tests were retired in the 2026-08-29 live-suite trim once that finding was captured there, since what remained (the overwrite-guard logic) is pure Python already covered by tests/test_flight.py's mocks. msfs_load_flight and msfs_load_flight_plan are mock-only by design — see tests/live/test_live_flight.py's module docstring for why. See Running the live tests below.

Variable Catalogs

The server ships with comprehensive variable catalogs for search and discovery, so that AI agents can find the right variable names without guessing.

SimVar Catalog (1,080+ variables)

The built-in SimVar catalog covers all documented MSFS simulation variables across 25 categories:

Category Vars Category Vars
Aircraft Engine 112 Aircraft Avionics 122
Aircraft Fuel 48 Miscellaneous 162
Aircraft Controls 50 Landing Gear 54
Autopilot 39 Flight Instrumentation 45
Aircraft Lights 25 Aircraft Position and Speed 46
Camera 34 Radio Navigation 66
Services 42 Aircraft Electrics 47
Flight Model 11 Aircraft Systems 24
Environment 14 and more...

The catalog is sourced from both the SimConnect Python package and the official MSFS SDK documentation, ensuring complete coverage including camera controls, ground services, circuit breakers, GPS/NAV/COM radios, and flight model variables.

Aircraft L-Var Catalogs

L-var catalogs provide searchable, human-readable databases for specific aircraft add-ons. The server picks one in three steps, and tells you in the result message which step answered — the three carry very different confidence:

  1. Probe the PMDG SDK client data area. Authoritative, and independent of what the aircraft calls itself. This is the step that matters, because PMDG airframes do not identify themselves as PMDG: a real PMDG 737-800 reports TITLE as 737-800 PAX SSW TC, with no vendor name anywhere in it. Matching titles alone never worked for them.
  2. Match title_pattern against TITLE/ATC_MODEL. The fallback, and the only mechanism available to a catalog you supply yourself.
  3. Search every catalog and say so. Results then carry a Catalog column so you can see which aircraft each row belongs to, rather than reading another aircraft's variables as if they were yours.

Pass catalog=<key> to scope a search explicitly, or call msfs_browse_lvar_catalog with no arguments to list the available keys.

The obvious shortcut — broadening title_pattern to 737 — is deliberately not taken. It would match the iFly 737 MAX and Asobo's own 737 just as happily, and hand their users a PMDG catalog for an aircraft that isn't a PMDG. An honest "no catalog detected" beats a confidently wrong one.

Included catalogs:

Aircraft Variables Panels Source
PMDG 777 (all variants) 1,607 28 SDK header parse + HubHop
PMDG 737 NG3 (-600/700/800/900/BBJ/BDSF/BCF) 1,861 27 SDK header parse + HubHop

Each variable includes a display name, category, writability flag, and (where applicable) a map of valid values.

No Fenix catalog ships — a prior fenix_a320.json (1,433 plain L-vars) was removed in favor of HubHop's own broader, community-maintained FenixSim coverage (2,273 presets, current the moment Fenix ships an update, where a bundled snapshot would only go stale). Search it live with msfs_search_hubhop(vendor="FenixSim"), or regenerate a local catalog file with the HubHop client below and drop it into src/simconnect_mcp/data/ — every *.json there is auto-discovered on startup, so it works immediately with no code change.

Adding New Aircraft Catalogs

The fastest way to add a new aircraft is via the built-in HubHop client:

# See what's available
python -m simconnect_mcp.data.hubhop --list-vendors

# Generate a catalog (example: FlyByWire A32NX)
python -m simconnect_mcp.data.hubhop \
    --vendor "FlyByWire Simulations" \
    --aircraft "A320neo" \
    --aircraft-name "FlyByWire A32NX" \
    --title-pattern "A32NX" \
    -o fbw_a32nx.json

Or update an existing one:

python -m simconnect_mcp.data.hubhop --vendor FenixSim --merge fenix_a320.json

You can also use the Python API:

from simconnect_mcp.data.hubhop import HubHopClient

client = HubHopClient()
presets = client.fetch_presets(vendor="FlyByWire Simulations", aircraft="A320neo")
catalog = client.build_catalog(presets, aircraft="FlyByWire A32NX", title_pattern="A32NX")
client.save_catalog(catalog, "fbw_a32nx.json")

Or create catalogs manually by placing a JSON file in src/simconnect_mcp/data/. All *.json files are auto-discovered on startup. See docs/extending-catalogs.md for the full guide, JSON schema, and best practices.

Resources

URI Type Content
simconnect://docs/overview text/markdown SimConnect architecture and key concepts
simconnect://docs/simvars/{category} text/markdown SimVar reference by category
simconnect://docs/events/{category} text/markdown Event reference by category
simconnect://docs/rpn text/markdown RPN calculator syntax guide
simconnect://docs/lvars text/markdown L-var usage for add-on development
simconnect://docs/best-practices text/markdown Common pitfalls and performance tips
simconnect://docs/pmdg/{variant} text/markdown PMDG SDK reference; variant is 777 or 737 (a leading B is accepted, case-insensitive)
simconnect://state/connection application/json Live connection status
simconnect://state/aircraft application/json Current aircraft title, type, and position

Prompts

Prompt Purpose
debug_simvar Step-by-step guide for debugging a misbehaving SimVar
analyze_aircraft_vars Enumerate and categorize all L-vars on current aircraft
create_addon_boilerplate Generate add-on starter code by type
rpn_helper Translate natural language to RPN calculator code
simconnect_code_review Review SimConnect code for common issues

Project Structure

src/simconnect_mcp/
├── server.py              # FastMCP instance, lifespan, tool registration
├── connection.py          # SimConnectManager singleton + native set_lvar
├── dispatch.py            # SimConnectDispatcher — owns the SimConnect dispatch loop
├── simvar_access.py       # SimVarAccessor — generic SimVar reads/writes via data definitions
├── facilities.py          # Facility (*_LIST) message parsing and accumulation
├── pmdg.py                # PMDG 777 SDK structs, CDU rendering, data manager
├── pmdg_ng3.py            # PMDG 737 NG3 SDK structs, CDU rendering, data manager
├── tools/
│   ├── __init__.py        # @handle_simconnect_errors, @require_connection decorators
│   ├── connection_tools.py # connect_to_sim, disconnect_from_sim, get_connection_status
│   ├── simvars.py         # SimVar CRUD via SimVarAccessor (1,080+ vars in the catalog)
│   ├── events.py          # Event trigger/search + built-in catalog
│   ├── lvars.py           # L-var read/write/search/enumerate/browse catalogs/calculator code
│   ├── pmdg.py            # PMDG tools — auto-dispatch to 777 or 737 NG3
│   ├── aircraft.py        # get_aircraft_snapshot — combined state snapshot
│   ├── facilities.py      # Airport/navaid lookup on top of facilities.py
│   ├── flight.py          # load/save flight, load flight plan, spawn AI object
│   ├── hubhop.py          # HubHop preset search, exposed as MCP tools
│   ├── utilities.py       # send_sim_text, set_aircraft_position
│   ├── models.py          # Shared Pydantic result/error models
│   └── formatting.py      # Pagination and markdown-table helpers
├── data/
│   ├── catalog.py         # L-var catalog loader and search engine
│   ├── simvar_catalog.py  # SimVar catalog loader, unit resolution, string-var detection
│   ├── hubhop.py          # MobiFlight HubHop API client (CLI + library), in-memory cache
│   ├── pmdg_777.json      # PMDG 777 catalog (1,607 vars, 28 panels)
│   ├── pmdg_737.json      # PMDG 737 NG3 catalog (1,861 vars, 27 panels)
│   └── simvars_catalog.json  # Built-in SimVar catalog (1,080+ vars, 25 categories)
├── vendor/                # Byte-faithful to upstream except two documented local changes
│   ├── simconnect_mobiflight.py          # unmodified
│   └── mobiflight_variable_requests.py   # log-level demotion + response-channel routing
└── docs/                  # Embedded documentation, served as MCP resources
    ├── overview.md, simvars.md, events.md, rpn.md, lvars.md, best_practices.md
    ├── pmdg_777.md        # PMDG 777 SDK reference
    └── pmdg_737.md        # PMDG 737 NG3 SDK reference

The PMDG catalogs are regenerated from the SDK headers via scripts/parse_pmdg_sdk.py — it auto-detects the struct name and CDU count, so the same script handles both 777 and 737 NG3.

Development

# Run the mocked test suite (no MSFS required; live tests are deselected by default)
uv run pytest

# Run tests with verbose output
uv run pytest -v

# Run only specific test files
uv run pytest tests/test_hubhop.py    # HubHop client tests
uv run pytest tests/test_simvars.py   # SimVar catalog tests

# Lint
uv run ruff check src/ tests/

Tests mock SimConnect so the suite above runs without MSFS. tests/conftest.py provides a mock SimConnect with realistic SimVar values.

Running the Live Tests

A second suite under tests/live/ exercises the real SimConnect DLL and is marked @pytest.mark.live. pyproject.toml deselects it by default (addopts = "-m 'not live'"), so it never runs on a machine without MSFS — including CI.

This suite is deliberately small and stays that way on purpose: a test belongs here only if a self-consistent mock could agree with itself regardless of whether the code is right — for example, a round trip that writes and reads back a single L-var name proves nothing about encoding, because a mangled datum name would make the write and the read-back agree with each other on the wrong variable (see test_two_distinct_lvars_do_not_collide in tests/live/test_live_lvars.py). What's left after that filter is real DLL/DLL-adjacent behaviour a mock can only assume rather than verify: unit conversion against the physical constant, wire-decode of structs whose third-party bindings this project has already caught wrong once, which real SimVars/events actually accept a write versus reject or silently ignore it, undocumented MobiFlight/WASM protocol quirks, and whether a real PMDG's binary client-data area answers a probe the way its struct decode expects.

Where a live finding can instead be frozen into a committed fixture and replayed offline, that's preferred over a live test: tests/fixtures/facilities/ holds real SimConnect wire bytes captured once, replayed by the mocked tests/test_facilities_parsing.py on every run, with no simulator and no flakiness — it pins the same discovery deterministically instead of depending on whatever aircraft happens to be loaded that day.

uv run pytest -m live

Requires MSFS running with an aircraft loaded; a test whose connection attempt fails is skipped rather than failed (see tests/live/conftest.py's live_manager fixture). tests/live/test_live_pmdg.py's tests need a real PMDG 737/777 loaded and skip — rather than fail — when the loaded aircraft doesn't look like one (see that file's gate in tests/live/conftest.py).

License

Copyright (C) 2025-2026 Robin Kipp

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. See LICENSE.txt for the full text.

This project is AGPL-3.0 because it depends on Python-SimConnect, which is itself AGPL-3.0 licensed.

The vendored MobiFlight bridge in src/simconnect_mcp/vendor/ is a separate work, MIT licensed by Koseng — see src/simconnect_mcp/vendor/MOBIFLIGHT_LICENSE.

Download files

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

Source Distribution

simconnect_mcp-1.0.1.tar.gz (590.4 kB view details)

Uploaded Source

Built Distribution

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

simconnect_mcp-1.0.1-py3-none-any.whl (309.3 kB view details)

Uploaded Python 3

File details

Details for the file simconnect_mcp-1.0.1.tar.gz.

File metadata

  • Download URL: simconnect_mcp-1.0.1.tar.gz
  • Upload date:
  • Size: 590.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for simconnect_mcp-1.0.1.tar.gz
Algorithm Hash digest
SHA256 2d00c85540a6bc995fe34866b4ff1243e70a350be9492844652d76054d6e06da
MD5 fa0b02b0529f540020467be2838a401c
BLAKE2b-256 52b8c89627395a680acec14edd58315c720cad97604631cc8c3e381e7007efd8

See more details on using hashes here.

File details

Details for the file simconnect_mcp-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: simconnect_mcp-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 309.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.8 {"installer":{"name":"uv","version":"0.12.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for simconnect_mcp-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1082b5a98f73d1a09f3cdfe1f838790b70a558cd64e27c99a4ecd9ac91d87379
MD5 ae94117b2196a5a02d85f8cce98da01e
BLAKE2b-256 ce48c6eb5480ff455cc97d7f56c76210060e79a2c0f07344bca48b11b170d55e

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 files

1.0.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page