Modal MCP

by george-bobby

Not rated
GitHub

About

An MCP server for managing Modal apps, containers, volumes, and secrets. It also helps in deploying & running Modal apps directly from Claude Code and other MCP clients.

Details

Author
george-bobby
Categories
Cloud Service, Infrastructure

Setup

Install Modal MCP in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/george-bobby/mcp-modal

Follow the installation instructions in the repository README, then restart your MCP client.

An MCP server for managingModal— apps, containers, volumes, and secrets — and for deploying & running Modal apps directly fromClaude Codeand other MCP clients.

Every tool shells out to your localmodalCLI, so it operates against whatever Modal profile and credentials are configured on your machine. There are no extra tokens to manage.

The server is published on PyPI asmcp-modal. No manual install is needed — the recommended way to run it is withuvx, which fetches and launches it on demand. Just point your MCP client at the command below (seeConfiguration).

This server uses your local Modal credentials. If you haven't authenticated yet, run:

This opens a browser to log in and stores a token in~/.modal.toml. Already logged in elsewhere? Check withmodal profile current.

Add the server to Claude Code with theclaude mcpCLI:

claude mcp add mcp-modal -- uvx mcp-modal

Or add it to a.mcp.jsonfile in your project root:

{ "mcpServers": { "mcp-modal": { "command": "uvx", "args": ["mcp-modal"] } } }

To pin a specific release, useuvx mcp-modal@0.2.0.

- Python 3.11 or higher
- uv(providesuvx)
- Modal CLI 1.x configured with valid credentials (modal setup)
- For Modaldeployandrunsupport:

- The project being deployed/run must useuvfor dependency management
- modalmust be installed in that project's virtual environment

This server shells out to your localmodalCLI using whatever credentials are in~/.modal.toml. A few tools are powerful by design — if the MCP client driving the server is ever prompt-injected (for example by malicious text inside logs it fetched), these are the escalation paths and should staybehind your client's tool-approval promptsrather than being auto-approved:

