# Conectar Claude con una API interna: herramientas directas o MCP

> Si tu aplicación ya controla la autenticación y ejecuta las llamadas, empieza con herramientas directas de Claude API. MCP compensa cuando varios clientes necesitan la misma interfaz; en ambos casos, tu código debe comprobar los permisos y el resultado real.

- URL: https://blog.laozhang.ai/es/posts/claude-mcp-internal-tools-api-integration
- Published: 2026-06-01
- Updated: 2026-10-07
- Author: LaoZhang AI Team (https://blog.laozhang.ai/es/about)
- Topic: Claude y Anthropic
- Tags: Claude, MCP, API de Claude, Herramientas internas, Desarrollo

---
Para conectar Claude con una API interna, **empieza por decidir quién ejecutará la operación**. Si tu aplicación ya autentica al usuario, conserva la conversación y accede al sistema interno, puede recibir una petición `tool_use`, ejecutar una llamada acotada y devolver `tool_result`. No necesitas añadir MCP para conseguirlo. Si varios clientes necesitan compartir las mismas herramientas, un servidor MCP permite mantener esa interfaz en un solo lugar. [Herramientas de cliente en Claude API](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview).

La integración está completa cuando puedes relacionar la petición de Claude con un usuario autorizado, una operación del sistema interno y un resultado comprobable. Que el modelo diga «he consultado el expediente» o que aparezca un conector configurado no demuestra esa cadena.

Esta guía utiliza una consulta de soporte: «¿En qué estado está el expediente EXP-204?». El ejemplo implementa la lectura y la devolución del resultado; después explica cómo ampliar el diseño a cambios aprobados. Las comprobaciones del código se realizaron únicamente con datos ficticios y sin conexión: no son una prueba de acceso a una API, de una sesión MCP ni de seguridad desplegada.

## Elige la ruta según dónde se ejecuta el trabajo

Una API HTTP existente no se convierte en MCP por añadir su URL a Claude. Necesitas una interfaz que describa las herramientas y ejecute sus operaciones. Puedes incorporarla a tu aplicación o publicarla mediante un servidor MCP, según el cliente que vaya a consumirla.

| Necesidad | Ruta de partida | Quién llama a la API interna |
| --- | --- | --- |
| Una aplicación ofrece consultas de soporte a sus usuarios | Herramientas directas en Messages API | El backend de tu aplicación, con la identidad y los permisos del usuario |
| Messages API debe utilizar un conjunto de herramientas MCP remoto | Conector MCP de Claude API | El servidor MCP, tras autorizar la petición |
| Varias aplicaciones y clientes necesitan las mismas operaciones | Servidor MCP propio o ya disponible | El servidor, manteniendo el contrato y las reglas del sistema interno |
| Un desarrollador trabaja con recursos locales o servicios del equipo | MCP en Claude Code | El proceso local para `stdio`, o un servidor remoto para HTTP |
| Una persona quiere usar las herramientas desde Claude, Cowork o Desktop | Conector remoto personalizado | El servidor MCP al que llega la infraestructura de Anthropic |

El [conector MCP de la API](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) y los [conectores de usuario](https://support.claude.com/zh-CN/articles/11175166-使用远程-mcp-开始自定义连接器) tienen configuración, autenticación y condiciones de uso distintas. La ayuda oficial de los conectores de usuario incluye actualmente Free, con un conector personalizado, además de los planes de pago; en organizaciones también intervienen las funciones de administración y la autorización de los miembros. Tener acceso a una de estas rutas no configura automáticamente las demás.

Para una primera integración dentro de tu producto, las herramientas directas evitan mantener un servidor de protocolo adicional. MCP empieza a compensar cuando el equipo responsable de la API necesita conservar una interfaz común entre clientes. En ambos casos siguen haciendo falta autorización, límites de salida y registros de ejecución: la elección del protocolo no resuelve esos requisitos.

## Expón una tarea pequeña, no toda la API administrativa

![Una capa de adaptación convierte operaciones de una API interna en herramientas pequeñas con resultados breves.](https://blog.laozhang.ai/posts/es/claude-mcp-internal-tools-api-integration/img/internal-api-wrapper.webp)

La herramienta del ejemplo se llama `consultar_expediente`. Acepta un identificador y devuelve estado, fecha de actualización y referencia del resultado. No admite una URL, SQL, comandos ni un cuerpo HTTP arbitrario. Tampoco recibe `usuario_id` u `organizacion_id` del modelo: esos valores proceden de la autenticación del backend.

Antes de programarla, acuerda estos detalles con quien mantiene la API:

| Parte del contrato | Decisión en este ejemplo |
| --- | --- |
| Operación permitida | Leer un expediente concreto |
| Recurso | `GET /v1/organizaciones/{organizacion_id}/expedientes/{expediente_id}` |
| Autorización | El usuario autenticado necesita `expedientes:leer`; la API vuelve a comprobar su acceso al recurso |
| Credencial de servicio | Permanece en el backend y tiene permiso de lectura; es independiente de cualquier token MCP |
| Resultado para Claude | Identificador, estado, fecha y `resultado_id`; se excluyen datos de contacto y notas privadas |
| Registro interno | ID de llamada, usuario, organización, recurso, decisión y referencia del resultado |

Es una propuesta de contrato para una API ficticia, no nombres de endpoints de Anthropic. En un sistema multicliente, la organización o *tenant* debe restringir la consulta antes de obtener los datos. No basta con quitar el campo de organización del resultado después de leer una fila ajena.

El servidor tampoco debe considerar `readOnlyHint` una autorización. Las anotaciones de herramientas MCP son metadatos y se tratan como información no confiable. Una herramienta anunciada como de lectura puede tener una implementación incorrecta; comprueba el método y los permisos en el código que ejecuta la operación. [Especificación de herramientas MCP, revisión 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/server/tools).

## Implementa la consulta y devuelve el resultado a Claude

Con herramientas directas, el recorrido es: enviar la definición, recibir `tool_use`, validar la llamada, consultar el sistema interno y añadir los resultados a la conversación. La aplicación ejecuta la herramienta; el modelo solicita la operación. [Tratamiento oficial de llamadas a herramientas](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls).

### Define la entrada y el adaptador HTTP

El siguiente código JavaScript contiene la definición, un adaptador HTTP y el ejecutor. Puedes guardar el bloque como `expedientes.mjs` en tu proyecto. No inicia ningún cliente de Claude ni realiza llamadas por sí solo. Para una integración real, tu capa de autenticación debe proporcionar `contexto` y la credencial de servicio; el registro `registrar` debe persistir los eventos en un sistema de auditoría. Ninguno de esos datos debe salir del texto generado por Claude.

La API ficticia devuelve `organizacion_id`, `expediente_id`, `estado`, `actualizado_en` y `resultado_id`. Los dos primeros permiten comprobar que la respuesta corresponde al recurso autorizado. La API debe verificar también los encabezados de identidad conforme a su propio mecanismo de confianza: un encabezado enviado por cualquier cliente no identifica a un usuario.

```js
export const herramienta = {
  name: "consultar_expediente",
  description: "Consulta el estado de un expediente accesible al usuario.",
  input_schema: {
    type: "object",
    properties: {
      expediente_id: { type: "string", pattern: "^EXP-[0-9]{1,8}$" }
    },
    required: ["expediente_id"],
    additionalProperties: false
  }
};

export function crearApi(baseUrl, credencialServicio, transporte) {
  const origen = new URL(baseUrl);
  if (origen.protocol !== "https:" || origen.pathname !== "/" ||
      origen.username || origen.password || origen.search || origen.hash) {
    throw new Error("ORIGEN_INVALIDO");
  }
  return {
    async leer(contexto, expedienteId) {
      const ruta = `/v1/organizaciones/${encodeURIComponent(contexto.organizacion_id)}` +
        `/expedientes/${encodeURIComponent(expedienteId)}`;
      const respuesta = await transporte(new URL(ruta, origen), {
        method: "GET",
        redirect: "error",
        signal: AbortSignal.timeout(5000),
        headers: {
          Authorization: `Bearer ${credencialServicio}`,
          "X-Usuario-Id": contexto.usuario_id,
          "X-Organizacion-Id": contexto.organizacion_id,
          Accept: "application/json"
        }
      });
      if (!respuesta.ok) throw new Error("API_NO_DISPONIBLE");
      const lector = respuesta.body.getReader();
      const partes = [];
      let bytes = 0;
      try {
        while (true) {
          const { done, value } = await lector.read();
          if (done) break;
          bytes += value.byteLength;
          if (bytes > 16384) {
            await lector.cancel();
            throw new Error("RESPUESTA_EXCESIVA");
          }
          partes.push(value);
        }
      } finally {
        lector.releaseLock();
      }
      const contenido = new Uint8Array(bytes);
      let posicion = 0;
      for (const parte of partes) {
        contenido.set(parte, posicion);
        posicion += parte.byteLength;
      }
      return JSON.parse(new TextDecoder().decode(contenido));
    }
  };
}

export async function ejecutar(llamada, contexto, api, registrar) {
  const expedienteId = llamada.input?.expediente_id;
  let resultado;
  let decision = "rechazada";
  let resultadoId = null;
  try {
    if (llamada.name !== herramienta.name ||
        !llamada.input || typeof llamada.input !== "object" ||
        Object.keys(llamada.input).length !== 1 ||
        typeof expedienteId !== "string" || !/^EXP-[0-9]{1,8}$/.test(expedienteId)) {
      throw new Error("ENTRADA_INVALIDA");
    }
    if (typeof contexto?.usuario_id !== "string" ||
        !/^[a-z0-9-]{1,64}$/.test(contexto.usuario_id) ||
        typeof contexto.organizacion_id !== "string" ||
        !/^[a-z0-9-]{1,64}$/.test(contexto.organizacion_id) ||
        !Array.isArray(contexto.permisos) || !contexto.permisos.includes("expedientes:leer")) {
      throw new Error("NO_AUTORIZADO");
    }
    const dato = await api.leer(contexto, expedienteId);
    if (dato.organizacion_id !== contexto.organizacion_id ||
        dato.expediente_id !== expedienteId ||
        !["abierto", "en_revision", "cerrado"].includes(dato.estado) ||
        typeof dato.actualizado_en !== "string" ||
        !Number.isFinite(Date.parse(dato.actualizado_en)) ||
        typeof dato.resultado_id !== "string" ||
        !/^RES-[A-Za-z0-9-]{1,64}$/.test(dato.resultado_id)) {
      throw new Error("RESULTADO_INVALIDO");
    }
    resultadoId = dato.resultado_id;
    decision = "completada";
    resultado = {
      expediente_id: dato.expediente_id,
      estado: dato.estado,
      actualizado_en: dato.actualizado_en,
      resultado_id: resultadoId
    };
  } catch (error) {
    const publicos = ["ENTRADA_INVALIDA", "NO_AUTORIZADO", "RESULTADO_INVALIDO"];
    resultado = { error: publicos.includes(error.message) ? error.message : "CONSULTA_FALLIDA" };
  }
  await registrar({
    llamada_id: llamada.id,
    usuario_id: contexto?.usuario_id ?? null,
    organizacion_id: contexto?.organizacion_id ?? null,
    herramienta: herramienta.name,
    expediente_id: typeof expedienteId === "string" && /^EXP-[0-9]{1,8}$/.test(expedienteId)
      ? expedienteId : null,
    decision,
    resultado_id: resultadoId
  });
  return {
    type: "tool_result",
    tool_use_id: llamada.id,
    is_error: decision !== "completada",
    content: JSON.stringify(resultado)
  };
}

export async function continuar(mensajes, respuesta, contexto, api, registrar) {
  const llamadas = respuesta.content.filter(bloque => bloque.type === "tool_use");
  if (llamadas.length === 0) throw new Error("SIN_LLAMADA");
  if (llamadas.length > 4 || llamadas.some(bloque => typeof bloque.id !== "string") ||
      new Set(llamadas.map(bloque => bloque.id)).size !== llamadas.length) {
    throw new Error("LLAMADAS_INVALIDAS");
  }
  const resultados = [];
  for (const llamada of llamadas) {
    resultados.push(await ejecutar(llamada, contexto, api, registrar));
  }
  return [
    ...mensajes,
    { role: "assistant", content: respuesta.content },
    { role: "user", content: resultados }
  ];
}
```

Para el adaptador real, `transporte` puede ser `fetch` del backend; para comprobar el ejecutor sin conexión, es una función ficticia. El origen es configuración de confianza y la herramienta no lo puede cambiar. El adaptador limita el tiempo y el volumen de la respuesta, rechaza redirecciones y utiliza un único método y una ruta determinada.

El ejemplo comprueba un permiso general de lectura y delega a la API la autorización sobre el expediente concreto. Si tu servicio interno solo conoce una cuenta de servicio con acceso a todos los expedientes, tienes que añadir esa comprobación de recurso antes de leer: copiar el usuario a un encabezado no la implementa. El ejecutor filtra la respuesta por campos y no devuelve correos, notas privadas ni credenciales.

`continuar` está pensado para una respuesta con herramientas de cliente como la del ejemplo. Conserva **todo** `respuesta.content`, incluidos los bloques de texto, y coloca el mensaje con resultados inmediatamente después. No utiliza solo `content[0]`. Cada resultado conserva exactamente el ID de la petición correspondiente. Las respuestas que mezclan herramientas de servidor todavía pendientes tienen reglas adicionales de continuación; aplica la rama documentada para ese caso en lugar de reutilizar esta función sin cambios. [Orden de mensajes y resultados](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls).

### Relaciona la petición con el resultado del sistema interno

En una petición a Messages API, envías `herramienta` dentro de `tools`, junto con el modelo, el presupuesto de salida y los mensajes. El modelo elegido y la autenticación de la API se configuran en tu cliente, fuera de la herramienta. Esta es una respuesta ilustrativa, no una llamada realizada:

```json
{
  "stop_reason": "tool_use",
  "content": [
    { "type": "text", "text": "Voy a consultar el estado del expediente." },
    {
      "type": "tool_use",
      "id": "toolu_ejemplo_204",
      "name": "consultar_expediente",
      "input": { "expediente_id": "EXP-204" }
    }
  ]
}
```

Supón que la autenticación del backend proporciona el usuario `operador-7`, la organización `org-norte` y el permiso `expedientes:leer`. El adaptador solicita `GET /v1/organizaciones/org-norte/expedientes/EXP-204`. Si la API autoriza ese recurso y devuelve la respuesta esperada, el mensaje añadido a Claude contiene:

```json
{
  "role": "user",
  "content": [
    {
      "type": "tool_result",
      "tool_use_id": "toolu_ejemplo_204",
      "is_error": false,
      "content": "{\"expediente_id\":\"EXP-204\",\"estado\":\"en_revision\",\"actualizado_en\":\"2026-10-07T08:30:00Z\",\"resultado_id\":\"RES-204-8\"}"
    }
  ]
}
```

La siguiente petición a Messages API utiliza los mensajes devueltos por `continuar` y las definiciones de herramientas. Claude ya dispone del dato para explicar que el expediente sigue en revisión. Si vuelve a solicitar una herramienta, la aplicación repite el tratamiento dentro de un límite total de llamadas y tiempo; no mantiene un bucle infinito.

`toolu_ejemplo_204` relaciona la solicitud con su `tool_result`. `RES-204-8` identifica el resultado en el sistema interno y debe permitir consultar su evidencia o registro. En una lectura, esa referencia acredita la consulta y su versión temporal; no es un ID de cambio. En una escritura necesitas además el ID de la operación y el estado final. Si el backend no genera estas referencias, incorpóralas a su contrato o usa su identificador equivalente: inventarlas en el modelo o solo en la respuesta visible no demuestra la ejecución.

Cuando falla la autorización, el ejecutor devuelve `is_error: true` y `NO_AUTORIZADO`, sin consultar la API. Un resultado de otra organización se descarta aunque la API lo haya devuelto. Si falla la persistencia de auditoría, la función propaga el error y no presenta la lectura como un éxito registrado. Esta decisión debe integrarse en el manejo de errores de tu aplicación.

## Si eliges MCP, cambia el adaptador y conserva las reglas de negocio

El servidor MCP puede reutilizar la misma operación acotada, pero debe obtener la identidad desde su autenticación, no desde argumentos de la herramienta. La autenticación de un servidor HTTP protegido verifica token, audiencia o recurso, caducidad y permisos; el acceso a la API interna necesita su propia autorización. No reenvíes sin más el token recibido del cliente MCP al servicio interno. [Autorización MCP](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization).

Para diagnosticar un fallo, distingue la respuesta del servidor MCP de la respuesta de tu API interna. En el esquema de autorización HTTP de MCP, un token inválido o caducado corresponde a `401`, mientras que permisos insuficientes corresponden a `403`. Corregir la credencial del conector no amplía por sí solo los permisos del servicio interno. La aplicación obtiene y renueva el token por su flujo de autorización aprobado; no lo entrega al modelo ni lo incluye en la URL.

No copies la definición de Anthropic literalmente al protocolo. Claude API usa `input_schema`; una definición MCP utiliza `inputSchema` y, si declara la forma de salida, `outputSchema`. Los resultados `mcp_tool_use` y `mcp_tool_result` del conector de la API tampoco son los bloques `tool_use` y `tool_result` del ejecutor anterior. Mantén un adaptador para cada interfaz.

### Conector de Messages API y catálogo fijado

Para la ruta remota habitual del [conector MCP de Claude API](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector), necesitas un servidor HTTPS alcanzable por la infraestructura de Anthropic, con transporte HTTP o SSE compatible. El conector admite herramientas; no es acceso general a todas las primitivas MCP ni ejecuta directamente un proceso local `stdio`.

La documentación consultada el 7 de octubre de 2026 mantiene `mcp-client-2025-11-20` y añade `mcp-client-2026-09-15` para fijar el catálogo. Esta última beta incluye la funcionalidad anterior. `mcp-client-2025-04-04` está obsoleta. Utiliza la cabecera correspondiente a la función que necesites y consérvala en las continuaciones. [Configuración y beta del catálogo](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#pin-an-mcp-servers-tool-list-beta).

Estos campos ilustran la parte MCP de una petición, con una URL y un token de marcador. No son una petición completa ni credenciales utilizables:

```json
{
  "mcp_servers": [
    {
      "type": "url",
      "name": "expedientes",
      "url": "https://mcp.example.com/mcp",
      "authorization_token": "TOKEN_DE_EJEMPLO"
    }
  ],
  "tools": [
    {
      "type": "mcp_toolset",
      "mcp_server_name": "expedientes",
      "default_config": { "enabled": false },
      "configs": {
        "consultar_expediente": { "enabled": true }
      }
    }
  ]
}
```

Cada entrada de `mcp_servers` debe corresponder a exactamente un `mcp_toolset`. Por defecto las herramientas están habilitadas; aquí se desactivan todas salvo la consulta elegida. Comprueba el nombre exacto: una configuración referida a una herramienta inexistente genera una advertencia, no necesariamente un error de petición. No trates una respuesta HTTP correcta como prueba de que se aplicó la selección deseada.

La beta del catálogo devuelve bloques `mcp_tool_listing`. Puedes conservar las definiciones recibidas en `MCPToolset.tools` para fijar lo que Claude verá, manteniendo el mensaje completo del asistente al continuar. **Fijar un catálogo no fija los permisos ni la implementación del servidor**. Una herramienta con el mismo nombre puede cambiar por detrás. Contrasta el catálogo aprobado, los esquemas y la identidad del servidor en tu control de cambios; aplica la autorización de recurso cuando se ejecute la llamada.

### Una API privada no exige abrir toda tu red

![Distinción entre un proceso MCP local y un servidor HTTP remoto accesible desde el cliente correspondiente.](https://blog.laozhang.ai/posts/es/claude-mcp-internal-tools-api-integration/img/local-remote-boundary.webp)

Si tu backend ya puede llegar a la API privada, las herramientas directas permiten mantener la ejecución allí y enviar a Claude únicamente el resultado seleccionado. Para un servidor MCP remoto, que la URL se abra desde tu portátil conectado a una VPN no demuestra que Anthropic pueda alcanzarla.

Anthropic documenta también [túneles MCP privados](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview): son una **vista previa de investigación que requiere acceso**, con conexiones salientes mediante una infraestructura de proxy y Cloudflare. Permiten una ruta privada para Messages API y Managed Agents bajo sus condiciones de espacio de trabajo, enrutamiento y certificados. No equivalen a un conector de claude.ai disponible para cualquier cuenta y siguen necesitando la autorización del servicio interno.

El túnel no convierte todo el tratamiento en local: el modelo recibe los resultados necesarios, y hay metadatos de conexión. Además, la tabla actual de [retención de datos de Claude API](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention) marca el conector MCP y los túneles como no elegibles para ZDR ni HIPAA. Messages API estándar tiene condiciones propias según el acuerdo y el modelo. Que una solicitud funcione técnicamente no demuestra que quede cubierta por un acuerdo de retención concreto.

### Claude Code: configuración, conexión y ejecución son pasos distintos

Claude Code admite servidores locales `stdio` y remotos HTTP. Para añadir un remoto, especifica el transporte, por ejemplo `claude mcp add --transport http expedientes https://mcp.example.com/mcp`. Para un proceso local, la forma es `claude mcp add --transport stdio expedientes -- RUTA_DEL_EJECUTABLE`; sustituye el marcador por un programa real aprobado. Son ejemplos de sintaxis, no comandos ejecutados aquí. [Configuración oficial de MCP en Claude Code](https://code.claude.com/docs/en/mcp).

Elige además el alcance `local`, `project` o `user` según quién deba usar la configuración. Añadirla no prueba conexión, autenticación ni disponibilidad de la herramienta. Comprueba por separado el estado del servidor, el catálogo visible y el resultado de una operación autorizada. Las confirmaciones dependen del modo y del entorno de ejecución; no presupongas que cualquier escritura de cualquier cliente siempre pedirá permiso.

En los conectores remotos de Claude o Desktop, la conexión procede de la nube de Anthropic; la configuración local de Desktop es una ruta distinta. Si se utilizan credenciales fijas compartidas, el servidor no obtiene automáticamente una identidad diferente para cada miembro. Define cómo distinguirás a los usuarios y sus recursos, o limita expresamente el uso al ámbito que representa esa credencial.

## Añade escrituras con una aprobación ligada al cambio concreto

Para ampliar el ejemplo a «cerrar EXP-204», separa consulta, preparación y ejecución. El usuario debe poder ver qué cambiará antes de aprobarlo. Una frase de Claude como «el usuario lo ha aprobado» no sirve como registro de aprobación.

Este contrato ilustrativo muestra las tres peticiones de tu aplicación al backend. Las rutas son del sistema ficticio y no forman parte de MCP:

| Paso | Petición y datos | Resultado que conserva la aplicación |
| --- | --- | --- |
| Preparar | `POST /v1/cierres/previas` con `expediente_id=EXP-204` y la versión consultada | `previa_id=PRE-51`, organización, versión, cambio «en revisión → cerrado», huella del cambio y caducidad |
| Aprobar | `POST /v1/cierres/PRE-51/aprobacion` desde la interfaz autenticada | `aprobacion_id=APR-73`, usuario aprobador, huella y hora; el backend comprueba su permiso para aprobar |
| Ejecutar | `POST /v1/cierres/PRE-51/ejecucion` con `aprobacion_id=APR-73` y clave de idempotencia | `operacion_id=OP-61`, `resultado_id=RES-204-9`, estado de ejecución y versión final del expediente |

En el ejecutor de escritura, el backend busca la aprobación almacenada y vuelve a comprobar organización, recurso, acción, huella, caducidad y permiso del solicitante. La comprobación de versión, el consumo de la aprobación y el cambio deben protegerse mediante la transacción o mecanismo equivalente que ofrece el sistema interno. Si el expediente ha cambiado desde la vista previa, devuelve un conflicto y solicita una nueva aprobación; no aplica una aprobación antigua a otro contenido.

La clave de idempotencia debe identificar la operación aprobada y quedar ligada a su organización y parámetros. Si se repite con el mismo cambio, el backend devuelve la operación existente; si cambia el contenido, rechaza la reutilización. Persistir esa relación es necesario para evitar duplicados: el nombre del campo por sí solo no los impide.

Tras un timeout, consulta `GET /v1/operaciones/OP-61` cuando tengas el ID, o el estado asociado a la clave de idempotencia cuando no lo hayas recibido. Si la operación ya terminó, devuelve su resultado; si está pendiente, espera dentro del plazo acordado; si no puedes determinar su estado, informa «resultado desconocido» y detén el reintento automático. No inventes una clave nueva para repetir una escritura incierta.

Registra por separado el intento, la decisión de aprobación y el efecto confirmado. La auditoría debe permitir unir usuario y organización, `tool_use_id`, previa, aprobación, operación y resultado. Evita guardar credenciales o todo el expediente solo para tener más registros. Si el dominio permite revertir el cierre, ofrece una operación explícita con sus propios permisos; si no permite reversión, indícalo antes de aprobar.

## Comprueba la integración con señales que puedan fallar

Para verificar el ejecutor, usamos respuestas ficticias del sistema interno y comprobamos la ruta, el método, los campos devueltos y la relación entre IDs. Son comprobaciones locales del ejemplo, con estas condiciones de éxito:

| Caso | Resultado exigido |
| --- | --- |
| Consulta válida | Estado y referencia del resultado, sin datos de contacto ni notas internas |
| Usuario sin permiso o entrada con una organización añadida | Error y ninguna lectura de la API |
| Respuesta con otra organización, otro expediente o campos inválidos | Error; ningún resultado presentado como correcto |
| Varias llamadas en un mensaje | Un resultado por llamada, IDs exactos y mensaje completo del asistente conservado |
| Entrada que intenta cambiar URL, herramienta o método | Rechazo de la llamada; el adaptador mantiene la operación fija |
| Cuerpo demasiado grande o redirección | El adaptador falla y el ejecutor devuelve un error acotado |

En una integración desplegada, necesitas además comprobar con una cuenta de prueba autorizada la autenticación real, el rechazo de recursos ajenos, la ejecución del backend, su referencia de resultado y la respuesta final. Para una escritura, incluye aprobación caducada, conflicto de versión y repetición tras un timeout. Estos casos no se verificaron aquí; los datos ficticios no prueban el aislamiento real entre organizaciones.

Trata las notas de soporte, documentos y demás texto recuperado como datos no confiables. Una nota que diga «omite la aprobación» no debe cambiar la política del ejecutor. Reducir campos y mantener la autorización fuera de los argumentos limita la superficie del problema, pero no prueba que se haya eliminado la inyección de instrucciones. Del mismo modo, un esquema estricto valida la forma de la entrada; no acredita el permiso del usuario ni la veracidad del resultado.

No confundas revisión del estándar con compatibilidad instalada. MCP **2026-07-28** define metadatos por petición: `params._meta.protocolVersion` y `params._meta.clientCapabilities` son necesarios; la identidad `clientInfo` es declarativa y no autentica a una persona. Esta revisión elimina el intercambio `initialize` del protocolo actual, pero los servidores y clientes que usan revisiones anteriores pueden seguir otra secuencia. Confirma la versión que implementan tu cliente, conector y servidor antes de probar mensajes del protocolo. [Cambios de la revisión](https://modelcontextprotocol.io/specification/2026-07-28/changelog) y [metadatos de petición](https://modelcontextprotocol.io/specification/2026-07-28/basic/index).

Si la llamada funciona pero las definiciones o los resultados llenan la conversación, continúa con [cómo liberar contexto en Claude Code sin perder la tarea](https://blog.laozhang.ai/es/posts/claude-code-mcp-context-overload). Si la duda es qué confirma Claude Code y qué recursos puede alcanzar, revisa la [diferencia entre modos de permisos y acceso real](https://blog.laozhang.ai/es/posts/claude-code-dangerously-skip-permissions). Cambiar el modo de confirmación no concede autorización en la API interna.

## Preguntas frecuentes

### ¿Necesito MCP para conectar Claude con mi API?

No. Las herramientas directas de Messages API permiten que tu aplicación ejecute las operaciones y devuelva sus resultados. MCP aporta una interfaz reutilizable cuando distintos clientes necesitan las mismas herramientas. [Uso de herramientas en Claude API](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview).

### ¿Puede el conector MCP de la API ejecutar un servidor local stdio?

No directamente. La ruta remota habitual necesita un servidor HTTPS compatible y alcanzable. Un proceso `stdio` se ejecuta en el cliente local correspondiente, como Claude Code. Los túneles privados documentados son otra ruta, en vista previa y con acceso requerido. [Conector MCP](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) y [túneles privados](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview).

### ¿Fijar el catálogo MCP impide acceder a datos de otra organización?

No. Fija las definiciones que ve Claude, no las reglas de acceso del backend. La ejecución debe obtener el usuario y la organización de una identidad autenticada y autorizar el recurso solicitado. [Catálogo fijado en el conector de la API](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#pin-an-mcp-servers-tool-list-beta).

### ¿Basta con que Claude diga que la herramienta funcionó?

No. Para una consulta, relaciona el ID de `tool_use` con su `tool_result`, la operación de lectura y una referencia verificable del backend. Para un cambio, comprueba además la aprobación y el estado final de la operación. Una respuesta automática sin llamada puede ser válida como explicación, pero no acredita que se hayan leído datos internos.

### ¿Qué hago si una escritura agota el tiempo de espera?

Comprueba su estado mediante el ID de operación o la misma clave de idempotencia. Un timeout no demuestra que el cambio haya fallado. Si no puedes determinar el resultado, detén la repetición automática y muestra el estado desconocido; repetir con otra clave puede duplicar el efecto.

## Fuentes

Páginas externas que cita esta guía, en el orden en que aparecen. Última actualización: 2026-10-07.

- [Herramientas de cliente en Claude API](https://platform.claude.com/docs/en/agents-and-tools/tool-use/overview) (platform.claude.com)
- [conector MCP de la API](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector) (platform.claude.com)
- [conectores de usuario](https://support.claude.com/zh-CN/articles/11175166-%E4%BD%BF%E7%94%A8%E8%BF%9C%E7%A8%8B-mcp-%E5%BC%80%E5%A7%8B%E8%87%AA%E5%AE%9A%E4%B9%89%E8%BF%9E%E6%8E%A5%E5%99%A8) (support.claude.com)
- [Especificación de herramientas MCP, revisión 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/server/tools) (modelcontextprotocol.io)
- [Tratamiento oficial de llamadas a herramientas](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls) (platform.claude.com)
- [Autorización MCP](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization) (modelcontextprotocol.io)
- [túneles MCP privados](https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview) (platform.claude.com)
- [retención de datos de Claude API](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention) (platform.claude.com)
- [Configuración oficial de MCP en Claude Code](https://code.claude.com/docs/en/mcp) (code.claude.com)
- [Cambios de la revisión](https://modelcontextprotocol.io/specification/2026-07-28/changelog) (modelcontextprotocol.io)
- [metadatos de petición](https://modelcontextprotocol.io/specification/2026-07-28/basic/index) (modelcontextprotocol.io)
