On this page
Guides / Custom connectors

Custom connectors

Register your business's MCP server by its URL and choose which actions your Mets use, from code. It is the same connector as the Connections screen.

Updated View .md

A custom connector is a remote MCP server —the one for your billing system, your ERP, your inventory, or a third party's such as Notion or Shopify— registered in your workspace. Meteor asks it for its list of actions, you choose which ones stay on, and your Mets use them like any other skill.

It is the same connector as the Connections screen: what you create over the API shows up there, and what someone creates there you see over the API.

Before you start

Create one by its URL

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

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

const connector = 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(connector.id, connector.status); // '48211' 'connected'
for (const a of connector.actions) console.log(a.enabled ? '●' : '○', a.name, '→', a.key);

Before saving, Meteor asks the server for its list of actions with your credential. If the server does not answer or rejects the key, you get a 400 and nothing is created: a connector that exists is one that answered.

With auth_mode: 'api_key' the key goes in a header; X-API-Key by default, or the one you set in header. With 'none' no credential is sent.

Each action has two names: name is the server's and key is the one a Met sees (mcp_c_<slug>_<action>). The c_<slug> prefix comes from the connector's name and does not change afterwards.

From a template

For third parties' official MCP servers you do not need to type the URL:

const templates = 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 tells you whether the template asks for an extra value: subdomain or url (your own instance). If the workspace already created one, connector says which. In templates, whatever deletes, cancels or refunds money starts switched off.

Connectors with OAuth

An oauth connector is created over the API, but it is authorized in Met: consent needs a browser, and a key cannot do that. The response tells you so:

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('Ask an administrator to authorize it in Met: Conexiones → Mi CRM → Autorizar.');
}

If the server does not allow automatic app registration, create your own app in that service and send its client_id (and client_secret, if it has one).

Switch actions on and off

await met.customConnectors.setDisabledActions(connector.id, ['borrar_factura', 'anular_factura']);

You send the complete list of switched-off actions; whatever is not on the list stays on. Each connector has room for the description of its actions (space): what does not fit is imported switched off (no_room: true). Switching off is always allowed; switching on one that does not fit answers 400 CUSTOM_CONNECTOR_NO_ROOM, and you have to switch another one off first.

Test and change the key

// Lists the actions again with the saved key and updates the status.
const tested = await met.customConnectors.test(connector.id);

// The new key is tested before it is saved: if the server rejects it, the previous one stays.
await met.customConnectors.updateCredentials(connector.id, { auth_mode: 'bearer', secret: newToken });

status uses the same vocabulary as the screen: connected, needs_reauth (the server rejected the credential), error or disconnected.

The credential cannot be read

The key or token is written and never returned: it is stored encrypted, and it only travels to the URL you created the connector with. credential.configured tells you whether there is one, and credential.updated_at when it was changed. If you need the key again, keep it on your side too.

The URL's query string does not come out either: some servers carry a key there.

The contact's phone

When a Met uses an action while handling a conversation, Meteor adds the X-Meteor-Contact-Phone header to that call with the phone of the conversation's contact, exactly as it is on their record (for example +573001112233). A flow node that runs inside a conversation does the same.

Use its actions from your code

The connector's id is also its key in integrations, so you can run an action without going through a Met (scope integrations:execute):

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

In 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"])

What about met.integrations.register?

It keeps working the same. A custom connector is the recommended way to bring your MCP server: the credential is encrypted, you choose which actions are used, and the team sees it in Connections.