8 min de lectura

Solicitudes MCP anidadas: rastrea cada acción externa de forma segura

Las solicitudes MCP anidadas necesitan algo más que registros de herramientas. Aprende a rastrear llamadas padre, reintentos, aprobaciones y las acciones externas que realmente activan los agentes.

Solicitudes MCP anidadas: rastrea cada acción externa de forma segura

Un agente puede llamar a una herramienta que llama a otra herramienta, que pide a un asistente resolver un entorno y que finalmente envía una solicitud HTTP o ejecuta un comando SSH. Si tus registros se detienen en el primer nombre de la herramienta, solo tienes una historia sobre la intención. No tienes un registro de lo que ocurrió fuera del proceso.

Las solicitudes MCP anidadas necesitan una trazabilidad que siga la cadena causal hasta cada acción externa que use credenciales. Eso implica registrar más que la transcripción del agente y más que un registro de solicitudes convencional. Necesitas un grafo capaz de responder: ¿qué ejecución provocó esta llamada saliente?, ¿a qué se resolvió la llamada?, ¿quién la aprobó? y ¿llegó a ejecutarse?

He visto equipos tratar una traza ordenada de herramientas como una prueba de que sus controles funcionan. Después ocurre un incidente y alguien pregunta qué llamada modificó un recurso de producción, pero la traza solo dice release_service. Los nombres amigables sirven a los operadores. Las pruebas de auditoría necesitan la operación concreta.

La acción externa es el registro que cuenta

La última llamada de una cadena anidada suele llevar consigo la consecuencia, por lo que necesita su propio registro duradero aunque todas las llamadas anteriores ya tengan un span. Una herramienta que comprueba el nombre de una rama puede ser inofensiva. Un asistente posterior que usa ese resultado para invocar un endpoint de despliegue es otro evento.

Separa tres cosas que los equipos suelen mezclar:

  • Una invocación de herramienta es una solicitud para ejecutar una capacidad con nombre y argumentos.
  • Un span de traza describe una unidad de trabajo y su lugar en un grafo causal.
  • Una acción externa es una operación concreta que cruza un límite de confianza, como una solicitud HTTP con credenciales inyectadas o un comando SSH en un host remoto.

Confundirlas produce dos fallos opuestos. Algunos equipos crean un registro de auditoría para cada llamada de función interna. Su diario se llena de ruido y nadie puede identificar las pocas llamadas que cambiaron algo. Otros equipos registran solo una línea final de éxito. Pierden la cadena que explica qué decisión del agente, consulta y aprobación provocaron esa llamada.

Asigna a cada acción externa un action_id estable. Conéctala con el span que la inició, pero no uses el ID del span como identidad. Un span puede abarcar la preparación local, un intento HTTP, una redirección y el análisis de la respuesta. Son detalles útiles. El registro de la acción debe seguir siendo comprensible aunque alguien cambie la implementación.

El registro de una acción debe describir el destino después de resolverlo. No basta con registrar environment=production o target=customer-api. Guarda el host, el puerto y el protocolo resueltos, el método de la solicitud o el comando SSH, y la referencia de la credencial seleccionada por el ejecutor. Guarda referencias a secretos, nunca sus valores.

La distinción también cambia la forma de evaluar el éxito. Una herramienta envoltorio puede devolver ok porque puso un trabajo en cola. Una capa inferior puede fallar antes de abrir una conexión. Registra por separado el resultado del span envoltorio y el de la acción externa. Esos hechos pueden discrepar sin que ninguno de los dos registros sea incorrecto.

MCP no proporciona todo tu grafo de llamadas

MCP ofrece a clientes y servidores un protocolo para descubrir y llamar a herramientas. No obliga a ninguna implementación a exponer un grafo de llamadas internas. Un host puede coordinar varios servidores. Un servidor puede llamar a asistentes locales. Una herramienta puede activar un trabajo que continúa después de la respuesta. Tu diseño de auditoría debe contemplar explícitamente esas formas.

