Tu agente no sale del repo: interoperabilidad de agentes de IA
Escribí un subagente de revisión de código para Claude Code. Lee el diff, comprueba el contrato del módulo y marca lo que rompe.
Un equipo con el que trabajo quiso ese mismo criterio en su pipeline, que no corre sobre Claude Code. Abrí el fichero para copiarlo y la ilusión me duró treinta segundos.
Lo único portable era el criterio, y el criterio son cuatro párrafos de texto. El resto —cómo pide las herramientas, dónde guarda lo revisado, quién arranca el bucle, cómo reporta— estaba pegado al harness.
Ese es el estado real de la interoperabilidad de agentes de IA hoy: no existe. Tenemos agentes que funcionan muy bien exactamente donde nacieron y en ningún otro sitio.
La interoperabilidad de agentes de IA es la capacidad de ejecutar el mismo agente —su criterio, sus herramientas, su memoria y su bucle— en un harness distinto de aquel donde se escribió, sin reescribirlo. No consiste en que hable con otros agentes: consiste en que se mude.
El software se volvió reutilizable. Los agentes, no
El software se convirtió en una industria enorme por una razón aburrida: se escribe una vez y se usa muchas.
Una librería la escribe un dev y la usan miles. Una API expone una capacidad y acaba dentro de productos que su autor nunca vio. Las app stores añadieron distribución global a eso. Cada pieza de software podía ser el bloque de construcción de otra cosa.
Un agente debería llevar esa idea más lejos, no menos. No expone una función: expone un criterio. Entiende un objetivo, decide, usa herramientas, se comunica y ejecuta trabajo. Un buen agente de revisión, de extracción de facturas o de migración de tests debería ser un trabajador digital que enchufas donde haga falta su capacidad.
Y sin embargo. El agente de extracción de facturas que montó tu compañero con LangChain no puede entrar en el CLI del equipo de al lado. El agente de tests que va fino en tu runtime se rompe entero en otro. No porque el criterio sea malo: porque el criterio nunca aprendió a viajar solo.
Eso tiene tres consecuencias que ya estamos pagando.
La primera es que cada equipo reconstruye lo mismo. Miles de empresas escribiendo su propio agente de research, su propio agente de soporte, su propio agente de procesamiento de documentos. El mismo trabajo de ingeniería repetido porque ninguno de esos agentes se mueve de su proyecto.
La segunda es que impide la especialización. Nadie puede dedicar dos años a construir el mejor agente de auditoría de accesibilidad del mundo y distribuirlo por muchos sistemas. Cada agente se trata como un detalle de implementación interno, no como un producto.
Y la tercera: sin portabilidad no hay mercado. No puede existir un marketplace real si un agente solo funciona dentro del harness donde nació, ni efecto red si añadirlo beneficia a una sola aplicación.
El acoplamiento no está donde crees
Cuando alguien dice "muevo mi agente a otro entorno" suele pensar en copiar el prompt. El prompt es lo barato. Lo caro es todo lo que el harness le daba gratis.
| Capa | Qué cambia al mover el agente |
|---|---|
| Tool calling | El esquema de las tools, sus nombres, cómo se serializan los resultados |
| Contexto y memoria | Qué entra en la ventana, qué se resume, dónde persiste entre turnos |
| Bucle de ejecución | Quién decide cuándo parar, cuántos pasos caben, quién reintenta |
| Transporte | stdio, HTTP con streaming, cola de mensajes |
| Permisos | Quién aprueba una escritura y con qué granularidad |
| Reporte de progreso | Logs sueltos, eventos tipados, estados de tarea |
Copiar el prompt y creer que has movido el agente es como copiar un componente de React sin llevarte el router, los tipos ni el ciclo de vida. Tienes el texto. No tienes el comportamiento.
Por eso insisto tanto en que el harness es la pieza que de verdad define a un agente. El modelo es intercambiable. El harness, hoy, no.
Qué resuelven MCP y A2A de la interoperabilidad de agentes de IA (y qué no)
MCP y A2A resuelven dos capas del problema: las herramientas y la comunicación entre agentes. Ninguno de los dos toca el runtime, el contexto ni el bucle, que es donde vive el acoplamiento real. Son dos intentos serios de estandarizar esto y conviene ser honesto con el alcance de cada uno.
MCP estandariza la capa de herramientas y el contexto que se sirve. En su revisión 2026-07-28, un servidor expone tres primitivas —tools, resources y prompts— sobre JSON-RPC 2.0, y cualquier cliente las descubre e invoca igual. Eso arregla la primera fila de la tabla y parte del transporte, y no es poco: el mismo servidor vale para clientes distintos. Si nunca has montado uno, empieza por qué es MCP exactamente.
Lo que MCP no define es el comportamiento del agente: qué entra en su ventana de contexto, quién arranca su bucle o cuándo decide parar. Los permisos ni siquiera intenta cubrirlos —la propia spec reconoce que "MCP itself cannot enforce these security principles at the protocol level" y los delega en el host. La revisión actual se acerca por los bordes, eso sí: la extensión Tasks cubre operaciones largas con polling y handles duraderos, y el grupo de trabajo Skills over MCP quiere distribuir instrucciones de agente como recurso. Ninguna de las dos, todavía, te deja mover un agente de harness.
A2A estandariza el intercambio entre agentes. La versión 1.0.0 define la Agent Card para descubrir capacidades, las Tasks con su ciclo de vida de ocho estados (submitted, working, input-required, auth-required, completed, failed, canceled, rejected), los Messages y los Artifacts. Eso arregla la fila del reporte y buena parte de la comunicación.
Y el límite lo pone la especificación misma, por escrito: los agentes colaboran "without needing to share their internal thoughts, plans, or tool implementations". Ahí está la frontera, literal. A2A te deja hablar con un agente remoto; no te deja traerte ese agente a casa.
Puestos capa por capa contra la tabla de antes, el reparto queda así:
| Capa de acoplamiento | MCP 2026-07-28 |
A2A 1.0.0 |
Quién la resuelve hoy |
|---|---|---|---|
| Tool calling | Sí | — | MCP |
| Transporte | Parcial (JSON-RPC 2.0) | Parcial | MCP / A2A |
| Reporte de progreso | Parcial | Sí (ciclo de vida de Task) | A2A |
| Contexto y memoria | Parcial (resources) | No | Casi nadie — tu harness |
| Bucle de ejecución | No | No | Nadie — tu harness |
| Permisos | No (delega en el host) | No | Nadie — tu harness |
Los dos juntos te dan el cableado. Ninguno te da el agente portable. Si quieres la comparativa fila a fila de A2A y MCP, la tienes desarrollada en su propio post.
Mi tesis es incómoda pero creo que es la correcta: el agente reutilizable de verdad todavía no existe, y la frontera no la marca el protocolo sino el harness. Lo que sí podemos hacer hoy es diseñar como si esa capa ya estuviera, para no tener que rehacerlo cuando llegue.
Los tres pilares de la interoperabilidad de agentes de IA
Un agente portable necesita tres propiedades arquitectónicas: concurrencia (se activa por eventos, no por su posición en una cadena), awareness o conciencia del entorno (lo consulta en vez de suponerlo) y adaptividad (decide con estado de runtime, no con un orden hardcodeado).
Compartir un agente es más que mover su código. Un agente que aterriza en un entorno nuevo tiene que poder trabajar sin esperar a una secuencia predefinida, entender qué hay a su alrededor y ajustar su comportamiento a lo que encuentra.
1. Concurrencia: fuera los pipelines secuenciales
Casi todos los sistemas multiagente que reviso son esto:
// Acoplado: el paso 3 no existe hasta que termina el 2.
const spec = await specAgent.run(input);
const code = await codeAgent.run(spec);
const review = await reviewAgent.run(code);
Esto no es un sistema de agentes. Es una función con tres llamadas caras. Que use await no lo salva: el orden está hardcodeado en el código que las invoca, así que el agente de revisión no puede existir fuera de ese fichero. Es el mismo error de fondo que hace fallar al mega-prompt cuando el sistema crece.
La alternativa es que cada agente sea una unidad independiente que decide si un evento le incumbe:
interface Agent {
readonly id: string;
readonly capabilities: readonly string[];
// ¿Este evento va conmigo?
accepts(event: AgentEvent): boolean;
handle(event: AgentEvent, ctx: RuntimeContext): Promise<AgentEvent[]>;
}
Ningún agente bloquea a otro. Ninguno conoce su posición en una cadena. Cuando esto está bien hecho, a menudo descubres que no necesitas orquestador.
2. Awareness: el entorno se consulta, no se supone
Un agente acoplado solo conoce su prompt. Lo que hay alrededor está implícito en el orden de las llamadas.
Un agente portable pregunta. Necesita dos cosas: un canal de eventos compartido y un registro de participantes.
type Unsubscribe = () => void;
type AgentEventType =
| 39;spec.ready39;
| 39;code.changed39;
| 39;review.blocked39;
| 39;test.requested39;;
interface AgentEvent {
readonly type: AgentEventType;
readonly source: string; // id del agente que lo emitió
readonly payload: unknown;
readonly at: number;
}
interface AgentDescriptor {
readonly id: string;
readonly capabilities: readonly string[];
}
interface Workspace {
// Quién más está trabajando aquí y qué sabe hacer.
participants(): readonly AgentDescriptor[];
publish(event: AgentEvent): void;
subscribe(handler: (event: AgentEvent) => void): Unsubscribe;
}
interface RuntimeContext {
// Todo lo que el agente necesita del entorno donde aterriza.
readonly workspace: Workspace;
}
La diferencia práctica: con esto, el mismo agente de revisión funciona en un entorno donde hay tres compañeros y en otro donde está solo, porque en el primer caso lo sabe. Monté el patrón completo en event bus para agentes descentralizados.
3. Adaptividad: la decisión sale del estado, no del orden
El tercer pilar es el que casi nadie implementa, y es el que separa un agente de un script con LLM dentro.
async function handle(
event: AgentEvent,
ctx: RuntimeContext,
): Promise<AgentEvent[]> {
const emit = (type: AgentEventType, payload: unknown): AgentEvent => ({
type,
source: 39;reviewer39;,
payload,
at: Date.now(),
});
const findings = await runReview(event.payload, ctx);
if (findings.length === 0) return [];
// Si hay alguien capaz de ejecutar tests, delego. Si no, bloqueo.
const peers = ctx.workspace.participants();
const hasTester = peers.some((p) => p.capabilities.includes(39;test.run39;));
return hasTester
? [emit(39;test.requested39;, { findings })]
: [emit(39;review.blocked39;, { findings })];
}
Fíjate en lo que no hay: ningún if (step === 'review'). La rama se decide con estado de runtime, no con una posición hardcodeada. Ese agente se comporta distinto en dos entornos distintos sin que nadie toque su código.
Las tres juntas son las caras del mismo triángulo: independencia, conexión, colaboración. Si te falta una, el agente no viaja.
Esta forma de pensar el sistema —el agente como unidad con contrato propio, no como paso de un flujo— es la que trabajo en el curso Construye con IA: de la idea al producto con Claude Code.
Lo que se desbloquea cuando los agentes viajan
Construyes un agente una vez y lo distribuyes en todas partes. Combinas especialistas en lugar de reconstruirlos. Y puedes monetizar una capacidad sin vender la aplicación entera alrededor.
El cambio de fondo es de economía, no de ingeniería. En un ecosistema interoperable, cada agente nuevo aumenta el valor de todos los demás. Hoy cada agente nuevo aumenta el valor de exactamente un repositorio.
Cómo diseñar hoy un agente portable en tu proyecto
No hace falta esperar a que se asiente ningún estándar. Cinco decisiones que puedes tomar esta semana:
- Separa el agente de su runtime. El agente es un objeto con capacidades declaradas y un
handle. Quién lo arranca y cada cuánto es responsabilidad de otro fichero. - Expón sus herramientas vía MCP, aunque hoy solo lo use tu propio harness. Es la capa que ya está estandarizada; aprovéchala.
- Saca el contexto del prompt. Ficheros, un store, lo que sea. Si la memoria del agente vive en la cadena de mensajes de tu framework, tu agente es tu framework.
- No hardcodees la secuencia. Sustituye
await a(); await b();por eventos tipados. Si te cuesta imaginarlo, empieza por construir un agente de IA desde cero y verás dónde está cada costura. - Escribe el contrato antes que el código. Qué acepta, qué emite, qué permisos pide, qué garantiza. Es revisión por contrato aplicada al diseño, y el mismo principio que desarrollo en Spec-Driven Development: la especificación es la parte portable; la implementación es desechable.
Si el punto 5 te suena a burocracia, empieza por el ebook gratuito Revisión por Contrato. Va justo de eso: definir por escrito qué puede y qué no puede hacer un agente antes de dejarlo suelto en tu repo.
En Dominicode Labs están las masterclasses y los repos donde desmonto este tipo de decisiones de arquitectura con el código delante y sin diapositivas.
Elige hoy uno de tus agentes y responde a una sola pregunta: si mañana cambias de harness, ¿qué sobrevive? Si la respuesta es "el prompt", ya sabes por dónde empezar.
Preguntas frecuentes
¿MCP no resuelve ya la interoperabilidad de agentes de IA?
Resuelve una parte importante, no el conjunto. MCP estandariza cómo un agente descubre e invoca herramientas y cómo un servidor le sirve contexto como recurso, así que el mismo servidor vale para clientes distintos y eso elimina una de las seis capas de acoplamiento. Hay trabajo en curso para llevarlo más lejos —la extensión Tasks y el grupo de Skills over MCP—, pero a día de hoy nada de eso está cerrado. Pero un agente no es solo el conjunto de herramientas que puede llamar: es también su bucle, su gestión de contexto, su política de permisos y su forma de reportar. Nada de eso está cubierto. Puedes tener dos agentes que hablan MCP perfectamente y seguir sin poder mover ninguno de los dos al entorno del otro.
Entonces, ¿A2A sobra?
Al contrario: resuelve un problema distinto y complementario. A2A estandariza el intercambio entre agentes —descubrimiento de capacidades, envío de tareas, mensajes y progreso— y con eso puedes hacer que tu sistema hable con un agente que corre en otra empresa. Lo que no te da es portabilidad: sigues invocando un agente remoto que vive en su propio runtime. MCP y A2A son cableado en dos capas diferentes. El agente portable es otra discusión.
¿Concurrencia no es simplemente lanzar todo con Promise.all?
No. Promise.all lanza varias llamadas a la vez, pero el punto donde se lanzan y el punto donde se espera siguen escritos en tu código: tú decides qué va junto y dónde se bloquea. Lo que pido aquí es otra cosa, desacoplamiento temporal: cada agente se activa por su cuenta cuando aparece un evento que le incumbe, sin que nadie coordine el orden desde fuera. La prueba está en si puedes añadir un agente nuevo al sistema sin tocar el fichero que orquesta. Si tienes que tocarlo, tienes llamadas concurrentes, no agentes autónomos.
¿No es sobreingeniería para un agente que solo uso yo?
Depende de cuánto te haya costado ese agente. Si es un script de veinte líneas, sí, es sobreingeniería. Si le has dedicado semanas a afinar su criterio —y en revisión de código o extracción de datos eso pasa rápido— entonces lo que estás haciendo al acoplarlo es tirar ese trabajo cada vez que cambies de herramienta. Y cambiamos de herramienta cada pocos meses. En mi experiencia, separar el agente de su runtime cuesta una tarde; reescribirlo entero, varias semanas.
Mi agente ya está acoplado al harness. ¿Por dónde empiezo?
Por el contexto, que suele ser lo más doloroso y lo que antes se rompe. Saca de la cadena de mensajes del framework todo lo que sea conocimiento del agente y llévalo a ficheros o a un store propio. Después extrae la lógica de decisión a una función pura que recibe estado y devuelve eventos. Cuando tengas esas dos piezas, el runtime original pasa a ser un adaptador fino de treinta líneas, y escribir un segundo adaptador para otro entorno deja de dar miedo.
Por Bezael Pérez — Developer senior con más de 15 años de experiencia y fundador de Dominicode.
¿Te resultó útil este artículo?
Compártelo con tu comunidad y ayuda a otros desarrolladores.
