# Conectores propios

Un **conector propio** es un servidor MCP remoto —el de tu sistema de facturación, tu ERP, tu
inventario o uno de un tercero como Notion o Shopify— registrado en tu workspace. Meteor le pide
la lista de acciones, tú eliges cuáles quedan encendidas y tus Mets las usan como cualquier otra
habilidad.

Es **el mismo conector de la pantalla de Conexiones**: lo que creas por API aparece allá, y lo que
alguien crea allá lo ves por API.

## Antes de empezar

- La key necesita `integrations:read` para leer e `integrations:manage` para crear y cambiar.
- La key tiene que ser **de un administrador del workspace**, igual que la pantalla. Con la key de
  alguien que no lo es, recibes `403` aunque traiga los scopes.
- El servidor tiene que estar en **HTTPS** y responder en internet. Las direcciones de redes
  internas se rechazan.

## Crear uno por su URL

```ts
import Met from '@meteor.ia/sdk';

const met = new Met(process.env.METEOR_API_KEY!);

const conector = await met.customConnectors.create({
  name: 'Facturación',
  url: 'https://mcp.mi-erp.com/mcp',
  auth_mode: 'bearer', // 'none' | 'api_key' | 'bearer' | 'oauth'
  secret: process.env.ERP_TOKEN!,
});

console.log(conector.id, conector.status); // '48211' 'connected'
for (const a of conector.actions) console.log(a.enabled ? '●' : '○', a.name, '→', a.key);
```

Antes de guardar, Meteor le pide la lista de acciones al servidor **con tu credencial**. Si el
servidor no responde o rechaza la clave, recibes un `400` y no se crea nada: un conector que existe
es uno que respondió.

Con `auth_mode: 'api_key'` la clave va en un header; por defecto `X-API-Key`, o el que digas en
`header`. Con `'none'` no se manda credencial.

Cada acción tiene dos nombres: `name` es el del servidor y `key` es el que ve un Met
(`mcp_c_<slug>_<acción>`). El prefijo `c_<slug>` sale del nombre del conector y no cambia después.

## Desde una plantilla

Para los servidores MCP oficiales de terceros no hace falta escribir la URL:

```ts
const plantillas = await met.customConnectors.templates();
// [{ id: 'notion', name: 'Notion', auth_mode: 'oauth', asks_for: 'none', connector: null }, …]

await met.customConnectors.create({ template: 'freshdesk', subdomain: 'miempresa', secret: process.env.FRESHDESK_KEY! });
```

`asks_for` dice si la plantilla pide un dato extra: `subdomain` o `url` (tu propia instancia). Si el
workspace ya creó una, `connector` trae cuál es. En las plantillas, lo que borra, cancela o devuelve
plata nace **apagado**.

## Conectores con OAuth

Un conector `oauth` se crea por API, pero **se autoriza en Met**: el consentimiento necesita un
navegador, y eso no lo hace una key. La respuesta lo dice:

```ts
const c = await met.customConnectors.create({ name: 'Mi CRM', url: 'https://mcp.mi-crm.com/mcp', auth_mode: 'oauth' });
if (c.requires_authorization) {
  console.log('Pídele a un administrador que lo autorice en Met: Conexiones → Mi CRM → Autorizar.');
}
```

Si el servidor no permite el registro automático de apps, crea la tuya en ese servicio y manda su
`client_id` (y `client_secret`, si tiene).

## Encender y apagar acciones

```ts
await met.customConnectors.setDisabledActions(conector.id, ['borrar_factura', 'anular_factura']);
```

Se manda la lista **completa** de las apagadas; lo que no esté en la lista queda encendido. Cada
conector tiene un espacio para la descripción de sus acciones (`space`): lo que no cabe se importa
apagado (`no_room: true`). Apagar siempre se puede; encender una que no cabe responde
`400 CUSTOM_CONNECTOR_NO_ROOM`, y hay que apagar otra primero.

## Probar y cambiar la clave

```ts
// Vuelve a listar las acciones con la clave guardada y actualiza el estado.
const probado = await met.customConnectors.test(conector.id);

// La clave nueva se prueba antes de guardarla: si el servidor la rechaza, queda la anterior.
await met.customConnectors.updateCredentials(conector.id, { auth_mode: 'bearer', secret: nuevoToken });
```

`status` usa el mismo vocabulario que la pantalla: `connected`, `needs_reauth` (el servidor rechazó
la credencial), `error` o `disconnected`.

## La credencial no se lee

La clave o el token se escriben y **nunca se devuelven**: van cifrados, y solo viajan a la URL con
que creaste el conector. `credential.configured` te dice si hay una, y `credential.updated_at`
cuándo se cambió. Si necesitas la clave de nuevo, guárdala también de tu lado.

Tampoco sale la query de la URL: hay servidores que llevan una clave ahí.

## Usar sus acciones desde tu código

El `id` del conector es también su `key` en las integraciones, así que puedes ejecutar una acción
sin pasar por un Met (scope `integrations:execute`):

```ts
await met.integrations.execute(conector.id, 'crear_factura', { cliente: 'Panadería Luz', total: 120000 });
```

## En Python

```python
from meteor_ia import Met

met = Met("met_live_…")
c = met.custom_connectors.create(name="Facturación", url="https://mcp.mi-erp.com/mcp", auth_mode="bearer", secret=token)
met.custom_connectors.set_disabled_actions(c["id"], ["borrar_factura"])
```

## ¿Y `met.integrations.register`?

Sigue funcionando igual. Un conector propio es la forma recomendada de traer tu servidor MCP: la
credencial va cifrada, eliges qué acciones se usan y el equipo lo ve en Conexiones.
