terminal-use

Permite que agentes de IA operem um terminal real: digitar, pressionar teclas, clicar, ler a tela e capturar screenshots.

Documentação

terminal-use

Um servidor MCP que permite a um agente de IA usar um terminal real da mesma forma que uma pessoa: digitar, pressionar teclas, clicar, ler a tela, tirar uma captura de tela.

An agent opening vim, pasting a program, saving it, running it, and taking a screenshot — each step labelled with the tool call that made it

Cada quadro acima foi desenhado pelo próprio renderizador de capturas de tela do terminal-use; a legenda em cada um é a chamada de ferramenta que o produziu.

A maioria das ferramentas de shell para agentes executa um comando e devolve sua saída. Isso falha para qualquer coisa interativa — vim, htop, um REPL, um instalador fazendo perguntas, git rebase -i, uma sessão SSH. O terminal-use dá ao agente um shell em um pseudo-terminal real, renderizado por um emulador de terminal real, para que programas interativos e de tela cheia funcionem e o agente veja o que você veria.

  • PTY real, emulador real — cores, movimento do cursor e a tela alternativa são interpretados, não repassados como códigos de escape.
  • Texto e pixels — leia a tela como texto simples ou como PNG quando layout e cor importam.
  • Espera adequada — bloqueia até o comando realmente terminar, ou até algum texto aparecer.
  • Acompanhe junto — anexe seu próprio terminal a qualquer sessão e digite junto com o agente.

Início rápido

Requer Node.js 20.19 ou mais recente, em macOS, Linux ou Windows.

Claude Code

claude mcp add terminal-use --scope user -- npx -y terminal-use

Outros clientes MCP (Claude Desktop, Cursor e qualquer outro que aceite um comando):

{
  "mcpServers": {
    "terminal-use": {
      "command": "npx",
      "args": ["-y", "terminal-use"]
    }
  }
}

Inicie uma nova sessão no seu cliente e peça para fazer algo em um terminal, por exemplo: "Abra o vim, escreva um haiku em /tmp/haiku.txt, salve e saia, e depois me mostre uma captura de tela de cat-o."

As opções do servidor vêm depois do comando: npx -y terminal-use --cols 100 --rows 40.

OpçãoPadrão
--shell <path>$SHELL ou /bin/bash; PowerShell no WindowsShell para executar em novas sessões
--cwd <path>onde o servidor foi iniciadoDiretório de trabalho para novas sessões
--cols <n> / --rows <n>120 / 30Tamanho do terminal
--scrollback <n>5000Linhas de histórico mantidas
--logindesligadoIniciar shells como shells de login (veja abaixo)

"command not found" dentro de uma sessão

Se programas que funcionam no seu próprio terminal (node, brew, pyenv…) estiverem ausentes dentro de uma sessão, o servidor provavelmente herdou um ambiente vazio. Isso acontece quando o cliente MCP é iniciado a partir do Dock ou de um lançador em vez de um terminal: seu PATH é configurado pelos arquivos de perfil do seu shell (~/.zprofile, ~/.bash_profile, ~/.profile), e nada os leu.

Um shell de login lê esses arquivos. Ative-o para toda sessão com a flag de servidor --login, ou para uma sessão com login: true em terminal_create. Ele fica desligado por padrão porque torna cada shell mais lento para iniciar e executa o que seu perfil executa. Não tem efeito no PowerShell ou cmd.exe, que não têm modo de login.

Ferramentas

Toda ferramenta, exceto terminal_create e terminal_list, recebe o sessionId que terminal_create retorna.

FerramentaO que faz
terminal_createInicia uma sessão: um shell interativo, ou um programa com command. Opcionais: label, cols, rows, shell, cwd, env, login, scrollback, theme.
terminal_listLista sessões.
terminal_destroyEncerra uma sessão.
terminal_typeDigita texto. \n pressiona Enter. paste: true envia como uma única colagem.
terminal_pressPressiona uma tecla ou combinação: Enter, Ctrl+C, ArrowUp, Shift+Tab, Alt+Enter, F5…
terminal_waitEspera o comando em execução terminar, uma regex aparecer, ou a saída ficar silenciosa.
terminal_readLê a tela ou o histórico de rolagem como texto.
terminal_screenshotRenderiza a tela como PNG.
terminal_clickClique esquerdo em uma célula, com etapa de pré-visualização.
terminal_scrollGira a roda do mouse sobre uma célula.
terminal_batchEnvia várias entradas em uma chamada e recebe a tela uma única vez.
terminal_resizeAltera o tamanho do terminal.
terminal_resetLimpa a tela e o histórico de rolagem, ou reinicia o shell com hardReset: true.

Docker

O repositório tem um Dockerfile para executar o servidor em um contêiner:

docker build -t terminal-use .
docker run -i --rm -v "$PWD":/workspace terminal-use

Em um cliente MCP, use docker como comando com run -i --rm terminal-use como seus argumentos. Os terminais que o agente recebe são então shells dentro do contêiner, não na sua máquina: ele vê apenas o que você monta, que é o objetivo se você quiser isolá-lo. Anexar a partir do seu próprio terminal não está disponível nessa configuração.

A habilidade

O terminal-use vem com uma Agent Skill: um guia curto para o agente sobre como usar bem essas ferramentas — quando usar uma sessão de comando, como esperar, como ler o que está selecionado — além de receitas para vim, paginadores, REPLs, programas dirigidos por menu, prompts de ssh e testes de ponta a ponta de uma TUI. Ela vive em skills/terminal-use.

  • Hosts que carregam habilidades de servidores MCP a obtêm automaticamente. O servidor implementa a extensão MCP Skills (io.modelcontextprotocol/skills): a habilidade é listada por skills/list e seus arquivos são servidos como recursos skill://terminal-use/.... Poucos hosts suportam isso ainda.

  • Hosts que carregam habilidades do disco podem instalar os mesmos arquivos. Para Claude Code:

    cp -r "$(npx -y terminal-use skills-dir)/terminal-use" ~/.claude/skills/
    

A habilidade é opcional. Sem ela, o agente ainda tem as descrições das ferramentas e as instruções embutidas do servidor.

Sessões de shell e sessões de comando

Por padrão, uma sessão é um shell interativo: digite comandos nele como faria em um prompt.

Passe command para terminal_create para executar um programa no terminal:

{"command": "npm test -- --watch", "cwd": "/path/to/project", "env": {"CI": "1"}}

O comando passa pelo shell da sessão (sh -c, PowerShell -Command, ou cmd /c), então aspas, pipes e redirecionamento funcionam como no prompt desse shell. A entrada vai direto para o programa. Quando ele sai:

  • seu status de saída é relatado (pela chamada em andamento, por terminal_wait, e em terminal_list);
  • a tela final permanece legível com terminal_read e terminal_screenshot;
  • ferramentas de entrada retornam um erro com o status de saída em vez de reiniciar qualquer coisa;
  • terminal_reset com hardReset: true o executa novamente, e terminal_destroy o remove.

Este é o modo para testar uma CLI ou TUI: inicie, dirija, verifique como terminou.

Assistindo e digitando junto

terminal_create retorna um comando que você pode executar no seu próprio terminal para entrar na sessão:

node /path/to/terminal-use/bin/terminal-use.js attach 3 --socket /tmp/terminal-use-501/41234-3.sock

Você vê o que o agente vê e pode digitar no mesmo shell. Funciona como uma sessão tmux compartilhada: várias pessoas podem se anexar ao mesmo tempo, e Ctrl+] desanexa.

  • Você recebe a tela atual e o histórico de rolagem recente ao conectar, não um terminal em branco.
  • --resize faz a sessão seguir o tamanho da sua janela. Por padrão, a sessão mantém o próprio tamanho.
  • --socket escolhe o servidor. Cada cliente MCP executa seu próprio terminal-use, e todos numeram sessões a partir de 1; sem --socket, attach <id> funciona quando apenas um servidor em execução tem esse id e lista os candidatos caso contrário.
  • No Windows, a sessão é alcançada por um pipe nomeado em vez de um arquivo de socket; o comando que você recebe funciona da mesma forma.
  • Sockets são por usuário (0600, dentro de um diretório 0700 sob o diretório temporário do sistema). Qualquer um que possa conectar obtém um shell como você, então eles não são expostos além disso.

Como funciona

agent ──MCP──▶ terminal-use ──▶ node-pty ──▶ your shell
                  │
                  └─ @xterm/headless  ◀── everything the shell prints
                        │
                        ├─ terminal_read        (text)
                        └─ terminal_screenshot  (PNG)

node-pty executa o shell em um pseudo-terminal. Tudo o que ele imprime é alimentado a um emulador xterm.js headless, e o buffer desse emulador é a fonte única de verdade: leituras e capturas de tela vêm ambas dele, então o agente recebe a tela renderizada em vez de um fluxo de códigos de escape.

Detalhes

Esperando por coisas

terminal_type, terminal_press e terminal_click retornam assim que a saída fica silenciosa por um momento (idleMs, padrão 200 ms) e nunca esperam mais de 10 segundos. Isso serve para teclas. Não serve para um build, que pode ficar silencioso por um bom tempo antes de terminar. Para qualquer coisa lenta, acompanhe com terminal_wait:

  • Padrão — espera o comando terminar. O terminal-use pergunta ao kernel qual processo é dono do primeiro plano do terminal. Um shell entrega o terminal a cada comando que executa e o retoma depois, então quando o shell o possui novamente, o prompt voltou. Isso não precisa de integração de shell ou análise de prompt, e funciona para comandos que não imprimem nada.
  • pattern — espera uma regex corresponder à tela. Para coisas que nunca saem (Listening on port), prompts de REPL, ou um estado específico de uma TUI. ^ e $ correspondem a inícios e fins de linha; um (?i) ou (?s) inicial define outras flags.
  • until: "quiet" — espera a saída parar por quietMs (padrão 1 s). A mesma regra que as ferramentas de digitação usam, sem o limite de 10 segundos.

Em uma sessão de comando, o modo padrão espera o programa sair e relata seu status de saída.

timeoutMs tem padrão de 30 segundos (máximo 10 minutos). Um tempo esgotado não é um erro: a resposta diz que o comando ainda está em execução, e você pode esperar novamente.

No Windows não há como perguntar quem é dono do terminal, então em uma sessão de shell o modo padrão espera dois segundos de silêncio e diz que é um palpite. Prefira um pattern lá, ou execute o programa como uma sessão de comando, onde esperar ele sair funciona em todas as plataformas.

Limites que valem saber: trabalhos em segundo plano (cmd &) não contam como em execução. Dentro de um programa aninhado como ssh ou um REPL, o shell externo não recupera o primeiro plano até esse programa sair, então use pattern ou until: "quiet" lá. Nenhum status de saída é relatado; execute echo $?.

Lendo a tela

terminal_read retorna texto em páginas do tamanho da tela: page: 0 é a tela atual, page: 1 a anterior, e assim por diante pelo histórico de rolagem.

Linhas que o terminal quebrou na borda direita são unidas de volta na linha única que o programa imprimiu (joinWrapped: false dá uma linha por linha da tela).

O texto não pode mostrar cor, então não pode mostrar qual entrada de menu está selecionada. Leituras portanto terminam com uma lista do que está destacado na tela — texto em vídeo reverso ou em cor de fundo — com a linha e colunas que terminal_click ocupa:

Highlighted on screen (reverse video or background color; screen row, columns):
  row 7, cols 3-18: "Unstaged changes"

Se a maior parte da tela é painéis coloridos, a lista é substituída por um ponteiro para terminal_screenshot. Desligue com highlights: false.

O cursor é marcado com ▌. Em uma célula vazia, ele simplesmente ocupa o lugar do espaço em branco. Em um caractere, é inserido na frente desse caractere, o que desloca o resto daquela linha em uma coluna; o cabeçalho diz em qual caractere ele está. O marcador é omitido enquanto o programa esconde o cursor (a maioria dos programas de tela cheia faz isso), e cursor: false retorna o texto intacto.

Capturas de tela

terminal_screenshot renderiza a tela com a JetBrains Mono incluída. Isto é o que uma chamada retorna, aqui com uma seleção visual no vim:

A terminal_screenshot of vim with Python syntax highlighting and four lines selected

Sessões recebem um theme na criação: dark (padrão), light, solarized-dark ou solarized-light.

A JetBrains Mono cobre latim, grego, cirílico, desenho de caixas e símbolos comuns. Emoji, texto chinês/japonês e coreano recorrem a fontes já no sistema, porque incluí-las adicionaria dezenas de megabytes:

EmojiCJKHangul
macOSApple Color EmojiHiragino Sans GB / PingFangApple SD Gothic Neo
WindowsSegoe UI EmojiMicrosoft YaHei / Yu GothicMalgun Gothic
LinuxNoto Color EmojiNoto Sans CJKNoto Sans CJK
O macOS já vem com esses recursos de fábrica, e o Windows tem a fonte de emojis (as fontes do Leste Asiático vêm com os recursos de idioma correspondentes). No Debian ou Ubuntu, instale-os com apt install fonts-noto-color-emoji fonts-noto-cjk. Sem eles (em uma imagem Docker mínima, por exemplo), esses caracteres aparecem como caixas vazias em capturas de tela. Os ícones Nerd Font e Powerline aparecem como caixas em qualquer lugar. terminal_read não é afetado e sempre retorna os caracteres reais.

Digitação, colagem e lote

terminal_type envia caracteres como pressionamentos de tecla. Para texto multilinha em um editor, um REPL ou um prompt de shell, adicione paste: true: programas que suportam colagem entre colchetes a recebem como uma única colagem e a inserem literalmente, sem auto-indentação ou execução de cada linha conforme chega. Programas que não suportam recebem os caracteres simples.

terminal_batch envia uma lista de entradas em uma única chamada e retorna a tela apenas no final, o que economiza uma ida e volta por pressionamento de tecla quando os passos já são conhecidos:

{
  "sessionId": 1,
  "actions": [
    {"type": "press", "key": "ArrowDown", "count": 3},
    {"type": "press", "key": "Enter"},
    {"type": "wait", "pattern": "Commit message"},
    {"type": "type", "text": "Fix typo"},
    {"type": "press", "key": "Ctrl+S"}
  ]
}

As ações são type, paste, press, click, scroll e wait (um ms fixo, ou um pattern para aparecer). O lote é verificado antes de qualquer envio e para na primeira ação que falhar, informando até onde chegou.

Clique e rolagem

  • Apenas botão esquerdo. As coordenadas são indexadas a partir de 1; (1, 1) é a célula no canto superior esquerdo.
  • preview está ativado por padrão. Uma pré-visualização retorna uma captura de tela com um anel desenhado ao redor da célula alvo e não envia clique. Repita a chamada com preview: false para clicar. Programas em tela cheia frequentemente têm ações destrutivas a um clique de distância, então vale o passo extra.
  • terminal_scroll gira a roda sobre uma célula. Programas que rastreiam o mouse recebem eventos de roda ali, então o painel sob o ponteiro rola; programas em tela cheia que não rastreiam (less, man) recebem teclas de seta, como em um terminal normal. Em um prompt de shell não há nada para rolar — leia a saída anterior com terminal_read e page.
  • Um clique real precisa que o programa tenha ativado o relatório de mouse — vim com set mouse=a, fzf, lazygit, htop e a maioria das TUIs modernas fazem isso. Em um prompt de shell simples, a chamada retorna um erro em vez de imprimir códigos de escape na sua linha de comando.

