dot-mcp

MCP auto-hospedado para Linux/Termux: shell, arquivos, memória, tarefas, navegador e um cofre local experimental. Acesso remoto protegido por OAuth; roda na sua própria máquina.

Documentação

dot-mcp

Agente MCP pessoal para ChatGPT, Claude e Gemini: shell, arquivos, memória, metas, tarefas, caixa de entrada, agendador e OAuth auto-hospedado — rodando na sua própria máquina.

⚠️ O servidor dá acesso total ao shell para quem possuir uma credencial. Exponha-o apenas enquanto estiver usando e depois pare-o (dot-mcp stop).

Instalação

pip install dot-mcp

Requer Python 3.10+ e OpenSSH (ssh, ssh-keygen) para o túnel.

Uso

dot-mcp start    # server + public URL (runs in background)
dot-mcp status   # check if it is running
dot-mcp stop     # stop server + tunnel

dot-mcp start imprime tudo o que o conector precisa:

Public URL            https://xxxx.tunnl.gg/mcp/
Owner secret          <stored on your machine>
OAuth Client ID       dots-xxxxxxxx
OAuth Client secret   <stored on your machine>

Adicione a URL pública como um conector MCP personalizado (auth = OAuth). Aprove uma vez com o segredo do proprietário quando solicitado. A URL do túnel permanece a mesma ao reiniciar; o túnel gratuito expira após 24h ou 2h ocioso.

Linux/Termux é o runtime suportado para gerenciamento de processos. Parar afeta apenas processos iniciados com os novos registros de propriedade. Ao atualizar de uma versão mais antiga, pare o servidor/túnel anterior antes de iniciar esta versão; arquivos PID legados simples não são deliberadamente confiáveis.

DOT_MCP_STATE_DIR substitui o diretório completo de credenciais/chaves SSH (padrão ~/.config/dot-mcp), não seu pai. Isso é separado de --data-dir.

Caminhos de arquivo são relativos a $HOME a menos que sejam absolutos. Caminhos absolutos mantêm sua localização e devem estar dentro de $HOME, $TMPDIR ou armazenamento compartilhado disponível; outros caminhos são rejeitados, não colocados silenciosamente em HOME. No Android, quando $TMPDIR está fora de /tmp, /tmp e /tmp/... mapeiam para $TMPDIR. As ferramentas de arquivo retornam o path efetivo. O texto de comandos shell nunca é remapeado, então use esse caminho efetivo em comandos shell quando esse mapeamento se aplicar.

As raízes de arquivo são proteções, não uma sandbox de shell. Uma credencial de shell ainda concede acesso total como o usuário do SO do servidor. Use um usuário/contêiner de SO separado para cargas de trabalho não confiáveis.

Opções: --port (padrão 33041), --data-dir (padrão ~/.dot-mcp), --json (saída amigável para scripts).

Túnel de desenvolvimento (somente teste)

dots start --dev usa um túnel rápido do Cloudflare em vez do fluxo padrão tunnl.gg com chave estável. Ele precisa de cloudflared no PATH, não OpenSSH. A ausência de cloudflared é relatada como not installed: cloudflared; nada é instalado.

DEV / INSTÁVEL: os nomes de host do túnel rápido mudam a cada reinicialização e não têm garantia de disponibilidade. Erro 1033/indisponibilidades podem ocorrer. Túneis rápidos do Cloudflare não suportam SSE, então algumas combinações de cliente/transporte MCP podem falhar mesmo se a inicialização passar. Não use este modo para conectores de produção.

A proteção de Host/Origem permanece ativada. O host trycloudflare.com descoberto é passado ao servidor antes de sua única inicialização, com verificação pública autenticada de initialize. Uma verificação falha interrompe o servidor e o túnel de propriedade. dots stop interrompe qualquer provedor; --json inclui modo, provedor e campos instáveis. Uma configuração Cloudflare vazia explícita impede reutilizar um túnel nomeado salvo.

Isso é uma troca de provedor, NÃO uma sandbox de segurança: use um contêiner/usuário de SO separado com credenciais descartáveis. O modo dev não altera os caminhos padrão de dados ou credenciais e ainda pode usar um vault local existente opcional. Em uma sandbox isolada, use caminhos DOT_MCP_DATA e DOT_MCP_STATE_DIR separados e um HOME descartável; não monte arquivos pessoais. Pacotes opcionais de navegador/vault não são necessários para um teste básico de MCP/OAuth. --dev --vault usa o mesmo provedor dev, mas requer o desbloqueio normal do vault local.

Documentação do Cloudflare: https://developers.cloudflare.com/tunnel/get-started/quick-tunnels/