La especificación de Model Context Protocol describe tools/call como una solicitud del cliente al servidor para una herramienta y unos argumentos concretos. Es un contrato de interfaz, no un contrato de trazabilidad. El protocolo no convierte una llamada de función local en un evento hijo observable ni define un campo de padre universal que todo intermediario deba conservar.

Esto importa cuando un equipo dice que una herramienta «llamó a otra herramienta MCP». A veces significa una segunda llamada real al protocolo. Otras veces significa que un servidor invocó una función de biblioteca con un nombre parecido. También puede significar que un host de agentes recibió un resultado, razonó sobre él e hizo una llamada nueva. El grafo resultante puede parecerse, pero sus límites de confianza son distintos.

Trata estos casos como tipos de arista diferentes en tus registros:

  • protocol_call conecta una solicitud de un cliente MCP con la invocación de una herramienta del servidor.
  • local_call conecta código dentro de un mismo proceso de confianza.
  • delegated_job conecta una solicitud con un trabajo que otro trabajador realizará más tarde.
  • external_action conecta un span con una operación HTTP o SSH.

No deduzcas el tipo de arista a partir del nombre de la herramienta. Regístralo en el punto en que se produce la transferencia. Ahí sabes si la identidad, las credenciales y las reglas de cancelación pasaron a otro proceso.

Un trabajo diferido requiere atención especial. Si una herramienta pone una tarea en cola y devuelve la respuesta, conserva el ID de traza original y el ID de ejecución raíz junto con la carga del trabajo. Cuando el trabajador se ejecute más tarde, crea un span nuevo para esa ejecución y conéctalo con el plan de acción original. No finjas que el trabajador permaneció dentro de la solicitud original. Su tiempo de ejecución, identidad y estado de autorización pueden haber cambiado.

Crea identificadores en cada límite de confianza

Una traza solo ayuda si cada participante puede vincular su trabajo con la misma cadena causal sin aceptar como hechos históricos datos falsificados. Genera tus propios identificadores cuando una solicitud entre en un componente que controlas y conserva el contexto ascendente como información de diagnóstico no fiable, salvo que lo haya proporcionado un par autenticado.

La recomendación W3C Trace Context define la cabecera traceparent con una versión, un ID de traza de 32 caracteres hexadecimales, un ID de padre de 16 caracteres hexadecimales y varias marcas. OpenTelemetry usa ampliamente este formato. Utilízalo cuando HTTP u otro transporte pueda llevar cabeceras, porque las herramientas de trazabilidad existentes lo entienden. No confundas compatibilidad con un modelo de auditoría.

En MCP sobre stdio puede no existir ninguna cabecera HTTP. Introduce un contexto equivalente en el envoltorio de tu aplicación o conserva el contexto en el proceso que distribuye la llamada. El mecanismo importa menos que estas dos propiedades: cada operación hija debe conocer a su padre inmediato y el componente receptor debe registrar quién le entregó el contexto.

Una estructura mínima de evento podría ser esta:

{
  "event_id": "evt_01J8...",
  "time": "2025-03-08T14:32:11.214Z",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "parent_span_id": "b7ad6b7169203331",
  "root_run_id": "run_8d43",
  "edge_type": "external_action",
  "actor": {
    "kind": "agent_process",
    "identity": "signed-process-identity"
  },
  "action": {
    "action_id": "act_5f17",
    "channel": "http",
    "method": "POST",
    "host": "deploy.internal.example",
    "path_template": "/v1/releases/{name}",
    "credential_ref": "ops-deploy"
  },
  "outcome": {
    "state": "sent",
    "http_status": 202
  }
}

La marca de tiempo anterior muestra una estructura de ejemplo, no un formato de conservación recomendado. En un sistema real, usa un formato de reloj que tu verificador de registros pueda analizar de forma coherente. Mantén los endpoints y argumentos sin procesar fuera de las exportaciones de telemetría general cuando contengan nombres de clientes, rutas de repositorios o datos personales. Una plantilla junto con un registro forense protegido por separado suele dar a los operadores suficiente contexto sin copiar información sensible en cada panel.

