Amadeus
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Amadeus check my access status and submit the 2-node GPU job script"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Amadeus
An MCP server that lets coding agents (Claude Code, Codex, …) work on MUSICA, the supercomputer of ASC
(Austrian Scientific Computing) in Vienna, without hand-written ssh and sbatch.
The agent gets tools: sign in, run light commands, draft and check job scripts, submit, wait, read logs, move files. The server enforces the runbook as it goes: the right account and QoS, time limits, the project's budget, and the human's approval for big or expensive jobs. It works for any ASC project; your project's details come from a small config file.
Amadeus is an independent project, not an ASC service. Platform facts were verified on MUSICA Vienna in October 2026; when the cluster disagrees with the docs, trust the cluster and report it.
Why
An agent with plain ssh to a supercomputer makes the same mistakes over and over: jobs on the wrong account, a
16-node run nobody approved, a --time that cannot be raised once the job runs, sbatch repeated after a dropped
connection, a build on the shared login node, logs grepped for "Error" by hand. Amadeus turns the lessons from
real agent sessions on MUSICA into tools that get these right by default, plus a runbook (AGENTS.md)
the agent reads.
Related MCP server: mcp-slurm
Install
You need an ASC account and project on MUSICA, a network path to it (the ASC WireGuard VPN or a partner-university network), macOS, Linux or Windows through WSL2, and an MCP client. Then tell your agent, on the machine that will reach MUSICA:
Install the Amadeus MCP server for me following INSTALL.md in https://github.com/cpietsch/amadeus.
Ask me for my ASC username, project details and WireGuard config when you need them.INSTALL.md is written for the agent. It will ask you for your ASC username, your project's Slurm account, filesystem, budget and working directory (the projects portal shows them), your WireGuard config if the machine has no VPN yet, and to approve a sign-in link in your browser (within about 60 s). Each machine an agent works on gets its own install.
By hand, after cloning (/path/to/amadeus is wherever you put it):
claude mcp add --scope user amadeus -- uv run --quiet --project /path/to/amadeus amadeus # Claude Code
codex mcp add amadeus -- uv run --quiet --project /path/to/amadeus amadeus # CodexCrush and other stdio clients: INSTALL.md §5.
Agent quickstart
Connected agents get these rules from the server itself. Paste the block into your project's CLAUDE.md or
AGENTS.md so they are in view from the start, or hand it to an agent as its brief:
## MUSICA via Amadeus
Use the `amadeus` MCP tools for all work on MUSICA, not raw ssh or sbatch.
1. Start with `access_status`. Certificate missing or under 60 min: call `start_login` and put the link on the
first line of your reply; the human has about 60 s to approve it.
2. The login node is for light work (`run_command`: ls, du, git, small checks). Builds, downloads and compute
go into jobs.
3. Jobs: `draft_job` or `job_templates` → `check_job(script_text=…)` → save the script in this repo →
`push_files` → `submit_job(script=…, purpose=…)`. Climb the test ladder: dev QoS (10 min), then 1, 2 and 4
nodes, before 16. Set `--time` from a measured estimate × 1.3: a running job's limit cannot be raised.
4. Ask the human first and pass their words as `approval`: 4 or more nodes at once, more than 20 tokens, B200,
long or priority QoS, deleting data, cancelling jobs you did not submit. A 16-node job needs its own
heads-up. Never invent an approval. (Defaults; the config's `[limits]` can set others.)
5. Wait with `wait_for_job`, not sleep loops. Logs: `job_log`; a failed job: `job_details` (diagnosis).
Results come back with `fetch_files`.
6. After a dropped connection, never resubmit blindly: `list_jobs` first.
7. A tool misbehaves or one is missing: `report_issue`.
Rules and patterns: `amadeus://runbook`; platform facts: `amadeus://notes`; this project: `amadeus://project`.Tools
Area | Tools |
Access |
|
Login node |
|
Writing jobs |
|
Running jobs |
|
Watching |
|
Files |
|
Budget |
|
Issues |
|
Resources: amadeus://runbook (AGENTS.md), amadeus://notes (NOTES.md),
amadeus://project (your project's own notes, if the config names a file). Every tool's details:
AGENTS.md §4a.
What the server enforces
Every job: the project's account, a partition with a matching QoS, an explicit
--time(at most 72 h; dev QoS 10 min and 2 nodes), CPUs per node within what the partition gives. Known script pitfalls are refused or flagged (AGENTS.md §8).The human's approval, quoted in their words, for 4 or more nodes at once or more than 20 tokens (running and pending jobs count together), the B200 partition, long or priority QoS. 16 or more nodes need an approval that names the node count. The thresholds are configurable.
Slurm's own reading: jobs are submitted on hold, checked again as Slurm parsed them, then released (or cancelled). After a dropped connection the server looks for the job instead of running
sbatchagain.Destructive actions (deleting or moving data, cancelling jobs the agent did not submit, killing processes on a node) need approval.
A ledger: every submission is recorded with its purpose, estimate and approval.
These guards catch mistakes; they are not a security boundary. The agent works with your ASC account.
Configuration
One file, ~/.config/amadeus/config.toml, copied from config.example.toml:
[cluster]
user = "user1234" # your ASC username
[project]
name = "my-project-2026"
account = "p123456" # Slurm account: p<number>, not the filesystem fs<number>
filesystem = "fs123456"
budget_tokens = 1000
ends = "2026-12-31"
workdir = "~/my-project" # code and job scripts on the clusterOptional: notes and template_dirs (your project's notes and job scripts), [limits] (approval thresholds),
[files] (where push_files/fetch_files may read and write, other machines). AMADEUS_* environment
variables override the file (INSTALL.md §6). Without an account the read-only
tools work and submissions are refused. Restart the agent after a change.
Without an agent
The shell helpers behind the server work on their own:
scripts/musica_auth.sh # tunnel + daily certificate; approve the printed link
scripts/mx 'squeue -u $USER' # a command on the login node (timeout, batch mode)
scripts/mx 'cd <workdir> && sbatch jobs/test_gpu.slurm'None of the server's checks apply there. Copying code by hand: AGENTS.md §4.
Docs
File | What |
Setup on a new machine (Mac, Linux, containers and dev VMs, WSL2), written for the agent | |
The runbook: rules, when to ask the human, job patterns, costs, troubleshooting | |
MUSICA reference: projects, hardware, Slurm, storage, software | |
The project config with placeholders | |
The issue channel and how fixes are made |
The runbook points into ASC's own docs; clone them next to the server (AGENTS.md §11).
Development
uv run python -m unittest discover -s tests -t . # against a fake cluster; nothing reaches MUSICAamadeus/ the server: server.py (tools), guard.py (runbook checks), slurm.py (options, token estimates),
drafts.py, templates.py (draft_job, job_templates), auth.py, network.py, remote.py, files.py,
logs.py (cleaning, diagnosis), ledger.py, issues.py, config.py
jobs/ tested generic job scripts: smoke tests, GPU node probe, container pull, vLLM on N nodes
scripts/ shell helpers: musica_auth.sh, mx, vpn.sh
tests/ tests with a fake SSH shim and stub Slurm commands
issues/ problems filed by agents (report_issue) or automatically; one Markdown file eachIssues and pull requests are welcome. Keep it general: no values of a particular project (account, paths,
budgets, results) in code, docs or jobs/; examples use placeholders (p123456, fs123456). A lesson learned in
a project goes into AGENTS.md as the general rule. report_issue writes into issues/ of the local clone: open
an issue or pull request here to send it upstream. CLAUDE.md sets up a maintainer session.
On start the server shows a banner and plays a short jingle, on errors a short sound; AMADEUS_SOUND=off turns
them off.
Credentials
Never commit or paste credentials: the WireGuard config, private keys, certificates, Hugging Face tokens. They
live in ~/.config/wireguard/, ~/.ssh/ and ~/.step/. The sign-in link goes only to the human. Issues are
redacted when they are written.
History
Amadeus grew out of a hackathon workspace: from 2026-10-07 to 2026-10-16 the repository was team Socratech's
workspace for the European AI Hackathon on MUSICA, where a sweep of the ASC docs became the runbook and NOTES.md,
shell helpers became tools, and the benchmark and labelling jobs became the tested patterns behind draft_job.
On 2026-10-14 it was turned into an MCP server, on 2026-10-15 a review of past agent sessions added guard rules
and tools, and on 2026-10-16 it was named Amadeus and made general for any ASC project.
License
MIT, see LICENSE.
Available Tools
21 toolsaccess_statusA
Tunnel, certificate expiry and an SSH test. Call first in every session. (Starts the tunnel if it is down; with
wireproxy, a stall before login restarts it, at most once a minute, also from other tools that run commands on
the login node, not yet from the copying in push_files/fetch_files: recovery.)
The first call of a server run also carries banner (Amadeus' ASCII art): show it to the human once.
Inputs: probe.
budgetBRead-only
Tokens (credits) used by the whole project since a date, per user, from sacct (CPU nodes included; B200 as node-hours, no published price) and what is left of the configured budget. The projects portal is authoritative. Without a configured account: only the user's own jobs.
Inputs: since.
cancel_jobADestructive
Cancel a job. Jobs submitted through this server can be cancelled directly; any other job needs the human's
approval in approval (AGENTS.md §9).
Inputs: job_id (required), reason (required), approval.
check_jobARead-only
Check a job before submitting: runbook rules (account, partition/QoS, time, dev limits, CPU limits, script
pitfalls), cost estimate at the time limit, whether a human must approve it (counting your running and pending
jobs), and sbatch --test-only. script is a path relative to cwd on the cluster (default: the configured
workdir), never the script's text (refused without touching the cluster); or pass the script itself as script_text (e.g. a draft_job result) to check it without pushing it first (cwd is still
where it would run). Pass each sbatch option and its value as separate list items. The test-only start time is
unreliable. Also tested on the cluster: that the models, containers, envs and inputs the script reads exist
(missing_paths; submit_job refuses them unless the job has a --dependency), and for vLLM on the dev QoS whether
a compile cache is warm. asc: what ASC's submit filter changed in the request (comfort mode).
expected_minutes: your runtime estimate; a --time far above it is flagged.
Inputs: cwd, script, sbatch_args, script_args, +2 more.
cluster_loadARead-only
Nodes per partition: allocated, idle (free now), planned (held free by the scheduler for jobs next in line:
not available to new jobs, except a short one backfilled before their planned start; plain sinfo %A/%F counts them
as idle), other (down, drained, reserved, maintenance, not responding) and total, plus states (node count per raw
Slurm state); pending and running jobs per partition; my fair-share and the priority factors of my pending jobs
(low fair-share means long waits; idle GPU nodes can take CPU work at 4×).
Inputs: no named parameters.
draft_jobARead-only
Draft a Slurm job script for MUSICA from the runbook's tested patterns; nothing is sent to the cluster.
kind: cpu (part of a CPU node: cores, mem_gb), cpu-node (whole CPU nodes), gpu (1-3 GPUs on a shared node:
gpus; shared nodes can take hours to start), gpu-node (whole H100 nodes; with vllm_model: vLLM servers on every
node, vllm_servers_per_node 1/2/4 = TP4/TP2/TP1, and command as their client on the first node).
command: the work (shell lines); with nodes > 1 it runs once on every node ($NODE_RANK, $NNODES, $HEAD).
time: minutes or HH:MM:SS; dev=True uses the dev QoS (at most 10 min, 2 nodes): test there first.
array: e.g. 0-9%2 ($TASK in the script). python_env: a venv path (e.g. $DATA/envs/train); container: a .sif
(prefix commands with run); modules: Lmod modules to load.
runs (gpu-node, 1 node): up to 8 commands in parallel on one whole node, run r on GPU r % 4 ($RUN, own caches,
log logs/--r.log; the job fails if any run failed; command runs first as setup); run_minutes:
one estimate per run (refused if the slowest exceeds time).
array_args: one argument string per array task (sets --array=0-(n-1)%throttle; the task gets $ARGS and
$OUT=results/--a); array_throttle: tasks at once (0 = within the approval limits); not
together with array.
vllm_preset: tested serve settings for some models, 'qwen38-fp8' or 'glm53-fp8' (flags for one TP4 server per
node; model and image default to $DATA/models/ and $DATA/containers/, which you must download
first, or set vllm_model/vllm_image; vllm_args are appended, later flags win); load_cap_s: drop a vLLM server whose weights are not loaded this many seconds
after its node's launch (60-3600).
Drafts check at job start that the env, container and model exist (exit 2 otherwise), set HF_HUB_OFFLINE=1 on
GPUs and OMP_NUM_THREADS=1 for vLLM. Returns the script, the static check (estimate, approvals needed) and notes;
then check_job(script_text=...) for sbatch --test-only and the path checks on the cluster.
Inputs: kind (required), name (required), dev, gpus, +21 more.
fetch_filesADestructive
Copy a file or directory from the cluster into local_dir on host (tar over SSH, retried; overwrites files of
the same name). Refuses more than max_mb (fetch subdirectories of big results). host as in push_files.
Inputs: local_dir (required), remote_path (required), host, max_mb.
job_detailsARead-only
State, exit code, times, time limit, nodes and cost of a job (every array task and requeue attempt), its sbatch
command line, the reason (and dependency) a pending job waits, and the cleaned tails of its output files (at most
20 files). An ended job that failed, or completed with errors in its log, gets a diagnosis: category
(infrastructure = cluster side, resubmit; script; program; benign), summary, known signatures with their meaning and action
(transient = a resubmit usually works), and the first real exceptions; harmless noise is not counted.
Inputs: job_id (required), log_lines.
job_logARead-only
Tail of a job's stdout (stream='out'), stderr ('err') or of file: a path or glob relative to the job's
working directory (%j %x %A %a allowed, e.g. 'logs/%x-%j-r*.log' or 'results/run-%j/train.log'; at most 20
files). For array jobs pass the task id (123_4) to see one task.
The text is cleaned: ANSI colours and binary bytes removed, \r progress updates collapsed to their last state
(raw=True: as written). grep: an extended regex, matched per line (also on \r updates and in binary logs).
progress=True: instead of text, the latest state of each progress bar per file (label, n, total, percent, rate,
elapsed, eta; kind loading / warmup / work: 'Loading weights 723/723' is not training).
hide_benign=True: drop known-harmless lines and tracebacks (vLLM usage-stats TLS error, shutdown noise, srun's
'forcing job termination', ...); counted in benign_hidden. A log missing while the job is pending or in its
first minutes is normal (node prolog).
Inputs: job_id (required), raw, file, grep, +4 more.
job_templatesARead-only
Tested job scripts to copy from: Amadeus's jobs/ and the project's template directories (config).
Without name: the list, each with a summary from its comments and its resources. With name (as listed, or
the file name): the script and the helper scripts it uses. Prefer draft_job for a new job; use these for
patterns it does not cover (vLLM multi-node benchmarks, DDP training, CPU-node arrays, container pulls).
Inputs: name.
ledger_entriesCRead-only
The last submissions, updates, cancellations and approved commands made through this server (local ledger, ~/.local/state/amadeus/jobs.jsonl by default; AMADEUS_LEDGER overrides).
Inputs: last.
list_issuesARead-only
Issues filed through report_issue or automatically. status: open | in-progress | needs-human | fixed | wontfix | duplicate | all.
Inputs: status.
list_jobsARead-only
My running and pending jobs (arrays as one row), with the purpose recorded at submission (if submitted through
this server), and what they hold together: nodes at once and the tokens they can still spend at their limits.
For pending jobs start is Slurm's estimate (unreliable) and reason why it waits.
Inputs: no named parameters.
node_execADestructive
Run a short diagnostic command on the node of one of your RUNNING jobs (ssh to compute nodes is refused on
MUSICA; this uses srun --jobid=<id> --overlap from the login node and shares the job's resources).
Typical: nvidia-smi, top -b -n1 | head -30, free -g, ps -u $USER -o pid,pcpu,rss,etime,args --forest,
$DATA/envs/tools/bin/py-spy dump --pid <pid>, tail of a node-local log, df -h /local.
node: one of the job's nodes (default: its first). timeout_s: 5 to 120. No background processes, no srun.
The same rules as run_command apply; deleting files or signalling processes (kill, pkill, fuser -k) needs the
human's approval in approval, in their words. The check goes by command word (also behind timeout, nice, env,
xargs, bash -c); killing processes by any other means (e.g. os.kill in a python -c) needs that approval too.
Inputs: job_id (required), command (required), node, approval, +1 more.
push_filesADestructive
Copy a directory to the cluster (tar over SSH, retried; staged, so a failed push changes nothing; overwrites
files of the same name, never deletes others). mode='tracked': git-tracked and untracked-but-not-ignored files plus
a REVISION file, for code repositories; mode='all': everything except .git, venvs, caches and *.sif.
host: the machine local_dir is on ('' = the machine the server runs on; default: the server's client machine,
see the result's 'host'). local_dir must be inside the local root there (the home directory, outside hidden directories); remote_dir under $DATA, $SCRATCH or ~/
(e.g. '$DATA/'). Code only: big data is fetched in jobs.
Warns (does not refuse) when your pending or running jobs work in or around remote_dir: Slurm keeps only a copy
of the batch script, so pending jobs run the pushed code and running ones may read changed files mid-run.
Inputs: local_dir (required), remote_dir (required), host, mode, +1 more.
report_issueA
Report a problem with this server or the cluster interface, for the maintainer session that fixes them. kind: bug | wrong-result | missing-feature | docs | cluster | other. severity: high (blocks work) | medium | low. Give the tool name, the arguments you used, what came back, what you expected, and your project (repository). No secrets. Returns the issue id; list_issues shows its status later.
Inputs: title (required), what_happened (required), kind, project, +4 more.
run_commandADestructive
Run a shell command on the login node (bash, non-interactive). $DATA, $SCRATCH, $USER expand there.
Light work only: no compute, builds or big downloads (use a job). lmod=True initialises Lmod first (for module).
Refused: Slurm-changing commands (use submit_job, cancel_job, update_job; sacctmgr only in its read-only
show/list forms, e.g. sacctmgr -nP show qos format=Name,MaxWall), ssh to compute nodes and srun (use node_exec)
and changes to SSH/shell/VPN config.
Deleting or moving files (rm, mv, rsync --delete, ...) needs the human's approval in approval, in their words.
The command is not repeated after an SSH failure; when recovery says the tunnel was restarted after a stall
(nothing ran remotely), run it again.
Inputs: command (required), lmod, approval, timeout_s.
start_loginA
Start a certificate login (or an early renewal while the current one is still valid) and return the device link. Show the link to the human immediately; it expires after about 60 s. Only one login runs at a time. Call it only when answering a message from the human, not from a cron, /loop or stop-hook turn (AGENTS.md §3).
Inputs: no named parameters.
submit_jobA
Submit a batch job after the runbook checks (see check_job) and record it in the local ledger.
script: the path of the job script on the cluster, relative to cwd (default: the configured workdir); script
text is refused (check a draft with check_job(script_text=...), then save it in the project, push_files, submit).
The job is submitted on hold, checked against Slurm's own reading of it, and released (or cancelled if Slurm
reads it differently and it then breaks the rules). purpose: one line on what the job is for. approval: the
human's explicit approval in their words (who, what, limit); required above the approval limits ([limits] in the
config; by default ≥ 4 nodes at once, > 20 tokens including your other jobs), for B200 and long/priority QoS; a job
of 16 or more nodes (headsup_nodes) needs an approval that names its node count, even inside an approved budget. Refused when a model, container, env or input the script reads does
not exist on the cluster (unless the job has a --dependency, or allow_missing=True for a job that fetches or
creates them itself before use: then a warning). Pass each sbatch option and its value as separate items.
expected_minutes: your runtime estimate (a --time far above it is flagged).
Inputs: script (required), purpose (required), cwd, approval, +4 more.
update_jobADestructive
Change a job: a new time limit (e.g. '02:00:00') or node count (pending jobs only), or release / hold it.
A time limit can be raised only while the job is pending: MUSICA denies raising a running job's limit (lowering
works). The new limits are re-checked like a submission (≥ 4 nodes at once, > 20 tokens need approval, the
human's words). Jobs not submitted through this server need approval for any change.
Inputs: job_id (required), hold, nodes, release, +2 more.
wait_for_jobARead-only
Wait for one job (job_id) or several (job_ids) and return at the first event that matters, with the new log lines since the last call. Returns at the latest after max_wait_s (10 to 3600).
until: 'end' / 'all_end' = all jobs ended (default), 'any_end' = the first job ends, 'any_fail' = the first job ends other than COMPLETED (or all ended), 'start' = a job starts (or ends). Alarms always return at once:
milestones: [{pattern, within_s, file}]: a regex (Perl/Python style) grepped in the job's 'out' (default), 'err' or a path relative to its working directory (%j %x %a allowed). A match returns MILESTONE; no match within_s seconds after the job's start returns LATE (e.g. vLLM 'ready after \d+s' within 600).
quiet_alarm_s: QUIET when a RUNNING job's logs have not grown for that long (0 = off). vLLM compile and graph capture can be silent for about 3 min: use 300 for big runs, 120-180 while testing.
expect: output paths relative to the working directory (%j %x %a, globs): OUTPUTS_MISSING when a job ended without files written since its start (a COMPLETED state can hide a failed run). Events: STARTED, ENDED, FAILED, MILESTONE, LATE, QUIET, OUTPUTS_MISSING; failed jobs come with a diagnosis. finished: True = all ended, False = still running (an event or max_wait_s), None = cluster or job not found. Pass next_cursor back as log_cursor: you then get only new log lines and events you have not seen yet. State lives in Slurm: after a restart, a dropped connection or a compaction just call again with the same ids; alarms this server already returned for these jobs then come back as info and do not end the call at once. Never build sleep/sacct watcher loops or background monitors. Each poll is one SSH command for all jobs.
Inputs: until, expect, job_id, poll_s, +5 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 21 tools
Tools are largely separable by resource and stage: job lifecycle (list/details/log/wait/check/draft/submit/update/cancel), execution (run_command vs node_exec), file transfer, diagnostics, and issue reporting. A few boundaries blur—job_details already includes log tails, and run_command/node_exec both execute commands—but the descriptions clarify context.
All names are snake_case and readable, but the set mixes verb_noun patterns (submit_job, check_job, push_files) with noun-only names (job_details, cluster_load, budget) and noun_verb (node_exec). The convention is not uniform, though the terms remain reasonably predictable.
21 tools is heavy for an MCP surface and lands in the borderline 16-25 range. The domain is broad—access, Slurm lifecycle, diagnostics, transfers, billing, issues—and no tool is obviously redundant, but the surface feels sprawling.
The core HPC workflow is covered thoroughly: login/access, job drafting/checking/submitting/updating/cancelling, monitoring/waiting/logs, cluster load, budget, transfers, and issue reporting. Minor gaps remain, such as no direct issue-detail/update path or general remote file listing beyond run_command, but workarounds exist.
Maintenance
Related MCP Connectors
Agentic workflow budget approvals with usage receipts.
Runtime permission, approval, and audit layer for AI agent tool execution.
Authorize AI agent tool calls before they run: policy-as-code, human approval, signed receipts.
Work on your own computers from Claude or ChatGPT: run commands, edit and search files.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Slurm HPC clusters via SSH, allowing job submission, monitoring, and error diagnosis through MCP clients like Claude Desktop.6MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage SLURM HPC clusters via SSH. Supports job submission, resource monitoring, queue management, and file operations.8 npm4-
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to manage SLURM cluster jobs with safety guardrails, including file transfer, job submission, log reading, and remote command execution.1MIT
- AlicenseBqualityCmaintenanceEnables users to work on a SLURM HPC cluster over SSH through plain-language requests, covering file browsing and editing, batch job generation and submission, queue monitoring, and log reading to debug failed jobs. It runs with built-in safety guardrails such as fixed commands and configurable path policies for reads and writes.27MIT