O que ele pode fazer (51 ferramentas nesta revisão de desenvolvimento)

  • Shell: run_command (sessões em segundo plano + timeout) + read_output
  • Arquivos: list_dir, read_file (paginado + sha256), write_file (atômico + proteções), append_file, edit_file
  • Memória: remember, recall, forget — persiste entre conversas
  • Metas/Tarefas: set_goal, add_update, get_state, add_task, complete_task
  • Caixa de entrada: notify_user, poll_inbox, ack_inbox — mensagens entre conversas
  • Agendador: add_schedule, list_schedules, remove_schedule — trabalhos em segundo plano que rodam entre conversas
  • Navegador: browser_open/navigate/snapshot/click/type/scroll/key/screenshot/close
    • browser_hover/select/wait/back/reload — snapshots relatam estado desabilitado, marcado e de opção selecionada; wait lida com páginas dinâmicas
  • Ao vivo: /live reconecta automaticamente (capacidade de sessionStorage), mostra o domínio atual, visualização em tela cheia; o controle ainda requer o token do proprietário
  • UI: open_workspace — painel embutido (tarefas, memória, sessões)

Trabalho durável (revisão de desenvolvimento)

Nomes/assinaturas de ferramentas existentes permanecem disponíveis. Novas ferramentas de trabalho:

  • create_work_task, get_work_task, list_work_tasks, update_work_task
  • start_command, get_session_status, cancel_command
  • register_artifact, bootstrap_context, ack_work_result, purge_session_output

Fluxo sugerido para ChatGPT/Claude:

  1. Chame bootstrap_context no início de uma nova conversa.
  2. Crie uma tarefa de trabalho, depois start_command com seu task_id.
  3. Consulte read_output / get_session_status. A saída é legível enquanto roda.
  4. Verifique o resultado, registre arquivos de saída e defina a tarefa como done com um resultado, ou blocked com uma pergunta. Sair com zero sozinho nunca finaliza uma tarefa.
  5. Em uma nova conversa, carregue o contexto e inspecione get_work_task para retomar.

start_command retorna imediatamente. Um idempotency_key reutilizado retorna a mesma sessão para uma solicitação idêntica; uma solicitação alterada com essa chave é rejeitada. Isso evita lançamentos duplicados, não efeitos externos exatamente-uma-vez. set_goal altera a meta atual sem excluir o histórico de add_update.

O run_command original permanece como a API síncrona legada. Use as novas ferramentas de início/status para trabalho assíncrono durável; read_output e get_session_status lidam com ambos. O status legado é apenas em memória e não sobrevive a reinicializações. purge_session_output limpa a saída legada finalizada mantendo seus metadados; saída ativa não pode ser purgada. A saída durável ainda requer ack_work_result antes da purga.

Limites padrão de comandos: 4 sessões ativas, 1 hora de tempo máximo de execução, 4 MiB combinados de saída por sessão e 64 MiB de saída salva antes que novo trabalho seja recusado. A saída não é excluída silenciosamente: reconheça um resultado finalizado e purgue explicitamente sua saída. Os metadados de tarefa/eventos/sessão permanecem em work.sqlite3 (arquivo privado).

No primeiro uso, tarefas legadas são copiadas de state.json uma vez, com um backup privado. Ferramentas JSON antigas ainda usam seus arquivos antigos, e bootstrap_context mostra tarefas/caixa de entrada legadas atuais separadamente. Memória/metas/agendamentos/OAuth não são migrados ou reescritos. Use as novas ferramentas de tarefas de trabalho consistentemente; a lista de tarefas legadas e a lista de trabalho durável são separadas após a importação inicial.

Um servidor possui a execução por diretório de dados. Após uma falha/reinicialização do servidor, comandos em execução não verificados são interrompidos se sua identidade de processo salva ainda corresponder, e marcados como interrupted. Eles nunca são reiniciados automaticamente. Isso é recuperação de registros verdadeiros, não sobrevivência transparente de processos.

Artefatos são caminhos de arquivo locais mais SHA-256, não links de download hospedados. Esta revisão não tem navegador, notificações push ou worker LLM autônomo, e não precisa de nova chave de API de modelo para o fluxo de trabalho de conversa ativa. Um host pode precisar atualizar suas ferramentas após uma atualização. A integração ao vivo com ChatGPT/Claude permanece a ser testada pelo proprietário.

Modelo de segurança

  • /mcp/ requer Authorization: Bearer (OAuth JWT ou segredo do proprietário) — qualquer outra coisa recebe 401, mesmo de localhost
  • OAuth 2.1 é auto-hospedado: registro dinâmico, PKCE, JWT de 1h + tokens de atualização rotativos de 30d, Client ID/segredo manual para conectores estilo Claude
  • Limites de taxa por IP (300/min API, 30/min auth), audit.jsonl somente anexação, bloqueios de arquivo entre processos, gravações atômicas
  • Limitações conhecidas: o provedor de túnel vê o tráfego (TLS termina na borda deles); faça backup de ~/.dot-mcp você mesmo

Modo somente local (sem túnel)