Un servicio receptor no debe confiar sin más en parent_span_id porque lo haya proporcionado un agente. Crea un span local nuevo, registra el valor recibido y añade un campo como upstream_context_source=authenticated_mcp_client o upstream_context_source=unverified_input. Esta pequeña distinción impide que un atacante vincule después su acción a una ejecución legítima.

Registra la resolución, no solo los argumentos de la herramienta

La acción que solicita un agente y la que ejecuta el ejecutor pueden diferir después de aplicar plantillas, valores predeterminados, alias, redirecciones, búsquedas de entorno y selección de credenciales. Tus registros deben conservar ambos lados, porque la diferencia suele ser el lugar donde se oculta un diseño inseguro.

Considera una llamada del agente con estos argumentos:

{
  "tool": "publish_release",
  "arguments": {
    "environment": "prod",
    "release": "2025.03.08-rc2"
  }
}

Una herramienta puede traducir prod a una URL base, seleccionar una credencial, convertir la cadena de versión en una ruta de solicitud y añadir cabeceras. La llamada inicial no demuestra el destino. Una cadena completa debería mostrar una transición como esta:

  1. El agente invoca publish_release en la ejecución run_8d43.
  2. La herramienta resuelve prod en un endpoint permitido concreto y selecciona la referencia de credencial ops-deploy.
  3. El ejecutor registra act_5f17 justo antes de enviar la solicitud.
  4. El ejecutor registra la respuesta o el error de transporte asociado a esa acción.
  5. El envoltorio devuelve un resultado que cita act_5f17 sin exponer las credenciales.

Esta secuencia da al investigador un camino desde la solicitud del agente hasta una operación de red. También proporciona al aprobador algo concreto que revisar antes de que el ejecutor envíe nada.

No registres cabeceras de autorización completas, cookies, comandos privados ni cuerpos de solicitud arbitrarios como sustituto de un buen modelo. La gente lo hace bajo presión porque una descarga sin filtrar resuelve el problema de depuración del día. Después crea una filtración de credenciales. Captura en su lugar una referencia de credencial, el nombre de la cabecera, un resumen del cuerpo, campos seleccionados que no sean secretos y un estado explícito de redacción.

SSH necesita la misma disciplina. Un registro que diga ssh deploy es demasiado impreciso si el asistente después amplía un alias de host, selecciona una identidad y construye un comando remoto. Registra el host y el puerto resueltos, el nombre de la cuenta, la referencia de identidad, una plantilla o resumen del comando y el estado de salida. Si el comando contiene datos sensibles, conserva una copia forense protegida solo cuando tengas un motivo claro y una regla de conservación definida.

Un reintento es otro intento, no una nota al pie

Pon SSH bajo control
Usa el asistente SSH de Sallyport para que los agentes ejecuten comandos remotos sin tener las claves SSH.

Los reintentos y la distribución paralela convierten un árbol sencillo en un grafo. Si los fuerzas a entrar en un único span con un campo final success, borras la información que explica los efectos secundarios duplicados y los fallos parciales.

Usa tres ID cuando una operación pueda reintentarse: un ID de traza para la ejecución completa, un ID de acción para la operación lógica prevista y un ID de intento para cada envío real. Cada intento recibe su propio span. El registro de la acción apunta entonces a todos los intentos.

Supón que una herramienta envía una solicitud de versión, agota el tiempo de espera después de que el servicio remoto la haya aceptado y vuelve a intentarlo. La segunda solicitud podría crear la misma versión dos veces si el endpoint remoto no gestiona la idempotencia. Un 200 final dice muy poco. El registro debe mostrar que el primer intento llegó a la red, terminó localmente por tiempo de espera y que el segundo recibió una respuesta.

Usa un token de idempotencia cuando el destino lo admita. Derívalo del ID de acción lógica, no de un ID de span temporal. Así el servicio remoto puede reconocer un duplicado aunque tu ejecutor se reinicie o tu biblioteca de trazabilidad genere spans nuevos.

