Modal MCP
Um servidor MCP para gerenciar aplicativos, containers, volumes e segredos do Modal. Também ajuda a implantar e executar aplicativos Modal diretamente do Claude Code e de outros clientes MCP.
Documentação
Servidor MCP Modal
Um servidor MCP para gerenciar Modal — apps, contêineres, volumes e segredos — e para implantar e executar apps Modal diretamente do Claude Code e de outros clientes MCP.
Cada ferramenta executa comandos na sua CLI modal local, então opera com o perfil e as credenciais Modal configurados na sua máquina. Não há tokens extras para gerenciar.
Instalação
O servidor é publicado no PyPI como mcp-modal. Não é necessária instalação manual — a forma recomendada de executá-lo é com uvx, que o busca e inicia sob demanda. Basta apontar seu cliente MCP para o comando abaixo (veja Configuração).
Fazendo login no Modal
Este servidor usa suas credenciais Modal locais. Se você ainda não se autenticou, execute:
modal setup
Isso abre um navegador para login e armazena um token em ~/.modal.toml. Já está logado em outro lugar? Verifique com modal profile current.
Configuração
Adicione o servidor ao Claude Code com a CLI claude mcp:
claude mcp add mcp-modal -- uvx mcp-modal
Ou adicione-o a um arquivo .mcp.json na raiz do seu projeto:
{
"mcpServers": {
"mcp-modal": {
"command": "uvx",
"args": ["mcp-modal"]
}
}
}
Para fixar uma versão específica, use uvx mcp-modal@0.2.0.
Requisitos
- Python 3.11 ou superior
uv(forneceuvx)- CLI Modal 1.x configurada com credenciais válidas (
modal setup) - Para suporte a deploy e run do Modal:
- O projeto sendo implantado/executado deve usar
uvpara gerenciamento de dependências modaldeve estar instalado no ambiente virtual desse projeto
- O projeto sendo implantado/executado deve usar
Segurança
Este servidor executa comandos na sua CLI modal local usando as credenciais presentes em
~/.modal.toml. Algumas ferramentas são poderosas por design — se o cliente MCP que controla o servidor
for alvo de injeção de prompt (por exemplo, por texto malicioso dentro de logs que ele buscou), estes
são os caminhos de escalonamento e devem permanecer atrás dos prompts de aprovação de ferramentas do seu cliente, em vez de
serem aprovados automaticamente:
deploy_modal_app/run_modal_app— executam Python local arbitrário no host (modal deployimporta o arquivo do app;uv runresolve e instala as dependências do projeto alvo).put_modal_volume_file— pode ler qualquer arquivo local (por exemplo,~/.ssh/id_rsa,~/.modal.toml) e enviá-lo para um volume na nuvem (uma primitiva de exfiltração de dados).get_modal_volume_filecomforce=True— pode sobrescrever qualquer caminho local (por exemplo,~/.zshrcou um perfil de shell, uma primitiva de persistência).exec_modal_container— executa comandos arbitrários dentro de um contêiner, por design.
Lista de permissões opcional de caminhos locais
Para conter as duas ferramentas de volume que acessam o sistema de arquivos, defina a
variável de ambiente MCP_MODAL_ALLOWED_LOCAL_PATHS como uma lista
os.pathsep-separada de
diretórios (: no macOS/Linux). Quando definida, put_modal_volume_file (seu local_path)
e get_modal_volume_file (seu local_destination) são recusados, a menos que o caminho resolvido —
após expandir ~ e colapsar ../links simbólicos — esteja dentro de uma dessas raízes. O
destino de download "-" (stream para stdout) é isento porque nada é gravado em disco.
Quando a variável está não definida (o padrão), não há restrição, então configurações existentes não são afetadas. Configure-a no seu cliente MCP, por exemplo:
{
"mcpServers": {
"mcp-modal": {
"command": "uvx",
"args": ["mcp-modal"],
"env": { "MCP_MODAL_ALLOWED_LOCAL_PATHS": "/Users/me/modal-workspace:/tmp/modal" }
}
}
}
Todas as ferramentas também passam nomes/caminhos fornecidos pelo usuário após um separador de fim de opções --, então um
valor que começa com - é sempre tratado como dado, nunca como um flag da CLI modal. Valores de
segredos passados para create_modal_secret são ocultados do comando ecoado, dos logs e de qualquer
saída de erro.
Ferramentas Suportadas
26 ferramentas, agrupadas por área. Ferramentas com escopo de conta aceitam um argumento opcional env para
segmentar um ambiente Modal específico; se
omitido, elas usam o padrão do perfil (ou MODAL_ENVIRONMENT).
Deploy & Run
-
Implantar App Modal (
deploy_modal_app)- Implanta um app Modal (
modal deploy). Endpoints web implantados persistem, então qualquer link na saída está ativo e compartilhável (retornado emurls). - Parâmetros:
absolute_path_to_app(obrigatório),env,name,tag,strategy(rolling/recreate),stream_logs - O diretório do app deve usar
uvcommodalinstalado em seu virtualenv.
- Implanta um app Modal (
-
Executar App Modal (
run_modal_app)- Executa uma função ou entrypoint local uma vez e transmite sua saída (
modal run). - Parâmetros:
absolute_path_to_app(obrigatório),function_name,env,detach,timeout_seconds(padrão 120) - Retorna um snapshot com
truncated: truese a execução ainda estiver em andamento no timeout. Passedetach=Truepara manter jobs longos ativos no Modal além do timeout.
- Executa uma função ou entrypoint local uma vez e transmite sua saída (
Por que não há ferramenta
modal serve?modal servesó mantém seus endpoints ativos enquanto o processo bloqueante está em execução — uma ferramenta MCP que retorna os derrubaria imediatamente, entregando uma URL morta. Usedeploy_modal_apppara um endpoint persistente e compartilhável.
Apps
-
Listar Apps Modal (
list_modal_apps)- Lista apps atualmente implantados/em execução ou parados recentemente. Use isso para encontrar o nome/ID do app para as outras ferramentas de app.
- Parâmetros:
env
-
Obter Logs do App Modal (
get_modal_app_logs)- Busca ou transmite logs de um app por nome ou ID (
modal app logs). - Parâmetros:
app_identifier(obrigatório),timeout_seconds(padrão 30),env,since,until,tail,search,source(stdout/stderr/system),timestamps(prefixa cada linha com seu horário de parede),follow - Com
follow=True, os logs são transmitidos até o app parar outimeout_secondsser atingido, retornando um snapshot comtruncated: true. - Cobre apenas os streams stdout/stderr/sistema; algumas falhas (por exemplo, uma falha relatada como "... exited with ...") são eventos do dashboard Modal, não linhas de log, e não aparecerão aqui.
- Busca ou transmite logs de um app por nome ou ID (
-
Parar App Modal (
stop_modal_app)- Para permanentemente um app e encerra seus contêineres (
modal app stop). - Parâmetros:
app_identifier(obrigatório),env
- Para permanentemente um app e encerra seus contêineres (
-
Reverter App Modal (
rollback_modal_app)- Reimplanta uma versão anterior de um app (
modal app rollback). - Parâmetros:
app_identifier(obrigatório),version(opcional — padrão para a versão anterior),env
- Reimplanta uma versão anterior de um app (
-
Obter Histórico do App Modal (
get_modal_app_history)- Retorna o histórico de implantação de um app (
modal app history). Use-o para encontrar umversionpara reversão. - Parâmetros:
app_identifier(obrigatório),env
- Retorna o histórico de implantação de um app (
Contêineres
-
Listar Contêineres Modal (
list_modal_containers)- Lista contêineres atualmente em execução (
modal container list). - Parâmetros:
app_id(filtro opcional),env
- Lista contêineres atualmente em execução (
-
Obter Logs do Contêiner Modal (
get_modal_container_logs)- Busca ou transmite logs de um ID de contêiner (
modal container logs). - Parâmetros:
container_id(obrigatório),timeout_seconds(padrão 30),since,until,tail,search,source,timestamps,follow - Mesma ressalva de stdout/stderr/sistema da ferramenta de logs de app acima.
- Busca ou transmite logs de um ID de contêiner (
-
Executar no Contêiner Modal (
exec_modal_container)- Executa um comando dentro de um contêiner em execução (
modal container exec --no-pty). - Parâmetros:
container_id(obrigatório),command(lista de argumentos, por exemplo,["python", "-c", "print('hi')"]),timeout_seconds(padrão 60)
- Executa um comando dentro de um contêiner em execução (
-
Parar Contêiner Modal (
stop_modal_container)- Encerra um contêiner em execução (
modal container stop). - Parâmetros:
container_id(obrigatório)
- Encerra um contêiner em execução (
Pesquisa de Logs
- Pesquisar Logs Modal (
search_modal_logs)- Busca nos logs de um app ou contêiner por um padrão e retorna cada ocorrência com as
linhas ao redor — feito para depuração de "onde deu errado?". Os logs são buscados
uma vez e pesquisados localmente, então (diferente do argumento
searchnas ferramentas de log) você obtém contexto, regex, controle de maiúsculas/minúsculas e contagens de correspondências, não apenas a linha correspondente nua. - Parâmetros:
identifier(obrigatório — nome/ID do app ou ID do contêiner),pattern(obrigatório),target(app/container, padrãoapp),regex,case_sensitive,context_lines(padrão 3),max_matches(padrão 50),since,tail(padrão para as últimas 1000 entradas),source(stdout/stderr/system),exclude(remove linhas de ruído antes de pesquisar, por exemplo,"queue put failed"),timestamps(padrãotrue— carrega o horário de parede de cada linha para o resultado),timeout_seconds,env - Retorna
match_countematches: blocos de contexto com timestamp e número de linha onde linhas correspondentes são prefixadas com>, por exemplo,> 8: 2026-06-04T... ValueError: bad input. Relataexcluded_linesquandoexcludeé usado. - Pesquisa apenas os streams stdout/stderr/sistema; falhas emitidas como eventos do dashboard Modal (por exemplo, "... exited with ...") retornam 0 correspondências mesmo quando a falha é real.
- Busca nos logs de um app ou contêiner por um padrão e retorna cada ocorrência com as
linhas ao redor — feito para depuração de "onde deu errado?". Os logs são buscados
uma vez e pesquisados localmente, então (diferente do argumento
Volumes — Arquivos
- Listar Volumes Modal (
list_modal_volumes) — lista todos os volumes. Parâmetros: nenhum. - Listar Conteúdo do Volume (
list_modal_volume_contents) —volume_name,path(padrão/). Defineempty: truecom uma mensagem quando a listagem genuinamente não retorna nada, para que um diretório vazio seja distinguível de um erro ou caminho errado. - Copiar Arquivos (
copy_modal_volume_files) —volume_name,paths(o último é o destino). - Remover Arquivo (
remove_modal_volume_file) —volume_name,remote_path,recursive. - Enviar Arquivo (
put_modal_volume_file) —volume_name,local_path,remote_path,force. - Baixar Arquivo (
get_modal_volume_file) —volume_name,remote_path,local_destination,force. Use-como destino para transmitir o conteúdo para stdout.
Volumes — Ciclo de Vida
- Criar Volume (
create_modal_volume) — cria um volume persistente nomeado. Parâmetros:volume_name,env. - Excluir Volume (
delete_modal_volume) — exclui um volume e todos os seus dados (irreversível). Parâmetros:volume_name,env. - Renomear Volume (
rename_modal_volume) — Parâmetros:old_name,new_name,env.
Segredos
-
Listar Segredos (
list_modal_secrets)- Lista segredos publicados (apenas nomes e timestamps — valores nunca são expostos).
- Parâmetros:
env
-
Criar Segredo (
create_modal_secret)- Cria um segredo a partir de chaves/valores inline ou de um arquivo local (
modal secret create). Valores de segredo são ocultados docommandretornado. - Parâmetros:
secret_name(obrigatório),key_values(dict),from_dotenv(caminho),from_json(caminho),force,env. Forneça pelo menos um dekey_values,from_dotenvoufrom_json.
- Cria um segredo a partir de chaves/valores inline ou de um arquivo local (
-
Excluir Segredo (
delete_modal_secret) — Parâmetros:secret_name,env.
Descoberta
-
Obter Perfil Modal (
get_modal_profile)- Mostra o perfil ativo e todos os perfis configurados. Use-o para confirmar em qual workspace/conta o servidor está autenticado. Parâmetros: nenhum.
-
Listar Ambientes Modal (
list_modal_environments)- Lista os ambientes no workspace atual; os nomes são argumentos válidos de
envpara as outras ferramentas. Parâmetros: nenhum.
- Lista os ambientes no workspace atual; os nomes são argumentos válidos de
Formato de Resposta
Todas as ferramentas retornam respostas em um formato padronizado, com pequenas variações dependendo do tipo de operação:
# 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
}
Licença
Este projeto é licenciado sob a Licença MIT - consulte o arquivo LICENSE para obter detalhes.