*MCP › Conectar*

# Crea tu propio cliente

> Usa los SDK oficiales de MCP o los conectores MCP de las APIs de Anthropic y OpenAI.

## SDK oficiales

Con este servidor, `Client.callTool` del SDK de TypeScript y `call_tool` del de Python devuelven los éxitos y los errores sin lanzar `-32602`. Filmo lo ha comprobado con `@modelcontextprotocol/sdk` 1.26.0 y 1.32.1, `@modelcontextprotocol/client` 2.3.1 y `mcp` 2.3.0 y 1.27.1. Cómo se lee un error está en [Errores](https://docs.filmo.io/es/mcp/guides/errors).

*Llamar a una herramienta con una clave*

**TypeScript**

```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(new URL("https://app.filmo.io/api/v1/mcp"), {
  requestInit: { headers: { Authorization: `Bearer ${process.env.FILMO_API_KEY}` } },
});
const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(transport);

const result = await client.callTool({ name: "filmo_orders_list", arguments: { limit: 20 } });
if (result.isError) {
  // A tool error: the problem is JSON in the first text block, and there is no structuredContent.
  const problem = JSON.parse((result.content as { text: string }[])[0].text);
  console.error(problem.code, problem.detail);
} else {
  console.log(result.structuredContent); // { data, meta }
}
```

**Python**

```python
import asyncio, json, os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def main():
    headers = {"Authorization": f"Bearer {os.environ['FILMO_API_KEY']}"}
    async with streamablehttp_client("https://app.filmo.io/api/v1/mcp", headers=headers) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("filmo_orders_list", arguments={"limit": 20})
            if result.isError:
                # A tool error: the problem is JSON in the first text block.
                problem = json.loads(result.content[0].text)
                print(problem["code"], problem["detail"])
            else:
                print(result.structuredContent)  # {"data": ..., "meta": ...}

asyncio.run(main())
```

Los paquetes de la línea 2 de los SDK (`@modelcontextprotocol/client`, `mcp` 2.x con `result.is_error` y `httpx2`) tienen otra API; el contrato del servidor es el mismo.

## Conectores MCP de las APIs de LLM

Las dos APIs admiten un servidor MCP remoto. Las listas de abajo salen del catálogo: son las herramientas de lectura del preset recomendado y las que piden confirmación humana.

**Anthropic**

```json
{
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://app.filmo.io/api/v1/mcp",
      "name": "filmo",
      "authorization_token": "<FILMO_API_KEY>"
    }
  ],
  "tools": [
    {
      "type": "mcp_toolset",
      "mcp_server_name": "filmo",
      "default_config": {
        "enabled": false
      },
      "configs": {
        "filmo_items_list": {
          "enabled": true
        },
        "filmo_items_get": {
          "enabled": true
        },
        "filmo_availability_check": {
          "enabled": true
        },
        "filmo_serialized_items_list": {
          "enabled": true
        },
        "filmo_serialized_items_get": {
          "enabled": true
        },
        "filmo_spaces_list": {
          "enabled": true
        },
        "filmo_spaces_get": {
          "enabled": true
        },
        "filmo_vehicles_list": {
          "enabled": true
        },
        "filmo_vehicles_get": {
          "enabled": true
        },
        "filmo_staff_list": {
          "enabled": true
        },
        "filmo_staff_get": {
          "enabled": true
        },
        "filmo_staff_availability_check": {
          "enabled": true
        },
        "filmo_vehicles_availability_check": {
          "enabled": true
        },
        "filmo_kits_list": {
          "enabled": true
        },
        "filmo_kits_get": {
          "enabled": true
        },
        "filmo_planner_services_list": {
          "enabled": true
        },
        "filmo_schedule_get": {
          "enabled": true
        },
        "filmo_unavailabilities_list": {
          "enabled": true
        },
        "filmo_planner_resources_list": {
          "enabled": true
        },
        "filmo_account_get": {
          "enabled": true
        }
      }
    }
  ]
}
```

**OpenAI**

```json
{
  "type": "mcp",
  "server_label": "filmo",
  "server_url": "https://app.filmo.io/api/v1/mcp",
  "authorization": "<FILMO_API_KEY>",
  "allowed_tools": [
    "filmo_items_list",
    "filmo_items_get",
    "filmo_availability_check",
    "filmo_serialized_items_list",
    "filmo_serialized_items_get",
    "filmo_spaces_list",
    "filmo_spaces_get",
    "filmo_vehicles_list",
    "filmo_vehicles_get",
    "filmo_staff_list",
    "filmo_staff_get",
    "filmo_staff_availability_check",
    "filmo_vehicles_availability_check",
    "filmo_kits_list",
    "filmo_kits_get",
    "filmo_planner_services_list",
    "filmo_schedule_get",
    "filmo_unavailabilities_list",
    "filmo_planner_resources_list",
    "filmo_account_get"
  ],
  "require_approval": {
    "never": {
      "tool_names": [
        "filmo_items_list",
        "filmo_items_get",
        "filmo_availability_check",
        "filmo_serialized_items_list",
        "filmo_serialized_items_get",
        "filmo_spaces_list",
        "filmo_spaces_get",
        "filmo_vehicles_list",
        "filmo_vehicles_get",
        "filmo_staff_list",
        "filmo_staff_get",
        "filmo_staff_availability_check",
        "filmo_vehicles_availability_check",
        "filmo_kits_list",
        "filmo_kits_get",
        "filmo_planner_services_list",
        "filmo_schedule_get",
        "filmo_unavailabilities_list",
        "filmo_planner_resources_list",
        "filmo_account_get"
      ]
    }
  }
}
```

Anthropic exige la cabecera `anthropic-beta: mcp-client-2025-11-20`; el campo `authorization_token` es el token Bearer. OpenAI no documenta una cabecera propia: solo `authorization`. En OpenAI, `require_approval` con `never` solo para las herramientas de lectura deja todo lo demás pidiendo aprobación.

**Herramientas que piden confirmación humana (para tu lista de aprobación)**

```json
[
  "filmo_contacts_delete",
  "filmo_contacts_update",
  "filmo_contacts_address_delete",
  "filmo_contacts_related_remove",
  "filmo_items_delete",
  "filmo_spaces_delete",
  "filmo_spaces_amenities_replace",
  "filmo_vehicles_delete",
  "filmo_staff_delete",
  "filmo_tags_delete",
  "filmo_tags_assignment_remove",
  "filmo_planner_assignment_remove",
  "filmo_unavailabilities_delete",
  "filmo_tasks_delete",
  "filmo_purchase_orders_receive",
  "filmo_repair_tickets_update",
  "filmo_treasury_payments_create",
  "filmo_orders_cancel",
  "filmo_items_accessories_update",
  "filmo_items_alternatives_update",
  "filmo_orders_line_items_return",
  "filmo_ai_ask",
  "filmo_workflows_run",
  "filmo_orders_unreserve",
  "filmo_projects_orders_unlink",
  "filmo_invoices_validate",
  "filmo_invoices_void",
  "filmo_credit_notes_validate",
  "filmo_credit_notes_void",
  "filmo_contracts_validate",
  "filmo_contracts_sign",
  "filmo_contracts_void",
  "filmo_contracts_cancel",
  "filmo_supplier_invoices_validate",
  "filmo_supplier_invoices_void"
]
```

> **Atención:** No pegues la clave en el código ni en un fichero del repositorio: léela de un almacén de secretos o del entorno.

---

URL canónica: https://docs.filmo.io/es/mcp/connect/build-your-own  
Última actualización: 2026-10-25