trace_id=4bf92f... action_id=act_5f17 attempt=1 state=timeout bytes_sent=418
trace_id=4bf92f... action_id=act_5f17 attempt=2 state=completed http_status=200

bytes_sent ayuda a distinguir un fallo de conexión anterior a la transmisión de la solicitud de un tiempo de espera posterior a que el cliente haya escrito datos, pero no demuestra qué confirmó el servicio remoto. Expresa esa incertidumbre en el registro. No etiquetes el primer intento como failed de una forma que sugiera que el lado remoto no hizo nada.

El trabajo paralelo necesita spans hermanos, no un campo de traza mutable y compartido que los trabajadores sobrescriban. Si una herramienta de planificación llama a cuatro comprobaciones de entorno, crea cuatro spans hijos y cuatro resultados separados. Si dos ramas conducen a acciones externas, emite dos ID de acción. Un operador debe poder revocar o investigar una rama sin confundirla con su hermana.

La aprobación debe vincularse con la operación resuelta

Una aprobación humana solo sirve si el revisor puede ver la operación que ocurrirá después de la resolución. Aprobar una etiqueta amplia como deploy deja muy poco que valorar, sobre todo cuando las herramientas anidadas seleccionan más tarde el host y la credencial reales.

Construye la información para la aprobación a partir del registro de la acción externa pendiente: canal, destino resuelto, forma de la operación, referencia de credencial, identidad del proceso y una descripción breve del impacto. Conserva los ID de traza y de acción en la decisión. Cuando el ejecutor envíe la solicitud, debe demostrar que consumió esa misma acción aprobada, no solo una aprobación perteneciente a la misma ejecución del agente.

No apruebes toda una cadena solo porque su primera herramienta pareciera inofensiva. Una cadena puede empezar con find_release y terminar con un comando SSH que modifica un host. Si el diseño permite que una resolución posterior amplíe lo que la cadena puede hacer, exige una decisión nueva en el límite saliente.

Esto no significa preguntar a una persona por cada concatenación de cadenas dentro de una herramienta. Significa colocar la decisión donde una capacidad sale del flujo de ejecución de confianza. Ese límite proporciona a las personas una solicitud comprensible y da a tu registro una conexión duradera entre el consentimiento y el efecto.

Sallyport aplica este enfoque a sus canales HTTP y SSH compatibles: mantiene las credenciales en su bóveda, ejecuta la acción por sí mismo y puede exigir aprobación para cada uso de una credencial seleccionada. El punto de integración útil es la acción externa resultante, no lo que un agente afirma que pretendía su asistente anidado.

Los registros de aprobación también necesitan reglas de caducidad y vinculación. Vincula una decisión al ID de acción, al destino resuelto, a la referencia de credencial y al resumen de los argumentos. Si alguno cambia entre la solicitud de aprobación y la ejecución, descarta la decisión y vuelve a solicitarla. Un token de aprobación reutilizable que siga al proceso del agente en llamadas no relacionadas terminará autorizando algo que nadie leyó.

Un diario de auditoría necesita orden y verificación

Verifica el historial de acciones
Verifica sin conexión el registro de auditoría cifrado y encadenado mediante hashes de Sallyport con sp audit verify.

Los registros de aplicación convencionales ayudan a diagnosticar un fallo, pero rara vez indican si alguien eliminó la línea incómoda. Para las acciones realizadas por agentes autónomos, conserva el orden de los eventos y haz que las modificaciones posteriores sean evidentes.

Una cadena de hashes registra los bytes serializados de forma canónica de cada evento, el hash del evento anterior y el nuevo hash del evento. Un verificador empieza en el primer registro conservado y recalcula cada enlace. Si un atacante cambia, inserta o elimina un registro en el centro, la verificación falla en el punto afectado.

La serialización canónica importa. Si un proceso ordena los campos JSON y otro no, registros equivalentes producen hashes distintos. Define el orden de los campos, la normalización Unicode, la precisión de las marcas de tiempo, el tratamiento de campos ausentes y la codificación de bytes. Prueba esas reglas en todos los lenguajes que escriban eventos. La mayoría de las cadenas de auditoría defectuosas fallan aquí, no en la función hash.

