Mac Developer Bridge
Dale a ChatGPT una terminal real en tu Mac: shell, archivos, sesiones PTY reales, trabajos en segundo plano e historial de Codex de solo lectura a través de MCP.
Documentación
Mac Developer Bridge
Dale a ChatGPT una terminal real en tu Mac.
Mac Developer Bridge convierte una conversación de ChatGPT en la capa de razonamiento para tu Mac real. Puede ejecutar comandos de shell, editar archivos, iniciar sesiones de terminal interactivas, gestionar trabajos de larga duración, leer hilos de Codex almacenados sin iniciar otro turno de modelo de Codex y, opcionalmente, operar tus pestañas reales de Chrome con sesión iniciada en segundo plano sin robar el foco.

Ejemplo: "Encuentra la sesión de Codex en la que trabajaba ayer, inspecciona el repositorio en vivo, arregla el CI, sube el resultado y dime qué cambió."
Ese es el tipo de flujo de trabajo para el que está construido este proyecto.
[!ADVERTENCIA] Mac Developer Bridge otorga deliberadamente a un cliente MCP los permisos efectivos de tu usuario de macOS. No está en un sandbox y no tiene lista blanca de comandos ni rutas. Lee SECURITY.md antes de habilitarlo.
La idea
ChatGPT tiene el razonamiento. Tu Mac tiene el código fuente, la terminal, las credenciales, las herramientas de compilación, los servicios locales y el trabajo en progreso. Mac Developer Bridge conecta ambos a través de MCP sin añadir otro modelo o bucle de agente en el medio.
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]
El puente en sí no realiza ninguna llamada de modelo de OpenAI. Expone herramientas locales deterministas; ChatGPT aporta el razonamiento. Las herramientas de historial de Codex usan métodos de solo lectura de codex app-server y nunca llaman a turn/start.
Lo que esto desbloquea
- Recupera un hilo de Codex almacenado, inspecciona el repositorio al que se refiere y continúa el trabajo desde ChatGPT.
- Ejecuta pruebas, compilaciones, Git, gestores de paquetes, CLIs de bases de datos, AppleScript y otras herramientas ya instaladas en tu Mac.
- Mantén shells interactivos y programas de terminal vivos a través de un PTY real en lugar de fingir que stdin es una terminal.
- Inicia trabajos locales de larga duración, inspecciona sus registros más tarde y detén todo el grupo de procesos.
- Lee y modifica archivos en cualquier lugar al que tu usuario de macOS pueda acceder.
- Opcionalmente, opera páginas aprobadas en tu perfil real de Chrome con sesión iniciada sin traer Chrome al primer plano.
Esto es intencionalmente diferente de un agente de codificación local. No hay un segundo bucle de razonamiento. ChatGPT sigue siendo el agente; el Mac es el entorno de ejecución.
Inicio rápido
Para una cuenta personal de ChatGPT, la aplicación de la barra de menú es el camino más fácil. Necesitas macOS, Node.js 18+, cloudflared, un hostname/túnel y el modo Desarrollador de ChatGPT.
git clone https://github.com/alexanderradahl/mac-developer-bridge.git
cd mac-developer-bridge
./menubar/build.sh
open /Applications/MacDevBridge.app
Usa Iniciar y luego Copiar configuración de ChatGPT desde la aplicación de la barra de menú. La configuración detallada de OAuth y Cloudflare está en Conectando a ChatGPT y DEPLOY.md.
Los usuarios de Workspace que tengan acceso a OpenAI Secure MCP Tunnel pueden usar install.sh en su lugar. Consulta Transports.
¿Quieres ver qué pedirle que haga? Comienza con los flujos de trabajo de copiar y pegar.
Si esto es útil, dale una estrella al repositorio para que otros desarrolladores puedan encontrarlo. Si construyes algo interesante con esto, comparte el flujo de trabajo exacto en ¿Qué estás haciendo que ChatGPT haga en tu Mac?.
Este es un proyecto independiente de código abierto y no es un producto oficial de OpenAI o Cloudflare. OpenAI, ChatGPT, Codex y Cloudflare son marcas comerciales de sus respectivos propietarios.
Código abierto
Mac Developer Bridge se publica bajo la Licencia MIT. Los informes de errores y las solicitudes de extracción enfocadas son bienvenidos; consulta CONTRIBUTING.md. Los informes sensibles a la seguridad deben seguir las pautas en SECURITY.md en lugar de publicarse públicamente.
Capacidades
- Comandos de shell arbitrarios a través de
/bin/zsh -lc, bajo el usuario de macOS con sesión iniciada - Trabajos en segundo plano desacoplados con registros persistentes de stdout/stderr, inspección de estado y terminación de grupos de procesos
- Lectura, escritura, adición, listado, stat, copia, movimiento, chmod, symlink, mkdir y eliminación recursiva de archivos sin restricciones
- Aplicación de diff unificado a través de
git apply - Descubrimiento y lectura de hilos de Codex almacenados sin reanudar un hilo ni iniciar un turno de modelo de Codex
- Recuperación paginada de turnos de Codex para historiales demasiado grandes para una sola respuesta
- Auditoría local en JSONL
- Conectividad privada solo de salida a través de OpenAI Secure MCP Tunnel, o un front-end de bucle local HTTP plano que Cloudflare Tunnel publica sobre HTTPS
- Persistencia por usuario a través de un LaunchAgent de macOS
- Pestillo de desbloqueo con cierre ante fallo:
bridge.mjsvuelve a leer el archivo de desbloqueo antes de cada llamada de herramienta, por lo que eliminarlo rechaza la siguiente llamada y sale — a menos que el proceso haya heredadoMAC_DEV_BRIDGE_FULL_ACCESS_ACK, que omite el archivo por completo - Interruptor de apagado local (
scripts/disable.sh), que detiene el front-end, el puente, el host nativo opcional de Chrome en segundo plano, los grupos de trabajos desacoplados deshell_start, las sesiones pty interactivas y los servidores MCP hijos federados, verificando los mismos objetivos que señaló
Git, gestores de paquetes, Vercel CLI, CLIs de bases de datos, AppleScript, CLIs de navegador, herramientas de compilación y otros programas instalados siguen siendo accesibles a través de shell_exec; el puente mantiene deliberadamente sin lista blanca de comandos.
Herramientas
| Herramienta | Propósito |
|---|---|
bridge_status | Identidad de tiempo de ejecución, rutas, contexto de permisos, shell, modo de auditoría, binario de Codex, política de foco y estado de Chrome en segundo plano |
chrome_workspace_status | Inspecciona el grupo de Chrome de MDB propiedad de la extensión, actividad de arrendamiento y grupo reutilizable de pestañas en segundo plano; no se requiere concesión de sitio web |
chatgpt_extension_status | Inspecciona la extensión de Chrome de ChatGPT instalada, el registro del host nativo de OpenAI y el estado del puente de página de solo lectura en vivo sin parchear la extensión de OpenAI |
chatgpt_conversation_start | Inicia o continúa experimentalmente una conversación exacta de ChatGPT a través de la acción de tiempo de ejecución de primera parte de la página con sesión iniciada; sin escribir/hacer clic en la interfaz ni exportar credenciales |
chrome_workspace_setup | Aprovisiona un objetivo de grupo de MDB de solo crecimiento de 1 a 32 pestañas; el valor predeterminado es ocho, con creación diferida hasta que Chrome esté naturalmente enfocado |
chrome_tabs | Lista pestañas en el perfil real de Chrome con sesión iniciada sin activar Chrome; solo se limita cuando las aprobaciones estrictas están activadas |
chrome_open | Arrienda una pestaña inactiva del grupo persistente de MDB y abre una URL sin crear una pestaña nueva |
chrome_navigate | Navega a una pestaña aprobada sin seleccionarla |
chrome_snapshot | Lee texto visible y elementos interactivos de una pestaña aprobada |
chrome_click | Haz clic en un elemento de una pestaña aprobada sin traer Chrome al primer plano |
chrome_fill | Rellena entradas, áreas de texto, selectores o campos contenteditable en segundo plano |
chrome_close | Libera una pestaña de espacio de trabajo de MDB de vuelta al grupo inactivo, o cierra una pestaña en segundo plano que no sea de espacio de trabajo |
shell_exec | Ejecuta cualquier comando de shell en primer plano, opcionalmente con cwd, env, stdin, tiempo de espera y límite de salida |
shell_start | Inicia un proceso desacoplado de larga duración |
shell_job_status | Inspecciona el estado de ejecución y las colas de registros |
shell_job_list | Lista metadatos de trabajos persistentes |
shell_job_kill | Señala un grupo de procesos en segundo plano |
fs_read | Lee texto o base64 con paginación por desplazamiento |
fs_write | Reemplazo atómico, creación, adición o escritura binaria |
fs_list | Listado de directorios recursivo o no recursivo |
fs_stat | Metadatos lstat y destino de symlink |
fs_manage | mkdir, eliminar, mover, copiar, chmod o symlink |
apply_patch | Aplica o verifica un diff unificado con git apply |
codex_thread_read | Lee un hilo de Codex almacenado sin reanudarlo |
codex_thread_list | Busca y pagina hilos de Codex almacenados |
codex_thread_turns_list | Pagina turnos almacenados con elementos completos, resumidos u omitidos |
audit_tail | Lee la cola de auditoría local del puente |
Chrome en segundo plano sin robar el foco
En macOS, la integración opcional de Navegador en segundo plano opera el mismo perfil de Chrome con sesión iniciada que ya usas, por lo que las sesiones de sitios web existentes funcionan, pero la automatización rutinaria ocurre a través de una pequeña extensión local en lugar de la automatización de interfaz de AppleScript o la selección de páginas del Protocolo de DevTools de Chrome. El host nativo está vinculado en el momento de la instalación al perfil/cuenta de Chrome seleccionado y rechaza un perfil sin sesión o no coincidente.
Esto es intencionalmente opcional porque el control autenticado del navegador es poderoso. Instala el host nativo una vez, luego carga la extensión desempaquetada una vez en Chrome:
./scripts/install-background-chrome.sh
Luego en Chrome abre chrome://extensions, habilita Modo desarrollador, elige Cargar descomprimida y selecciona el directorio chrome-extension/ de este repositorio. El id de extensión esperado es pcebfblnmcappinbenkmddjdapaoajgm.
La extensión mantiene un grupo de pestañas nativo de Chrome llamado MDB. Por defecto, apunta a ocho pestañas inactivas propiedad de la extensión, con un máximo duro de 32. Se crean solo mientras la ventana existente de Chrome de MDB ya está naturalmente en primer plano, luego se arriendan y reutilizan para trabajo rutinario. El grupo está colapsado cuando está inactivo y se expande mientras una o más pestañas están arrendadas. Esto preserva el límite de no robo de foco alrededor de una peculiaridad de macOS/Chrome medida en este proyecto: incluso chrome.tabs.create({ active:false }) puede traer Chrome al primer plano.
El grupo se auto-repara y tiene un objetivo de capacidad persistente de solo crecimiento. chrome_workspace_setup(pool_size=16) registra un objetivo de 16 pestañas inmediatamente. Si la ventana de Chrome de MDB ya está enfocada, las pestañas faltantes se crean y agrupan de inmediato; de lo contrario, el estado informa el recuento pendiente y la extensión se expande en el siguiente foco natural de Chrome. Una solicitud posterior más baja nunca cierra pestañas existentes. Cuando cada pestaña actual está arrendada y no hay expansión pendiente, la presión eleva el objetivo en cuatro, hasta 32, e intenta la creación inmediata solo cuando Chrome ya está enfocado. MDB nunca activa Chrome para satisfacer el aprovisionamiento manual o automático.
chrome_workspace_status no requiere concesión porque solo lee el estado del espacio de trabajo local propiedad de la extensión. Informa los tamaños de grupo actuales y objetivo, el máximo de 32 pestañas, el paso de crecimiento automático de cuatro pestañas, la capacidad pendiente, los metadatos de antigüedad/inactividad del arrendamiento, el tiempo de espera de recuperación de inactividad de 10 minutos y el presupuesto de espera de arrendamiento de 20 segundos. chrome_workspace_setup tampoco requiere concesión: el aprovisionamiento siempre se acepta localmente, mientras que la creación real permanece diferida cuando Chrome no está enfocado. Los llamadores heredados/internos de tabs.open se enrutan al mismo camino de arrendamiento de workspace.open, por lo que no pueden crear pestañas sueltas fuera de MDB. Cuando todas las pestañas están ocupadas, chrome_open primero aprovisiona o crea capacidad donde es seguro, luego espera brevemente una liberación; los arrendamientos abandonados se recuperan después de 10 minutos sin actividad del navegador, mientras que cada navegación/captura/clic/relleno renueva un arrendamiento activo.
El acceso relajado es el predeterminado. El trabajo HTTP/HTTPS normal, incluidos localhost y puertos no predeterminados, a través del perfil de Chrome de MDB con sesión iniciada no requiere un comando de aprobación de terminal ni una lista blanca por sitio. Esto es intencional: Mac Developer Bridge ya expone autoridad de shell/archivos sin restricciones como el usuario de macOS con sesión iniciada, y el valor predeterminado útil es que la ejecución del navegador coincida con ese nivel de confianza elegido por el operador mientras permanece primero en segundo plano.
La aprobación relajada no relaja el enrutamiento de Chrome. El control directo de Chrome a través de shell_exec/shell_start — AppleScript, JXA, lanzamientos directos del ejecutable de Chrome o open de shell de una URL HTTP/HTTPS (incluido open -g) — siempre se rechaza con CHROME_BACKGROUND_REQUIRED, tanto en modo Relajado como Estricto. El trabajo del navegador debe usar las herramientas de chrome_* y el grupo gestionado de MDB. Esto mantiene el comportamiento de no robo de foco estructural en lugar de depender de qué modo de aprobación esté seleccionado.
Si quieres un flujo de trabajo de navegador/aplicación más estricto, habilita Aprobaciones estrictas desde la aplicación de la barra de menú de Mac Developer Bridge. El interruptor está en vivo; no se necesita reinicio. En modo Estricto, las aprobaciones de chrome-background son aditivas y compartidas en cada sesión de ChatGPT conectada al puente hasta que cada concesión expire:
./scripts/approve-personal-browser.sh \
--provider chrome-background \
--url-pattern 'https://www.producthunt.com/*' \
--url-pattern 'https://www.reddit.com/*' \
--ttl 900
Un flujo de trabajo normal es:
chrome_openuna URL aprobada en una pestaña inactiva arrendada del grupoMDB.chrome_snapshotpara leer la página y obtener selectores suficientemente estables para los controles visibles.chrome_fill/chrome_click/chrome_navigatesegún sea necesario.chrome_closepara devolver la pestaña del espacio de trabajo a su página de extensión inactiva y liberar el arrendamiento. La liberación del espacio de trabajo es una limpieza local/sin concesión, por lo que las concesiones de URL en modo estricto no pueden dejar un arrendamiento terminado varado.
La vinculación de perfil siempre se aplica. En modo relajado, la extensión permite sitios HTTP/HTTPS normales sin una concesión por sitio. En modo estricto, cada aprobación de chrome-background se almacena como su propio archivo con modo 0600 bajo $DATA_DIR/chrome-background-grants/, expira después de como máximo 15 minutos y se fusiona con otras aprobaciones aún activas. Los archivos caducados se eliminan automáticamente y los patrones de URL se aplican dentro de Chrome. Los proveedores federados de navegador personal mantienen su comportamiento separado de un solo uso.
chatgpt_extension_status es deliberadamente de solo lectura. Informa la versión instalada de la extensión ChatGPT de Chrome, el registro local del host nativo com.openai.codexextension y—cuando una pestaña de chatgpt.com ya está abierta—el estado en vivo devuelto por el puente de página propio de OpenAI. MDB no parchea la extensión de OpenAI, no se agrega a la lista de permitidos del host nativo de OpenAI, no expone llamadas RPC privadas arbitrarias de OpenAI, ni abre programáticamente el panel lateral de ChatGPT. La extensión actual de ChatGPT no declara externally_connectable; su ruta de apertura del panel lateral también requiere un gesto de usuario confiable.
Inicio experimental de conversación con ChatGPT
chatgpt_conversation_start es un experimento deliberadamente limitado para iniciar o continuar una conversación de ChatGPT de consumo desde Codex/Work Mode. Su transporte predeterminado de runtime arrienda una pestaña nueva de fondo de chatgpt.com, resuelve la acción de la tienda de submitComposer de primera parte montada de ChatGPT a través de una huella semántica fija, y envía el mensaje como un text_action. No escribe ni hace clic en el compositor. El propio runtime de ChatGPT construye la solicitud privada y su material de requisitos/prueba generado por el navegador. MDB observa el flujo inicial limitado/entrega renderizada, recarga la conversación devuelta exacta y lee el id exacto del mensaje de asistente persistido antes de devolver texto. Esa recarga es verificación, no un segundo envío de modelo. La pestaña nunca se activa y se libera al grupo de MDB después.
La herramienta acepta prompt, opcional transport (runtime por defecto o raw de diagnóstico explícito), opcional model (predeterminado gpt-5-6-pro), opcional thinking_effort, opcional max_runtime_seconds (30–3600), opcional continue_in_work, opcional conversation_id exacto para continuación, y un tab_id arrendado existente opcional. El modelo de runtime seleccionado debe conservar el esfuerzo solicitado admitido antes del envío; continue_in_work se aplica solo a diagnósticos sin procesar. El transporte sin procesar conserva la sonda de solicitud privada directa anterior y aún puede fallar con CHATGPT_CONVERSATION_REQUIREMENTS_UNAVAILABLE. Ningún transporte acepta autorización copiada, cookies, dispositivo, Sentinel, Turnstile, Arkose o campos de prueba, y ninguno los devuelve ni los persiste. Los registros de auditoría de mensajes conservan solo la longitud en bytes y un prefijo corto de SHA-256.
Los orquestadores locales pueden invocar la misma operación a través de una ruta 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>"}'
Esa ruta acepta solo una conexión directa de loopback con el portador estático de MDB. Rechaza credenciales OAuth y solicitudes reenviadas/tunelizadas, devuelve Cache-Control: no-store y envuelve la operación MCP exacta en lugar de exponer el socket del host nativo de Chrome.
Modelo de navegador experimental de ChatGPT
MDB también expone un adaptador separado de portador estático, loopback directo POST /v1/responses para los modelos explícitos de OpenCodex chatgpt-runtime/chatgpt-browser y chatgpt-runtime/chatgpt-sol. El primero usa el runtime de navegador estándar fijo. La entrada Sol activa el modelo gpt-5-6-thinking montado de ChatGPT y mapea los niveles de esfuerzo de Codex como low -> low, medium -> standard, high -> high, xhigh -> max, max -> max y ultra -> max. El adaptador reconstruye cada turno sin estado a partir de instrucciones/entrada de Responses, presenta herramientas admitidas de function y custom al runtime de ChatGPT a través de un protocolo de decisión JSON fijo, y convierte un mensaje validado o selección de herramienta de vuelta a salida canónica de Responses JSON/SSE. Codex sigue siendo responsable de ejecutar herramientas locales y reproducir sus resultados en el siguiente turno.
Codex puede representar herramientas de forma libre como exec ya sea como una herramienta personalizada o como una función cerrada con un input de cadena requerido. El adaptador acepta solo la variación de envoltura determinista exacta para esas dos formas equivalentes y rechaza llamadas mixtas o más amplias. Antes de analizar la decisión JSON, MDB verifica el mensaje de asistente persistido exacto de la conversación de ChatGPT devuelta para que los fragmentos de renderizado transitorios no puedan activar reintentos de transporte.
Este modelo es intencionalmente separado y experimental. No se agrega al modelo predeterminado, combos, predeterminados de subagente o cadenas de respaldo automáticas. La declaración de web_search alojada en la API de Codex se omite para este proveedor en lugar de bloquear cada turno de Work mode; ChatGPT puede usar su propia navegación de primera parte de forma independiente. Otras herramientas alojadas, imágenes/audio, persistencia de respuestas del lado del servidor, rastros de razonamiento nativos y contabilidad confiable de tokens no son compatibles. El texto plano no JSON se devuelve como mensaje final y nunca puede invocar una herramienta; la salida malformada similar a JSON/herramienta, una selección de herramienta desconocida propiedad del llamador, desviación del runtime, mensaje sobredimensionado o envío ambiguo falla de forma cerrada sin reintento ni automatización de UI.
Ejemplo de solicitud directa:
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}'
El registro local de OpenCodex usa un proveedor personalizado de openai-responses apuntando a http://127.0.0.1:8787, con allowPrivateNetwork: true, statelessResponses: true, el portador estático de MDB como clave de API del proveedor, y ids de modelo personalizados chatgpt-browser y chatgpt-sol. Sus ids calificados visibles para Codex son chatgpt-runtime/chatgpt-browser y chatgpt-runtime/chatgpt-sol. Ambas filas del catálogo usan la ventana de 372k tokens y el umbral de compactación automática de 334.8k de gpt-5.6-sol; MDB permite hasta 4,000,000 bytes UTF-8 para el mensaje serializado del runtime del navegador, de modo que el valor más grande del catálogo está respaldado por un límite de transporte real.
Para mantener estos turnos experimentales fuera del historial general de ChatGPT, coloque un id de Proyecto en un archivo de runtime privado:
{"projectId":"g-p-..."}
Guárdelo como $DATA_DIR/chatgpt-runtime.json con modo 0600. Cuando esté configurado, cada nueva conversación de runtime de navegador de /v1/responses arrienda la página de primera parte de ese Proyecto y envía solo después de que la ruta cargada y el conversationMode montado identifiquen ambos el Proyecto exacto. Las cookies capturadas, autorización, Sentinel, dispositivo, sesión y campos de prueba no son necesarios ni aceptados.
Lo que el modo de fondo no promete: CAPTCHAs, diálogos de permisos nativos del navegador/SO, selectores de archivos, descargas que requieren un gesto de usuario confiable, claves de acceso y otra UI de seguridad del navegador pueden requerir un paso en primer plano/manual. El puente informa esa limitación en lugar de activar Chrome silenciosamente. Esto también es deliberadamente más limitado que JavaScript de página arbitrario o captura de encabezados de red: la resolución del runtime es fija, las rutas de módulos/scripts/selectores proporcionados por el llamador se rechazan, y un runtime cambiado o ambiguo falla sin un segundo envío; consulte SECURITY.md.
Para eliminar la integración:
./scripts/uninstall-background-chrome.sh
Aplicaciones de escritorio y enfoque
Para aplicaciones nativas de macOS, MDB aún prefiere APIs con capacidad de fondo o rutas web porque la automatización de accesibilidad/AppleScript de aplicaciones como Slack puede requerir que la aplicación objetivo se convierta en la frontal. En el modo relajado predeterminado, el control de aplicaciones nativas que no son Chrome se permite sin una aprobación de terminal separada, por lo que MDB aún puede completar la tarea cuando una interacción de aplicación en primer plano es genuinamente necesaria. Chrome es la excepción: debido a que MDB tiene una extensión de fondo dedicada con sesión iniciada, la automatización directa de GUI de Chrome siempre se fuerza de vuelta a la ruta del navegador MDB en lugar de permitirle robar el enfoque.
Prefiera, en orden:
- una API o conector MCP para el servicio;
- la aplicación web del servicio a través del grupo de Chrome
MDBcon sesión iniciada; - automatización de GUI de aplicaciones nativas solo cuando la interacción en primer plano sea genuinamente requerida.
Cuando Aprobaciones estrictas está habilitado, el control de aplicaciones nativas en primer plano se bloquea a menos que el operador cree una concesión de un solo uso, específica de la aplicación:
./scripts/approve-foreground-gui.sh --app Slack --ttl 60
El modo estricto es opcional y está desactivado por defecto. La casilla de verificación de la barra de menú lo cambia en vivo.
Sesiones de terminal interactivas
Un pty real, asignado por lib/ptyhelper.pl (Perl central, sin dependencia agregada). Se anuncia solo cuando el helper se ejecuta en este host; de lo contrario, las seis herramientas están ausentes en lugar de rotas.
| Herramienta | Propósito |
|---|---|
pty_start | Iniciar un programa en un terminal real y devolver un id de sesión |
pty_read | Leer la transcripción desde un cursor de bytes, opcionalmente con polling largo |
pty_write | Enviar pulsaciones de teclas, incluidos caracteres de control |
pty_resize | Cambiar el tamaño de la ventana, confirmado por una lectura de vuelta del kernel |
pty_signal | Enviar señal al grupo de procesos de la sesión |
pty_close | Terminar la sesión y reclamarla |
Límites que serán visibles en el uso normal:
- Longitud de línea. Mientras el terminal está en modo canónico—el predeterminado, y lo que usa cada mensaje interactivo—la disciplina de línea descarta una línea de entrada de 1024 bytes o más en lugar de truncarla.
pty_writerechaza tal escritura conPTY_WRITE_CANON_LIMITen lugar de informar bytes que el programa nunca verá. Los bytes se acumulan entre llamadas hasta un\ro\n, por lo que la fragmentación no lo evade. Envíe líneas de como máximo 1023 bytes. Una sesión que ha puesto su terminal en modo sin procesar se verifica y se permite. - Concurrencia. El límite de sesiones se toma, no solo se verifica, por lo que las llamadas concurrentes de
pty_startno pueden excederlo. - Retención. Cada sesión conserva los últimos
MAC_DEV_BRIDGE_PTY_RING_BYTESde salida en un anillo fijo;pty_readinformalostBytescuando un cursor se queda atrás. - Contención. Consulte SECURITY.md—
pty_closeinformaleaderGroupGone,ttyProcessesKilledyuncontainedPidspor separado, ycontainmentVerifiedes verdadero solo cuando nada sobrevivió.
Servidores MCP hijos federados
Si un registro de proveedores está configurado, las herramientas de cada proveedor se anuncian con un prefijo de key__tool y se proxifican. No hay proveedor integrado: el registro es proporcionado por el operador. El modo de perfil de navegador personal requiere una concesión de operador por uso—consulte SECURITY.md.
Entorno del puente
Estos son leídos por bridge.mjs en ambos transportes.
| Variable | Valor por defecto | Propósito |
|---|---|---|
MAC_DEV_BRIDGE_DATA_DIR | ~/Library/Application Support/MacDeveloperBridge | Estado, metadatos de trabajos, raíces de federación. |
MAC_DEV_BRIDGE_LOG_DIR | ~/Library/Logs/MacDeveloperBridge | Directorio de registros. |
MAC_DEV_BRIDGE_AUDIT_LOG | $LOG_DIR/audit.jsonl | Ruta del JSONL de auditoría. |
MAC_DEV_BRIDGE_AUDIT_MODE | metadata | off, metadata o full. full registra los argumentos de las herramientas; consulta la advertencia en SECURITY.md. |
MAC_DEV_BRIDGE_UNLOCK_FILE | $DATA_DIR/FULL_ACCESS_ENABLED | El pestillo de desbloqueo revocable. Se vuelve a leer antes de cada llamada a una herramienta. |
MAC_DEV_BRIDGE_UNLOCK_RECHECK_MS | 3000 | Con qué frecuencia se vuelve a leer el pestillo mientras existe una sesión pty o un hijo federado y el cliente está en silencio. Limita cuánto tiempo puede sobrevivir cualquiera de ellos a un archivo de desbloqueo eliminado. |
MAC_DEV_BRIDGE_SHELL | shell de inicio de sesión | Shell utilizado para shell_exec/shell_start. |
MAC_DEV_BRIDGE_DEFAULT_OUTPUT_BYTES | 1000000 | Límite de salida predeterminado por llamada. |
MAC_DEV_BRIDGE_MAX_OUTPUT_BYTES | 8000000 | Tope que una llamada puede solicitar. |
MAC_DEV_BRIDGE_PTY_PERL | /usr/bin/perl | Intérprete para el asistente pty. |
MAC_DEV_BRIDGE_PTY_HELPER | lib/ptyhelper.pl junto a bridge.mjs | Ruta del script del asistente. |
MAC_DEV_BRIDGE_PTY_MAX_SESSIONS | 8 (1–64) | Límite de sesiones en vivo. kern.tty.ptmx_max es 511 en todo el sistema, por lo que esto protege la propia Terminal.app del operador, no solo este proceso. |
MAC_DEV_BRIDGE_PTY_RING_BYTES | 262144 (4 KiB–4 MB) | Retención de salida por sesión. La retención total es esto multiplicado por el límite de sesiones. |
MAC_DEV_BRIDGE_PTY_IDLE_TIMEOUT_MS | 900000 (1 s–1 h) | Ventana de reclamación inactiva, y un tope: pty_start puede solicitar una más corta, nunca una más larga. El valor efectivo de una sesión en vivo está en bridge_status. |
MAC_DEV_BRIDGE_PTY_MAX_LIFETIME_MS | 28800000 (5 s–24 h) | Tope duro, aplicado incluso en una sesión en uso activo. |
MAC_DEV_BRIDGE_PTY_START_TIMEOUT_MS | 5000 | Cuánto tiempo espera pty_start a que el asistente informe un pty real. |
MAC_DEV_BRIDGE_MCP_SERVERS | — | Ruta a un archivo JSON de registro de proveedores MCP hijo. |
MAC_DEV_BRIDGE_MCP_SERVERS_JSON | — | El mismo registro en línea. Tiene prioridad. |
MAC_DEV_BRIDGE_MCP_START_DEADLINE_MS | 15000 (1 s–120 s) | Tope de tiempo de pared para el arranque completo de un proveedor: protocolo de enlace, verificación de concesión y cada página de tools/list. Un proveedor que lo exceda se abandona en lugar de dejar bloqueada la superficie de herramientas. |
MAC_DEV_BRIDGE_MCP_PING_IDLE_MS | 30000 | Intervalo de inactividad tras el cual se hace ping a un hijo federado; un hijo que falle el ping se trata como colgado y se reinicia. |
MAC_DEV_BRIDGE_PERSONAL_APPROVAL_FILE | $DATA_DIR/PERSONAL_BROWSER_APPROVED | Ruta de concesión heredada/federada de un solo uso para navegador personal. Una concesión chrome-background heredada aquí se importa al grupo compartido por compatibilidad con versiones anteriores. |
MAC_DEV_BRIDGE_BACKGROUND_CHROME_GRANT_DIR | $DATA_DIR/chrome-background-grants | Directorio de concesiones aditivas y caducantes de URL de Chrome en segundo plano, compartidas en todas las sesiones y recargadas tras reinicios del puente. |
MAC_DEV_BRIDGE_SETTINGS_FILE | $DATA_DIR/settings.json | Configuración del operador. strictApprovals tiene como valor predeterminado false cuando el archivo/clave está ausente. La app de la barra de menús lo gestiona. |
MAC_DEV_BRIDGE_FOREGROUND_GUI_APPROVAL_FILE | $DATA_DIR/FOREGROUND_GUI_APPROVED | Aprobación de GUI en primer plano, de un solo uso y limitada a la app en modo estricto. |
MAC_DEV_BRIDGE_CHROME_SOCKET | $DATA_DIR/chrome-background.sock | Socket Unix entre bridge.mjs y el host opcional de mensajería nativa de Chrome. Modo 0600 dentro del directorio de datos en modo 0700. |
MAC_DEV_BRIDGE_CHROME_NATIVE_PID_FILE | $DATA_DIR/chrome-native-host.pid | Registro de PID utilizado por el interruptor de apagado para el host nativo opcional de Chrome. |
MAC_DEV_BRIDGE_FULL_ACCESS_ACK | — | Forma de entorno del reconocimiento. No revocable; ver más abajo. |
Qué significa "acceso completo"
El servidor MCP se ejecuta con los permisos efectivos de la cuenta de macOS que lo inicia. No tiene lista blanca de rutas, lista blanca de comandos de shell, sandbox ni puerta de aprobación interna por comando.
macOS aún aplica los controles de privacidad TCC, Acceso a Disco Completo, ACL, SIP, controles de acceso al Llavero y autenticación sudo. Las llamadas de shell MCP no interactivas no proporcionan mágicamente una contraseña de sudo ni una interfaz de terminal. Configura sudo sin contraseña solo cuando quieras deliberadamente esa escalada separada.
El puente se niega a iniciar hasta que exista un reconocimiento deliberado, y lo vuelve a verificar antes de cada llamada a una herramienta — por lo que eliminar el archivo de reconocimiento tanto previene futuros inicios como detiene un puente en ejecución en su próxima llamada.
La forma de entorno (MAC_DEV_BRIDGE_FULL_ACCESS_ACK) es deliberadamente no revocable de esa manera: un puente que la heredó nunca lee el archivo, por lo que eliminar el archivo no lo detiene. Los pasos de Instalación a continuación exportan esa variable, por lo que un puente iniciado desde tal shell solo se puede detener deteniendo el proceso. La app de la barra de menús la elimina de sus hijos exactamente por esta razón.
Los permisos de acciones de ChatGPT y el comportamiento de confirmación son separados. El servidor MCP anuncia anotaciones de escritura y destructivas con honestidad y no puede eludir las restricciones impuestas por el producto o espacio de trabajo de ChatGPT.
Transportes
El puente habla MCP sobre stdio. Dos transportes pueden llevarlo a ChatGPT.
OpenAI Secure MCP Tunnel (install.sh, documentado abajo) es solo de salida
y no necesita un endpoint público. Requiere el tipo de conexión Tunnel en el
diálogo de complementos de ChatGPT, que no está disponible en cuentas personales — la
opción se muestra pero está deshabilitada.
Cloudflare Tunnel + Server URL (mcp-http.mjs) es el respaldo cuando Tunnel
no está disponible. mcp-http.mjs pone el puente al frente con Streamable HTTP en
127.0.0.1:8787 detrás de OAuth 2.1 (y un bearer estático para otros clientes),
y cloudflared lo publica:
export MAC_DEV_BRIDGE_HTTP_TOKEN="$(openssl rand -hex 32)"
node mcp-http.mjs
El diálogo de complementos de ChatGPT ofrece Autenticación: OAuth, Sin Auth o Mixta — no hay campo de clave API/bearer.
mcp-http.mjspor lo tanto implementa también un servidor de autorización OAuth 2.1, y así es como conectas ChatGPT. Ver Conectando a ChatGPT abajo. El token bearer estático aún funciona para cualquier cliente que pueda enviar un encabezadoAuthorization: Bearer.
El host está fijado a loopback y la ruta a /mcp, deliberadamente — el único
par previsto es cloudflared en la misma máquina.
Entorno:
| Variable | Valor por defecto | Propósito |
|---|---|---|
MAC_DEV_BRIDGE_HTTP_TOKEN | — | Token bearer. Mínimo 24 bytes, ASCII imprimible. Se niega a iniciar sin uno. |
MAC_DEV_BRIDGE_HTTP_TOKEN_FILE | — | Lee el token de un archivo en modo 0600 en su lugar, manteniéndolo fuera de ps eww. Tiene prioridad. |
MAC_DEV_BRIDGE_HTTP_PORT | 8787 | Puerto de loopback. |
MAC_DEV_BRIDGE_HTTP_TIMEOUT_MS | 600000 | Tope por solicitud, para llamadas largas de shell_exec. |
MAC_DEV_BRIDGE_CHATGPT_RESPONSES_BROWSER_MODEL | gpt-5-6-pro | Anulación de compatibilidad para la entrada fija de chatgpt-browser. La entrada Sol siempre usa gpt-5-6-thinking. |
MAC_DEV_BRIDGE_CHATGPT_RESPONSES_MAX_RUNTIME_SECONDS | 600 | Tope de tiempo de ejecución del navegador por turno para /v1/responses, limitado a 30–3600 segundos. |
MAC_DEV_BRIDGE_CHATGPT_RUNTIME_CONFIG_FILE | $DATA_DIR/chatgpt-runtime.json | Configuración JSON en modo 0600 que contiene el projectId opcional de ChatGPT. |
MAC_DEV_BRIDGE_CHATGPT_RESPONSES_PROJECT_ID | — | Anulación directa opcional del Project-id. El archivo de configuración privado es preferido para la configuración local persistente. |
MAC_DEV_BRIDGE_ENTRY | bridge.mjs junto a mcp-http.mjs | Costura solo para pruebas para sustituir un puente simulado. Cambiarlo significa que scripts/disable.sh no reconocerá al hijo. |
MAC_DEV_BRIDGE_PUBLIC_URL | derivado de Host | Fija el emisor OAuth. Fíjalo: Host es controlable por el cliente, y el emisor debe coincidir con lo que el cliente descubrió. |
MAC_DEV_BRIDGE_OAUTH_CLIENT_ID | generado | El id de cliente pegado en ChatGPT. Estable entre reinicios. |
MAC_DEV_BRIDGE_OAUTH_REDIRECT_URIS | — | Callbacks adicionales de coincidencia exacta, separados por comas. Se agrega a los integrados. |
MAC_DEV_BRIDGE_OAUTH_CLIENT_SECRET | — | Segundo factor opcional en /token, aplicado mediante client_secret_post o client_secret_basic. Pon el mismo valor en el campo OAuth Client Secret de ChatGPT. Eliminado de los entornos hijos. |
MAC_DEV_BRIDGE_BODY_IDLE_TIMEOUT_MS | 30000 | Descarta una solicitud cuyo cuerpo se detiene este tiempo. Inactivo, no total, por lo que una subida lenta pero progresiva no se trunca. |
MAC_DEV_BRIDGE_MAX_BUFFERED_BYTES | 100663296 (96 MiB) | Presupuesto global para cuerpos de solicitud almacenados en búfer. Excederlo descarga la carga con un 503 reintentable. |
Entiende la diferencia en exposición antes de elegir este. El transporte Tunnel hace solo conexiones salientes. Este publica un endpoint HTTPS que pone al frente acceso de shell sin restricciones, con un solo token bearer como toda la barrera. Rota el token si alguna vez se divulga, y considera Cloudflare Access al frente para un segundo factor.
Aún no automatizado para este transporte: install.sh requiere tunnel-client y
rechaza un id de tunnel_... faltante, por lo que no puede instalar la ruta HTTP, y
no hay LaunchAgent — nada reinicia mcp-http.mjs o cloudflared después de un
reinicio o un bloqueo. scripts/doctor.sh sí cubre este transporte.
uninstall.sh elimina los archivos pero no detiene un front end en ejecución.
Conectando a ChatGPT
El diálogo de complementos de ChatGPT ofrece tres opciones de Autenticación — OAuth, Sin
Auth, Mixta — y no hay campo de clave API/bearer, por lo que el token bearer estático no
tiene dónde ingresarse. mcp-http.mjs por lo tanto implementa un servidor de autorización OAuth 2.1, y así es como ChatGPT se conecta.
Completa el diálogo de la siguiente manera:
| Campo | Valor |
|---|---|
| Conexión | Server URL |
| Server URL | https://<hostname>/mcp |
| Autenticación | OAuth |
| Método de registro | User-Defined OAuth Client |
| OAuth Client ID | registrado al inicio, o establece MAC_DEV_BRIDGE_OAUTH_CLIENT_ID |
| OAuth Client Secret | dejar en blanco |
| Método de autenticación del endpoint de token | none |
| Scopes predeterminados | mcp |
| OIDC habilitado | desmarcar |
La opción Copy ChatGPT Setup de la app de la barra de menús produce esta lista prellenada.
Desmarca OIDC porque /.well-known/openid-configuration se sirve solo como un alias
de los metadatos OAuth y omite deliberadamente cada campo de firma y sujeto. No se emite
ningún token de ID, por lo que un cliente estricto de OIDC debería abortar en lugar de exigir uno.
ChatGPT luego abre una página de consentimiento servida por tu propia máquina. Nombra el callback
exacto al que redirigirá y pide el token del puente, que es cómo sabe
que la aprobación vino de ti. Lee la línea "Will redirect to" antes de aprobar —
cualquier ruta de /connector/oauth/<token> es un conector válido de ChatGPT, incluido uno
que alguien más creó.
Usa un túnel Cloudflare con nombre. El hostname de un túnel rápido cambia en cada inicio, y ese hostname es el emisor OAuth — por lo que un reinicio entre el descubrimiento y el callback hace que el emisor deje de coincidir con lo que ChatGPT registró, y un cliente estricto descarta el callback silenciosamente. Un túnel con nombre también significa crear el conector una vez en lugar de cada ejecución.
Endpoints servidos: /.well-known/oauth-protected-resource,
/.well-known/oauth-authorization-server, /.well-known/openid-configuration
más /.well-known/oauth-protected-resource/mcp,
/.well-known/oauth-authorization-server/mcp, /.well-known/openid-configuration/mcp
y /mcp/.well-known/openid-configuration — siete rutas en total, ya que la
forma con prefijo /mcp/ existe solo para openid-configuration. Luego /authorize,
/token, /revoke, /revoke-all y /healthz. Un 401
de /mcp lleva WWW-Authenticate: Bearer resource_metadata="…", que es lo que
permite a un cliente descubrir el resto.
App de la barra de menús (transporte HTTP)
menubar/ construye una pequeña app de barra de estado AppKit que posee los dos procesos que este
transporte necesita y muestra las tres cosas que realmente usas: la URL pública,
el token bearer y si el endpoint está respondiendo.
./menubar/build.sh # also installs a copy to /Applications
open /Applications/MacDevBridge.app
La compilación instala en /Applications (con respaldo a ~/Applications) porque
Launchpad y Spotlight no muestran apps que viven en ~/Downloads. El bundle
localiza mcp-http.mjs mediante MAC_DEV_BRIDGE_HOME, luego un paquete junto a sí mismo,
luego una ruta horneada en Info.plist en tiempo de compilación — por lo que la copia instalada aún
encuentra el paquete.
El menú te da: estado actual, el modo de túnel, Copy Server URL, Copy
OAuth Client ID, Copy ChatGPT Setup (todo el diálogo completado, en orden),
Copy Bearer Token, Iniciar/Detener, una casilla en vivo de Aprobaciones estrictas (desactivada por defecto), Rotar Token, Abrir Registros y Salir.
Prefiere un túnel nombrado de Cloudflare cuando ~/.cloudflared/config.yml declara
uno, lo que proporciona una URL estable; de lo contrario, un túnel rápido, cuyo
nombre de host cambia en cada inicio y obliga a recrear el conector de ChatGPT
cada vez. El menú muestra qué modo está activo.
Por qué vale la pena usarlo en lugar de los comandos sin procesar:
- Es el supervisor. Iniciar genera
mcp-http.mjsycloudflared; Detener y Salir detienen exactamente lo que inició, en lugar de descubrir procesos por nombre. - Iniciar escribe el archivo de desbloqueo y Detener lo elimina, por lo que detener
falla de forma segura a través del bloqueo por llamada de
bridge.mjs, no solo mediante una eliminación de proceso. - El token vive en un archivo con modo 0600 y se pasa mediante
MAC_DEV_BRIDGE_HTTP_TOKEN_FILE, manteniéndolo fuera deps eww. - El estado se consulta desde
/healthzy desde la actividad de los procesos secundarios, por lo que la muerte de un hijo se informa en lugar de asumirse. - Al iniciar, reclama huérfanos — ambos hijos.
applicationWillTerminateno se ejecuta en una salida forzada, un bloqueo o un reinicio duro, por lo que una ejecución anterior podría dejar el archivo de desbloqueo armado, el front end sirviendo ycloudflaredaún publicando un nombre de host público. Al iniciar, se desarma el bloqueo y se detiene lo que esté registrado enmcp-http.pidycloudflared.pid, cada uno verificado por identidad primero porque los pids se reciclan y esos archivos sobreviven aSIGKILLy al reinicio. Reclamar solo el front end anteriormente dejaba una entrada pública que ninguna ejecución posterior podía cerrar, y que el siguiente Inicio volvería a armar junto con un segundo túnel. - Nunca pasa
MAC_DEV_BRIDGE_FULL_ACCESS_ACKa sus hijos. Esa variable es un desbloqueo permanente enbridge.mjs, por lo que heredarla haría que Detener no pudiera revocar nada — y los documentos de instalación le indican exportarla. - La muerte de un hijo detiene al otro. Informar una falla mientras se deja vivo al
hermano dejaba a
cloudflaredpublicando con el bloqueo aún armado y el menú mostrando "no en ejecución". - Los hijos heredan el shell de inicio de sesión
PATH, por lo queshell_execse comporta igual que en una terminal (una aplicación iniciada por GUI de otro modo no tiene nvm ni Homebrew).
La aplicación está firmada ad-hoc y no está notarizada. Localiza mcp-http.mjs a
través de MAC_DEV_BRIDGE_HOME, luego un paquete junto al bundle, luego una ruta
incorporada en Info.plist en tiempo de compilación — por lo que la copia de
/Applications funciona con el paquete dejado donde está. Reconstruya después de
mover el paquete para que la ruta incorporada siga siendo correcta.
MAC_DEV_BRIDGE_HOME.
No reemplaza a scripts/disable.sh: los trabajos shell_start separados sobreviven
al front end por diseño, y solo ese script los reclama del registro de trabajos.
Requisitos previos
Ambos transportes:
- macOS y un usuario de escritorio con sesión iniciada.
- Node.js 18 o más reciente.
- Modo desarrollador de ChatGPT.
- Una CLI de
codexfuncional solo para las tres herramientas de historial de Codex. El acceso a shell y sistema de archivos no depende de Codex.
El túnel seguro de MCP de OpenAI además requiere:
- El binario oficial de
tunnel-client, descargado de OpenAI Platform Tunnels o de la versión oficial de OpenAI en GitHub, ejecutable y disponible enPATHo en~/.local/bin/tunnel-client. - Un ID de túnel de OpenAI limitado al espacio de trabajo de ChatGPT que lo usará.
- Una clave de API en tiempo de ejecución cuyo principal tenga permisos de Lectura + Uso de Túneles.
- La opción de conexión Tunnel en el diálogo del plugin de ChatGPT.
Cloudflare Tunnel + URL del servidor además requiere:
cloudflared, autenticado en una cuenta de Cloudflare.- Un nombre de host que controle, o una URL de túnel rápido.
opensslpara generar el token de portador.- La opción de conexión Server URL con OAuth — consulte Conectarse a ChatGPT. No hay modo sin autenticación:
/mcpestá codificado sin anulación, ymcp-http.mjsse niega a iniciar sin un token.
La disponibilidad del modo desarrollador está controlada por el despliegue de la cuenta y la política del espacio de trabajo. Si el interruptor de modo desarrollador está ausente, este paquete no puede anular esa limitación del lado del producto. La opción Tunnel específicamente no está disponible en cuentas personales — se muestra pero está deshabilitada — por lo que existe el transporte HTTP.
Instalar
Clone el repositorio (o descargue una versión/archivo) y abra Terminal en su carpeta:
git clone https://github.com/alexanderradahl/mac-developer-bridge.git
cd mac-developer-bridge
Luego 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
El instalador también puede solicitar el ID del túnel y la clave en tiempo de ejecución cuando se ejecuta de forma interactiva. La clave en tiempo de ejecución se almacena en el llavero de inicio de sesión de macOS y no se escribe en el paquete, el perfil del túnel ni el plist del agente de lanzamiento.
El instalador:
- Requiere el reconocimiento exacto de acceso completo.
- Valida macOS, Node, túnel-cliente, descubrimiento de Codex, formato del ID del túnel, modo de auditoría y shell.
- Copia el puente a
~/.local/share/mac-developer-bridge. - Crea
~/Library/Application Support/MacDeveloperBridge/FULL_ACCESS_ENABLEDcon modo 0600. - Ejecuta pruebas de sintaxis, protocolo MCP, sistema de archivos, parche, proceso, limpieza de secretos y adaptador de Codex.
- Almacena la clave en tiempo de ejecución en el llavero.
- Crea un perfil stdio único de
tunnel-clienty ejecutatunnel-client doctor. - Instala e inicia un agente de lanzamiento persistente por usuario.
Se admiten ubicaciones personalizadas con las variables de entorno MAC_DEV_BRIDGE_INSTALL_DIR, MAC_DEV_BRIDGE_BIN_DIR, MAC_DEV_BRIDGE_PLIST_DIR, MAC_DEV_BRIDGE_DATA_DIR y MAC_DEV_BRIDGE_LOG_DIR.
Conectar ChatGPT
- Habilite el modo desarrollador en ChatGPT.
- Abra los plugins de ChatGPT y cree una aplicación en modo desarrollador.
- Configure la conexión, según el transporte:
- Transporte de túnel: elija Tunnel, luego seleccione o pegue el mismo ID de túnel usado durante la instalación. No disponible en cuentas personales — la opción se muestra pero está deshabilitada.
- Transporte HTTP: elija Server URL e ingrese
https://<hostname>/mcp. La autenticación ofrece solo OAuth, sin autenticación o mixta — consulte Conectarse a ChatGPT; el token de portador no tiene campo en este diálogo.
- Revise y habilite las herramientas, y marque el reconocimiento de riesgo.
- Inicie una nueva conversación de Chat, seleccione la aplicación y llame a
bridge_status.
Primer mensaje 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 y codex_thread_turns_list usan APIs de lectura locales de codex app-server. El puente no expone ningún método de Codex que inicie un turno de modelo.
Acceso completo al disco
Verifique el estado actual antes de adivinar:
scripts/tcc-doctor.sh # add --open to jump to the settings pane
Sondea una ruta protegida por TCC como node y como $MAC_DEV_BRIDGE_SHELL — solo esas dos — e informa cuáles tienen el permiso. El acceso completo al disco no se puede otorgar desde un script — las bases de datos de TCC están protegidas por SIP, por lo que no se pueden escribir ni como root, y tccutil solo puede restablecer entradas. Un humano debe agregar el binario en Configuración del sistema, o un MDM debe enviar un perfil de PPPC.
Si las lecturas fallan con EPERM o "Operación no permitida", otorgue acceso completo al disco a los ejecutables reales en la cadena de ejecución:
- el binario exacto de
nodemostrado porbridge_status /bin/zsh- el binario instalado de
tunnel-client, solo para el transporte de túnel
cloudflared no lo necesita: solo reenvía HTTP a loopback y nunca toca el sistema de archivos en nombre de una herramienta.
Un agente de lanzamiento puede no heredar los permisos de privacidad otorgados previamente a Terminal o a una instalación diferente de Node. El acceso completo al disco es independiente de los permisos POSIX ordinarios.
Operaciones
Las rutas de ~/.local/share/mac-developer-bridge a continuación existen solo si install.sh se ejecutó, lo que requiere tunnel-client — por lo que en el transporte HTTP ese directorio no existe y ejecuta los scripts desde el directorio del paquete extraído en su lugar.
Ambos 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 de túnel:
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 actualmente requiere el plist del agente de lanzamiento, por lo que no funciona en el transporte HTTP. Para volver a habilitarlo allí, recree el archivo de desbloqueo y reinicie el front end como en la Opción B de DEPLOY.md.
tunnel-client normalmente expone endpoints de salud de loopback y una interfaz de operador en http://127.0.0.1:8080/healthz, /readyz, /metrics y /ui mientras se ejecuta.
Auditoría
El modo predeterminado es metadata. Registra:
- marca de tiempo y nombre de la herramienta
- una vista previa redactada de los argumentos
- hash SHA-256 de los argumentos completos
- un resumen compacto del resultado o error
En el transporte HTTP no hay instalación, y una aplicación de barra de menú iniciada por GUI no tiene entorno de shell para heredar — por lo que las únicas formas de cambiar el modo de auditoría allí son exportarlo en un shell e iniciar mcp-http.mjs desde ese shell, o lanzar la aplicación con open -a MacDevBridge --env MAC_DEV_BRIDGE_AUDIT_MODE=full. De lo contrario, permanece en metadata.
Establezca MAC_DEV_BRIDGE_AUDIT_MODE antes de la instalación a uno de:
MAC_DEV_BRIDGE_AUDIT_MODE=off
MAC_DEV_BRIDGE_AUDIT_MODE=metadata
MAC_DEV_BRIDGE_AUDIT_MODE=full
full puede persistir argumentos de comandos sensibles y contenido de archivos incluso después de la redacción común de patrones de tokens. Trate el registro de auditoría como sensible. La clave en tiempo de ejecución del túnel se elimina del entorno del proceso del puente antes de que cualquier herramienta de shell o sistema de archivos pueda ejecutarse, aunque el acceso de shell sin restricciones aún puede alcanzar otras credenciales disponibles para la cuenta de macOS.
Verificar el enrutamiento de uso
El puente en sí no contiene ningún cliente de inferencia de OpenAI y los adaptadores de Codex llaman a métodos de solo lectura del servidor de la aplicación. Aun así, verifique el comportamiento específico de la cuenta después de la conexión:
- Registre el saldo actual de créditos de Codex/Trabajo.
- En Chat, llame solo a
bridge_statusyfs_staten una ruta inofensiva. - Actualice la página de uso de Codex/Trabajo.
- Confirme que no se registró ningún uso de modelo de Codex.
- Luego lea el hilo de Codex almacenado y continúe el trabajo aquí.
No use shell_exec para ejecutar Codex en sí si el propósito es evitar el uso del modelo de Codex.
Desinstalar
Desde el paquete extraído o el directorio instalado:
./uninstall.sh
El desinstalador elimina el agente de lanzamiento, la instalación del puente, el enlace simbólico de comandos, el archivo de desbloqueo y la clave en tiempo de ejecución del llavero.
No elimina el directorio de datos, por lo que estos sobreviven a una desinstalación — incluidas dos credenciales activas:
http-token— el token de portador (modo 0600)oauth-state.json— el ID de cliente de OAuth más los resúmenes de token de acceso/actualización (modo 0600)oauth-client-id,mcp-http.pid,cloudflared.pid,jobs/y el registro de auditoría
Elimine también ~/Library/Application Support/MacDeveloperBridge si desea que las credenciales desaparezcan. Tampoco detiene un front end en ejecución; ejecute scripts/disable.sh primero.