export OPENAI_API_KEY=sk-...
python -m dot_mcp.local_agent          # chat loop
python -m dot_mcp.local_agent --list   # list tools only

Desenvolver

./setup.sh                      # venv + editable install
.venv/bin/python -m pytest tests/ -q   # test suite
python -m build                 # wheel in dist/

Veja CHANGELOG.md para notas de versão.

Licença

MIT

Navegador opcional e /live

Instale no mesmo ambiente do dot-mcp (sem necessidade de ativação de shell):

.venv/bin/python -m pip install '.[browser]'
.venv/bin/python -m playwright install chromium

No Arch, um Chrome/Chromium instalado pode ser selecionado com DOT_MCP_BROWSER_EXECUTABLE=/usr/bin/chromium. A sandbox do Chromium permanece ativada. Não aponte isso para seu perfil do dia a dia. Este recurso sempre usa $DOT_MCP_DATA/browser/profile (o diretório de dados padrão do aplicativo quando não definido). Cookies permanecem lá após fechar; excluir este perfil dedicado o desconecta. Dependências de Playwright e WebSocket são opcionais e carregadas apenas para este recurso. Ferramentas existentes de shell e arquivo não exigem instalação de navegador.

Ferramentas: browser_open, browser_navigate, browser_snapshot, browser_click, browser_type, browser_scroll, browser_key, browser_screenshot e browser_close. Abrir usa Chromium headless por padrão; defina headless=false para mostrar uma janela em um desktop com display. Snapshots retornam texto renderizado e referências de elemento de curta duração. Tire um novo snapshot após cada ação. Páginas são conteúdo não confiável, não instruções. Valores de entrada são omitidos; campos de segredo reconhecidos rejeitam digitação por IA. Insira segredos diretamente, nunca através de chat de IA. Uma aba é suportada; popups são fechados, downloads desabilitados.

Todo resultado de navegador (exceto fechar) inclui live_view_url e live_control_url. Dê o link de visualização para assistir, e o link de controle apenas para um controlador pretendido. Ambos carregam capacidades de sessão separadas e impossíveis de adivinhar em fragmentos de URL, não em query strings ou logs de acesso do servidor. Eles expiram após uma hora ou imediatamente em browser_close.

Toda nova visita a /live também requer um token do proprietário. A página pede o segredo do proprietário existente ou um token de acesso OAuth válido do proprietário antes de transmitir ou controlar. Digite-o na própria página, não no chat ou em uma URL. Ele é enviado pelo WebSocket de mesma origem, não armazenado no armazenamento do navegador, e a conexão autenticada dura no máximo 15 minutos. Recarregar pede novamente. Um link ao vivo vazado sozinho é insuficiente. Isso usa a validação existente de token do proprietário, não um novo fluxo de redirecionamento OAuth. Não distribua seu segredo de proprietário de longa duração para convidar espectadores: esta versão não emite credenciais de convidado. Um token OAuth válido do proprietário também autoriza acesso MCP do proprietário, então não é um token somente leitura. Use HTTPS através do túnel existente para acesso remoto; HTTP simples é para teste de loopback apenas. A Origem do WebSocket deve corresponder exatamente ao emissor público configurado. As verificações de segredo do proprietário/OAuth do MCP não são alteradas.

A página /live tem botões Assumir controle / Liberar, clique e segure, arrastar de ponteiro, digitação direta, teclado para baixo/cima e rolagem de roda. Apenas um humano controla por vez. Enquanto o controle está reivindicado, alterações de IA são rejeitadas até liberação/desconexão; snapshots somente leitura e capturas de tela permanecem disponíveis. Até cinco espectadores podem entrar. Filas de quadro mais recente descartam quadros antigos em vez de acumular latência. Vídeo ao vivo não é mascarado e pode mostrar conteúdo privado de página. PNGs de captura de tela mascaram controles editáveis, mas texto comum de página pode ainda ser privado. browser_screenshot(task_id=...) registra o PNG local com artefatos de trabalho existentes; não é um link de download público.

A transmissão visa 60 fps usando screencast JPEGs do CDP do Chromium. A página mostra taxas recebidas e capturadas. Páginas estáticas naturalmente emitem menos quadros; rede, CPU, decodificação de imagem e velocidade do túnel podem reduzir a taxa. Falha na configuração do CDP recorre à amostragem de capturas de tela até 5 fps, relatada em stream_mode. Sem garantia de 60 fps. Isso é automação de navegador em sua máquina local, não uma sandbox de rede: sites HTTP/HTTPS podem alcançar serviços localhost ou LAN. O perfil separado não torna o shell completo existente seguro.

Testes de integração locais (opcionais, precisam de Chromium instalado):

TEST_CHROME=/usr/bin/chromium .venv/bin/python -m pytest tests/test_browser.py -q -s
.venv/bin/python -m pytest tests -q