Un verificador debe producir resultados sobre los que un operador pueda actuar:

$ audit verify journal.events
records_checked: 1842
first_sequence: 91001
last_sequence: 92842
chain: valid
signature: valid

Cuando encuentre daños, debe identificar la primera secuencia incorrecta y comparar el hash predecesor esperado con el observado. No debe intentar reparar el archivo en silencio. La reparación destruye las pruebas sobre lo que salió mal.

Las cadenas de hashes no resuelven todas las amenazas. Alguien que controle el material de firma y el almacenamiento puede reescribir una historia alternativa completa. Los puntos de control firmados periódicamente y almacenados fuera del control habitual del escritor reducen ese riesgo. También conviene separar las vías de acceso para escribir y leer eventos. Describe con precisión la protección disponible en lugar de llamar inmutable a cualquier registro.

Mantén el evento de acción cerca del punto de ejecución. Un recolector en segundo plano que recibe lotes después de los hechos puede perder el único registro que demuestra que ocurrió una llamada saliente. El ejecutor debe añadir un registro de «planned» antes de la transmisión y un registro de finalización justo después de recibir un resultado. Si se bloquea entre ambos, el par incompleto indica que la acción pudo haber salido.

Prueba la traza contra los fallos que la gente realmente provoca

Aprueba cada acción con credenciales
Exige aprobación para cada uso de una credencial seleccionada, no solo para la primera llamada de la herramienta.

Un diseño de trazabilidad solo resulta creíble después de superar contextos malformados, trabajadores perdidos, envíos duplicados y revocaciones del operador. Las demostraciones del camino feliz ocultan precisamente los extremos que importan cuando un agente se comporta de forma inesperada.

Ejecuta una pequeña batería de pruebas contra un endpoint o host desechable. Haz que cada prueba compruebe el grafo de auditoría, no solo la respuesta de la herramienta:

  • Envía una llamada anidada con un ID de padre falsificado y confirma que el receptor marca ese contexto como no verificado.
  • Fuerza un tiempo de espera después de que los bytes de la solicitud salgan del cliente, repite la operación y confirma que ambos intentos comparten un ID de acción.
  • Pon un trabajo en cola, reinicia el trabajador y confirma que el span reanudado se vincula con la ejecución original sin fingir que se ejecutó de forma continua.
  • Revoca la autorización después de la planificación pero antes de la ejecución y confirma que ningún registro de acción externa llega a sent.
  • Realiza dos llamadas hermanas en paralelo y confirma que ninguna rama adopta el span padre ni el resultado de la otra.

La tercera prueba detecta una mentira habitual en los registros. Los sistemas suelen informar de una única solicitud ininterrumpida aunque un trabajador se haya reiniciado horas después con otra identidad de proceso. Eso oculta quién realizó realmente la acción. Registra la identidad y la hora de inicio del trabajador como hechos del span nuevo.

La cuarta prueba detecta otro fallo conocido. Una herramienta obtiene autorización antes de resolver su destino final y después usa esa decisión obsoleta para la llamada resuelta. Tu prueba debe cambiar el destino o la referencia de credencial después de la aprobación y esperar que el ejecutor la rechace.

No te conformes con capturas de pantalla de un visor de trazas. Exporta los registros sin procesar, verifica su cadena y escribe aserciones sobre los ID de padres, los ID de acciones, los destinos, los vínculos de autorización y los resultados. El visor es una comodidad. El flujo de eventos es la prueba.

Construye primero el límite y completa después el grafo

Empieza por el código que realiza operaciones HTTP y SSH. Haz que acepte un contexto de traza explícito, cree un registro de acción antes de enviar, cree un registro de resultado después y se niegue a ejecutar cuando la autorización no esté vinculada a la operación resuelta.

