A 100% Private MCP Coding Assistant and Scientific Porting Pipeline
Project description
fortranspire
An LLM + Model Context Protocol pipeline that ports legacy Fortran HPC kernels to GPU (OpenACC) and differentiable JAX.
fortranspire automates the four transformations a senior HPC engineer
would perform by hand when porting a Fortran 90 kernel to GPU and
Python: AST parsing with Loki
(ECMWF), kernel extraction into a MODULE with explicit INTENT,
PURE/ELEMENTAL annotation, OpenACC pragma insertion, and a Cython
wrapper validated by gfortran and nvfortran. The pipeline is
exposed both as a CLI and as an MCP server, so it is callable from
mistral-vibe, Claude Code, Claude Desktop, Cursor, or any MCP-aware
agent — and from CI.
⚡ Quick start with mistral-vibe (60 seconds)
fortranspire ships an MCP server you can plug straight into
mistral-vibe over stdio
— no port, no auth, the inference stays in EU.
uv tool install fortranspire # console script on PATH, isolated venv
brew install mistral-vibe
Find the absolute path of the installed binary — vibe is a brew
subprocess and may not inherit your shell PATH:
which fortranspire # e.g. /Users/you/.local/bin/fortranspire
Then append to ~/.vibe/config.toml:
[[mcp_servers]]
name = "fortranspire"
transport = "stdio"
command = "/Users/you/.local/bin/fortranspire" # paste output of `which`
args = ["mcp", "--stdio"]
[mcp_servers.env]
MISTRAL_API_KEY = "${MISTRAL_API_KEY}"
MISTRAL_ENDPOINT = "https://api.mistral.ai/v1"
MISTRAL_MODEL = "codestral-latest"
Launch vibe in a Fortran project and ask, in plain French or English:
Donne-moi le coût estimé de portage GPU pour
src/common/turb/mode_compute_function_thermo.F90.
In ~2 seconds, vibe calls the fortranspire_explain_port_cost MCP
tool and prints a port-cost table — routines, tokens, USD estimate,
FORT00x risks — with zero LLM tokens consumed by fortranspire.
Full walkthrough (PHYEX kernel triage → call-graph → Phase-1 OpenACC
port) in docs/getting-started/with-mistral-vibe.md.
Why this matters. The codebase stays on disk, Mistral codestral runs in EU, Loki + the deterministic harness absorb 60-70% of the work — the LLM is a fungible component, swappable for Claude or self-hosted vLLM.
What this solves
Legacy scientific HPC codes — IFS at ECMWF, ARPEGE and AROME at Météo-France, PHYEX at CNRM, SURFEX, seismic codes at the major energy research labs — total several million lines of Fortran 90 written between 1990 and 2010. They run on CPU clusters (BullSequana, Cray EX) while the GPU partitions of EuroHPC (LUMI, MareNostrum, Jean Zay) sit underused — not for lack of hardware, but for lack of ported code.
A manual port of one PHYEX-class kernel to GPU takes a senior HPC engineer 2–6 weeks. The skill profile — Fortran 90 + OpenACC + Cython
- numerics — is structurally rare in Europe, and the engineers who wrote these codes are retiring.
fortranspire automates that port: deterministic AST analysis
(Loki) for 60-70% of the work, a small number of targeted LLM calls
for the semantic stages (kernel extraction, OpenACC pragmas, Cython
wrapping). The same toolchain produces JAX-translatable kernels (Phase
2) — opening legacy physics to differentiable training, RL feedback
loops, and surrogate modelling.
Architecture
A six-stage LangGraph state machine. Two stages call the LLM; four are deterministic.
📂 kernel.f90 (monolithic Fortran)
│
▼ 🔍 parser Loki AST — detects INTENT, SAVE, COMMON, loops, I/O
│ Deterministic, no LLM
│
▼ 🔧 extractor LLM (1 call) — refactors PROGRAM into a MODULE of
│ subroutines; removes COMMON, surfaces SAVE as
│ INTENT(INOUT)
│
▼ ✨ pure_elemental AST rules — annotate PURE/ELEMENTAL where legal
│ (no I/O, no SAVE, INTENT explicit)
│
▼ 🚀 openacc LLM (1 call) — !$acc parallel loop collapse(2),
│ !$acc data copyin/copy around the time loop
│
▼ 🐍 cython_wrapper LLM (2 calls) — .pyx + iso_c_binding C header,
│ NumPy typed memoryviews
│
▼ ✅ validation gfortran × 2 flavours + nvfortran -acc
│ Deterministic, compilation only
│
📦 output/fortran_gpu/*.f90 + output/cython/*.pyx
Four LLM calls maximum per kernel (~2 min wall-clock, ~$0.06 at
codestral tariffs). See
docs/concepts/architecture.md for
the activation-order rationale and worked examples.
Installation
From PyPI (recommended)
uv tool install fortranspire # console script, isolated venv
# or, inside a project venv:
uv pip install fortranspire # core + Loki (via loki-ifs)
uv pip install "fortranspire[gpu]" # Phase 1 (LangChain + Cython)
uv pip install "fortranspire[mcp]" # MCP server
uv pip install "fortranspire[all]" # Phase 1 + Phase 2 + MCP
About Loki. ECMWF Loki is not published on PyPI under its original name (the slot is taken by an unrelated astronomy package). We maintain a redistribution under the name
loki-ifs, trackingecmwf-ifs/loki@0.3.7. The Python import name is stillfrom loki import …—loki-ifsis the PyPI distribution name only.
From source
git clone https://github.com/maurinl26/fortranspire
cd fortranspire
cp .env.example .env
uv sync --extra all
Connect to a Mistral endpoint
# .env
MISTRAL_ENDPOINT="https://api.mistral.ai/v1"
MISTRAL_API_KEY="<your-key-from-console.mistral.ai>"
MISTRAL_MODEL="codestral-latest" # default for code-gen stages
For self-hosted inference (vLLM / TGI / Ollama / Scaleway Generative
APIs / OVHcloud AI Endpoints), point MISTRAL_ENDPOINT at your
OpenAI-compatible server — see
docs/concepts/llm-endpoints.md.
CLI usage
fortranspire analyze src/ # Loki AST audit — no LLM, CI-friendly
fortranspire explain src/kernel.f90 # Pre-flight cost & risk estimate
fortranspire graph -o graph.md src/ # Mermaid call-graph
fortranspire doc --no-llm src/ # Inject !> docstring placeholders
fortranspire gpu src/kernel.f90 # Phase 1 — Fortran → OpenACC + Cython
fortranspire translate src/kernel.f90 # Phase 2 — Fortran → JAX (experimental)
fortranspire mcp --stdio # MCP server, stdio transport
fortranspire mcp # MCP server, SSE on $MCP_HOST:$MCP_PORT
Always call explain before a paid gpu/translate — it tells you
whether the file is portable and what a full port would cost in
tokens. Zero LLM tokens are consumed by explain, analyze, graph,
or doc --no-llm.
IDE integrations
mistral-vibe
See the quick start above, or the full walkthrough covering stdio config, HTTP/SSE deployment for permanent service, and the PHYEX demo.
Claude Code
A turnkey skill is shipped at
skills/claude-code/fortranspire/.
Copy it into your project's .claude/skills/ and the /fortranspire
slash command appears in Claude Code. The skill instructs Claude to
always run explain first.
For MCP-based use (rather than skill-based), register the same stdio server:
claude mcp add fortranspire --scope user \
-e MISTRAL_API_KEY=$MISTRAL_API_KEY \
-e MISTRAL_ENDPOINT=https://api.mistral.ai/v1 \
-e MISTRAL_MODEL=codestral-latest \
-- $(which fortranspire) mcp --stdio
See docs/integrations/claude-code.md.
MCP tool surface
Nine tools exposed by the server:
| Tool | Purpose | LLM call? |
|---|---|---|
analyze_kernels |
Loki AST analysis, optional SARIF output | No |
explain_port_cost |
Pre-flight cost & risk estimate | No |
build_call_graph |
Mermaid call-graph | No |
generate_docs |
!> docstring injection (no-LLM or LLM-driven) |
Optional |
translate_kernel_gpu |
Phase 1 — Fortran → OpenACC + Cython | Yes |
translate_kernel |
Phase 2 — Fortran → JAX (experimental) | Yes |
profile_kernels |
Performance benchmarking | No |
ask_agent |
Natural-language query against the codebase | Yes |
agent_status |
Dump server config | No |
Fortran patterns handled
Eleven recurring patterns from production seismic and atmospheric
codes are documented in
docs/concepts/fortran-patterns.md:
INTENT, COMMON, SAVE, POINTER, AoS → SoA + collapse,
stencil-vs-recurrence dependencies, ELEMENTAL + !$acc routine seq,
explicit KIND types, LOGICAL PARAMETER flags → #ifdef, MPI halo
exchange → GHEX (Phase 3), and Fortran I/O → xarray/zarr + DLPack
(Phase 4).
If you hit a pattern not on that list, please open an issue with a minimal reproducer — adding a new pattern is usually a one-stage change plus a fixture.
Roadmap
The strategic roadmap, technical phases, and deployment surfaces are tracked in ROADMAP.md. Quick view:
| Phase | Target | Status |
|---|---|---|
| 1 — OpenACC + Cython | Fortran → GPU + Python wrapper | Shipped (0.1.0) |
| 1.5 — OpenMP target | Multi-vendor pragmas (gfortran 13+, nvfortran, ifx) | Shipped (0.1.0) |
| 1.6 — GT4Py.next | Python cartesian + unstructured DSL (FVM / ICON) | Scoped — #42 |
| 2 — JAX | Differentiable functional kernels | Partial (0.2.x) |
| 3 — GHEX | GPU-to-GPU MPI communications | Future |
| 4 — Modern I/O | xarray / zarr cloud-native | Future |
| 5 — Neural surrogates | FNO operators trained on GPU outputs | Future |
Work in progress is tracked publicly on the issue tracker.
Documentation, citation, contribution
- Documentation: fortranspire.readthedocs.io (Sphinx)
- JOSS paper draft:
paper.md— build via thedraft-paperGitHub Action - Citation: see
CITATION.cff/codemeta.json/.zenodo.json. Once a DOI is assigned, the badge above will resolve. - Contributing:
CONTRIBUTING.md— testing, PR conventions, pattern-fixture format. - Code of conduct:
CODE_OF_CONDUCT.md— Contributor Covenant 2.1.
Beta testers welcome. If you maintain a Fortran legacy code (weather,
seismic, CFD, plasma) and a .f90 file breaks the pipeline, please
open an issue with the file attached — adding fixture-driven coverage
is the fastest path to making the pipeline more robust.
Contact
Loïc Maurin — External Lecturer, École Nationale de la Météorologie, Toulouse — ORCID 0009-0004-8117-4850.
Email: maurin.loic.ac@gmail.com — for collaborations, JOSS-related questions, custom HPC porting missions on legacy Fortran codes, or self-hosted deployment assistance.
License
Apache 2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fortranspire-0.2.0.tar.gz.
File metadata
- Download URL: fortranspire-0.2.0.tar.gz
- Upload date:
- Size: 499.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e997b9122e6395dad896ce1ea568b6118ebb3eebfa273cf7ceb864d882e5f58
|
|
| MD5 |
42d4385d876f5bd5c61dacc882ca1e94
|
|
| BLAKE2b-256 |
99d9582c47a898ba3ac9bbd494ee03b0dcd1b6b49eedc8a7da65eb71ce2c6f6b
|
File details
Details for the file fortranspire-0.2.0-py3-none-any.whl.
File metadata
- Download URL: fortranspire-0.2.0-py3-none-any.whl
- Upload date:
- Size: 170.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1093872fbfa7693bc0994e6b62129c2494168358c37af394db5a6626fe3bfe5
|
|
| MD5 |
8aa21d861f054be0014bf0287f6d64ea
|
|
| BLAKE2b-256 |
d579309769ea64a4f075857a51cf1ed8b1345ec719100c0200520f56735cb8f9
|