Os testes de navegador usam apenas um fixture de loopback, incluindo controle /live autenticado, segurar, texto, rolagem, referências obsoletas, expiração de capacidade e fallback.

Cofre local opcional somente para preenchimento (experimental)

Instale o .[browser,vault]. O cofre usa criptografia autenticada AES-256-GCM com um salt aleatório de 16 bytes e chave derivada de Scrypt (N=32768, r=8, p=1) a partir de uma senha humana. Ele fica bloqueado por padrão. Nomes, origens e valores estão todos dentro do arquivo criptografado; o formato/versão da criptografia é público. Os arquivos são privados (0600), com substituição atômica e um bloqueio de processo cooperativo. Mantenha um backup offline: não há recuperação de senha. Escolha uma senha longa e única; 12 caracteres é um mínimo, não uma garantia de segurança.

Configuração local de terminal somente para humanos (sem segredos em argumentos de comando, chat ou env):

.venv/bin/python -m dot_mcp.cli vault init
.venv/bin/python -m dot_mcp.cli vault set --name example-login --origin https://example.com --field username --field password
.venv/bin/python -m dot_mcp.cli vault list

Cada comando solicita getpass e não ecoa valores. Os nomes não são secretos por design. --origin é normalizado para esquema, host e porta exatos; caminhos não limitam credenciais dentro de uma origem. Sem curingas de subdomínio ou correspondência de sufixo. HTTPS é obrigatório. --allow-loopback-http permite explicitamente apenas fixtures de desenvolvimento HTTP localhost/127.0.0.1/::1, nunca HTTP em LAN.

Para executar com um cofre desbloqueado, pare qualquer servidor existente que mantenha o mesmo diretório de dados, configure a autenticação/túnel do proprietário MCP existente normalmente, e então inicie em primeiro plano:

.venv/bin/python -m dot_mcp.cli vault serve

Isso solicita a senha localmente e inicia o servidor HTTP nesse mesmo processo. Ele não cria um túnel nem imprime segredos do proprietário/cliente. Não passe uma senha por variáveis de ambiente ou argumentos. Um dots start normal inicia bloqueado e não pode desbloquear o cofre via MCP. Não há API ou página de desbloqueio/edição remota. Após 15 minutos ociosos, o próximo acesso ao cofre auto-bloqueia; reinicie o comando em primeiro plano para desbloquear novamente. vault_lock o bloqueia imediatamente. Python não pode prometer apagamento forense de chaves da memória.

Ferramentas MCP adicionadas: vault_list retorna apenas nomes; vault_fill(name,key,ref) preenche um nome de usuário/senha/token salvo em uma ref de entrada visível nova, com verificação exata de origem permitida e sem envio; vault_lock remove o estado desbloqueado. Um preenchimento em outra origem é recusado. Tire um snapshot do navegador antes de preencher e use essas refs para a sequência de nome de usuário/senha e envio. As refs de pré-preenchimento permanecem válidas para preenchimentos consecutivos, sujeitas à identidade do DOM e verificações de URL. Ações subsequentes normais do navegador invalidam refs como antes.

Antes de preencher, o navegador entra em modo de privacidade fixo: ele limpa frames ao vivo enfileirados, pausa vídeo e bloqueia todos os snapshots/capturas de tela/URL da página/títulos de saída até browser_close. Isso inclui o fallback de captura de tela. browser_key('Enter') pode enviar, mas revise a ação primeiro. Uma página pode refletir uma senha em qualquer lugar, então mascaramento seletivo de entrada não é uma promessa segura. Este modo conservador significa que a IA não pode verificar visualmente um login após o preenchimento; o humano verifica na janela dedicada do navegador (headless=false) e a fecha quando terminar. Nenhuma API restaura vídeo em uma página já preenchida.

Modelo de ameaça e limites

Esta é uma interface de saída de ferramenta somente para preenchimento, não um limite de isolamento de segredos. O JavaScript da página do navegador necessariamente vê valores preenchidos em entradas HTML comuns (mesmo type=password), e o site autorizado os recebe. A vinculação de origem impede o preenchimento em uma origem diferente; ela não protege contra um site autorizado comprometido, XSS, extensões maliciosas ou phishing na origem aprovada. Redirecionamentos HTTP são verificados contra a origem da página atual antes do preenchimento; nenhum conteúdo geral da página pode conceder permissão para usar uma chave.

Não habilite acesso total ao shell para uma IA que você não confia. As ferramentas sh/comando existentes são executadas como o mesmo usuário do SO. Elas podem inspecionar arquivos/processos, ler material de chave da memória, automatizar um segundo navegador ou instrumentar código. O armazenamento criptografado em repouso não pode impedir isso. Guardas de raiz do sistema de arquivos não isolam o shell. Um limite real precisa de um principal de SO separado para o cofre, IPC restrito e uma política de navegador/entrada fora do controle da IA, além de nenhum shell irrestrito do mesmo usuário. Essa arquitetura endurecida não está neste patch. Da mesma forma, capturas de tela salvas antes do uso do cofre, scrollback do terminal, caches de página, cookies de perfil e logs de serviços remotos têm suas próprias vidas úteis. Segredos não devem ser incorporados em nomes de entrada ou enviados ao chat. Nenhum fluxo de cartão de pagamento ou TOTP é implementado ainda. Use apenas credenciais descartáveis ao avaliar este recurso experimental.