Cuando ese límite funcione correctamente, instrumenta las llamadas a herramientas anidadas que están por encima. Sabrás qué información debe transmitir cada padre porque el ejecutor la exigirá. Trabajar en la dirección contraria suele producir árboles bonitos con nodos hoja en los que no se puede confiar.

Mantén separados del diario de acciones externas los nombres de las herramientas, las notas de planificación y el razonamiento del modelo. Pueden ayudar a entender por qué ocurrió una ejecución. No sustituyen un registro del sistema remoto que recibió la solicitud, la referencia de credencial utilizada, la aprobación previa y el resultado obtenido. Esa es la cadena que necesitarás cuando la respuesta del agente parezca plausible y el sistema remoto diga otra cosa.

FAQ

¿Qué debo auditar cuando una herramienta MCP invoca varias herramientas más?

Trata la operación final que usa credenciales como la acción principal que debes registrar. La llamada MCP que inició la cadena sigue siendo importante para el diagnóstico, pero no indica a un auditor si la cadena creó un repositorio, cambió un registro DNS o reinició un servicio.

¿MCP conserva automáticamente la trazabilidad entre padres e hijos en las llamadas a herramientas?

No. MCP define el descubrimiento y las llamadas a herramientas, pero un host de agentes o un servidor puede crear su propio grafo de llamadas internas. Tu diseño de trazabilidad debe capturar ese grafo, no asumir que el protocolo lo proporciona.

¿Cómo propago un ID de traza a través de herramientas de agentes anidadas?

Asigna un ID de traza y un ID de span a cada llamada entrante, y haz que cada llamada hija transporte el mismo ID de traza, usando como padre el ID de span de quien la realiza. Genera un nuevo ID de span para cada operación, incluidos los reintentos y las ramas paralelas.

¿Qué campos debe contener un registro de auditoría de una acción externa?

Registra la operación solicitada, el destino completamente resuelto, la referencia de la credencial, la decisión de autorización, los tiempos, el resultado y un resumen seguro de la respuesta. No incluyas tokens de acceso, claves privadas ni cuerpos de solicitud sin redactar en una traza solo para facilitar la depuración.

¿Los reintentos deben compartir el mismo span que la solicitud original?

Un reintento necesita su propio registro de intento porque crea otra solicitud saliente y puede generar otro efecto secundario. Conecta cada intento con un único ID de acción lógica para que el investigador pueda ver tanto la operación que se pretendía realizar como cada intento de red usado para conseguirlo.

¿Cómo trazo llamadas paralelas a herramientas MCP?

Sí, siempre que cada rama reciba su propio span y cada operación externa tenga su propio registro de acción. Compartir solo el padre no basta, porque una rama correcta puede ocultar una llamada hermana fallida o peligrosa.

¿Puedo aprobar toda una cadena de herramientas anidadas con una sola confirmación?

La aprobación debe identificar la operación externa resuelta, no limitarse al nombre conocido de la herramienta. «Desplegar» es demasiado amplio; «enviar esta solicitud firmada a este endpoint de producción» da al revisor algo concreto que valorar.

¿Puede un agente falsificar la información del padre de una traza?

No confíes en los ID de los padres proporcionados por el agente como fuente de verdad para la auditoría. Consérvalos como contexto de diagnóstico si resultan útiles, pero crea relaciones de traza en el servidor en cada límite de confianza y registra el proceso o principal autenticado que realizó la llamada.

¿Cómo hago que un registro de acciones MCP permita detectar manipulaciones?

Un registro de eventos de solo escritura con números de secuencia, hashes del registro anterior y verificaciones periódicas ofrece pruebas más sólidas que los registros de aplicación editables. No puede hacer que una máquina comprometida sea honesta, pero dificulta mucho ocultar eliminaciones o cambios de orden posteriores.

¿Por dónde debe empezar un equipo con la trazabilidad de MCP anidado?

Empieza con una herramienta límite que realice una solicitud HTTP o un comando SSH y exige que emita un ID de acción y el contexto de la traza. Cuando ese registro sea fiable, añade los spans internos que expliquen cómo llegó la cadena hasta él.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov