Mac Developer Bridge
Dê ao ChatGPT um terminal real no seu Mac: shell, arquivos, sessões PTY reais, tarefas em segundo plano e histórico do Codex somente leitura via MCP.
Documentação
Mac Developer Bridge
Dê ao ChatGPT um terminal real no seu Mac.
O Mac Developer Bridge transforma uma conversa do ChatGPT na camada de raciocínio para o seu Mac real. Ele pode executar comandos de shell, editar arquivos, iniciar sessões interativas de terminal, gerenciar trabalhos de longa duração, ler threads do Codex armazenadas sem iniciar outra rodada do modelo Codex e, opcionalmente, operar suas abas reais do Chrome conectado em segundo plano, sem roubar o foco.

Exemplo: "Encontre a sessão do Codex em que eu estava trabalhando ontem, inspecione o repositório ao vivo, corrija o CI, envie o resultado e me diga o que mudou."
Esse é o tipo de fluxo de trabalho para o qual este projeto foi criado.
[!WARNING] O Mac Developer Bridge deliberadamente dá a um cliente MCP as permissões efetivas do seu usuário macOS. Ele não é isolado em sandbox e não possui lista de permissões de comandos ou caminhos. Leia SECURITY.md antes de ativá-lo.
A ideia
O ChatGPT tem o raciocínio. O seu Mac tem o código-fonte, terminal, credenciais, ferramentas de build, serviços locais e trabalho em andamento. O Mac Developer Bridge conecta os dois via MCP sem adicionar outro modelo ou loop de agente no meio.
flowchart LR
A[ChatGPT] -->|MCP| B[Mac Developer Bridge]
B --> C[Shell, Git and local CLIs]
B --> D[Filesystem]
B --> E[Real PTY sessions]
B --> F[Background jobs]
B --> G[Stored Codex history]
B --> H[Audit log and kill switch]
A ponte em si não faz nenhuma chamada de modelo da OpenAI. Ela expõe ferramentas locais determinísticas; o ChatGPT fornece o raciocínio. As ferramentas de histórico do Codex usam métodos codex app-server somente leitura e nunca chamam turn/start.
O que isso possibilita
- Recuperar uma thread do Codex armazenada, inspecionar o repositório ao qual ela se refere e continuar o trabalho a partir do ChatGPT.
- Executar testes, builds, Git, gerenciadores de pacotes, CLIs de banco de dados, AppleScript e outras ferramentas já instaladas no seu Mac.
- Manter shells interativos e programas de terminal vivos através de um PTY real, em vez de fingir que o stdin é um terminal.
- Iniciar trabalhos locais de longa duração, inspecionar seus logs depois e interromper todo o grupo de processos.
- Ler e modificar arquivos em qualquer lugar que seu usuário macOS possa acessar.
- Opcionalmente, operar páginas aprovadas no seu perfil real do Chrome conectado sem trazer o Chrome para o primeiro plano.
Isso é intencionalmente diferente de um agente de codificação local. Não há um segundo loop de raciocínio. O ChatGPT continua sendo o agente; o Mac é o ambiente de execução.
Início rápido
Para uma conta pessoal do ChatGPT, o aplicativo da barra de menus é o caminho mais fácil. Você precisa de macOS, Node.js 18+, cloudflared, um hostname/túnel e o modo Desenvolvedor do ChatGPT.
git clone https://github.com/alexanderradahl/mac-developer-bridge.git
cd mac-developer-bridge
./menubar/build.sh
open /Applications/MacDevBridge.app
Use Iniciar e depois Copiar configuração do ChatGPT no aplicativo da barra de menus. A configuração detalhada de OAuth e Cloudflare está em Conectando ao ChatGPT e DEPLOY.md.
Usuários de Workspace que têm acesso ao OpenAI Secure MCP Tunnel podem usar install.sh em vez disso. Veja Transports.
Quer ver o que pedir para ele fazer? Comece com os fluxos de trabalho de copiar e colar.
Se isso for útil, dê uma estrela no repositório para que outros desenvolvedores possam encontrá-lo. Se você construir algo interessante com ele, compartilhe o fluxo de trabalho exato em O que você está fazendo o ChatGPT fazer no seu Mac?.
Este é um projeto open-source independente e não é um produto oficial da OpenAI ou Cloudflare. OpenAI, ChatGPT, Codex e Cloudflare são marcas registradas de seus respectivos proprietários.
Open source
O Mac Developer Bridge é lançado sob a Licença MIT. Relatórios de bugs e pull requests focados são bem-vindos; veja CONTRIBUTING.md. Relatórios sensíveis à segurança devem seguir as orientações em SECURITY.md em vez de serem postados publicamente.
Capacidades
- Comandos de shell arbitrários através de
/bin/zsh -lc, sob o usuário macOS conectado - Trabalhos em segundo plano destacados com logs persistentes de stdout/stderr, inspeção de status e término de grupo de processos
- Leitura, escrita, anexação, listagem, stat, cópia, movimentação, chmod, symlink, mkdir e exclusão recursiva de arquivos sem restrições
- Aplicação de diff unificado através de
git apply - Descoberta e leitura de threads do Codex armazenadas sem retomar uma thread ou iniciar uma rodada do modelo Codex
- Recuperação paginada de turnos do Codex para históricos grandes demais para uma única resposta
- Auditoria local em JSONL
- Conectividade privada somente de saída através do OpenAI Secure MCP Tunnel, ou um front-end de loopback HTTP simples que o Cloudflare Tunnel publica via HTTPS
- Persistência por usuário através de um LaunchAgent do macOS
- Trava de desbloqueio com falha segura:
bridge.mjsrelê o arquivo de desbloqueio antes de cada chamada de ferramenta, então removê-lo recusa a próxima chamada e encerra — a menos que o processo tenha herdadoMAC_DEV_BRIDGE_FULL_ACCESS_ACK, que ignora o arquivo completamente - Interruptor de desligamento local (
scripts/disable.sh), que interrompe o front-end, a ponte, o host nativo opcional do Chrome em segundo plano, grupos de trabalhosshell_startdestacados, sessões interativas de pty e servidores MCP filhos federados, verificando os mesmos alvos que sinalizou
Git, gerenciadores de pacotes, Vercel CLI, CLIs de banco de dados, AppleScript, CLIs de navegador, ferramentas de build e outros programas instalados permanecem acessíveis através de shell_exec; a ponte deliberadamente não mantém lista de permissões de comandos.
Ferramentas
| Ferramenta | Finalidade |
|---|---|
bridge_status | Identidade de runtime, caminhos, contexto de permissões, shell, modo de auditoria, binário do Codex, política de foco e status do Chrome em segundo plano |
chrome_workspace_status | Inspecionar o grupo do Chrome MDB de propriedade da extensão, atividade de lease e pool reutilizável de abas em segundo plano; nenhuma concessão de site necessária |
chatgpt_extension_status | Inspecionar a extensão do ChatGPT instalada no Chrome, o registro do host nativo da OpenAI e o status ao vivo da ponte de página somente leitura sem modificar a extensão da OpenAI |
chatgpt_conversation_start | Iniciar ou continuar experimentalmente uma conversa exata do ChatGPT através da ação de runtime de primeira parte da página conectada; sem digitação/clique na UI ou exportação de credenciais |
chrome_workspace_setup | Provisionar um alvo de pool MDB somente de crescimento de 1 a 32 abas; o padrão é oito, com criação adiada até o Chrome estar naturalmente em foco |
chrome_tabs | Listar abas no perfil real do Chrome conectado sem ativar o Chrome; escopo limitado apenas quando Aprovações estritas está ativado |
chrome_open | Alugar uma aba ociosa do grupo persistente MDB e abrir uma URL sem criar uma nova aba |
chrome_navigate | Navegar em uma aba aprovada sem selecioná-la |
chrome_snapshot | Ler texto visível e elementos interativos de uma aba aprovada |
chrome_click | Clicar em um elemento em uma aba aprovada sem trazer o Chrome para o primeiro plano |
chrome_fill | Preencher inputs, textareas, selects ou campos contenteditable em segundo plano |
chrome_close | Liberar uma aba de workspace MDB de volta ao pool ocioso, ou fechar uma aba em segundo plano que não seja de workspace |
shell_exec | Executar qualquer comando de shell em primeiro plano, opcionalmente com cwd, env, stdin, timeout e limite de saída |
shell_start | Iniciar um processo destacado de longa duração |
shell_job_status | Inspecionar estado de execução e caudas de log |
shell_job_list | Listar metadados persistentes de trabalhos |
shell_job_kill | Sinalizar um grupo de processos em segundo plano |
fs_read | Ler texto ou base64 com paginação por deslocamento |
fs_write | Substituição atômica, criação, anexação ou escrita binária |
fs_list | Listagem de diretório recursiva ou não recursiva |
fs_stat | Metadados lstat e alvo de symlink |
fs_manage | mkdir, remover, mover, copiar, chmod ou symlink |
apply_patch | Aplicar ou verificar um diff unificado com git apply |
codex_thread_read | Ler uma thread do Codex armazenada sem retomá-la |
codex_thread_list | Pesquisar e paginar threads do Codex armazenadas |
codex_thread_turns_list | Paginar turnos armazenados com itens completos, resumidos ou omitidos |
audit_tail | Ler a cauda de auditoria local da ponte |
Chrome em segundo plano sem roubar o foco
No macOS, a integração opcional do Navegador em Segundo Plano opera o mesmo perfil do Chrome conectado que você já usa, então as sessões de site existentes funcionam, mas a automação rotineira acontece através de uma pequena extensão local em vez de automação de UI via AppleScript ou seleção de página via Chrome DevTools Protocol. O host nativo é vinculado no momento da instalação ao perfil/conta do Chrome selecionado e recusa um perfil desconectado ou incompatível.
Isso é intencionalmente opcional porque o controle autenticado do navegador é poderoso. Instale o host nativo uma vez e depois carregue a extensão descompactada uma vez no Chrome:
./scripts/install-background-chrome.sh
Depois, no Chrome, abra chrome://extensions, ative o Modo desenvolvedor, escolha Carregar sem compactação e selecione o diretório chrome-extension/ deste repositório. O id esperado da extensão é pcebfblnmcappinbenkmddjdapaoajgm.
A extensão mantém um grupo de abas nativo do Chrome chamado MDB. Por padrão, ela tem como alvo oito abas ociosas de propriedade da extensão, com um máximo rígido de 32. Elas são criadas apenas enquanto a janela existente do Chrome MDB já está naturalmente em primeiro plano, e depois são alugadas e reutilizadas para trabalho rotineiro. O grupo é recolhido quando ocioso e se expande enquanto uma ou mais abas estão alugadas. Isso preserva o limite de não roubo de foco em torno de uma peculiaridade do macOS/Chrome medida neste projeto: até mesmo chrome.tabs.create({ active:false }) pode trazer o Chrome para o primeiro plano.
O pool se auto-repara e tem um alvo de capacidade persistente somente de crescimento. chrome_workspace_setup(pool_size=16) registra um alvo de 16 abas imediatamente. Se a janela do Chrome MDB já estiver em foco, as abas ausentes são criadas e agrupadas de uma vez; caso contrário, o status relata a contagem pendente e a extensão se expande no próximo foco natural do Chrome. Uma solicitação posterior menor nunca fecha abas existentes. Quando todas as abas atuais estão alugadas e nenhuma expansão está pendente, a pressão aumenta o alvo em quatro, até 32, e tenta a criação imediata apenas quando o Chrome já está em foco. O MDB nunca ativa o Chrome para satisfazer o provisionamento manual ou automático.
chrome_workspace_status é sem concessão porque apenas lê o estado local do workspace de propriedade da extensão. Ele relata os tamanhos atual e alvo do pool, o máximo de 32 abas, o passo de crescimento automático de quatro abas, capacidade pendente, metadados de idade/ociosidade do lease, o timeout de recuperação de ociosidade de 10 minutos e o orçamento de espera de lease de 20 segundos. chrome_workspace_setup também é sem concessão: o provisionamento é sempre aceito localmente, enquanto a criação real permanece adiada quando o Chrome não está em foco. Chamadores legados/internos de tabs.open são roteados para o mesmo caminho de lease de workspace.open, então não podem criar abas soltas fora de MDB. Quando todas as abas estão ocupadas, chrome_open primeiro provisiona ou cria capacidade onde for seguro, depois espera brevemente por uma liberação; leases abandonados são recuperados após 10 minutos sem atividade do navegador, enquanto cada navegação/captura/clique/preenchimento renova um lease ativo.
Acesso relaxado é o padrão. Trabalho HTTP/HTTPS normal, incluindo localhost e portas não padrão, através do perfil do Chrome MDB conectado não exige um comando de aprovação no terminal ou lista de permissões por site. Isso é intencional: o Mac Developer Bridge já expõe autoridade irrestrita de shell/arquivo como o usuário macOS conectado, e o padrão útil é que a execução do navegador corresponda a esse nível de confiança escolhido pelo operador, permanecendo em segundo plano.
A aprovação relaxada não relaxa o roteamento do Chrome. O controle direto do Chrome através de shell_exec/shell_start — AppleScript, JXA, execuções diretas do executável do Chrome ou open de shell de uma URL HTTP/HTTPS (incluindo open -g) — é sempre recusado com CHROME_BACKGROUND_REQUIRED, tanto no modo Relaxado quanto no Estrito. O trabalho no navegador deve usar as ferramentas chrome_* e o grupo gerenciado MDB. Isso mantém o comportamento de não roubo de foco estrutural em vez de depender de qual modo de aprovação está selecionado.
Se você quiser um fluxo de trabalho mais restrito de navegador/app, ative Aprovações estritas no aplicativo da barra de menus do Mac Developer Bridge. A alternância é ao vivo; nenhum reinício é necessário. No modo Estrito, as aprovações de chrome-background são aditivas e compartilhadas em cada sessão do ChatGPT conectada à ponte até que cada concessão expire:
./scripts/approve-personal-browser.sh \
--provider chrome-background \
--url-pattern 'https://www.producthunt.com/*' \
--url-pattern 'https://www.reddit.com/*' \
--ttl 900
Um fluxo de trabalho normal é:
chrome_openuma URL aprovada em uma aba ociosa alugada do grupoMDB.chrome_snapshotpara ler a página e obter seletores suficientemente estáveis para os controles visíveis.chrome_fill/chrome_click/chrome_navigateconforme necessário.chrome_closepara retornar a aba do workspace à sua página de extensão ociosa e liberar o aluguel. A liberação do workspace é uma limpeza local/sem concessão, portanto, concessões de URL em modo Strict não podem prender um aluguel concluído.
A vinculação de perfil é sempre aplicada. No modo relaxado, a extensão permite sites HTTP/HTTPS normais sem uma concessão por site. No modo Strict, cada aprovação chrome-background é armazenada como seu próprio arquivo com modo 0600 em $DATA_DIR/chrome-background-grants/, expira após no máximo 15 minutos e é mesclada com outras aprovações ainda ativas. Arquivos expirados são removidos automaticamente e os padrões de URL são aplicados dentro do Chrome. Provedores federados de navegador pessoal mantêm seu comportamento separado de uso único.
chatgpt_extension_status é deliberadamente somente leitura. Ele relata a versão instalada da extensão ChatGPT do Chrome, o registro local do host nativo com.openai.codexextension e—quando uma aba chatgpt.com já está aberta—o status ao vivo retornado pela ponte de página da própria OpenAI. O MDB não modifica a extensão da OpenAI, não se adiciona à lista de permissões do host nativo da OpenAI, não expõe chamadas RPC privadas arbitrárias da OpenAI nem abre programaticamente o painel lateral do ChatGPT. A extensão atual do ChatGPT não declara externally_connectable; seu caminho de abertura do painel lateral também exige um gesto de usuário confiável.
Início experimental de conversa com ChatGPT
chatgpt_conversation_start é um experimento deliberadamente restrito para iniciar ou continuar uma conversa de consumidor com o ChatGPT a partir do Codex/Work Mode. Seu transporte padrão runtime aluga uma nova aba de fundo chatgpt.com, resolve a ação da loja de primeira parte montada do ChatGPT submitComposer por meio de uma impressão digital semântica fixa e envia o prompt como um text_action. Ele não digita nem clica no compositor. O próprio runtime do ChatGPT constrói a solicitação privada e seu material de requisitos/prova gerado pelo navegador. O MDB observa o fluxo inicial limitado/entrega renderizada, recarrega a conversa retornada exata e lê o id exato da mensagem do assistente persistida antes de retornar o texto. Esse recarregamento é verificação, não uma segunda submissão de modelo. A aba nunca é ativada e é liberada para o pool do MDB depois.
A ferramenta aceita prompt, transport opcional (runtime por padrão ou raw de diagnóstico explícito), model opcional (padrão gpt-5-6-pro), thinking_effort opcional, max_runtime_seconds opcional (30–3600), continue_in_work opcional, conversation_id exato opcional para continuação e um tab_id alugado existente opcional. O modelo de runtime selecionado deve reter o esforço suportado solicitado antes da submissão; continue_in_work aplica-se apenas a diagnósticos brutos. O transporte bruto retém a sonda de solicitação privada direta anterior e ainda pode falhar com CHATGPT_CONVERSATION_REQUIREMENTS_UNAVAILABLE. Nenhum transporte aceita autorização copiada, cookie, dispositivo, Sentinel, Turnstile, Arkose ou campos de prova, e nenhum os retorna ou persiste. Os registros de auditoria de prompt retêm apenas o comprimento em bytes e um prefixo curto de SHA-256.
Orquestradores locais podem invocar a mesma operação por meio de uma rota separada:
curl --fail-with-body \
--request POST \
--url http://127.0.0.1:8787/experimental/chatgpt/conversation \
--header "Authorization: Bearer $MAC_DEV_BRIDGE_HTTP_TOKEN" \
--header 'Content-Type: application/json' \
--data '{"prompt":"Start a new research conversation","transport":"runtime","model":"gpt-5-6-pro","thinking_effort":"standard"}'
# Continue the exact returned conversation later:
curl --fail-with-body \
--request POST \
--url http://127.0.0.1:8787/experimental/chatgpt/conversation \
--header "Authorization: Bearer $MAC_DEV_BRIDGE_HTTP_TOKEN" \
--header 'Content-Type: application/json' \
--data '{"prompt":"Continue the assigned work","conversation_id":"<returned-conversation-id>"}'
Essa rota aceita apenas uma conexão direta de loopback com o bearer estático do MDB. Ela rejeita credenciais OAuth e solicitações encaminhadas/tuneladas, retorna Cache-Control: no-store e encapsula a operação MCP exata em vez de expor o socket do host nativo do Chrome.
Modelo de navegador experimental do ChatGPT
O MDB também expõe um adaptador separado de bearer estático e loopback direto POST /v1/responses para os modelos explícitos do OpenCodex chatgpt-runtime/chatgpt-browser e chatgpt-runtime/chatgpt-sol. O primeiro usa o runtime de navegador padrão fixo. A entrada Sol ativa o modelo gpt-5-6-thinking montado do ChatGPT e mapeia os níveis de esforço do Codex como low -> low, medium -> standard, high -> high, xhigh -> max, max -> max e ultra -> max. O adaptador reconstrói cada turno sem estado a partir das instruções/entrada do Responses, apresenta ferramentas suportadas function e custom ao runtime do ChatGPT por meio de um protocolo de decisão JSON fixo e converte uma mensagem validada ou seleção de ferramenta de volta para a saída canônica JSON/SSE do Responses. O Codex permanece responsável por executar ferramentas locais e reproduzir seus resultados no próximo turno.
O Codex pode representar ferramentas de forma livre, como exec, como uma ferramenta personalizada ou como uma função fechada com uma string obrigatória input. O adaptador aceita apenas a variação exata do wrapper determinístico para essas duas formas equivalentes e rejeita chamadas mistas ou mais amplas. Antes de analisar a decisão JSON, o MDB verifica a mensagem exata do assistente persistida da conversa retornada do ChatGPT, para que fragmentos de renderização transitórios não possam acionar novas tentativas de transporte.
Este modelo é intencionalmente separado e experimental. Ele não é adicionado ao modelo padrão, combos, padrões de subagente ou cadeias de fallback automáticas. A declaração web_search hospedada na API do Codex é omitida para este provedor em vez de bloquear cada turno do Work mode; o ChatGPT ainda pode usar sua própria navegação de primeira parte de forma independente. Outras ferramentas hospedadas, imagens/áudio, persistência de resposta no servidor, rastros de raciocínio nativos e contabilidade confiável de tokens não são suportados. Texto simples não JSON é retornado como mensagem final e nunca pode invocar uma ferramenta; saída malformada semelhante a JSON/ferramenta, seleção de ferramenta desconhecida de propriedade do chamador, desvio de runtime, prompt superdimensionado ou submissão ambígua falha de forma fechada sem nova tentativa ou automação de UI.
Exemplo de solicitação direta:
curl --fail-with-body \
--request POST \
--url http://127.0.0.1:8787/v1/responses \
--header "Authorization: Bearer $MAC_DEV_BRIDGE_HTTP_TOKEN" \
--header 'Content-Type: application/json' \
--data '{"model":"chatgpt-browser","input":"Reply with exactly MDB_MODEL_OK","stream":false}'
O registro local do OpenCodex usa um provedor personalizado openai-responses apontado para http://127.0.0.1:8787, com allowPrivateNetwork: true, statelessResponses: true, o bearer estático do MDB como chave de API do provedor e ids de modelo personalizados chatgpt-browser e chatgpt-sol. Seus ids qualificados visíveis ao Codex são chatgpt-runtime/chatgpt-browser e chatgpt-runtime/chatgpt-sol. Ambas as linhas do catálogo usam a janela de 372 mil tokens e o limite de compactação automática de 334,8 mil de gpt-5.6-sol; o MDB permite até 4.000.000 de bytes UTF-8 para o prompt serializado do runtime do navegador, de modo que o valor maior do catálogo é respaldado por um limite real de transporte.
Para manter esses turnos experimentais fora do histórico geral do ChatGPT, coloque um id de Projeto em um arquivo de runtime privado:
{"projectId":"g-p-..."}
Salve-o como $DATA_DIR/chatgpt-runtime.json com modo 0600. Quando configurado, cada nova conversa de runtime de navegador /v1/responses aluga a página de primeira parte desse Projeto e submete somente após a rota carregada e o conversationMode montado identificarem o Projeto exato. Cookies capturados, autorização, Sentinel, dispositivo, sessão e campos de prova não são necessários nem aceitos.
O que o modo de fundo não promete: CAPTCHAs, diálogos de permissão nativos do navegador/SO, seletores de arquivos, downloads que exigem um gesto de usuário confiável, chaves de acesso e outra UI de segurança do navegador podem exigir uma etapa em primeiro plano/manual. A ponte relata essa limitação em vez de ativar silenciosamente o Chrome. Isso também é deliberadamente mais restrito do que JavaScript de página arbitrário ou captura de cabeçalhos de rede: a resolução de runtime é fixa, caminhos de módulo/scripts/seletores fornecidos pelo chamador são rejeitados e um runtime alterado ou ambíguo falha sem uma segunda submissão; consulte SECURITY.md.
Para remover a integração:
./scripts/uninstall-background-chrome.sh
Aplicativos de desktop e foco
Para aplicativos nativos do macOS, o MDB ainda prefere APIs com capacidade de fundo ou caminhos web, pois a automação por Accessibility/AppleScript de aplicativos como o Slack pode exigir que o aplicativo de destino se torne o primeiro plano. No modo relaxado padrão, o controle de aplicativos nativos não Chrome é permitido sem uma aprovação separada de terminal, então o MDB ainda pode concluir a tarefa quando uma interação de aplicativo em primeiro plano for genuinamente necessária. O Chrome é a exceção: como o MDB tem uma extensão de fundo dedicada com sessão iniciada, a automação direta da GUI do Chrome é sempre forçada de volta ao caminho do navegador MDB em vez de permitir roubar o foco.
Prefira, nesta ordem:
- uma API ou conector MCP para o serviço;
- o aplicativo web do serviço por meio do grupo Chrome
MDBcom sessão iniciada; - automação de GUI de aplicativo nativo somente quando a interação em primeiro plano for genuinamente necessária.
Quando Aprovações Strict está habilitado, o controle de aplicativos nativos em primeiro plano é bloqueado, a menos que o operador crie uma concessão de uso único, com escopo de aplicativo:
./scripts/approve-foreground-gui.sh --app Slack --ttl 60
O modo Strict é opcional e desativado por padrão. A caixa de seleção na barra de menu o altera ao vivo.
Sessões de terminal interativas
Um pty real, alocado por lib/ptyhelper.pl (Perl central, sem dependência adicionada). Anunciado somente quando o auxiliar é executado neste host; caso contrário, as seis ferramentas estão ausentes em vez de quebradas.
| Ferramenta | Finalidade |
|---|---|
pty_start | Iniciar um programa em um terminal real e retornar um id de sessão |
pty_read | Ler a transcrição a partir de um cursor de bytes, opcionalmente com long-polling |
pty_write | Enviar teclas, incluindo caracteres de controle |
pty_resize | Alterar o tamanho da janela, confirmado por uma leitura de volta do kernel |
pty_signal | Enviar sinal ao grupo de processos da sessão |
pty_close | Encerrar a sessão e recuperá-la |
Limites que serão visíveis no uso normal:
- Comprimento de linha. Enquanto o terminal está no modo canônico — o padrão, e o que todo prompt interativo usa — a disciplina de linha descarta uma linha de entrada de 1024 bytes ou mais em vez de truncá-la.
pty_writerecusa tal escrita comPTY_WRITE_CANON_LIMITem vez de relatar bytes que o programa nunca verá. Os bytes se acumulam entre chamadas até um\rou\n, então o particionamento não o contorna. Envie linhas de no máximo 1023 bytes. Uma sessão que colocou seu terminal em modo bruto é verificada e permitida. - Concorrência. O limite de sessões é tomado, não apenas verificado, então chamadas
pty_startconcorrentes não podem excedê-lo. - Retenção. Cada sessão mantém os últimos
MAC_DEV_BRIDGE_PTY_RING_BYTESde saída em um anel fixo;pty_readrelatalostBytesquando um cursor fica para trás dele. - Contenção. Consulte SECURITY.md —
pty_closerelataleaderGroupGone,ttyProcessesKilledeuncontainedPidsseparadamente, econtainmentVerifiedé verdadeiro somente quando nada sobreviveu.
Servidores MCP filhos federados
Se um registro de provedor estiver configurado, as ferramentas de cada provedor são anunciadas com um prefixo key__tool e encaminhadas. Não há provedor embutido: o registro é fornecido pelo operador. O modo de perfil de navegador pessoal exige uma concessão do operador por uso — consulte SECURITY.md.
Ambiente da ponte
Estes são lidos por bridge.mjs em ambos os transportes.
| Variável | Padrão | Finalidade |
|---|---|---|
MAC_DEV_BRIDGE_DATA_DIR | ~/Library/Application Support/MacDeveloperBridge | Estado, metadados de jobs, raízes de federação. |
MAC_DEV_BRIDGE_LOG_DIR | ~/Library/Logs/MacDeveloperBridge | Diretório de logs. |
MAC_DEV_BRIDGE_AUDIT_LOG | $LOG_DIR/audit.jsonl | Caminho do JSONL de auditoria. |
MAC_DEV_BRIDGE_AUDIT_MODE | metadata | off, metadata ou full. full registra argumentos de ferramentas; veja a ressalva em SECURITY.md. |
MAC_DEV_BRIDGE_UNLOCK_FILE | $DATA_DIR/FULL_ACCESS_ENABLED | A trava de desbloqueio revogável. Releia antes de cada chamada de ferramenta. |
MAC_DEV_BRIDGE_UNLOCK_RECHECK_MS | 3000 | Com que frequência a trava é relida enquanto uma sessão pty ou um filho federado existe e o cliente está silencioso. Limita por quanto tempo qualquer um pode sobreviver a um arquivo de desbloqueio removido. |
MAC_DEV_BRIDGE_SHELL | shell de login | Shell usado para shell_exec/shell_start. |
MAC_DEV_BRIDGE_DEFAULT_OUTPUT_BYTES | 1000000 | Limite padrão de saída por chamada. |
MAC_DEV_BRIDGE_MAX_OUTPUT_BYTES | 8000000 | Teto que uma chamada pode solicitar. |
MAC_DEV_BRIDGE_PTY_PERL | /usr/bin/perl | Interpretador para o auxiliar pty. |
MAC_DEV_BRIDGE_PTY_HELPER | lib/ptyhelper.pl ao lado de bridge.mjs | Caminho do script auxiliar. |
MAC_DEV_BRIDGE_PTY_MAX_SESSIONS | 8 (1–64) | Limite de sessões ativas. kern.tty.ptmx_max é 511 em todo o sistema, então isso protege o Terminal.app do próprio operador, não apenas este processo. |
MAC_DEV_BRIDGE_PTY_RING_BYTES | 262144 (4 KiB–4 MB) | Retenção de saída por sessão. A retenção total é este valor vezes o limite de sessões. |
MAC_DEV_BRIDGE_PTY_IDLE_TIMEOUT_MS | 900000 (1 s–1 h) | Janela de recuperação ociosa, e um teto: pty_start pode solicitar uma mais curta, nunca uma mais longa. O valor efetivo de uma sessão ativa está em bridge_status. |
MAC_DEV_BRIDGE_PTY_MAX_LIFETIME_MS | 28800000 (5 s–24 h) | Teto rígido, aplicado mesmo em uma sessão em uso ativo. |
MAC_DEV_BRIDGE_PTY_START_TIMEOUT_MS | 5000 | Quanto tempo pty_start espera pelo auxiliar para relatar um pty real. |
MAC_DEV_BRIDGE_MCP_SERVERS | — | Caminho para um arquivo JSON de registro de provedores MCP filhos. |
MAC_DEV_BRIDGE_MCP_SERVERS_JSON | — | O mesmo registro inline. Tem precedência. |
MAC_DEV_BRIDGE_MCP_START_DEADLINE_MS | 15000 (1 s–120 s) | Teto de tempo de parede para a inicialização inteira de um provedor — handshake, verificação de concessão e cada página de tools/list. Um provedor que exceder é abandonado em vez de segurar a superfície de ferramentas. |
MAC_DEV_BRIDGE_MCP_PING_IDLE_MS | 30000 | Intervalo ocioso após o qual um filho federado é pingado; um filho que falhar no ping é tratado como travado e reiniciado. |
MAC_DEV_BRIDGE_PERSONAL_APPROVAL_FILE | $DATA_DIR/PERSONAL_BROWSER_APPROVED | Caminho legado/federado de concessão de navegador pessoal de uso único. Uma concessão legada de chrome-background aqui é importada para o pool compartilhado para compatibilidade retroativa. |
MAC_DEV_BRIDGE_BACKGROUND_CHROME_GRANT_DIR | $DATA_DIR/chrome-background-grants | Diretório de concessões aditivas e expiráveis de URLs de Chrome em segundo plano, compartilhadas entre todas as sessões e recarregadas após reinícios da ponte. |
MAC_DEV_BRIDGE_SETTINGS_FILE | $DATA_DIR/settings.json | Configurações do operador. strictApprovals assume o padrão de false quando o arquivo/chave está ausente. O app da barra de menus gerencia isso. |
MAC_DEV_BRIDGE_FOREGROUND_GUI_APPROVAL_FILE | $DATA_DIR/FOREGROUND_GUI_APPROVED | Aprovação de GUI em primeiro plano, de uso único e restrita ao app, em modo estrito. |
MAC_DEV_BRIDGE_CHROME_SOCKET | $DATA_DIR/chrome-background.sock | Socket Unix entre bridge.mjs e o host opcional de mensagens nativas do Chrome. Modo 0600 dentro do diretório de dados modo-0700. |
MAC_DEV_BRIDGE_CHROME_NATIVE_PID_FILE | $DATA_DIR/chrome-native-host.pid | Registro de PID usado pelo interruptor de segurança para o host nativo opcional do Chrome. |
MAC_DEV_BRIDGE_FULL_ACCESS_ACK | — | Forma de ambiente do reconhecimento. Não revogável; veja abaixo. |
O que "acesso total" significa
O servidor MCP roda com as permissões efetivas da conta macOS que o inicia. Ele não tem lista de permissões de caminhos, lista de permissões de comandos de shell, sandbox ou portão interno de aprovação por comando.
O macOS ainda aplica controles de privacidade TCC, Acesso Total ao Disco, ACLs, SIP, controles de acesso ao Keychain e autenticação sudo. Chamadas de shell MCP não interativas não fornecem magicamente uma senha de sudo ou uma interface de terminal. Configure sudo sem senha apenas quando você deliberadamente quiser essa escalada separada.
A ponte se recusa a iniciar até que exista um reconhecimento deliberado, e o re-verifica antes de cada chamada de ferramenta — então remover o arquivo de reconhecimento tanto impede futuros inícios quanto para uma ponte em execução na sua próxima chamada.
A forma de ambiente (MAC_DEV_BRIDGE_FULL_ACCESS_ACK) é deliberadamente não revogável dessa maneira: uma ponte que a herdou nunca lê o arquivo, então deletar o arquivo não a para. Os passos de Instalação abaixo exportam essa variável, então uma ponte iniciada de tal shell só pode ser parada parando o processo. O app da barra de menus a remove de seus filhos exatamente por esse motivo.
As permissões de ações do ChatGPT e o comportamento de confirmação são separados. O servidor MCP anuncia anotações de escrita e destrutivas honestamente e não pode contornar restrições impostas pelo produto ou workspace do ChatGPT.
Transportes
A ponte fala MCP sobre stdio. Dois transportes podem levá-la ao ChatGPT.
OpenAI Secure MCP Tunnel (install.sh, documentado abaixo) é somente de saída
e não precisa de endpoint público. Requer o tipo de conexão Tunnel no
diálogo de plugin do ChatGPT, que não está disponível em contas pessoais — a
opção aparece, mas está desabilitada.
Cloudflare Tunnel + Server URL (mcp-http.mjs) é o fallback quando Tunnel
não está disponível. mcp-http.mjs fica na frente da ponte com Streamable HTTP em
127.0.0.1:8787 atrás de OAuth 2.1 (e um bearer estático para outros clientes),
e cloudflared o publica:
export MAC_DEV_BRIDGE_HTTP_TOKEN="$(openssl rand -hex 32)"
node mcp-http.mjs
O diálogo de plugin do ChatGPT oferece Autenticação: OAuth, No Auth ou Mixed — não há campo de chave de API/bearer.
mcp-http.mjsportanto implementa um servidor de autorização OAuth 2.1 também, e é assim que você conecta o ChatGPT. Veja Conectando ao ChatGPT abaixo. O token bearer estático ainda funciona para qualquer cliente que possa enviar um cabeçalhoAuthorization: Bearer.
O host está fixado em loopback e o caminho para /mcp, deliberadamente — o único
peer pretendido é cloudflared na mesma máquina.
Ambiente:
| Variável | Padrão | Finalidade |
|---|---|---|
MAC_DEV_BRIDGE_HTTP_TOKEN | — | Token bearer. Mínimo de 24 bytes, ASCII imprimível. Recusa-se a iniciar sem um. |
MAC_DEV_BRIDGE_HTTP_TOKEN_FILE | — | Leia o token de um arquivo modo-0600 em vez disso, mantendo-o fora de ps eww. Tem precedência. |
MAC_DEV_BRIDGE_HTTP_PORT | 8787 | Porta de loopback. |
MAC_DEV_BRIDGE_HTTP_TIMEOUT_MS | 600000 | Teto por requisição, para chamadas longas de shell_exec. |
MAC_DEV_BRIDGE_CHATGPT_RESPONSES_BROWSER_MODEL | gpt-5-6-pro | Substituição de compatibilidade para a entrada fixa de chatgpt-browser. A entrada Sol sempre usa gpt-5-6-thinking. |
MAC_DEV_BRIDGE_CHATGPT_RESPONSES_MAX_RUNTIME_SECONDS | 600 | Teto de runtime de navegador por turno para /v1/responses, limitado a 30–3600 segundos. |
MAC_DEV_BRIDGE_CHATGPT_RUNTIME_CONFIG_FILE | $DATA_DIR/chatgpt-runtime.json | Configuração JSON modo-0600 contendo o projectId opcional do ChatGPT. |
MAC_DEV_BRIDGE_CHATGPT_RESPONSES_PROJECT_ID | — | Substituição direta opcional de Project-id. O arquivo de configuração privado é preferido para configuração local persistente. |
MAC_DEV_BRIDGE_ENTRY | bridge.mjs ao lado de mcp-http.mjs | Costura somente para teste para substituir uma ponte simulada. Alterá-lo significa que scripts/disable.sh não reconhecerá o filho. |
MAC_DEV_BRIDGE_PUBLIC_URL | derivado de Host | Fixa o emissor OAuth. Fixe-o: Host é controlável pelo cliente, e o emissor deve corresponder ao que o cliente descobriu. |
MAC_DEV_BRIDGE_OAUTH_CLIENT_ID | gerado | O id de cliente colado no ChatGPT. Estável entre reinícios. |
MAC_DEV_BRIDGE_OAUTH_REDIRECT_URIS | — | Callbacks extras de correspondência exata, separados por vírgula. Acrescenta aos embutidos. |
MAC_DEV_BRIDGE_OAUTH_CLIENT_SECRET | — | Segundo fator opcional em /token, aplicado via client_secret_post ou client_secret_basic. Coloque o mesmo valor no campo OAuth Client Secret do ChatGPT. Removido dos ambientes filhos. |
MAC_DEV_BRIDGE_BODY_IDLE_TIMEOUT_MS | 30000 | Descarta uma requisição cujo corpo estagna por esse tempo. Ocioso, não total, então um upload lento mas em progresso não é truncado. |
MAC_DEV_BRIDGE_MAX_BUFFERED_BYTES | 100663296 (96 MiB) | Orçamento global para corpos de requisição em buffer. Excedê-lo descarrega carga com um 503 retryable. |
Entenda a diferença na exposição antes de escolher este. O transporte Tunnel faz apenas conexões de saída. Este publica um endpoint HTTPS que fica na frente de acesso irrestrito ao shell, com um único token bearer como toda a barreira. Gire o token se ele for divulgado, e considere Cloudflare Access na frente dele para um segundo fator.
Ainda não automatizado para este transporte: install.sh requer tunnel-client e
rejeita um id de tunnel_... ausente, então não pode instalar o caminho HTTP, e
não há LaunchAgent — nada reinicia mcp-http.mjs ou cloudflared após um
reinício ou uma falha. scripts/doctor.sh cobre este transporte.
uninstall.sh remove os arquivos, mas não para um front end em execução.
Conectando ao ChatGPT
O diálogo de plugin do ChatGPT oferece três escolhas de Autenticação — OAuth, No
Auth, Mixed — e nenhum campo de chave de API/bearer, então o token bearer estático não
tem onde ser inserido. mcp-http.mjs portanto implementa um servidor de autorização OAuth 2.1, e é assim que o ChatGPT conecta.
Preencha o diálogo da seguinte forma:
| Campo | Valor |
|---|---|
| Connection | Server URL |
| Server URL | https://<hostname>/mcp |
| Authentication | OAuth |
| Registration method | User-Defined OAuth Client |
| OAuth Client ID | registrado no início, ou defina MAC_DEV_BRIDGE_OAUTH_CLIENT_ID |
| OAuth Client Secret | deixe em branco |
| Token endpoint auth method | none |
| Default scopes | mcp |
| OIDC enabled | desmarque |
O Copy ChatGPT Setup do app da barra de menus produz esta lista pré-preenchida.
Desmarque OIDC porque /.well-known/openid-configuration é servido apenas como um alias
dos metadados OAuth e deliberadamente omite todos os campos de assinatura e assunto. Nenhum token
de ID é emitido, então um cliente estrito de OIDC deve abortar em vez de exigir um.
O ChatGPT então abre uma página de consentimento servida pela sua própria máquina. Ela nomeia o callback exato
para o qual redirecionará e pede o token da ponte, que é como sabe
que a aprovação veio de você. Leia a linha "Will redirect to" antes de aprovar —
qualquer caminho /connector/oauth/<token> é um conector válido do ChatGPT, incluindo um
criado por outra pessoa.
Use um túnel Cloudflare nomeado. O hostname de um túnel rápido muda a cada início, e esse hostname é o emissor OAuth — então um reinício entre descoberta e callback faz o emissor parar de corresponder ao que o ChatGPT registrou, e um cliente estrito descarta o callback silenciosamente. Um túnel nomeado também significa criar o conector uma vez em vez de a cada execução.
Endpoints servidos: /.well-known/oauth-protected-resource,
/.well-known/oauth-authorization-server, /.well-known/openid-configuration
mais /.well-known/oauth-protected-resource/mcp,
/.well-known/oauth-authorization-server/mcp, /.well-known/openid-configuration/mcp
e /mcp/.well-known/openid-configuration — sete caminhos no total, já que a
forma prefixada com /mcp/ existe apenas para openid-configuration. Então /authorize,
/token, /revoke, /revoke-all e /healthz. Um 401
de /mcp carrega WWW-Authenticate: Bearer resource_metadata="…", que é o que
permite a um cliente descobrir o resto.
App da barra de menus (transporte HTTP)
menubar/ constrói um pequeno app de barra de status AppKit que possui os dois processos que este
transporte precisa e expõe as três coisas que você realmente usa: a URL pública,
o token bearer e se o endpoint está respondendo.
./menubar/build.sh # also installs a copy to /Applications
open /Applications/MacDevBridge.app
A compilação instala em /Applications (com fallback para ~/Applications) porque
Launchpad e Spotlight não exibem apps que vivem em ~/Downloads. O bundle
localiza mcp-http.mjs via MAC_DEV_BRIDGE_HOME, depois um pacote ao lado de si mesmo,
depois um caminho embutido em Info.plist no momento da compilação — então a cópia instalada ainda
encontra o pacote.
O menu dá a você: status atual, o modo de túnel, Copy Server URL, Copy
OAuth Client ID, Copy ChatGPT Setup (o diálogo inteiro preenchido, em ordem),
Copy Bearer Token, Start/Stop, uma caixa de seleção ao vivo Strict approvals (desligada por padrão), Rotate Token, Open Logs e Quit.
Ele prefere um túnel nomeado do Cloudflare quando ~/.cloudflared/config.yml declara
um, fornecendo uma URL estável — caso contrário, um túnel rápido, cujo hostname muda a cada
início e força o conector do ChatGPT a ser recriado toda vez. O menu mostra
qual modo está ativo.
Por que vale a pena usar em vez dos comandos brutos:
- Ele é o supervisor. Iniciar gera
mcp-http.mjsecloudflared; Parar e Sair interrompem exatamente o que ele iniciou, em vez de descobrir processos pelo nome. - Iniciar grava o arquivo de desbloqueio e Parar o remove, então a interrupção é à prova de falhas
através do bloqueio por chamada de
bridge.mjs, não apenas uma eliminação de processo. - O token vive em um arquivo com modo 0600 e é passado por
MAC_DEV_BRIDGE_HTTP_TOKEN_FILE, mantendo-o fora deps eww. - O status é consultado de
/healthze da vivacidade dos processos filhos, então um filho que morre é relatado em vez de ser presumido como ativo. - Na inicialização, ele recupera órfãos — ambos os filhos.
applicationWillTerminatenão é executado em uma saída forçada, falha ou reinicialização abrupta, então uma execução anterior pode deixar o arquivo de desbloqueio armado, o front end servindo ecloudflaredainda publicando um hostname público. A inicialização desarma o bloqueio e interrompe o que estiver registrado emmcp-http.pidecloudflared.pid, cada um verificado por identidade primeiro porque pids são reciclados e esses arquivos sobrevivem aSIGKILLe reinicializações. Recuperar apenas o front end anteriormente deixava um ingresso público que nenhuma execução posterior podia fechar, e que o próximo Iniciar rearmaria junto com um segundo túnel. - Ele nunca passa
MAC_DEV_BRIDGE_FULL_ACCESS_ACKpara seus filhos. Essa variável é um desbloqueio permanente embridge.mjs, então herdá-la tornaria Parar incapaz de revogar qualquer coisa — e a documentação de instalação diz para você exportá-la. - Um filho que morre interrompe o outro. Relatar uma falha enquanto deixa o irmão vivo
deixava
cloudflaredpublicando com o bloqueio ainda armado e o menu lendo "não está em execução". - Os filhos herdam o
PATHdo shell de login, entãoshell_execse comporta da mesma forma que em um terminal (um aplicativo iniciado pela GUI não tem nvm ou Homebrew).
O aplicativo é assinado ad-hoc e não é notarizado. Ele localiza mcp-http.mjs via
MAC_DEV_BRIDGE_HOME, depois um pacote ao lado do bundle, depois um caminho embutido em
Info.plist no momento da compilação — então a cópia /Applications funciona com o pacote
deixado onde está. Recompile após mover o pacote para que o caminho embutido permaneça correto.
MAC_DEV_BRIDGE_HOME.
Ele não substitui scripts/disable.sh: trabalhos shell_start destacados sobrevivem ao
front end por design, e apenas esse script os recupera do registro de trabalhos.
Pré-requisitos
Ambos os transportes:
- macOS e um usuário de desktop conectado.
- Node.js 18 ou mais recente.
- Modo de desenvolvedor do ChatGPT.
- Uma CLI
codexfuncional apenas para as três ferramentas de histórico do Codex. O acesso a shell e sistema de arquivos não depende do Codex.
O OpenAI Secure MCP Tunnel adicionalmente requer:
- O binário oficial
tunnel-client, baixado de OpenAI Platform Tunnels ou do lançamento oficial do OpenAI no GitHub, executável e disponível emPATHou em~/.local/bin/tunnel-client. - Um ID de túnel OpenAI com escopo para o workspace do ChatGPT que o usará.
- Uma chave de API em tempo de execução cujo principal tenha Tunnels Read + Use.
- A opção de conexão Tunnel no diálogo do plugin do ChatGPT.
Cloudflare Tunnel + Server URL adicionalmente requer:
cloudflared, autenticado em uma conta Cloudflare.- Um hostname que você controla, ou uma URL de túnel rápido.
opensslpara gerar o token de portador.- A opção de conexão Server URL com OAuth — veja Conectando ao ChatGPT. Não há modo No-Auth:
/mcpé codificado sem substituição, emcp-http.mjsse recusa a iniciar sem um token.
A disponibilidade do modo de desenvolvedor é controlada pelo rollout da conta e pela política do workspace. Se a alternância do modo de desenvolvedor estiver ausente, este pacote não pode substituir essa limitação do lado do produto. A opção Tunnel especificamente não está disponível em contas pessoais — ela é renderizada, mas desabilitada — que é o motivo pelo qual o transporte HTTP existe.
Instalação
Clone o repositório (ou baixe um lançamento/arquivo) e abra o Terminal em sua pasta:
git clone https://github.com/alexanderradahl/mac-developer-bridge.git
cd mac-developer-bridge
Depois instale:
chmod +x install.sh uninstall.sh bridge.mjs scripts/*.sh
export MAC_DEV_BRIDGE_FULL_ACCESS_ACK='I_UNDERSTAND_THIS_GRANTS_FULL_ACCESS'
export CONTROL_PLANE_TUNNEL_ID='tunnel_0123456789abcdef0123456789abcdef'
# Hidden input; the key is not placed in shell history.
read -r -s -p 'Tunnel runtime API key: ' CONTROL_PLANE_API_KEY; printf '\n'
export CONTROL_PLANE_API_KEY
./install.sh
unset CONTROL_PLANE_API_KEY MAC_DEV_BRIDGE_FULL_ACCESS_ACK
O instalador também pode solicitar o ID do túnel e a chave de tempo de execução quando executado interativamente. A chave de tempo de execução é armazenada no Keychain de login do macOS e não é gravada no pacote, perfil de túnel ou plist do LaunchAgent.
O instalador:
- Exige o reconhecimento exato de acesso total.
- Valida macOS, Node, tunnel-client, descoberta do Codex, formato do ID do túnel, modo de auditoria e shell.
- Copia a ponte para
~/.local/share/mac-developer-bridge. - Cria
~/Library/Application Support/MacDeveloperBridge/FULL_ACCESS_ENABLEDcom modo 0600. - Executa testes de sintaxe, protocolo MCP, sistema de arquivos, patch, processo, limpeza de segredos e adaptador Codex.
- Armazena a chave de tempo de execução no Keychain.
- Cria um perfil stdio
tunnel-clientúnico e executatunnel-client doctor. - Instala e inicia um LaunchAgent persistente por usuário.
Locais personalizados são suportados com as variáveis de ambiente MAC_DEV_BRIDGE_INSTALL_DIR, MAC_DEV_BRIDGE_BIN_DIR, MAC_DEV_BRIDGE_PLIST_DIR, MAC_DEV_BRIDGE_DATA_DIR e MAC_DEV_BRIDGE_LOG_DIR.
Conecte o ChatGPT
- Habilite o modo de desenvolvedor no ChatGPT.
- Abra Plugins do ChatGPT e crie um aplicativo em modo de desenvolvedor.
- Defina a conexão, por transporte:
- Transporte Tunnel: escolha Tunnel, depois selecione ou cole o mesmo ID de túnel usado durante a instalação. Indisponível em contas pessoais — a opção é renderizada, mas desabilitada.
- Transporte HTTP: escolha Server URL e insira
https://<hostname>/mcp. A autenticação oferece apenas OAuth, No Auth ou Mixed — veja Conectando ao ChatGPT; o token de portador não tem campo neste diálogo.
- Revise e habilite as ferramentas, e marque o reconhecimento de risco.
- Inicie uma nova conversa no Chat, selecione o aplicativo e chame
bridge_status.
Primeiro prompt sugerido:
Use only the Mac Developer Bridge app for local-machine operations.
First call bridge_status and report the effective user, home directory, shell, Codex binary, audit mode, and whether the tunnel runtime key was scrubbed from child command environments.
Then call codex_thread_read with:
{"thread_id":"019fa926-dbbd-7d72-aa0c-8edd41bd585c","include_turns":true}
If the result is too large, call codex_thread_turns_list in ascending order with items_view="full" and continue through nextCursor until the complete persisted history is recovered.
Do not invoke codex, codex exec, codex-reply, turn/start, or any OpenAI API from shell commands. The Chat conversation is the reasoning agent. Inspect the repository and branch referenced by the thread, report the current state, and continue the unfinished work.
Ask before production deployments, destructive database operations, credential changes, force pushes, or deleting user data.
codex_thread_read e codex_thread_turns_list usam APIs de leitura locais do codex app-server. A ponte não expõe nenhum método do Codex que inicie uma rodada de modelo.
Acesso Total ao Disco
Verifique o estado atual antes de adivinhar:
scripts/tcc-doctor.sh # add --open to jump to the settings pane
Ele testa um caminho protegido por TCC como node e como $MAC_DEV_BRIDGE_SHELL — apenas esses dois — e relata quais têm a
concessão. O Acesso Total ao Disco não pode ser concedido por um script — os bancos de dados
TCC são protegidos por SIP, então não são graváveis mesmo como root, e tccutil só pode
redefinir entradas. Um humano deve adicionar o binário em Ajustes do Sistema, ou um MDM deve
enviar um perfil PPPC.
Se as leituras falharem com EPERM ou "Operação não permitida", conceda Acesso Total ao Disco aos executáveis reais na cadeia de tempo de execução:
- o binário exato
nodemostrado porbridge_status /bin/zsh- o binário instalado
tunnel-client, apenas para o transporte Tunnel
cloudflared não precisa disso: ele apenas encaminha HTTP para loopback e nunca
toca no sistema de arquivos em nome de uma ferramenta.
Um LaunchAgent pode não herdar permissões de privacidade anteriormente concedidas ao Terminal ou a uma instalação diferente do Node. O Acesso Total ao Disco é separado das permissões POSIX comuns.
Operações
Os caminhos ~/.local/share/mac-developer-bridge abaixo existem apenas se install.sh
foi executado, o que requer tunnel-client — então no transporte HTTP esse diretório
não existe e você executa os scripts do diretório do pacote extraído
em vez disso.
Ambos os transportes:
# Full diagnostic report (includes the Full Disk Access check)
./scripts/doctor.sh # or ~/.local/share/mac-developer-bridge/scripts/doctor.sh
# Kill switch. Read its output; a non-zero exit means NOT contained.
./scripts/disable.sh
# Audit log
tail -f "$HOME/Library/Logs/MacDeveloperBridge/audit.jsonl"
Transporte HTTP:
# Logs (only populated if you redirected them, as DEPLOY.md step 2 does)
tail -f "$HOME/Library/Logs/MacDeveloperBridge/http.stderr.log"
# Restart: there is no LaunchAgent, so stop and re-run it.
# disable.sh REMOVES the unlock file, so it must be recreated — without this the
# front end starts and /healthz answers 200 while every tool call fails 503,
# because /healthz never spawns the bridge.
./scripts/disable.sh
printf 'I_UNDERSTAND_THIS_GRANTS_FULL_ACCESS\n' \
> "$HOME/Library/Application Support/MacDeveloperBridge/FULL_ACCESS_ENABLED"
chmod 600 "$HOME/Library/Application Support/MacDeveloperBridge/FULL_ACCESS_ENABLED"
export MAC_DEV_BRIDGE_HTTP_TOKEN='<the same token the plugin uses>'
node mcp-http.mjs >>"$HOME/Library/Logs/MacDeveloperBridge/http.stderr.log" 2>&1 &
Transporte Tunnel:
launchctl print "gui/$(id -u)/com.openai.mac-developer-bridge-tunnel"
launchctl kickstart -k "gui/$(id -u)/com.openai.mac-developer-bridge-tunnel"
# Re-enable after an explicit acknowledgement (requires the LaunchAgent plist)
export MAC_DEV_BRIDGE_FULL_ACCESS_ACK='I_UNDERSTAND_THIS_GRANTS_FULL_ACCESS'
~/.local/share/mac-developer-bridge/scripts/enable.sh
unset MAC_DEV_BRIDGE_FULL_ACCESS_ACK
# Rotate the tunnel runtime key with hidden input
~/.local/share/mac-developer-bridge/scripts/rotate-tunnel-key.sh
tail -f "$HOME/Library/Logs/MacDeveloperBridge/tunnel.stderr.log"
enable.sh atualmente requer o plist do LaunchAgent, então não funciona no
transporte HTTP. Para reativar lá, recrie o arquivo de desbloqueio e reinicie o
front end como na Opção B do DEPLOY.md.
tunnel-client normalmente expõe endpoints de saúde de loopback e uma UI de operador em http://127.0.0.1:8080/healthz, /readyz, /metrics e /ui enquanto está em execução.
Auditoria
O modo padrão é metadata. Ele registra:
- timestamp e nome da ferramenta
- uma prévia editada dos argumentos
- hash SHA-256 dos argumentos completos
- um resumo compacto do resultado ou erro
No transporte HTTP não há instalação, e um aplicativo de barra de menus iniciado pela GUI não tem
ambiente de shell para herdar — então as únicas maneiras de mudar o modo de auditoria lá são
exportá-lo em um shell e iniciar mcp-http.mjs desse shell, ou iniciar o aplicativo
com open -a MacDevBridge --env MAC_DEV_BRIDGE_AUDIT_MODE=full. Caso contrário, ele permanece
em metadata.
Defina MAC_DEV_BRIDGE_AUDIT_MODE antes da instalação para um dos:
MAC_DEV_BRIDGE_AUDIT_MODE=off
MAC_DEV_BRIDGE_AUDIT_MODE=metadata
MAC_DEV_BRIDGE_AUDIT_MODE=full
full pode persistir argumentos de comandos sensíveis e conteúdo de arquivos mesmo após a edição comum de padrões de token. Trate o log de auditoria como sensível. A chave de tempo de execução do túnel é removida do ambiente do processo da ponte antes que qualquer ferramenta de shell ou sistema de arquivos possa ser executada, embora o acesso irrestrito ao shell ainda possa alcançar outras credenciais disponíveis para a conta macOS.
Verifique o roteamento de uso
A ponte em si não contém nenhum cliente de inferência OpenAI e os adaptadores do Codex chamam métodos somente leitura do servidor de aplicativos. Mesmo assim, verifique o comportamento específico da conta após a conexão:
- Registre o saldo atual de créditos Codex/Work.
- No Chat, chame apenas
bridge_statusefs_statem um caminho inofensivo. - Atualize a página de uso do Codex/Work.
- Confirme que nenhum uso de modelo do Codex foi registrado.
- Depois leia o thread do Codex armazenado e continue o trabalho aqui.
Não use shell_exec para executar o Codex em si se o objetivo for evitar o uso de modelo do Codex.
Desinstalação
Do diretório do pacote extraído ou instalado:
./uninstall.sh
O desinstalador remove o LaunchAgent, a instalação da ponte, o symlink de comando, o arquivo de desbloqueio e a chave de tempo de execução do Keychain.
Ele não remove o diretório de dados, então estes sobrevivem a uma desinstalação — incluindo duas credenciais ativas:
http-token— o token de portador (modo 0600)oauth-state.json— o ID do cliente OAuth mais os digests do token de acesso/atualização (modo 0600)oauth-client-id,mcp-http.pid,cloudflared.pid,jobs/e o log de auditoria
Exclua ~/Library/Application Support/MacDeveloperBridge também se quiser que as credenciais desapareçam. Ele também não interrompe um front end em execução; execute scripts/disable.sh primeiro.