| manage_modal_appA | Change a deployed app's state. Both actions affect live traffic.
Args:
action: "stop" — shut the app down, ending web endpoints (`modal app stop`).
"rollback" — restore a previous deployment (`modal app rollback`).
app_identifier: App name ("my-app") or ID ("ap-...").
version: Rollback target; omit for the immediately preceding version. List valid
versions with list_modal_resources(resource="app_history", name=...).
env: Modal environment to target.
Returns: {message, stdout, stderr} or {error}.
|
| manage_modal_containerA | Act on one running container. Find IDs with
list_modal_resources(resource="containers").
Args:
action: "exec" — run a command inside the container (`modal container exec`).
This is arbitrary remote code execution: treat it like SSH, not a lookup.
"stop" — terminate it (`modal container stop`); in-flight inputs are
cancelled and rescheduled elsewhere.
container_id: Container ID ("ta-..."). Unique across environments, so no `env`
argument is needed (the CLI accepts none for these subcommands).
command: For "exec": argv list, e.g. ["python", "-c", "print('hi')"] or
["ls", "-la", "/"].
timeout_seconds: For "exec": max seconds to wait. Default 60.
Returns: exec → {output, returncode, truncated, output_capped}; stop → {message}.
|
| analyze_modal_costsA | Break down what the workspace is spending (`modal billing`). Costs are fetched once
and aggregated locally, so you get ranked totals and period-over-period changes
rather than hundreds of raw rows.
Answering common questions:
"what is my costliest app?" -> view="by_app", period="this month"
"why was Monday expensive?" -> view="timeline", period="last week" (the
`explanation` field diffs the peak day against
the day before and ranks which apps grew)
"what did that day cost hourly?" -> view="timeline", start="2026-08-31",
end="2026-09-01", resolution="h"
"where does the money go?" -> view="by_resource" (CPU / GPU / memory / ...)
"what is the bill this cycle?" -> view="summary"
Billing is workspace-wide, so this reports across every environment; use
`environment` to narrow it after the fact.
Args:
view: "by_app" (default), "timeline" (per interval, with an explanation of the
peak), "by_environment", "by_resource", "summary" (billed vs metered for a
month cycle), or "rates" (current unit prices).
period: Convenience range — "today", "yesterday", "this week", "last week",
"this month", "last month". For "summary" also accepts "YYYY-MM".
start / end: Explicit range instead of `period` — ISO dates ("2026-08-31") or
relative ("3 days ago"). Start is inclusive, end exclusive; end defaults to now.
resolution: "d" (daily, default) or "h" (hourly). Hourly is what you want when
drilling into a single day.
timezone: Timezone for interpreting dates — "local", an offset ("+05:30"), or an
IANA name. Requires resolution="h".
app: Only include apps whose name or ID contains this string (case-insensitive).
environment: Only include rows from this Modal environment.
top_n: How many groups/movers to return. Default 10.
tag_names: Comma-separated cost-attribution tag names to include.
Returns: {total_cost, groups | intervals, explanation (for timeline), row_count}.
Costs are strings of US dollars with 4 decimals. `total_cost` always covers every
row in range, even when `groups` is cut to top_n.
|
| deploy_modal_appA | Deploy a Modal app (`modal deploy`). Deployed endpoints persist after this returns,
so any URLs in the result are live, shareable links.
Args:
absolute_path_to_app: Absolute path to the app file. Its directory must use `uv`
and have `modal` installed in its virtualenv.
env: Modal environment to deploy into.
name: Deployment name (`--name`).
tag: Version tag (`--tag`).
strategy: Rollout strategy — "rolling" or "recreate".
stream_logs: Stream the app's logs after deploying.
Returns: {message, urls (live endpoints), stdout, stderr}.
|
| run_modal_appA | Run a Modal function or local entrypoint once and collect its output (`modal run`).
Use this to test on Modal compute; use deploy_modal_app to publish.
Args:
absolute_path_to_app: Absolute path to the app file. Its directory must use `uv`
and have `modal` installed in its virtualenv.
function_name: Function/entrypoint name, e.g. "main". Omit if the module has
exactly one.
env: Modal environment to target.
detach: Keep the run alive on Modal past this call (`--detach`) — for long jobs.
timeout_seconds: Max seconds to collect output. Default 120.
Returns: {output, urls, truncated (still running at the timeout), output_capped}.
|
| get_modal_logsA | Fetch logs for an app or container (`modal app logs` / `modal container logs`).
To find where something went wrong, prefer search_modal_logs — it returns matches
with surrounding context instead of a raw tail.
Covers the stdout/stderr/system streams ONLY. Crash events shown on the Modal
dashboard (e.g. "... exited with ...") are not log lines and never appear here.
Args:
identifier: App name/ID ("my-app", "ap-...") or container ID ("ta-...").
target: "auto" (default — "ta-..." is a container), "app", or "container".
timeout_seconds: Max seconds to collect. Default 30.
env: Modal environment. Apps only — container logs take no environment.
since / until: Time range, ISO 8601 or relative ("2h", "30m", "1d"). Max 35 days.
`since` without `tail` fetches EVERY entry in the range — pass `until` too
(or a `tail`) to bound the volume on a busy app.
tail: Only the last N entries (max 20000).
source: "stdout", "stderr", or "system".
timestamps: Prefix each line with its wall-clock timestamp.
follow: Live-stream until the app/container stops or the timeout hits.
Returns: {logs, truncated (still streaming at the timeout), output_capped (text
trimmed to fit context — narrow with tail/since/source)}.
|
| search_modal_logsA | Search an app's or container's logs and return each hit WITH surrounding context —
the fastest way to find a traceback, an error or a request ID. Logs are fetched once
and grepped locally, so you get the lines around each match, not just the match.
Covers the stdout/stderr/system streams ONLY. Crash events shown on the Modal
dashboard (e.g. "... exited with ...") are not log lines, so a search for them
returns 0 matches even though the failure is real — check the dashboard instead.
Args:
identifier: App name/ID ("my-app", "ap-...") or container ID ("ta-...").
pattern: Text to find, or a Python regex when regex=True.
target: "auto" (default — "ta-..." is a container), "app", or "container".
regex / case_sensitive: Match mode. Both default False.
context_lines: Lines of context each side of a match. Default 3.
max_matches: Cap on match blocks returned. Default 50.
since / until: Time range, ISO 8601 or relative ("2h", "30m", "1d"). PREFER a
bounded range (both ends) when you know roughly when something happened —
`since` alone fetches every entry from then until now, which on a busy app
is megabytes and gets cut off at the timeout. Range must be <= 35 days.
tail: Search only the last N entries (max 20000) instead of a whole range.
With no since/until/tail, defaults to the last 1000 entries.
source: Search only "stdout", "stderr", or "system".
exclude: Drop lines matching this BEFORE searching, to strip repeated noise.
prefilter: Push `pattern` down to Modal as a server-side substring filter, so
non-matching lines are never fetched. The big lever for huge logs, but it
requires regex=False and leaves `context_lines` showing only other matching
lines — use it to find *where* something is, then re-query that window.
timestamps: Prefix lines with their timestamp. Default True.
timeout_seconds: Max seconds spent fetching logs. Default 30.
env: Modal environment (apps only).
Returns: {match_count (exact, whole log searched), returned (matches actually shown),
returned_blocks, matches (context blocks, matched lines prefixed ">"), excluded_lines,
output_capped}.
|
| list_modal_resourcesA | Read-only lookup of everything in the Modal account. Start here to find the app name,
container ID or volume name that the other tools take.
Args:
resource: One of:
"apps" — deployed/running/recently-stopped apps.
"app_history" — one app's deployment versions (`name` = app name/ID); use it
to pick a version for manage_modal_app(action="rollback").
"containers" — running containers ("ta-..."); `name` = app ID to filter.
"volumes" — named volumes.
"volume_files" — files in a volume (`name` = volume, plus `path`).
"secrets" — secret names only; values are never returned.
"environments" — valid values for every `env` argument.
"profile" — active profile + all profiles (which account am I?).
name: App name/ID, app ID filter, or volume name — see `resource`.
path: Path inside the volume for "volume_files". Default "/".
env: Modal environment. Ignored for "environments"/"profile".
Returns: {<resource key>: [...]} — e.g. "apps", "containers", "contents". Listings
over 200 entries are capped, with `omitted_items` giving the count dropped.
|
| manage_modal_secretA | Create or delete a secret. To list secret names use
list_modal_resources(resource="secrets") — values are never readable.
Values are redacted from every field returned (command, stdout, stderr, error), so
they cannot leak back into the transcript on failure.
Args:
action: "create" or "delete".
secret_name: Secret name.
key_values: For "create": {"API_KEY": "abc", ...}.
from_dotenv / from_json: For "create": load key/values from a local file instead.
force: For "create": overwrite an existing secret.
env: Modal environment to target.
Returns: {message, stdout, stderr} or {error}, with values redacted.
|
| inspect_modal_secretA | List the KEY NAMES inside a Modal secret — never the values.
Modal exposes no API for this: neither the CLI, the SDK, nor the gRPC layer can read
a secret's contents, by design. The only way to see which keys a secret defines is to
mount it in a container and look at the environment variable names. So this tool
starts a short-lived container (`modal shell --secret ...`), prints the variable NAMES
only, and subtracts the ones the image and the Modal runtime would have set anyway.
That means, unlike every other read in this server, a call here **starts remote
compute and costs a few cents** (and takes tens of seconds — longer on the first run
for a given image, which has to be built). It is not a free lookup: use
list_modal_resources(resource="secrets") to see which secrets exist, and reach for
this only when you need to know what is inside one.
Values never leave the container: the probe is `compgen -e`, a bash builtin that
prints exported variable NAMES only, so no value is ever printed or read.
Args:
secret_name: Name of the secret, from list_modal_resources(resource="secrets").
env: Modal environment the secret lives in.
image: Optional container image. Omit it to use Modal's default image, which is
built to match this server's Python — that is the most reliable choice. Pass one
(e.g. "python:3.12-slim") if the workspace's image builder rejects that Python.
timeout_seconds: Max seconds to wait, including image build. Default 300.
Returns: {keys: [...names...], all_env_names: [...], filtered_out: n}. `all_env_names`
is the unfiltered list, so a key that looks like a runtime variable (e.g. one
literally named "PATH") is still visible rather than silently dropped.
|
| manage_modal_volumeA | Volume lifecycle. For the files inside a volume use modal_volume_files (writes) or
list_modal_resources(resource="volume_files") (reads).
Args:
action: "create", "delete" (removes the volume and ALL its data — irreversible),
or "rename".
volume_name: Volume name (the current name, for "rename").
new_name: Required for "rename".
env: Modal environment. Volumes are environment-scoped, so this must match the
environment the volume lives in.
Returns: {message, stdout, stderr} or {error}.
|
| modal_volume_filesA | Write operations on a volume's files. To LIST a volume's contents use
list_modal_resources(resource="volume_files").
Args:
action: "put" (upload local_path → remote_path), "get" (download remote_path →
local_path; "-" returns the contents instead of writing a file), "cp" (copy
inside the volume, using `paths`), "rm" (delete remote_path).
volume_name: Volume name.
local_path: Local source ("put") or destination ("get", default ".").
remote_path: In-volume destination ("put", default "/", trailing "/" keeps the
filename), source ("get"), or target ("rm").
paths: For "cp": sources followed by the destination, e.g. ["a.txt", "dest/"].
recursive: Needed to "rm" or "cp" a directory.
force: Overwrite existing files ("put"/"get").
env: Modal environment the volume lives in.
Returns: {message, stdout, stderr} or {error}. When MCP_MODAL_ALLOWED_LOCAL_PATHS is
set, "put"/"get" are refused for local paths outside the allowlist.
|