Credenciais de inicialização e UI de consentimento

A inicialização agora mantém segredos do proprietário/cliente fora da saída normal do terminal e dots start --json. O resultado JSON inclui credentials_hidden=true em vez de owner_secret / client_secret. Esta é uma mudança de quebra deliberada para scripts que leem segredos do JSON de inicialização. O ID do cliente e a URL pública permanecem disponíveis. Use dots credentials para locais de arquivos ou dots credentials --show em um terminal interativo privado somente: ele requer uma confirmação explícita de REVELAR e recusa saída redirecionada. Gravação de terminal/ scrollback ainda captura uma revelação intencional, então não a grave. Não cole segredos no chat de IA. A página OAuth descreve acesso a shell/arquivos de nível de proprietário antes da aprovação, não usa ativos remotos e envia cabeçalhos sem cache, sem referrer e anti-framing. Parâmetros OAuth e regras de verificação são inalterados.

Largura de banda e backpressure do stream ao vivo

O stream agora usa padrão JPEG qualidade 55 e largura máxima de captura 960 (o viewport do navegador controlado permanece 1280x720). Configure DOT_MCP_STREAM_QUALITY=30..85 e DOT_MCP_STREAM_WIDTH=640..1280 antes de iniciar para texto mais nítido ou menor largura de banda. Coordenadas de controle ainda se referem ao viewport 1280x720. Isso troca intencionalmente alguma nitidez de imagem por largura de banda; capturas de tela permanecem PNGs de viewport completo. É configurável, não um estimador automático de largura de banda.

O cliente /live reconhece frames decodificados. Uma janela limitada de quatro frames mais fila de último frame evita backlog ilimitado enquanto tolera tempo de ida e volta de rede. Um cliente que não reconhece frames é desconectado após cinco segundos. Os contadores agora distinguem frames capturados, recebidos e exibidos; 'exibido' significa imagem decodificada e desenhada no canvas, não refresh de monitor medido. Páginas estáticas emitem poucos frames naturalmente. Sem garantia sustentada de 60 fps.

Diagnósticos e reconexões

dots doctor (ou dots doctor --json) verifica versões de pacotes locais, escolha de interpretador/fonte, disponibilidade de dependências opcionais e a contagem de ferramentas /health de loopback ao vivo sem iniciar um navegador ou revelar credenciais. Ele distingue o Python de diagnóstico do Python do servidor selecionado; versões de pacotes são para o interpretador de diagnóstico. Disponibilidade instalada do Chromium é uma pista, não um teste de lançamento bem-sucedido.

Após aplicar patches, reinicie o servidor Python em execução. Editar arquivos não recarrega o processo antigo. A Rodada 3 sozinha registra 42 ferramentas; a Rodada 4 de cofre adiciona 3 para 45; a rodada de controle do navegador adiciona hover/select/wait/back/reload para 51. Verifique dots status ou /health ao vivo, então reconecte/atualize a lista de ferramentas do conector do assistente. Importar código do servidor em um shell separado apenas verifica arquivos, não o servidor já em execução. Nunca contorne ferramentas browser_* ausentes com um processo Python separado: seu navegador/tokens não são de propriedade do manipulador /live do servidor. Não há rota pública de captura de tela /shot/... nestes patches; artefatos de captura de tela são arquivos locais privados.

vault serve reutiliza o arquivo de segredo do proprietário local privado da CLI quando MCP_PATH_SECRET não está definido, então não cria uma credencial de proprietário aleatória inalcançável. Ele ainda não imprime nenhum segredo. Env de proprietário explícito existente tem precedência. O processo recebe essa credencial de proprietário como dots start normal; isso não é uma variável de env de senha do cofre.

O Chromium usa um diretório temporário privado curto para seus sockets de processo quando o /tmp do sistema é gravável, mesmo se seu TMPDIR de aplicativo configurado estiver profundamente aninhado. Ele é limpo no fechamento do navegador. Perfil do navegador e capturas de tela ainda vivem no diretório de dados dedicado. Isso evita estouro de caminho de socket Unix no Linux; não enfraquece o sandbox do Chromium.

O CSP de consentimento OAuth permite a origem HTTPS de callback validada, bem como self para envio de formulário. O Chromium aplica form-action ao redirecionamento após um POST; restringi-lo apenas a self bloqueou callbacks OAuth bem-sucedidos. Esta permissão é gerada a partir do redirecionamento já validado, não um curinga, e não substitui a verificação de segredo do proprietário/redirecionamento/PKCE.