Ciclo de vida da sessão

  • As sessões são independentes. Chamadas para uma sessão são executadas em ordem; chamadas para sessões diferentes não bloqueiam umas às outras.
  • Se o shell de uma sessão de shell sair, a sessão ficar ociosa por seis horas, ou o limite de 50 sessões for atingido, a sessão é encerrada, mas seu id permanece reservado por 30 dias. A próxima chamada para esse id inicia um shell novo com o mesmo tamanho, shell, diretório de trabalho e tema, e retorna um aviso informando o que aconteceu — incluindo a última tela que o shell antigo imprimiu, se ele saiu por conta própria. O comando nessa chamada não é executado; envie-o novamente se ainda quiser.
  • Ocioso significa sem chamadas de ferramenta e sem saída. Um servidor de desenvolvimento que ainda está imprimindo não está ocioso.
  • terminal_destroy encerra uma sessão definitivamente; seu id não é reservado.
  • Quando o cliente MCP desconecta ou o servidor é interrompido, todos os shells são fechados e todos os sockets de anexo são removidos.

Suporte ao protocolo

Construído sobre o SDK oficial do MCP TypeScript (v2). Via stdio, ele fala tanto a revisão de 28 de julho de 2026 do protocolo, que é sem estado, quanto as revisões anteriores baseadas em handshake; a primeira mensagem do cliente decide qual usar.

Sem estado refere-se ao protocolo, não aos terminais: as sessões vivem no processo do servidor e são endereçadas pelo sessionId que você passa em cada chamada. O servidor também fornece instruções de uso, títulos e dicas de comportamento para cada ferramenta, cancelamento, atualizações de progresso de terminal_wait e a extensão de Skills descrita acima.

Suporte de plataforma

macOS (arm64, x64)Suportado; testado em CI
Linux (arm64, x64)Suportado; testado em CI no Node 20, 22 e 24
Windows (x64)Suportado; testado em CI contra PowerShell e cmd.exe

No Windows, as sessões são executadas via ConPTY, o shell padrão é o Windows PowerShell, e duas coisas diferem: terminal_wait não consegue detectar que um comando de shell terminou (veja Esperando por coisas), e login não faz nada.

As dependências nativas (node-pty, @napi-rs/canvas) vêm com binários pré-compilados, então nenhum compilador é necessário para instalar.

Desenvolvimento

git clone https://github.com/computer-agent-labs/terminal-use.git
cd terminal-use
yarn install
yarn build      # compile src/ to dist/
yarn test       # build, then run the full suite

Outros scripts:

yarn dev            # run the server straight from source
yarn lint           # eslint
yarn typecheck      # tsc, no output
yarn test:unit      # unit tests only
yarn test:windows   # what CI runs on Windows: shell-independent tests + tests/windows
yarn smoke          # quick end-to-end check without an MCP client
yarn demo           # regenerate docs/demo.gif (needs ffmpeg, vim and python3)

Para apontar seu cliente MCP para um checkout local, compile-o e use o caminho para o script bin:

claude mcp add terminal-use --scope user -- node "$PWD/bin/terminal-use.js"

O código é organizado por camada: src/pty (spawning, codificação de teclas e mouse), src/emulator (o buffer xterm, renderização, espera), src/session (um terminal), src/attach (o socket pelo qual você anexa) e src/mcp (as ferramentas). A habilidade do agente está em skills/.

Segurança

terminal-use dá ao cliente conectado um shell na sua máquina, executando como você, sem sandbox. Conecte-o apenas a clientes em que você confiaria um terminal, e use as configurações de aprovação de ferramentas do seu cliente para controlar o que é executado sem solicitação. Ele não abre portas de rede; os sockets de anexo são restritos ao seu próprio usuário. Veja SECURITY.md para detalhes e para saber como relatar uma vulnerabilidade.

Contribuindo

Issues e pull requests são bem-vindos. CONTRIBUTING.md cobre a configuração, execução dos testes e o que um bom pull request parece. Este projeto segue o Contributor Covenant.

Licença

MIT. As fontes JetBrains Mono incluídas são licenciadas sob a SIL Open Font License.