- deploy_modal_app/run_modal_app— execute arbitrary local Python on the host (modal deployimports the app file;uv runresolves and installs the target project's dependencies).
- put_modal_volume_file— can read any local file (e.g.~/.ssh/id_rsa,~/.modal.toml) and upload it to a cloud volume (a data-exfiltration primitive).
- get_modal_volume_filewithforce=True— can overwrite any local path (e.g.~/.zshrcor a shell profile, a persistence primitive).
- exec_modal_container— runs arbitrary commands inside a container, by design.

To contain the two filesystem-touching volume tools, set theMCP_MODAL_ALLOWED_LOCAL_PATHSenvironment variable to anos.pathsep-separated list of directories (:on macOS/Linux). When it is set,put_modal_volume_file(itslocal_path) andget_modal_volume_file(itslocal_destination) are refused unless the resolved path — after expanding~and collapsing../symlinks — falls inside one of those roots. The download target"-"(stream to stdout) is exempt because nothing is written to disk.

When the variable isunset (the default) there is no restriction, so existing setups are unaffected. Configure it in your MCP client, e.g.:

{ "mcpServers": { "mcp-modal": { "command": "uvx", "args": ["mcp-modal"], "env": { "MCP_MODAL_ALLOWED_LOCAL_PATHS": "/Users/me/modal-workspace:/tmp/modal" } } } }

All tools also pass user-supplied names/paths after a--end-of-options separator, so a value beginning with-is always treated as data, never as amodalCLI flag. Secret values handed tocreate_modal_secretare redacted from the echoed command, logs, and any error output.

26 tools, grouped by area. Account-scoped tools accept an optionalenvargument to target a specificModal environment; if omitted, they use the profile's default (orMODAL_ENVIRONMENT).

- Deploys a Modal app (modal deploy). Deployed web endpoints persist, so any links in the output are live and shareable (returned inurls).
- Parameters:absolute_path_to_app(required),env,name,tag,strategy(rolling/recreate),stream_logs
- The app's directory must useuvwithmodalinstalled in its virtualenv.

- Runs a function or local entrypoint once and streams its output (modal run).
- Parameters:absolute_path_to_app(required),function_name,env,detach,timeout_seconds(default 120)
- Returns a snapshot withtruncated: trueif the run is still going at the timeout. Passdetach=Trueto keep long jobs alive on Modal past the timeout.

Why nomodal servetool?modal serveonly keeps its endpoints alive while the blocking process runs — an MCP tool that returns would tear them down immediately, handing back a dead URL. Usedeploy_modal_appfor a persistent, shareable endpoint.

- Lists apps currently deployed/running or recently stopped. Use this to find the app name/ID for the other app tools.
- Parameters:env

Get Modal App Logs(get_modal_app_logs)

- Fetches or streams logs for an app by name or ID (modal app logs).
- Parameters:app_identifier(required),timeout_seconds(default 30),env,since,until,tail,search,source(stdout/stderr/system),timestamps(prefix each line with its wall-clock time),follow
- Withfollow=True, logs stream until the app stops ortimeout_secondsis reached, returning a snapshot withtruncated: true.
- Only covers the stdout/stderr/system streams; some failures (e.g. a crash reported as "... exited with ...") are Modal dashboard events, not log lines, and won't appear here.

- Permanently stops an app and terminates its containers (modal app stop).
- Parameters:app_identifier(required),env

Roll Back Modal App(rollback_modal_app)

- Redeploys a previous version of an app (modal app rollback).
- Parameters:app_identifier(required),version(optional — defaults to the previous version),env

Get Modal App History(get_modal_app_history)

- Returns an app's deployment history (modal app history). Use it to find aversionfor rollback.
- Parameters:app_identifier(required),env
-

List Modal Containers(list_modal_containers)

- Lists currently running containers (modal container list).
- Parameters:app_id(optional filter),env

Get Modal Container Logs(get_modal_container_logs)

- Fetches or streams logs for a container ID (modal container logs).
- Parameters:container_id(required),timeout_seconds(default 30),since,until,tail,search,source,timestamps,follow
- Same stdout/stderr/system-only caveat as the app-logs tool above.

Exec in Modal Container(exec_modal_container)

- Runs a command inside a running container (modal container exec --no-pty).
- Parameters:container_id(required),command(list of args, e.g.
["python", "-c", "print('hi')"]),timeout_seconds(default 60)

Stop Modal Container(stop_modal_container)

- Terminates a running container (modal container stop).
- Parameters:container_id(required)
- Search Modal Logs(search_modal_logs)

- Greps an app's or container's logs for a pattern and returns each hitwith the surrounding lines— built for "where did it go wrong?" debugging. Logs are fetched once and searched locally, so (unlike thesearchargument on the log tools) you get context, regex, case control, and match counts, not just the bare matching line.
- Parameters:identifier(required — app name/ID or container ID),pattern(required),target(app/container, defaultapp),regex,case_sensitive,context_lines(default 3),max_matches(default 50),since,tail(defaults to the last 1000 entries),source(stdout/stderr/system),exclude(drop noise lines before searching, e.g."queue put failed"),timestamps(defaulttrue— carry each line's wall-clock time into the result),timeout_seconds,env
- Returnsmatch_countandmatches: timestamped, line-numbered context blocks where matched lines are prefixed with>, e.g.> 8: 2026-06-04T... ValueError: bad input. Reportsexcluded_lineswhenexcludeis used.
- Only searches the stdout/stderr/system streams; failures emitted as Modal dashboard events (e.g. "... exited with ...") return 0 matches even when the failure is real.
- List Modal Volumes(list_modal_volumes) — lists all volumes. Parameters: none.
- List Volume Contents(list_modal_volume_contents) —volume_name,path(default/). Setsempty: truewith a message when the listing genuinely returns nothing, so an empty directory is distinguishable from an error or a wrong path.
- Copy Files(copy_modal_volume_files) —volume_name,paths(last is destination).
- Remove File(remove_modal_volume_file) —volume_name,remote_path,recursive.
- Upload File(put_modal_volume_file) —volume_name,local_path,remote_path,force.
- Download File(get_modal_volume_file) —volume_name,remote_path,local_destination,force. Use-as the destination to stream contents to stdout.
- Create Volume(create_modal_volume) — creates a named persistent volume. Parameters:volume_name,env.
- Delete Volume(delete_modal_volume) — deletes a volumeand all its data(irreversible). Parameters:volume_name,env.
- Rename Volume(rename_modal_volume) — Parameters:old_name,new_name,env.

- Lists published secrets (names and timestamps only — values are never exposed).
- Parameters:env

- Creates a secret from inline key/values or a local file (modal secret create). Secret values areredactedfrom the returnedcommand.
- Parameters:secret_name(required),key_values(dict),from_dotenv(path),from_json(path),force,env. Provide at least one ofkey_values,from_dotenv, orfrom_json.

Delete Secret(delete_modal_secret) — Parameters:secret_name,env.

- Shows the active profile and all configured profiles. Use it to confirm which workspace/account the server is authenticated as. Parameters: none.

List Modal Environments(list_modal_environments)

- Lists the environments in the current workspace; the names are validenvarguments for the other tools. Parameters: none.

All tools return responses in a standardized format, with slight variations depending on the operation type:

# JSON / list operations (apps, containers, volumes, secrets, history, ...): { "success": True, "apps": [...] # or "containers", "volumes", "secrets", "history", "environments" } # Action operations (deploy, stop, create, delete, rename, copy, put, get, rm): { "success": True, "message": "Operation successful message", "command": "executed command string", "stdout": "command output", # if any "stderr": "error output" # if any } # Log / run / exec operations (snapshot-based): { "success": True, "logs": "...", # or "output" for run/exec "truncated": False, # True when cut off at timeout_seconds "command": "executed command string" } # Error case (all operations): { "success": False, "error": "Error message describing what went wrong", "command": "executed command string", "stdout": "command output", # if available "stderr": "error output" # if available }

This project is licensed under the MIT License - see theLICENSEfile for details.

Create, build, deploy, and manage Netlify resources using natural language.

Integrate with the Coolify API to manage your servers, applications, and databases.

An MCP server for interacting with the Coolify API to manage servers and applications.

An MCP server for integrating with Coolify, the self-hostable alternative to Netlify and Vercel.

Integrate with the Laravel Forge API to manage servers and deployments using MCP-compliant tools.

Interact with Modal volumes and deploy Modal applications from within Cursor.

An MCP server providing comprehensive access to Netlify's features and services.

Manage Laravel Forge servers and sites using the Forge API.

A command-line tool to automate the deployment of MCP servers to AWS ECS.

Core AWS MCP server providing prompt understanding and server management capabilities.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.