URLs públicas estáveis e um auxiliar somente de túnel

Um servidor Python em execução não aprende um novo hostname público apenas porque um túnel foi aberto. Defina MCP_PUBLIC_HOST para o hostname HTTPS canônico antes da inicialização do servidor. URLs de emissor/recurso OAuth, hosts permitidos de rebinding de DNS e verificações de Origem WebSocket /live usam essa configuração. Reiniciar/reconectar é necessário quando o hostname muda. Cabeçalhos Host/X-Forwarded-Host controlados pelo chamador não escolhem o emissor nem autorizam uma nova origem. Nunca desative essas verificações apenas para fazer um proxy funcionar. Verificações de Origem/Referer de consentimento comparam esquema exato, host e porta; cookies de aviso de proxy não autenticam o proprietário.

tunnl.gg estável (sem conta)

dots tunnel executa um túnel SSH de chave estável em primeiro plano para um servidor de loopback saudável já em execução. Ele não inicia/reinicia o servidor nem reescreve sua configuração OAuth. Stdout contém apenas a URL base não secreta e a URL /mcp/; banners do provedor são salvos em um log de túnel privado. Ctrl+C para o filho SSH deste auxiliar, não o servidor. Ele não reconecta infinitamente nem ignora limites do provedor. OpenSSH é obrigatório. Por padrão, ele cria uma chave privada dedicada em ~/.dot-mcp/tunnel/tunnl-key; mantenha essa mesma chave para reter a URL estável.

Auxiliar amigável ao Fish e comando manual equivalente:

.venv/bin/python -m dot_mcp.cli tunnel --port 33041
# Existing dedicated SSH key:
.venv/bin/python -m dot_mcp.cli tunnel --port 33041 -i ~/.ssh/dot-mcp-tunnel
# Equivalent manual command (keep this terminal open):
ssh -t -i ~/.ssh/dot-mcp-tunnel -o IdentitiesOnly=yes -o ServerAliveInterval=30 -o ExitOnForwardFailure=yes -R 80:localhost:33041 stable@proxy.tunnl.gg

A configuração inicial é em duas fases porque o provedor escolhe o hostname: inicie um servidor local, execute o auxiliar para aprender sua URL estável, pare o servidor usando seu comando de ciclo de vida normal, defina o hostname apenas retornado, então inicie o servidor com essa configuração. O túnel pode permanecer aberto enquanto reinicia apenas o servidor local. Reutilizar a chave SSH mantém a URL do provedor; ela não faz um emissor em execução obsoleto se atualizar sozinho. Um exemplo de inicialização direta do servidor após você provisionar credenciais de proprietário usando configuração CLI normal:

set -gx MCP_PUBLIC_HOST your-returned-host.tunnl.gg
set -gx MCP_PORT 33041
# Human vault serve reuses the provisioned owner credential, starts foreground,
# and prompts locally for vault unlock (no secret in arguments):
.venv/bin/python -m dot_mcp.cli vault serve

Se você não quiser o cofre desbloqueado, use dots start normal para o fluxo de servidor+túnel empacotado; o auxiliar somente de túnel é para um servidor em execução gerenciado independentemente, não um gerenciador de ciclo de vida substituto. Não cole segredos de proprietário/cliente no ChatGPT nem os inclua em argumentos de URL. dots credentials fornece locais de arquivos de credenciais privados; revelação explícita requer um TTY privado.

A página de aviso gratuita do navegador do provedor aparece uma vez por dia por site. Ela redireciona GETs do navegador antes do nosso aplicativo; use seu botão normal Continuar para o site, então continue o OAuth. Clientes não navegador podem ignorá-la de acordo com a política do provedor. dot-mcp não ignora nem trata esse aviso/cookie como autenticação. Para /live, passe o aviso primeiro na URL base pública, então reabra o link ao vivo original contendo seu fragmento #token=. Um servidor não pode receber fragmentos de URL, então não assuma que um redirecionamento intersticial preserva uma capacidade ao vivo. /live ainda requer entrada de token do proprietário e Origem configurada exata. Um proxy deve suportar upgrades WebSocket. Nossos testes de unidade modelam cabeçalhos de proxy, presença de cookie do provedor e verificações de autenticação; eles não provam a implementação de aviso futura ou uptime de nenhum provedor.

O provedor atualmente documenta 2 horas de inatividade/24 horas de vida útil máxima, 3 túneis por IP, limites de WebSocket e limites de taxa de solicitação. Reconecte com a mesma chave privada para manter seu nome estável, dentro desses limites. Mudar chaves muda URLs. TLS termina no provedor; ele vê tráfego em trânsito. Veja a documentação atual do tunnl.gg e detalhes de URL estável.

Tailscale Funnel (conta/tailnet obrigatórios)

