Skip to main content
Glama

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                 # Codex

Crush 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

access_status (tunnel, certificate, SSH test; restarts a stalled tunnel), start_login (the ASC device login and early renewal; certificates last about 16 h)

Login node

run_command: light commands with a timeout. Slurm-changing commands, ssh to compute nodes and config edits are refused; deletions need approval

Writing jobs

draft_job (scripts in the form MUSICA accepts: CPU or GPU, part of a node or whole nodes, multi-node with launch retry, arrays, vLLM servers with a client), job_templates (tested scripts), check_job (runbook checks, sbatch --test-only, missing models, containers and envs)

Running jobs

submit_job, update_job, cancel_job, list_jobs

Watching

wait_for_job (start, end, failure, log milestones with deadlines, quiet-log alarm, expected outputs), job_log (cleaned logs, progress bars), job_details (diagnosis: infrastructure, script or program), node_exec (nvidia-smi, ps, py-spy on a running job's node)

Files

push_files, fetch_files (tar over SSH, staged, with the code's git revision; never deletes remote files)

Budget

budget (tokens spent against the project's budget), cluster_load (idle, planned and busy nodes), ledger_entries (the local record of every submission)

Issues

report_issue, list_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 sbatch again.

  • 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 cluster

Optional: 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

INSTALL.md

Setup on a new machine (Mac, Linux, containers and dev VMs, WSL2), written for the agent

AGENTS.md

The runbook: rules, when to ask the human, job patterns, costs, troubleshooting

NOTES.md

MUSICA reference: projects, hardware, Slurm, storage, software

config.example.toml

The project config with placeholders

issues/README.md

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 MUSICA
amadeus/     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 each

Issues 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 tools
access_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.

budgetB
Read-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_jobA
Destructive

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_jobA
Read-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_loadA
Read-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_jobA
Read-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_filesA
Destructive

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_detailsA
Read-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_logA
Read-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_templatesA
Read-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_entriesC
Read-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_issuesA
Read-only

Issues filed through report_issue or automatically. status: open | in-progress | needs-human | fixed | wontfix | duplicate | all.

Inputs: status.

list_jobsA
Read-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_execA
Destructive

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_filesA
Destructive

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_commandA
Destructive

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_jobA
Destructive

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_jobA
Read-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

    A3.5/5.0

    Scored across 21 tools

    Disambiguation4/5

    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.

    Naming Consistency3/5

    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.

    Tool Count3/5

    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.

    Completeness4/5

    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

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to manage SLURM HPC clusters via SSH. Supports job submission, resource monitoring, queue management, and file operations.
      8 npm
      4
      -
    • A
      license
      B
      quality
      C
      maintenance
      Enables 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.
      27
      MIT