casino-mcp
This server is an MCP control plane for running, monitoring, stopping, and analyzing CASINO quantum Monte Carlo calculations without dumping raw output into a model's context.
Start calculations:
casino_runlaunches a CASINO job in a given workdir with configurable MPI process count, binary flavour (opt/debug), restart, resume, and stale-lock unlock.Prepare new calculations:
casino_preparecopies a calculation directory, rewrites/creates theinputfor a target runtype, applies keyword overrides, and writes blank Jastrow factors, backflow functions, or geminal wave-function files for first runs.Check job status:
casino_statusreports running/finished/failed/stopped state, PID, runtime, and exit code for a job.Read physics results:
casino_resultsparsesoutinto structured phases with energies, error bars, variance, per-block numbers, and file/line provenance; it can also readdmc.statusfor still-running DMC runs.List known jobs:
casino_list_jobsreturns all tracked jobs, newest first, with current states.Stop and make continuable:
casino_stopsends SIGTERM to the job's processes, then runshaltqmc -f -uso the directory can be resumed later.Wait for completion: via
casino_wait(shown in README) you can block until a job ends and get final status.Inspect the input actually used:
casino_inputretrieves keywords and%blocks, includingrandom_seed, for a job or prepared directory.Command-line interface: the same operations are available through
casino-mcp run/status/wait/stop/jobs/results/prepare/input/parse/servefor scripting and debugging.
casino-mcp
An MCP control plane over the Fortran CASINO quantum Monte
Carlo code: write the input for the next calculation — and the blank Jastrow factor, backflow
function and geminal wave function for the first one — start it, know what is running, stop it, and read the
result as structured data instead of shipping 4000 lines of text into a model's context,
including from a DMC run that is still going, which has no energy in out at all until its
last block.
Beta (0.6.0). Everything below is tested against a real CASINO: the recipes against
runqmc's own input check, and every file the wave function writer produces against a CASINO test run. Interfaces may still move before 1.0.
What it is, and what it is not
CASINO already has the primitives — opt_plan, runqmc --auto-continue, multirun,
envmc, make_E_v_dt. What it has no place for is the layer between them: machine-readable
results, a memory of what was run, and the judgement calls that sit between the steps
("has the variance plateaued?", "is this timestep still in the linear regime?"). That layer
is what this package is, and three rules keep it honest:
No number is produced by the model. Every value a tool returns is read from a file and carries the line it came from. What CASINO did not print comes back as
nullwith a reason, never a guess.Every result is reproducible from its record. A job record freezes the command, the process count, and the path, size and mtime of the
casinobinary that ran.Nothing destructive is implicit. A run refuses to start in a directory that already holds results, and refuses harder when that
outis committed reference data.
There is deliberately no execute_shell(command) tool. Every tool is a named CASINO
operation with typed arguments.
Related MCP server: AutoDL MCP Server
Install
pip install casino-mcp # needs Python 3.11+ and a working CASINO installationFrom a checkout:
pip install -e '.[dev]'The package does not bundle, build or replace CASINO. It drives runqmc, which stays the
runtime: arch detection, MPI variants, batch-queue submission and the lock file are its job,
not ours.
Register it with Claude Code
.mcp.json, project scope:
{
"mcpServers": {
"casino": {
"command": "casino-mcp",
"args": ["serve"],
"env": {
"CASINO_HOME": "/home/you/bin/CASINO",
"CASINO_ARCH": "linuxpc-gcc-parallel.openblas"
}
}
}
}Tools
tool | returns |
| job_id, pid, workdir, command, binary stamp, what |
| running / finished / failed / stopped / unknown, pid, runtime, exit code |
| the same, once the calculation has ended — plus |
| what was signalled, final status, what |
| every known job, newest first; |
| the physics: phases, energies, error bars, variance, acceptance, correlation time, efficiency, per-block numbers — each with the file and line it was read from; |
| the keywords and |
| a new calculation directory with the |
casino_results and casino_input answer different questions on purpose: what a run did
against what it was told to do. The keywords in a result are CASINO's own echo, which is
neither the file nor a superset of it — it holds every default CASINO applied, 70 entries
against the 23 a file typically sets, and drops what it does not print, random_seed among
them. casino_input also reads a directory nothing has run in, which is how a prepared
calculation is checked before there is a job to name it by, and keeps the input a stopped job
was started from, since haltqmc -u rewrites that file in place.
fields is what a scan wants from casino_results: a whole parsed run is 10–16 kB of JSON,
and 38 directories' worth of it is 600 kB to say six numbers a point. A path is written in the
run's own keys — vmc, opt, dmc_equil, dmc_stats mean the last phase of that kind,
opt[3] the cycle CASINO itself numbered, phases[-1] a position, and anything else is a key:
keywords.DTVMC, cpu_time, vmc.energy.error. A path that does not exist comes back in
problems naming what is there instead; a path that exists but holds a number CASINO never
printed comes back as null with its reason. keywords.DTVMC against vmc.dtvmc is the pair
worth asking for together — the step the input asked for against the step the run used.
Every job_id above is either the id casino_run returned or the calculation directory,
which is what a chain of runs actually holds: the registry knows which job ran where, so
nothing has to be written into the calculation directory to record it.
The runtype (vmc, vmc_opt, vmc_dmc, …) comes from the input file in workdir; there
is no tool per runtype, because that multiplies the surface without adding a capability.
What casino_prepare adds is the other half of that: it writes the input, filling in the
keywords a runtype requires and the source directory does not set, and refusing to write one
that CASINO would reject.
Starting a chain: the blank wave function
The first calculation of a chain comes out of an orbital code with a wave function file and
nothing else, and use_jastrow : T needs a correlation.data that does not exist yet. No
CASINO utility writes one — the manual's own instruction is to copy an example and delete its
numbers by hand — so casino_prepare(..., jastrow=['u', 'chi', 'f'], backflow=['eta', 'mu', 'phi']) writes it, both blocks in the one file:
the atoms come from the orbital file's own header, because
inputsays how many electrons there are and never how many nuclei; one set per element, every atom labelled;which atoms are pseudo-atoms comes from the
*_pp.datafiles, each of which states its own atomic number. In the Jastrow that decides where the chi cusp is refused, because CASINO errstops on it; in the backflow it decides the cusp type of every mu and phi set, which CASINO believes without checking — 1 for a bare nucleus, 0 behind a pseudopotential;every coefficient starts at zero, which is what the first optimisation cycle is for;
the cutoffs are written as zero, which CASINO reads as use your own default: 2 or 5 a.u. for u, 4 for chi, 3 for f, 4.5 for mu and phi, and 1 or 4 for eta depending on whether the channel carries the e-e cusp.
warningssays which values that will be. No AE CUTOFFS block is written either — it is optional, and CASINO picks those lengths itself.
jastrow_settings overrides any of the shape, for both blocks: trunc_order,
bf_trunc_order, n_u, n_chi, n_f_en, n_f_ee, n_eta, n_mu, n_phi_en, n_phi_ee,
every spin_dep_*, cusp_chi, irrotational, every cutoff_*, and cusp_bf for the rare
all-electron orbital set that does not satisfy the cusp condition. Finite systems so far: a
periodic Jastrow wants a P term, whose stars of reciprocal lattice vectors come from CASINO's
own make_p_stars.
A block is written only if the input turns its keyword on, and a keyword that is on with no
block is refused rather than left for CASINO to errstop over — the two halves of the same
mistake.
The geminal wave function
psi_s : geminal replaces the Slater determinant with a sum of geminal determinants — the
electrons are paired by Φ(r,r′) = Σ g_mk φ_m(r) φ_k(r′) instead of put in orbitals — and
every parameter of it lives in the GEMINAL block of a parameters.casl. CASINO ships no
utility that writes one either, so casino_prepare(..., geminal=[...]) does:
casino_prepare('./hf', './gem', geminal=[]) # the Hartree-Fock geminal alone
casino_prepare(
'./hf',
'./gem',
geminal=['p:2', 'd:1'], # ... and a correlating one over
geminal_settings={'anchors': [1]},
) # the first two p and first d levelsgeminal=[]is the Hartree-Fock determinant, exactly.g_m,m = 1over the doubly occupied orbitals and oneu_m,kper singly occupied one; the manual recommends it as the check to make before correlating anything, andtests/integration/test_geminal_casl.pymakes it — a VMC run over it has to land on the energy the same system gives withpsi_s : slater. Being channel-less it reads no orbital file and works for any basis.A channel is a degenerate level, not an orbital.
p:2means the first two p levels of the orbital file, and the whole of each is tied together inConstraints, component by component — a correlating geminal built out of one component of a level is not spherically symmetric, and optimizing it breaks the symmetry of the state it describes. The levels are read off the orbital coefficients ofgwfn.data, so a channel needs a gaussian basis.A level whose orbitals are not one clean m-component each is demoted, not guessed at. It gets a diagonal-only tie and a line in
warningssaying so, because component-wise off-diagonal ties between two levels that are mixed differently constrain orbitals that are not each other's counterparts.The unpaired columns are not optional. An open shell needs one
u_m,kin every geminal with a non-zeroc, since an empty unpaired column makes the geminal matrix singular at every configuration — CASINO'scheck_umaterrstops on it — and they are written fixed, becauseparse_umat_elrefuses an optimizable one.
geminal_settings holds the rest: seed and seed2 (−0.05 and −0.02, the two leading
correlating diagonals, which start away from zero because a geminal holding only its anchors
is singular and has no gradient to move it), anchors (derived — every occupied orbital no
correlated level holds — unless given), mirror (a third geminal with c = -1, tied to the
second parameter for parameter), and purity.
Reading a DMC run before it ends
A DMC calculation runs for hours and has no energy in out until the last block: CASINO
writes the mixed estimators once, at the end. Until then the current estimate lives in
dmc.status, which it rewrites after every statistics block and deletes when the run
finishes — copying the same text into out at that moment, so nothing is lost, but nothing is
available either while it matters most.
casino_results reads that file when it is there, and points result at it. So a running job
answers with the estimate as of its last block, and never with the VMC energy of the
configuration-generation phase — which is the trial wave function's, not the calculation's. A
run stopped by casino_stop keeps its dmc.status, so the last estimate it reached survives
the stop; a run still equilibrating has none, and result says so rather than reaching for an
earlier phase.
Starting, stopping and continuing a calculation all go through CASINO's own scripts, and only
through them: runqmc starts, haltqmc ends and tidies, runqmc --continue or a plain
runqmc over the input that haltqmc -u rewrote carries on. Nothing here moves a config
file, edits an input, or decides what a half-finished calculation should do next.
A directory that already holds an out
runqmc appends to out, vmc.hist and dmc.hist rather than replacing them, so running
twice in one directory produces files that are two runs glued together. That is refused by
default, and there are two ways past it — opposites, so pass one:
| delete what the earlier run left and start over. |
| carry the interrupted run on from where it stopped. Which of CASINO's two continuation routes that takes is read out of |
On the command line these are --restart and --resume, and --continue is accepted for
the latter, which is what runqmc calls it. The tool parameter cannot be spelled that way:
continue is a Python keyword.
One machine, one run at a time
A second run is refused while a job this server started is still going. Not because the
machine is busy — because of what sharing it does to the numbers. Two CASINO runs land on the
cores the scheduler gives them, and Total CASINO CPU time counts seconds of CPU across the
MPI processes: two jobs that ended up on the same core measured 97.2 s of CPU against
194.41 s of real time, and efficiency, which is computed from the CPU time, was wrong by
the same factor. Nothing in the output says this happened. The ratio of cpu_time to
real_time does, which is one casino_results(fields=['cpu_time', 'real_time']).
another job of this server is running | refused; |
a job of this server is running in this directory | refused, and nothing overrides it. One directory is one calculation. Stop it with |
Only jobs this server started are known here. A pgrep casino over the machine is
deliberately not done: someone else's process is someone else's business, and "something is
computing" with no owner and no job id is a refusal the caller has nothing to answer with. So
the reading afterwards is not a backstop but the check that actually holds — a run started
around the server spoils the timings just the same, and the registry never sees it.
Rerunning a directory without losing the last answer
restart deletes out, and with it what the previous run found. keep_previous moves it to
the first free out.1, out.2, … instead; the rest of what restart deletes goes as before,
and the reply says where the file went, under kept. The numbering ends up being the order
the runs happened in.
The archives are deliberately not in the list of things restart deletes, and they are
not called out_part.N — that name is runqmc's own, for the finished segments of a
--continue, and it is in that list.
The half that matters is in the registry rather than in the directory. A job record holds a
directory, not a file, so before this a casino_results for the earlier job read whatever
out was in the directory now — and answered under the earlier job's id, with its status and
its start time, and nothing in the reply saying the physics belonged to the run after it. The
record follows the file, so each job goes on answering with its own numbers:
first = casino_run(workdir='calc')['job_id'] # writes calc/out
second = casino_run(workdir='calc', restart=True, keep_previous=True) # out -> out.1
casino_results(first)['cpu_time'] # from calc/out.1
casino_results(second)['cpu_time'] # from calc/out
casino_results('calc')['cpu_time'] # a directory still means its newest runThe alternative is a fresh directory through casino_prepare, which copies the wave function
too — for a blip calculation, a bwfn.data of hundreds of megabytes to keep a text file of
ten kilobytes.
Stopping a run, and continuing it
casino_stop sends SIGTERM to that job's casino processes and to nothing else — the same
signal haltqmc -k sends, except that haltqmc's is a pkill -x casino over the whole
account, which would take down every other job on the machine. mpirun puts each rank in a
process group of its own, so the ranks are found by session id: the session is the launcher's,
and the whole tree shares it. runqmc itself is left alive to finish its epilogue, and only a
job still running after timeout has its process group signalled and then killed.
Then the directory goes to haltqmc -f -u, which is the part that makes a stopped run
continuable: config.out becomes config.in, the lock and marker files go, and input is
rewritten for the work that is left — newrun : F, the finished blocks subtracted, the
runtype moved on to the next stage. The reply carries what it did under halt. The input
as it was before that is copied into the job directory, and halt.input_saved says where.
Which continuation route resume=true then takes is decided by the last run in out:
|
|
no such block | a plain |
the run reached its own end | refused: there is nothing to continue. |
restart=true is refused on a directory whose input says newrun : F, because restarting
deletes the config.in that CASINO then demands. Put back the saved input first.
Command line
The same runtime without a model in the loop — which is also how you debug the server:
casino-mcp config # the resolved configuration, and the files it came from
casino-mcp run ./calc -p 4 # start a calculation
casino-mcp run ./calc --restart # ... after deleting what an earlier run left there
casino-mcp run ./calc --continue # ... or carrying that run on instead
casino-mcp status 20260823-164511-qobn
casino-mcp status ./calc # every job argument takes a directory: its newest job
casino-mcp wait ./calc # block until that calculation ends
casino-mcp stop 20260823-164511-qobn # stop the run, then hand the directory to haltqmc
casino-mcp jobs # the registry, newest first
casino-mcp jobs -C ./calc # ... or only what ran in one directory
casino-mcp results 20260823-164511-qobn # the physics of that job, live runs included
casino-mcp prepare ./vmc ./dmc --runtype vmc_dmc -s dtdmc=0.005 # the next calculation
casino-mcp prepare ./hf ./opt --runtype vmc_opt --jastrow u,chi,f # ... and the first one
casino-mcp prepare ./hf ./bf --jastrow --backflow -s backflow=T # ... with backflow in it
casino-mcp prepare ./hf ./gem --geminal p:2,d:1 -g anchors=1 # ... as a geminal wave function
casino-mcp input ./calc # the keywords it was given, random_seed included
casino-mcp parse ./calc # the `out` file as JSON
casino-mcp serve # the MCP server on stdioEvery subcommand prints JSON and exits non-zero when that JSON carries an error.
Configuration
There is no configuration file. An MCP server is configured where it is registered — the
env block of the .mcp.json above — and CASINO's own variables keep their names, so
setting them once configures both layers:
variable | |
| root of the CASINO installation (default |
| build target, the directory under |
| explicit path to |
| explicit path to |
| the job registry; otherwise |
| directories no run may ever touch, |
Everything else — one MPI process, the opt binary, twenty seconds for a stopped job to end
on its own, a minute for haltqmc to tidy, two hundred job records kept — is a constant in
settings.py. casino-mcp config
prints what the server would use right now and which variable said so; run it first when a
tool call refuses.
CASINO_MCP_FORBID is the one guard with no per-call override. restart=true/resume=true
and unlock=true unlock the other two; a directory listed here cannot be run in at all, which
is what makes it the right place for a tree of committed reference calculations.
How it works
Claude Code ──stdio──> server.py ──spawn──> launcher.py ──> runqmc ──> mpirun ──> casino
│ │
│ └─ writes status.json (exit code, end time)
└─ reads/writes jobs.json + one directory per jobState lives outside the calculation, under $XDG_STATE_HOME/casino-mcp/:
jobs.json index: job_id -> record
jobs/<job_id>/meta.json what was launched, frozen at spawn
jobs/<job_id>/status.json written by the launcher when the run ends
jobs/<job_id>/runqmc.log runqmc's own output (not CASINO's `out`)
jobs/<job_id>/input.before_halt the input as it was, kept when a stop rewrites itThe calculation directory only ever gets what CASINO puts there.
Why a launcher process. runqmc is a bash script that execs mpirun -np N casino;
signalling its pid orphans the tree. The launcher runs in its own session, which is what makes
the tree identifiable — killpg reaches runqmc and mpirun, and the session id finds the ranks
that mpirun put in process groups of their own — its exit code survives the MCP server being
restarted, and runqmc's output goes to a log instead of the JSON-RPC stream. A recycled pid
cannot pass for a live job: /proc/<pid> start time is compared, and a zombie does not count
as running.
The out parser
parse_out is a plain function with no MCP and no dependencies. An out file is a sequence
of phases, not one result — vmc_opt writes a VMC and an OPTIMIZATION phase per cycle,
vmc_dmc writes VMC, DMC equilibration and DMC statistics accumulation — so it returns
phases, and result points at the last phase that carries an energy.
from casino_mcp.parse_out import parse_out
parsed = parse_out('./calc')
parsed['result']['energy'] # {'value': -2.861829862553, 'error': 0.000659077167, 'line': 237}The one derived number in it is the sample-variance error of a single-block run, which CASINO
does not print; it is taken from the one block exactly as envmc does, and labelled
derived. Nothing shells out to envmc or endmc at runtime — endmc misparses numbers
under a non-C locale.
parse_dmc_status reads the dmc.status of a run that has not finished, through the same
parser: write_dmc_status in CASINO's dmc.f90 writes that file and the out section from
one place, so reading them with two would be one more thing to keep in step. parse_out picks
it up on its own when the file is next to the out it was given.
The input writer
input_file is the same shape in the other direction: text in, text out, no MCP.
from casino_mcp import input_file
current = input_file.read('./vmc')
filled, missing = input_file.recipe('vmc_dmc', {'dtdmc': '0.02083'}, present=current['keywords'])
text = input_file.apply(current['text'], filled) # edits; it does not regenerate
input_file.check(*input_file.parse_text(text)) # [] when CASINO would take itapply only touches the lines it is named for, so hand comments, %blocks and expert
keywords no recipe has heard of all survive a rewrite — a calculation's input is a document,
and the parts nobody can reconstruct are exactly the parts a template would drop. build
writes a whole file from a recipe for callers that have no source to start from.
The recipes and the rules come from runqmc's own checks rather than from reading the manual,
and tests/integration/test_recipes_check_only.py puts every one of them back to
runqmc --check-only: a recipe is right when CASINO says the input is runnable, not when our
own check does.
The correlation.data writer
correlation_data is the same shape again, and the layer under the jastrow and backflow
arguments above:
from casino_mcp import correlation_data
geometry = correlation_data.read_geometry('./hf/gwfn.data') # atoms, not orbitals
pseudo = correlation_data.pseudo_species('./hf') # {8}, out of o_pp.data
problems = correlation_data.check(geometry, terms=('u', 'chi', 'f'), backflow=('eta', 'mu', 'phi'))
text = correlation_data.blank(geometry, backflow=('eta', 'mu', 'phi'), pseudo=pseudo)Every label and every line of it is CASINO's own: the unit suite strips the numbers out of two
committed files — an optimised Jastrow and a hand-written blank backflow — and asserts that what
is left is exactly what this writes for the same atoms. runqmc --check-only is no oracle here,
it never opens the file, so tests/integration/test_blank_correlation.py uses testrun : T,
which makes CASINO read the input files, impose the cusp, no-duplication and no-cusp
constraints, count what is left free, check that they hold, and stop. That is also how the one
rule nobody could read off the source was found: an all-electron phi set with N_eN = 1 has
no free parameters left, whatever N_ee is, while a pseudo-atom set at the same order is fine.
The parameters.casl writer
geminal is the third writer of the same shape, and the layer under the geminal argument
above:
from casino_mcp import geminal
orbitals = geminal.read_orbitals('./hf/gwfn.data') # orbitals, not atoms
levels = geminal.mo_levels(orbitals) # {1: [([3, 5, 4], True), ...], ...}
shells, diagonal, problems, notes = geminal.select(levels, [(1, 2)]) # the first two p levels
text = geminal.geminal_section([1, 2], [], [1], shells, diagonal)CASL is not YAML — a constraint line reads 2^g_5,5=2^g_4,4, which is a bare scalar no YAML
parser accepts — so the block is generated as plain text. Each MO is classified by the
(l, m-slot) its coefficients live on, after the solid-harmonic constants CASINO premultiplies
into d coefficients (and, per molden2qmc.py, not into f and g ones) are divided back out;
MOs of the same l are grouped into levels of 2l+1 in file order.
The oracle is again the committed examples plus a testrun : T CASINO: the unit suite asserts
that what this writes for the geminal calculations under examples/ declares the same
parameters and imposes the same constraint groups as their hand-written parameters.casl, and
tests/integration/test_geminal_casl.py puts the files to CASINO itself, which parses the
block, resolves the constraint groups, checks them for contradictions and calls check_umat
before it stops.
Tests
pytest # 337 tests, ~6 s, no CASINO neededThe unit suite runs anywhere: the parser is checked field by field against five real out
files under tests/data/ — each with the input that produced it — and over all eighteen
calculations under examples/, while the launcher, the process group and the guardrails are
exercised against a fake runqmc shell script.
pytest -m integrationThe integration suite needs a real CASINO, but nothing outside this repository. It checks
parse_out against CASINO's own envmc over every out in examples/, puts every input
recipe to runqmc --check-only and every blank correlation.data and parameters.casl to a
testrun : T CASINO, re-runs the whole tree against the installed binary, and drives the
server over real stdio MCP, running and stopping actual VMC calculations.
examples/ holds eighteen calculations chosen as a cover of the settings CASINO can be run
with — every runtype, basis type, optimiser and wavefunction option appears at least once, and
so do the two files a parser gets wrong quietly: a run that never printed an energy, and one
interrupted between optimisation cycles. examples/README.md says what each is there for.
They are short and seeded, so the tree doubles as a check on CASINO itself: re-run it on a new
release and any line the parser reads that has been renamed or dropped is named, rather than
silently becoming a None. Only that is asserted — moved numbers are reported for a person to
judge.
python tools/refresh_examples.py --nproc 4 # run the tree, report, touch nothing
python tools/refresh_examples.py --nproc 4 --write # adopt the new outputtools/protocol_dump.py speaks the JSON-RPC by hand with no SDK and prints every line in
both directions. Read it before adding a tool.
Licence
Apache-2.0 — see LICENSE.
Available Tools
6 toolscasino_list_jobsC
Every known job, newest first, with its current state.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden, but it does not state whether the operation is read-only or requires authentication. More importantly, it claims 'Every known job' while the schema shows a default limit of 20, suggesting the list is limited and not actually every job. This creates a transparency gap about the tool's real behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, compact sentence with no wasted words. It front-loads the core subject ('Every known job') and delivers the key dimensions (order and state) efficiently. For a simple list tool, this is an ideal length and structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is incomplete for a tool with no annotations and an underspecified schema. It does not explain the limit parameter's effect, the read-only nature, or when to use it relative to siblings. Although an output schema exists, key operational context is missing, leaving an agent uncertain about how to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, 'limit', has zero schema description coverage, and the description does not mention it at all. The description's phrase 'Every known job' actively obscures the fact that the limit parameter controls how many jobs are returned. The description provides no semantic help for the parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly indicates that the tool lists all known jobs with their current state, newest first. It implies a listing operation and distinguishes itself from siblings like casino_status or casino_results by covering all jobs rather than a specific one. It lacks a direct verb like 'list', but the intended purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided about when to use this tool versus the sibling tools. There is no mention of use cases, exclusions, or alternatives such as casino_status for a single job's status. The description only states what the tool does, not when to choose it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
casino_prepareA
Copy a calculation into a new directory and write the input for the next run in it.
This is how a calculation becomes the next one: optimise a wave function, then prepare a
vmc_dmc directory beside it; halve the timestep into another; change the target weight
into a third. A copy rather than an edit, because a number whose input was overwritten in
place can no longer be reproduced, and because casino_run refuses a directory that already
holds a run -- rightly.
What is copied is what a calculation is given and never what a run produced: input, the
orbital file, correlation.data, parameters.casl, the pseudopotentials, and config.in
(which a dmc-only or opt runtype reads as an input). Not out, not the .hist files, not
config.out. A symlinked orbital file is copied by content, so the new directory stands on
its own.
runtype: the runtype the new directory is for -- vmc, vmc_opt, opt, vmc_dmc, vmc_dmc_equil,
dmc_dmc, dmc_equil, dmc_stats. Every keyword that runtype needs and the source input
does not set is filled from a working default; every keyword the source does set is
kept, so the electron count, the basis and any hand tuning survive. Leave it empty to
keep the source's runtype and only apply overrides.
overrides: keywords to set, as {name: value}, and they win over both the source and the
defaults. A null value deletes the keyword; a value containing newlines is written as a
%block (that is how opt_plan and npcell are set). Values are written verbatim, so
booleans are 'T' and 'F' as CASINO spells them.
jastrow: the terms of a blank Jastrow factor to write into the new directory -- ['u', 'chi',
'f'] for the usual one, ['u'] for a system with no atoms. This is for the first
calculation of a chain, the one whose directory holds an orbital file and nothing else:
use_jastrow : T needs a correlation.data, no CASINO utility writes one, and the
manual's own instruction is to copy an example and delete its numbers by hand. Every
coefficient starts at zero, which is what the first optimisation cycle is for. Leave it
unset when the source already has a correlation.data; asking for both is refused,
because a blank Jastrow would discard an optimised one. Finite systems only so far: a
periodic Jastrow wants a P term, whose stars come from CASINO's own make_p_stars.
backflow: the terms of a blank backflow function, in the same file -- ['eta', 'mu', 'phi']
for the usual one. It goes with backflow : T in the input, and the two blocks are
written together for a calculation that wants both. The electron-nucleus cusp type of
each set is not a setting: it is read off the pseudopotentials in the directory, 1 for a
bare nucleus and 0 behind a pseudopotential, because CASINO believes the flag without
checking it. No AE CUTOFFS section is written -- it is optional, and CASINO chooses the
lengths itself.
jastrow_settings: the shape of both blocks, where the defaults are not wanted. Jastrow:
trunc_order (3), n_u (8), n_chi (8), n_f_en (3), n_f_ee (3), spin_dep_u (1),
spin_dep_chi (0), spin_dep_f (1), cusp_chi (0), cutoff_u / cutoff_chi / cutoff_f (0,
which CASINO reads as "use your own default"), no_dup_u (0), no_dup_chi (0),
optimizable (1, the cutoffs). Backflow: bf_trunc_order (3), n_eta (9), n_mu (9),
n_phi_en (3), n_phi_ee (3), spin_dep_eta (1), spin_dep_mu (0), spin_dep_phi (1),
cutoff_eta / cutoff_mu / cutoff_phi (0), irrotational (0), cusp_bf (-1, meaning derive
it from the pseudopotentials).
Nothing is written unless the result would actually run: the keyword combinations CASINO
only rejects at run time are checked first (an optimisation sample smaller than the DMC
target weight, opt_backflow without backflow, a missing mandatory keyword), and so is
the presence of every file the input tells CASINO to read. A refusal names the problems and
creates no directory. What is legal but probably unintended -- a dtdmc still at CASINO's
placeholder default, dmc_stats_nstep not divisible by its block count, keywords left over
from the runtype this was copied from -- comes back in warnings and does not stop it.
| Name | Required | Description | Default |
|---|---|---|---|
| dest | Yes | ||
| source | Yes | ||
| jastrow | No | ||
| runtype | No | ||
| backflow | No | ||
| overrides | No | ||
| jastrow_settings | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the behavioral burden: which files are copied, which are excluded, symlink handling, default filling, validation checks, refusal behavior, warnings, and precedence rules. This is exceptionally transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but every paragraph earns its place given the domain complexity. It is front-loaded with purpose, then systematically covers file selection, parameters, and validation behavior without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter tool with no annotations, this description is complete: all parameters are explained, valid runtypes are enumerated, defaulting and overrides are specified, and refusal/warning behavior is disclosed. The presence of an output schema covers return-value specifics.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and does so thoroughly: runtype values and defaults, overrides precedence and %block behavior, jastrow/backflow semantics, and jastrow_settings defaults. Even the required source/dest parameters are clear from context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states the exact action: copy a calculation into a new directory and write the input for the next run. The workflow explanation and examples make it clearly distinct from sibling tools like casino_run or casino_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives strong workflow context ('This is how a calculation becomes the next one') and concrete examples, and it explains why copying rather than editing is required because casino_run refuses a directory that already holds a run. It stops short of explicitly naming when-not-to-use alternatives such as 'use casino_run to execute instead'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
casino_resultsA
Physics out of a job's files: energies, error bars, variance, per-block numbers.
Reads out and returns it as phases, because a CASINO run is a sequence of them and not
one result: vmc_opt writes a VMC and an optimization phase per cycle, vmc_dmc writes
VMC, DMC equilibration and DMC statistics accumulation. result points at the number that
is this run's answer, and every value carries the file and line it was read from. Nothing
is computed here that CASINO did not print, and a value it did not print comes back as null
with the reason.
A DMC run that has not ended is readable too, and this is the only way to read one: CASINO
writes the mixed estimators into out at the very end, and until then the current estimate
lives in dmc.status, which it rewrites after every statistics block and deletes when the
run finishes. When that file is there it is parsed into dmc_status and result points at
it, so a running job answers with the estimate as of its last block -- and never with the
VMC energy of the configuration-generation phase, which is the trial wave function's and not
the calculation's. A run stopped by casino_stop keeps its dmc.status, so the last estimate
it reached survives the stop.
While the run is still equilibrating there is no DMC energy anywhere yet, and result then
says so rather than answering with an earlier phase.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden and does so thoroughly. It explains that values come from CASINO-printed data, that missing values return null with a reason, that running DMC results are read from dmc.status, that dmc.status is deleted on completion, and that casino_stop preserves the last estimate. This is rich, non-obvious behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but information-dense, with each paragraph covering a distinct behavioral area: output contents, phase semantics, running jobs, and equilibration. The structure is front-loaded with purpose and then deepens into edge cases. The awkward opening phrase 'Physics out of a job's files' slightly reduces clarity but does not waste space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that an output schema exists and the tool has only one parameter, the description is unusually complete. It covers completed runs, running DMC runs, stopped runs, equilibration, value provenance, and the meaning of `result`. An agent has enough context to invoke the tool correctly and interpret its results in most scenarios.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has one required parameter, job_id, with 0% schema description coverage, and the tool description never mentions job_id explicitly. It refers to 'a job's files' and 'this run,' but it does not explain how job_id selects the job, where to obtain valid job IDs, or any constraints. Because schema coverage is low, the description was expected to compensate and did not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states that the tool reads a job's `out` file and returns energies, error bars, variance, per-block numbers, and phases, which clearly identifies it as a results-reading tool. It also explains the `result` field as the run's answer, giving concrete purpose. It does not explicitly name sibling distinctions, but the resource and operations are clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides useful conditions for when this tool is appropriate, especially for running DMC runs, saying it is 'the only way to read one.' It also covers stopped runs and equilibration states. However, it never explicitly contrasts the tool with casino_status or casino_list_jobs, so alternative routing is only implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
casino_runA
Start a CASINO calculation in workdir and return immediately.
The runtype (vmc, vmc_opt, vmc_dmc, ...) comes from the input file in workdir;
this tool only decides how the binary is launched. The calculation keeps running
after the call returns and after this server is restarted.
A directory that already holds an out is refused, because runqmc appends to it and
the result is two runs in one file. restart and resume are the two ways past that,
and they are opposites -- pass one.
workdir: directory holding input and the wave function files.
nproc: number of MPI processes (vmc_nstep in input is the total over all of them).
version: binary flavour, 'opt' or 'debug'.
restart: delete out and everything else the earlier run left -- .hist files, configs,
optimisation output -- and start the calculation over. Inputs are kept. Destructive:
config.in goes too, so what could have been continued no longer can be. Refused on a
directory whose input haltqmc has set up to continue (NEWRUN : F), because CASINO
then wants the config.in this would delete; casino_stop keeps a copy of the input as
it was, and the reply to the stop says where.
resume: carry the interrupted run on, keeping the work already done. Which of CASINO's
two continuation routes that takes is read out of out, not chosen here: a run that
CASINO stopped on max_cpu_time / max_real_time is continued by runqmc --continue,
and a run that casino_stop halted is continued by a plain runqmc over the input
that haltqmc -u rewrote. The reply says which one under resume. A run that
reached its own end is refused -- there is nothing to continue.
unlock: clear a stale .runqmc.lock left by a runqmc instance that died.
| Name | Required | Description | Default |
|---|---|---|---|
| nproc | No | ||
| resume | No | ||
| unlock | No | ||
| restart | No | ||
| version | No | opt | |
| workdir | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden, and it delivers: it discloses that the calculation outlives the call and server restart, that `out` is appended to and can corrupt results, that restart is destructive to `config.in` and optimization output, and how resume behaves under different halting conditions. This is deep, honest behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence earns its place. It is front-loaded with the core purpose, then organizes the non-obvious behavioral details and parameter semantics in a structured, scannable way. The density is justified by the tool's complexity and destructive options.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a 6-parameter tool with no annotations, the description is exceptionally complete: it covers prerequisites, launch semantics, background persistence, destructive behavior, failure conditions, and parameter interactions. The presence of an output schema relieves it from detailing return values, so nothing critical is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does thoroughly. Every parameter — workdir, nproc, version, restart, resume, unlock — gets meaningful explanation beyond its name, including relationships like nproc counting total vmc_nstep, version being a binary flavour, and the precise effects of restart versus resume.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: 'Start a CASINO calculation in workdir and return immediately.' It clarifies that the runtype comes from the input file and that this tool only controls binary launch, making it easy to distinguish from siblings like casino_prepare, casino_status, and casino_stop.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives strong when-to-use and when-not-to-use guidance: directories with existing `out` are refused, restart and resume are opposites, resume is refused for completed runs, and restart is refused when NEWRUN : F is set. It does not explicitly name sibling alternatives for common flows, but the contextual sibling list makes the intended role clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
casino_statusA
State of one job: running / finished / failed / stopped, pid, runtime in seconds, exit code.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description must carry the behavioral burden. It does disclose the status vocabulary and returned metrics, and 'state of one job' strongly implies a read-only query. However, it does not explicitly state that it has no side effects, how unknown or expired job IDs are handled, or whether it is safe to poll repeatedly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence with no filler. It front-loads the core scoping ('State of one job') and then lists the concrete status and metric fields, so every word adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a low-complexity one-parameter status query, the description is largely complete: it defines the job scope and the returned state fields, and the output schema covers the return contract. The main omissions are explicit usage routing and side-effect disclosure, but the tool is simple enough that the given information allows a correct call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must add meaning to job_id. It adds minimal context by indicating the parameter refers to the specific job whose state is checked, but it does not mention job_id by name, explain how to obtain a valid value, or provide any format guidance beyond the schema's string type.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as reporting the state of a single job and enumerates the key fields returned (status, pid, runtime, exit code). The phrase 'one job' helps separate it from casino_list_jobs, but it does not explicitly contrast with casino_results or other siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: an agent can infer that this tool is for checking an individual job's status after invoking casino_run. There is no explicit guidance about when to use it instead of casino_results, casino_stop, or casino_list_jobs, and no mention of prerequisites such as having a valid job_id.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
casino_stopA
Stop a running calculation and leave its directory ready to be continued.
SIGTERM goes to this job's casino processes, as haltqmc -k does for the whole
account, so runqmc stays alive to finish writing out. CASINO has no graceful-halt
signal: the blocks it had finished stay in out, vmc.hist and dmc.hist, the
current block is lost. Then haltqmc -f -u tidies the directory -- config.out to
config.in, the lock file, and input rewritten for the work that is left -- so
casino_run(workdir, resume=true) carries this calculation on.
timeout: seconds the job gets to end on its own before the process group is killed.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | ||
| timeout | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and succeeds. It details that SIGTERM targets the job's casino processes, that runqmc survives to write output, that the current block is lost, and that haltqmc -f -u tidies the directory for resumption. It also explains the timeout fallback behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and then adds only high-signal behavioral details. Every sentence contributes meaningful operational knowledge without repetition or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a side-effect-heavy tool with no annotations, the description is remarkably complete: it covers signal behavior, persistence of completed data, loss of current block, directory cleanup, resumption path, and timeout semantics. An output schema is present, so explaining return values is not necessary.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It fully explains timeout as the seconds a job gets before its process group is killed, but job_id is left to its schema title and the contextual phrase 'running calculation.' The main parameter is not explicitly defined or sourced.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Stop a running calculation and leave its directory ready to be continued.' This clearly distinguishes casino_stop from the sibling tools casino_run, casino_prepare, casino_status, casino_results, and casino_list_jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly establishes the tool's purpose for stopping a running calculation and contrasts it with haltqmc -k's account-wide behavior, implying this tool is job-scoped. It does not explicitly enumerate when to use it over siblings, but the intended use is unambiguous in context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
v0.4.0- First observed
casino_list_jobs - First observed
casino_prepare - First observed
casino_results - First observed
casino_run - First observed
casino_status - First observed
casino_stop
TDQS
Scored across 6 tools
Each tool addresses a distinct lifecycle stage: preparing a directory, launching/interrupting a run, listing/checking jobs, and extracting physics results. Status and list_jobs are adjacent, but one is explicitly per-job detail while the other is an overview, so there is no real ambiguity.
All tools share the casino_ prefix and use snake_case, but the pattern mixes simple verbs (run, prepare, stop), a verb-object phrase (list_jobs), and bare nouns (status, results). This is readable and predictable, though not a uniform verb_noun convention.
Six tools is a well-scoped set for a job-management server. Each tool covers a necessary action without redundancy, and the count sits comfortably in the ideal 3-15 range.
The tool surface covers the full CASINO workflow: prepare a calculation, run or restart it, monitor it, stop it, and retrieve physics results. Missing cleanup or job-forgetting operations are not essential to the stated purpose.
Maintenance
Related MCP Connectors
QuLab MCP remote server (Streamable HTTP) for computational science and lab tools.
Dispatch and track Alchemist Cloud tickets, watch deploys, read logs, and query your project DB.
Manage CloudPepper servers, Odoo instances, backups, and deployments over MCP.
Read and write Mission Control state via MCP — projects, tasks, subtasks, templates, status updates.
Related MCP Servers
- AlicenseAqualityBmaintenanceA unified CLI, web dashboard, and Python API for SLURM job management.15149 PyPI18Apache 2.0
- AlicenseNot gradedqualityDmaintenanceManages AutoDL GPU cloud instances, including lifecycle management, SSH operations, file transfer, and GPU monitoring.1MIT
- AlicenseNot gradedqualityBmaintenanceConverts Quantum ESPRESSO output files to structured JSON and serves them via an HTTP API for use with MCP clients.MIT
- AlicenseAqualityAmaintenanceDurable MCP server for managing long-running jobs locally, over SSH, or on Slurm clusters. Jobs survive client disconnects and return exit codes, bounded logs, and JSON artifacts.1141 PyPI1MIT