Com um cliente Tailscale instalado e conectado, e Funnel habilitado para o seu tailnet, exponha a porta de loopback:

tailscale funnel 33041

Use o hostname HTTPS impresso como MCP_PUBLIC_HOST antes de iniciar o dot-mcp, e sua URL /mcp/ para o conector. O Funnel tem requisitos de HTTPS/MagicDNS/tailnet-policy e limites de banda; não é uma rota sem conta. Habilitá-lo pode alterar a política do tailnet, então o proprietário da conta deve fazer a configuração. Não exponha um diretório de arquivos no lugar do serviço MCP autenticado. Guia oficial: https://tailscale.com/kb/1223/funnel .

Cloudflare named tunnel (conta e domínio obrigatórios)

Use um named tunnel gerenciado pelo dashboard e uma rota publicada apontando para http://127.0.0.1:33041, com seu hostname público fixo escolhido. Siga os passos atuais de instalação/execução do dashboard ou instale-o como um serviço gerenciado. O token do túnel é uma credencial: não o coloque em chat ou scripts versionados. Configure MCP_PUBLIC_HOST para o hostname fixo antes de iniciar o servidor. Mantenha as verificações de owner-secret/OAuth habilitadas mesmo ao adicionar controles de acesso de proxy, e garanta que qualquer política do Cloudflare Access seja compatível com seu conector.

Execução amigável para um named tunnel gerenciado localmente já configurado cujas credenciais/configuração são mantidas privadas:

cloudflared tunnel run dot-mcp

A configuração named e a gerenciada pelo dashboard diferem; não substitua uma URL de Quick Tunnel pela sua rota named configurada. Configuração oficial: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/ .

Quick/free tunnels são adequados para experimentos curtos, não para endpoints de conector confiáveis. Em testes, o Cloudflare Quick Tunnel intermitentemente retornou Erro 1033 enquanto o processo estava ativo; criar uma nova URL aleatória forçou uma mudança de conector. A saúde funcionando por alguns minutos não garantiu a próxima chamada de ferramenta. A documentação oficial do Quick Tunnel não promete SLA de uptime e observa limitações de SSE: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/do-more-with-tunnels/trycloudflare/ .

Chrome instalado e inicialização conveniente do vault local

browser_open agora seleciona seu Chrome/Chromium instalado do PATH quando DOT_MCP_BROWSER_EXECUTABLE não está definido, nesta ordem: google-chrome, google-chrome-stable, chromium, chromium-browser. Isso inclui um executável em ~/.local/bin se esse diretório estiver no PATH. Um DOT_MCP_BROWSER_EXECUTABLE explícito ainda tem prioridade. Se nenhum binário instalado for encontrado, o Playwright usa seu Chromium gerenciado. dots doctor relata a mesma lógica de seleção, mas a descoberta não é um teste de inicialização bem-sucedido. Os pacotes Playwright e WebSocket ainda são necessários. O binário é reutilizado, não seu perfil principal do navegador ou abas já abertas; o dot-mcp mantém seu próprio perfil e sandbox.

As ferramentas de vault estão presentes por padrão; a criptografia ainda precisa de um vault local inicializado. dots start agora abre o túnel tunnl.gg de chave estável primeiro, descobre seu hostname, define MCP_PUBLIC_HOST para o servidor e o inicia uma vez. Nenhum hostname exportado manualmente ou segundo terminal de túnel é necessário. A chave dedicada e o arquivo known-hosts ficam no diretório de estado local. Mantenha essa chave para reter a identidade estável do provedor. A disponibilidade do túnel e a página de aviso ainda dependem do tunnl.gg; "estável" não promete uptime.

Para um prompt manual de passphrase local e tempo de vida em primeiro plano:

.venv/bin/python -m dot_mcp.cli start --vault

Isso inicia seu próprio túnel. Mantenha o terminal aberto; Ctrl+C interrompe ambos. Em modo não interativo ou JSON não há prompt. Uma aceitação prévia de keyring pode ainda desbloquear o servidor destacado. Sem aceitação/keyring, o vault permanece bloqueado.

Aceitação única de desbloqueio automático do vault local (Linux Secret Service)

Após vault init/vault set humano, instale a dependência opcional de desbloqueio automático somente se você escolher usá-la. No Arch, um provedor de Secret Service desbloqueado (por exemplo, o keyring usado pelo seu desktop) e sua sessão D-Bus devem estar disponíveis no ambiente do servidor. Nenhum provedor ou pacote é instalado por este comando.

.venv/bin/python -m pip install -e '.[vault-auto]'
.venv/bin/python -m dot_mcp.cli vault enable-auto
.venv/bin/python -m dot_mcp.cli start

enable-auto requer um terminal local, mostra um aviso, pede que você digite ENABLE, e então solicita a passphrase com getpass. Ele verifica o vault existente e armazena a passphrase apenas no OS Secret Service. Um marcador privado de aceitação não contém segredo. O servidor recupera o segredo diretamente na inicialização, nunca via argumentos, ambiente, chat ou uma transferência de chave pai-para-filho. Não há fallback de texto simples ou backend de keyring alternativo. Keyring ausente/bloqueado, aceitação ausente, segredo errado ou desbloqueio falho deixa o vault bloqueado. O log do servidor relata apenas o status bloqueado/desbloqueado, não a passphrase.

Aviso: qualquer processo do mesmo usuário com acesso ao keyring do SO desbloqueado pode recuperar esta passphrase e desbloquear o vault. Isso é conveniência em sua própria máquina confiável, não uma fronteira contra seu shell ou outro software do mesmo usuário. Bloqueio automático por inatividade e vault_lock ainda bloqueiam; eles não reabrem automaticamente em uma chamada de ferramenta posterior. Reiniciar o servidor tenta o desbloqueio automático novamente.

.venv/bin/python -m dot_mcp.cli vault disable-auto

Desabilitar remove a aceitação primeiro e exclui a entrada do keyring. Se o keyring do SO estiver indisponível/bloqueado, o comando relata que a exclusão da credencial falhou; desbloqueie-o localmente e execute novamente. O desbloqueio automático permanece desabilitado enquanto isso. Pare/reinicie qualquer servidor já desbloqueado para descartar sua chave em memória. O modo de privacidade de preenchimento de origem exata e pós-preenchimento permanece inalterado. dots tunnel permanece disponível para um servidor já em execução; não execute um segundo túnel para dots start.

Dependências de navegador ausentes

browser_open verifica o Python do servidor em execução para Playwright e websockets, então seleciona o Chrome/Chromium do PATH instalado ou o Chromium gerenciado pelo Playwright. Uma substituição explícita de executável é verificada como um arquivo executável. Com nem um navegador instalado nem um gerenciado, ele relata o navegador como ausente.

Dependências ausentes retornam um resultado de ferramenta como:

{"ok": false, "error": "not_installed", "missing": ["playwright", "websockets"], "message": "not installed: playwright, websockets", "next_action": "Ask the user whether to install or configure the missing dependencies. Do not install without user approval."}

A ferramenta não executa pip, um gerenciador de pacotes ou um instalador de navegador. A IA deve perguntar antes de instalar. Essas verificações são executadas novamente a cada nova tentativa de browser_open; após a instalação aprovada, reinicie o servidor se seu ambiente mudou. dots doctor --json inclui optional.browser_missing para pacotes e um executável explícito/PATH; ele não inicia o Playwright para verificar seu navegador gerenciado. Imports instalados mas quebrados, bibliotecas de sistema ausentes, falhas de exibição ou sandbox são falhas de tempo de execução, não prova de que o Chrome está ausente. Nenhum rebaixamento de sandbox ou correção automática de dependência é tentado. A inicialização do vault é inalterada.

Visualização ao vivo sem senha (aceitação explícita de sessão)

browser_open(..., share_view=true) ou browser_share_view(enabled=true) habilita a visualização sem senha para essa sessão de navegador e retorna um live_view_url pronto para abrir. Sessões padrão ainda exigem autenticação do proprietário para visualização. O token aleatório longo está no fragmento da URL, não nas URLs de solicitação do servidor. /live sozinho nunca expõe vídeo. Os tokens expiram após uma hora e fechar os revoga; as conexões de visualização duram no máximo 15 minutos antes de reconectar.

Qualquer pessoa com um link de visualização habilitado pode ver vídeo de página sem máscara, incluindo informações privadas. Trate o link como um segredo. A IA deve obter sua aprovação antes de habilitá-lo ou compartilhá-lo. browser_share_view(enabled=false) rotaciona o token de visualização, desconecta visualizadores antigos e restaura a visualização autenticada pelo proprietário. O controle é separado: um link de controle mais seu segredo de proprietário/token OAuth é sempre necessário. Um token de visualização não pode se tornar um token de controle, mesmo com uma senha. As verificações existentes de origem exata, limites e bloqueio de vídeo pós-preenchimento do vault permanecem.

A página ao vivo tenta visualização tokenizada automaticamente. Links privados de visualização/controle mostram um formulário de token do proprietário. Ele nunca armazena esse token do proprietário.

Erros seguros de ferramenta

Falhas de ferramenta retornam isError com texto JSON contendo ok: false e um objeto error: valores code, message seguro, field opcional e allowed opcional. Os códigos incluem not_found, bad_argument, invalid_state, precondition_failed, permission_denied, resource_limit e tool_failed. Validação e falhas antecipadas se comportam da mesma forma sob MCP 1 e 2. Texto bruto de exceção, valores de argumento, caminhos de SO e texto de página do navegador não são retornados. Falhas desconhecidas dão uma causa segura genérica em vez de adivinhar um diagnóstico.