# Servidor MCP (Model Context Protocol)

El servidor MCP de Salescaling permite que agentes de IA como Claude, Cursor y otros clientes compatibles con el protocolo MCP accedan a tus datos de reuniones, transcripciones y resúmenes de forma estructurada y segura.

## ¿Qué es MCP?

Model Context Protocol (MCP) es un protocolo estándar que permite a los modelos de lenguaje (LLMs) interactuar con sistemas externos de forma estructurada. El servidor MCP de Salescaling implementa este protocolo para exponer tus datos de reuniones a través de herramientas que los agentes de IA pueden usar.

## Características

* ✅ **Spec-Compliant**: Implementación completa del protocolo MCP oficial
* ✅ **11 Herramientas Disponibles**: Reuniones (videollamada y presencial), llamadas telefónicas, búsqueda, listados, transcripción, resumen con action items, detalle, estadísticas y más
* ✅ **Búsqueda Avanzada**: Full Text Search con PostgreSQL para búsquedas semánticas con índices GIN optimizados
* ✅ **Control de Payload**: Límites configurables para evitar overflow de contexto
* ✅ **Autenticación Segura**: API key de Salescaling u **OAuth Clients** (Authorization Code + PKCE)
* ✅ **Multi-tenant**: Aislamiento automático por organización
* ✅ **Alto Rendimiento**: Optimizado para millones de filas con índices GIN y control de concurrencia

## Endpoints MCP

El servidor MCP expone dos endpoints principales:

### GET `/api/v1/mcp` - Listar Herramientas

Retorna la lista de herramientas disponibles con sus esquemas de entrada.

**Ejemplo:**

```bash
curl -X GET https://api.salescaling.com/api/v1/mcp \
  -H "X-API-Key: sk_xxx"
```

### POST `/api/v1/mcp` - Ejecutar Herramienta

Ejecuta una herramienta específica con los argumentos proporcionados.

**Ejemplo:**

```bash
curl -X POST https://api.salescaling.com/api/v1/mcp \
  -H "X-API-Key: sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "search_meetings",
    "arguments": {
      "query": "performance",
      "limit": 10
    }
  }'
```

## Conexión MCP vía OAuth Clients

Además de la API key, puedes conectar clientes MCP que soporten **OAuth 2.0** (flujo *Authorization Code* con **PKCE**). Los clientes OAuth se registran de forma **explícita** en Salescaling (no hay registro dinámico de clientes en el servidor de autorización).

### Requisitos

* Cuenta con permisos para gestionar **OAuth Clients** (normalmente administradores de la organización).
* El cliente MCP debe poder completar el flujo OAuth en el navegador y enviar `Authorization: Bearer <access_token>` al servidor MCP.

### Configurar el cliente en Salescaling

1. En la plataforma, ve a **Configuración → OAuth Clients** (o **Settings → OAuth Clients**).
2. Crea un nuevo cliente OAuth.
3. Añade las **Redirect URIs** permitidas. Para **Claude (Anthropic)** usa exactamente:

   `https://claude.ai/api/mcp/auth_callback`
4. Asigna los **scopes** que necesite el MCP (como mínimo `meetings:read` para las herramientas actuales de reuniones).
5. Guarda el cliente y copia el **`client_id`** (y el secreto solo si creaste un cliente confidencial; muchos clientes MCP usan cliente público con PKCE).

### Metadatos del servidor de autorización

Salescaling expone metadatos compatibles con descubrimiento OpenID en el propio endpoint MCP:

* `GET https://api.salescaling.com/api/v1/mcp/.well-known/openid-configuration`

Ahí encontrarás `issuer`, `authorization_endpoint`, `token_endpoint`, `revocation_endpoint` y scopes soportados (sustituye el host si usas otro entorno).

### Ejemplo: MCP para Claude con OAuth

Tras crear el OAuth Client con la redirect anterior, configura el cliente MCP con la URL del servidor MCP y los endpoints OAuth (ajusta dominios si tu tenant usa otra URL de app):

```json
{
  "mcpServers": {
    "salescaling": {
      "url": "https://api.salescaling.com/api/v1/mcp",
      "oauth": {
        "authorizationUrl": "https://app.salescaling.com/oauth/authorize",
        "tokenUrl": "https://api.salescaling.com/v1/oauth/token",
        "clientId": "<client_id_creado_en_oauth_clients>",
        "scopes": ["meetings:read"]
      }
    }
  }
}
```

**Resumen de URLs típicas**

| Uso                                     | URL                                           |
| --------------------------------------- | --------------------------------------------- |
| Servidor MCP                            | `https://api.salescaling.com/api/v1/mcp`      |
| Autorización (login usuario)            | `https://app.salescaling.com/oauth/authorize` |
| Token (intercambio código / refresh)    | `https://api.salescaling.com/v1/oauth/token`  |
| Redirect URI en Salescaling para Claude | `https://claude.ai/api/mcp/auth_callback`     |

Las peticiones al MCP usarán el token de acceso en el header `Authorization: Bearer …` en lugar de `X-API-Key`.

## Reuniones vs llamadas telefónicas

Salescaling guarda **videollamadas**, **reuniones presenciales** y **llamadas telefónicas** en la misma entidad de reunión. Para que la API MCP sea clara:

* Las herramientas cuyo nombre incluye **`meetings`** (`search_meetings`, `list_meetings`, `find_meetings_by_participant`) solo incluyen **videollamadas y presenciales** (no devuelven llamadas telefónicas).
* Las herramientas **`list_calls`**, **`search_calls`** y **`find_calls_by_participant`** están dedicadas a **llamadas telefónicas** y admiten filtros como dirección (`INBOUND` / `OUTBOUND`) y números de teléfono.
* **`get_meeting_transcript`**, **`get_meeting_summary`**, **`get_meeting_details`** y **`get_meeting_action_items`** funcionan con **cualquier** ID de reunión o llamada (el mismo identificador).

## Herramientas Disponibles

### 1. `search_meetings` - Búsqueda Avanzada

Busca **videollamadas y reuniones presenciales** por texto en títulos y/o transcripciones (Full Text Search). **No incluye llamadas telefónicas**; para eso usa `search_calls`.

**Parámetros:**

| Parámetro  | Tipo   | Requerido | Descripción                                   |
| ---------- | ------ | --------- | --------------------------------------------- |
| `query`    | string | Sí        | Término de búsqueda                           |
| `scope`    | string | No        | `title`, `sentences` o `all` (default: `all`) |
| `fromDate` | string | No        | Fecha inicio (YYYY-MM-DD)                     |
| `toDate`   | string | No        | Fecha fin (YYYY-MM-DD)                        |
| `limit`    | number | No        | Máximo 50 (default: 20)                       |

**Nota:** Solo actividades de tipo videollamada o presencial.

**Ejemplo:**

```json
{
  "name": "search_meetings",
  "arguments": {
    "query": "performance review",
    "scope": "all",
    "fromDate": "2024-12-01",
    "limit": 10
  }
}
```

### 2. `list_meetings` - Listar Reuniones

Lista **videollamadas y reuniones presenciales** con filtros estructurados (excluye llamadas telefónicas).

**Parámetros:**

| Parámetro      | Tipo      | Requerido | Descripción                                                  |
| -------------- | --------- | --------- | ------------------------------------------------------------ |
| `keyword`      | string    | No        | Búsqueda en nombres / título                                 |
| `fromDate`     | string    | No        | Fecha inicio                                                 |
| `toDate`       | string    | No        | Fecha fin                                                    |
| `limit`        | number    | No        | Máximo 50 (default: 20)                                      |
| `skip`         | number    | No        | Paginación (default: 0)                                      |
| `sortOrder`    | string    | No        | `asc` o `desc` — orden por fecha de inicio (default: `desc`) |
| `participants` | string\[] | No        | Emails de participantes                                      |
| `organizers`   | string\[] | No        | Emails de organizadores                                      |

**Ejemplo:**

```json
{
  "name": "list_meetings",
  "arguments": {
    "fromDate": "2024-12-01",
    "toDate": "2024-12-31",
    "participants": ["cliente@empresa.com"],
    "limit": 20
  }
}
```

### 3. `get_meeting_transcript` - Obtener Transcripción

Obtiene la transcripción detallada con atribución de speakers (reunión o llamada).

**Parámetros:**

| Parámetro      | Tipo   | Requerido | Descripción                              |
| -------------- | ------ | --------- | ---------------------------------------- |
| `transcriptId` | string | Sí        | ID de la reunión o llamada               |
| `language`     | string | No        | Código de idioma (ej: "es", "en")        |
| `maxSentences` | number | No        | Límite de oraciones (control de payload) |

**Control de Payload:**

* Auto-trunca en 10,000 oraciones si no se especifica `maxSentences`
* Indica en la respuesta si se truncó el contenido

**Ejemplo:**

```json
{
  "name": "get_meeting_transcript",
  "arguments": {
    "transcriptId": "meeting-uuid-here",
    "language": "es",
    "maxSentences": 100
  }
}
```

### 4. `get_meeting_summary` - Obtener Resumen

Obtiene el resumen generado por IA: texto (`summaryText`), **action items** (`actionItems` / `next_steps`), y según el tipo, **topics/highlights** (reuniones) o **call insights** (llamadas).

**Parámetros:**

| Parámetro      | Tipo   | Requerido | Descripción                |
| -------------- | ------ | --------- | -------------------------- |
| `transcriptId` | string | Sí        | ID de la reunión o llamada |
| `language`     | string | No        | Código de idioma           |

**Ejemplo:**

```json
{
  "name": "get_meeting_summary",
  "arguments": {
    "transcriptId": "meeting-uuid-here",
    "language": "es"
  }
}
```

### 5. `get_meeting_details` - Detalles Completos

Obtiene detalles completos de una reunión (metadatos + transcripción + resumen).

**Parámetros:**

| Parámetro           | Tipo    | Requerido | Descripción                           |
| ------------------- | ------- | --------- | ------------------------------------- |
| `id`                | string  | Sí        | ID de la reunión                      |
| `includeTranscript` | boolean | No        | Incluir transcripción (default: true) |
| `includeSummary`    | boolean | No        | Incluir resumen (default: true)       |
| `maxSentences`      | number  | No        | Límite de oraciones en transcript     |

**Ejemplo:**

```json
{
  "name": "get_meeting_details",
  "arguments": {
    "id": "meeting-uuid-here",
    "includeTranscript": true,
    "includeSummary": true,
    "maxSentences": 500
  }
}
```

### 6. `find_meetings_by_participant` - Buscar Reuniones por Participante

Encuentra reuniones donde participó una persona específica. Busca por nombre (coincidencia parcial) o email (coincidencia exacta).

**Parámetros:**

| Parámetro     | Tipo   | Requerido | Descripción                                                          |
| ------------- | ------ | --------- | -------------------------------------------------------------------- |
| `participant` | string | Sí        | Nombre o email del participante                                      |
| `fromDate`    | string | No        | Fecha inicio (YYYY-MM-DD)                                            |
| `toDate`      | string | No        | Fecha fin (YYYY-MM-DD)                                               |
| `limit`       | number | No        | Máximo 50 (default: 20)                                              |
| `skip`        | number | No        | Paginación (default: 0)                                              |
| `sortOrder`   | string | No        | `asc` o `desc` por fecha de inicio (default: `desc`)                 |
| `titleFilter` | string | No        | Filtro opcional sobre el título de la reunión (coincidencia parcial) |

**Características:**

* Solo **videollamadas y presenciales** (no llamadas telefónicas).
* **Búsqueda por email**: Coincidencia exacta (case-insensitive)
  * Ejemplo: `jon@empresa.com` encontrará solo ese email exacto
* **Búsqueda por nombre**: Coincidencia parcial
  * Ejemplo: `Jon` encontrará "Jon Smith", "Jonathan", "Jon Doe", etc.
* Retorna información completa de participantes y organizador
* Orden configurable con `sortOrder`

**Ejemplos:**

Buscar por email:

```json
{
  "name": "find_meetings_by_participant",
  "arguments": {
    "participant": "jon@empresa.com",
    "fromDate": "2024-12-01",
    "limit": 20
  }
}
```

Buscar por nombre:

```json
{
  "name": "find_meetings_by_participant",
  "arguments": {
    "participant": "Jon",
    "fromDate": "2024-01-01",
    "toDate": "2024-12-31",
    "limit": 50
  }
}
```

### 7. `list_calls` - Listar llamadas telefónicas

Lista solo **llamadas telefónicas** (`phonecall`), con filtros por fechas, título, participantes, dirección y números.

| Parámetro                 | Tipo      | Requerido | Descripción                                     |
| ------------------------- | --------- | --------- | ----------------------------------------------- |
| `titleFilter`             | string    | No        | Coincidencia parcial en el nombre/título        |
| `fromDate` / `toDate`     | string    | No        | Rango de fechas (YYYY-MM-DD)                    |
| `limit`                   | number    | No        | Máximo 50 (default: 20)                         |
| `skip`                    | number    | No        | Paginación                                      |
| `sortOrder`               | string    | No        | `asc` o `desc` (default: `desc`)                |
| `direction`               | string    | No        | `INBOUND` o `OUTBOUND`                          |
| `participants`            | string\[] | No        | Emails de participantes                         |
| `fromNumber` / `toNumber` | string    | No        | Filtro parcial por número de llamante o destino |

### 8. `search_calls` - Buscar en llamadas

Búsqueda en títulos y/o transcripciones **solo para llamadas telefónicas**. Parámetros similares a `search_meetings`, más `direction`, `fromNumber`, `toNumber` opcionales.

### 9. `find_calls_by_participant` - Llamadas por participante

Igual que `find_meetings_by_participant` pero solo para **llamadas telefónicas**, con los mismos filtros extra que `list_calls` (`titleFilter`, `sortOrder`, `direction`, números).

### 10. `get_meeting_action_items` - Action items del resumen

Devuelve los **next steps** estructurados del resumen IA para un ID de reunión o llamada.

| Parámetro   | Tipo   | Requerido |
| ----------- | ------ | --------- |
| `meetingId` | string | Sí        |
| `language`  | string | No        |

### 11. `get_meetings_statistics` - Estadísticas agregadas

Totales, duraciones medias por tipo de actividad, y **top participantes** (muestra acotada). Ámbito configurable:

| Parámetro             | Tipo   | Descripción                                                               |
| --------------------- | ------ | ------------------------------------------------------------------------- |
| `fromDate` / `toDate` | string | Rango opcional                                                            |
| `type`                | string | `meetings` (video+presencial), `calls` (solo teléfono), o `all` (default) |

## Configuración en Clientes MCP

Para **OAuth** (incluido Claude con redirect `https://claude.ai/api/mcp/auth_callback`), sigue la sección [Conexión MCP vía OAuth Clients](#mcp-oauth-clients).

### Claude Desktop (API Key)

1. Localiza tu archivo de configuración:
   * **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
   * **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
2. Agrega la configuración del servidor MCP:

```json
{
  "mcpServers": {
    "salescaling": {
      "url": "https://api.salescaling.com/api/v1/mcp",
      "headers": {
        "X-API-Key": "sk_tu_api_key_aqui"
      }
    }
  }
}
```

3. Reinicia Claude Desktop
4. Verifica que el servidor esté conectado:
   * Busca el ícono de herramientas en la interfaz
   * Deberías ver "salescaling" como servidor disponible
   * Las 11 herramientas deberían aparecer listadas

### Cursor IDE

1. Abre la configuración de Cursor (`Cmd/Ctrl + ,`)
2. Busca "MCP Servers" en la configuración
3. Agrega el servidor de Salescaling:

```json
{
  "mcp.servers": {
    "salescaling": {
      "url": "https://api.salescaling.com/api/v1/mcp",
      "headers": {
        "X-API-Key": "sk_tu_api_key_aqui"
      }
    }
  }
}
```

4. Reinicia Cursor
5. Usa el servidor desde el chat de Cursor:
   * Menciona "@salescaling" en el chat
   * O pide directamente: "Busca reuniones sobre performance"

### Otros Clientes MCP

Para cualquier cliente compatible con MCP:

1. **URL del servidor**: `https://api.salescaling.com/api/v1/mcp`
2. **Autenticación**: Header `X-API-Key` con tu API key
3. **Protocolo**: HTTP/HTTPS estándar
4. **Formato**: JSON

## Ejemplos de Uso

### Ejemplo 1: Buscar Reuniones con Claude

```
Usuario: "Busca reuniones sobre pricing del último mes"

Claude → POST /api/v1/mcp
{
  "name": "search_meetings",
  "arguments": {
    "query": "pricing",
    "scope": "all",
    "fromDate": "2024-12-01",
    "limit": 20
  }
}

Claude: "Encontré 5 reuniones sobre pricing:
1. Reunión de pricing con Acme Corp - 15 dic 2024
2. Review de estrategia de precios - 10 dic 2024
..."
```

### Ejemplo 2: Obtener Transcripción Completa

```
Usuario: "Dame la transcripción completa de la reunión con ID abc-123"

Claude → POST /api/v1/mcp
{
  "name": "get_meeting_transcript",
  "arguments": {
    "transcriptId": "abc-123",
    "language": "es"
  }
}

Claude: "Aquí está la transcripción de la reunión:
[00:00 - 00:15] Juan Pérez: Buenos días a todos..."
```

### Ejemplo 3: Análisis de Múltiples Reuniones

```
Usuario: "Analiza las reuniones de ventas de diciembre y dame insights"

Claude:
1. Lista reuniones → list_meetings (diciembre)
2. Para cada reunión → get_meeting_summary
3. Analiza patrones y genera insights

Claude: "He analizado 15 reuniones de diciembre:
- Temas más discutidos: pricing (8), implementación (6)
- Objeciones comunes: tiempo de implementación (5)
- Oportunidades identificadas: 3 cuentas enterprise..."
```

## Formato de Respuesta

Todas las herramientas retornan respuestas en formato MCP estándar:

```json
{
  "content": [
    {
      "type": "text",
      "text": "Descripción legible del resultado"
    },
    {
      "type": "resource",
      "resource": {
        "uri": "salescaling://meeting/xxx",
        "mimeType": "application/json",
        "text": "{...datos JSON estructurados...}"
      }
    }
  ]
}
```

## Seguridad y Privacidad

### Autenticación

* Las peticiones requieren **API key** (`X-API-Key`) **o** un **access token OAuth** (`Authorization: Bearer`) emitido para un OAuth Client autorizado
* Las API keys se gestionan desde **Configuración > API Keys**; los clientes OAuth desde **Configuración > OAuth Clients**
* Cada credencial está vinculada a tu organización (tenant)

### Aislamiento de Datos

* El servidor MCP respeta el aislamiento multi-tenant
* Solo puedes acceder a reuniones de tu organización
* Los permisos de OpenFGA se aplican automáticamente

### Mejores Prácticas

1. **Nunca compartas tu API key**: Trátala como una contraseña
2. **Usa variables de entorno**: No hardcodees la key en archivos
3. **Rota las keys periódicamente**: Crea nuevas keys y elimina las antiguas
4. **Establece fechas de expiración**: Para keys temporales o de prueba
5. **Monitorea el uso**: Revisa los logs de acceso regularmente

## Límites y Cuotas

### Rate Limiting

El servidor MCP comparte los mismos límites de la API pública:

* **Corto plazo**: 35 peticiones por segundo
* **Mediano plazo**: 200 peticiones cada 10 segundos
* **Largo plazo**: 1000 peticiones por minuto

### Límites de Payload

* **Transcripciones**: Auto-trunca en 10,000 oraciones
* **Búsquedas**: Máximo 50 resultados por petición
* **Listados**: Máximo 50 reuniones por petición

Usa el parámetro `maxSentences` para controlar el tamaño de las transcripciones.

## Troubleshooting

### Error: "Unauthorized - missing or invalid API key"

**Causa**: API key no válida o no proporcionada

**Solución**:

1. Verifica que el header `X-API-Key` esté presente
2. Confirma que la key sea válida en **Configuración > API Keys**
3. Verifica que la key no haya expirado

### Error: "Unknown tool: xxx"

**Causa**: Nombre de herramienta incorrecto

**Solución**:

1. Verifica el nombre de la herramienta (case-sensitive)
2. Usa `GET /api/v1/mcp` para ver las herramientas disponibles
3. Nombres válidos (entre otros): `search_meetings`, `list_meetings`, `get_meeting_transcript`, `get_meeting_summary`, `get_meeting_details`, `find_meetings_by_participant`, `list_calls`, `search_calls`, `find_calls_by_participant`, `get_meeting_action_items`, `get_meetings_statistics`

### Error: "Meeting not found"

**Causa**: ID de reunión no existe o no tienes acceso

**Solución**:

1. Verifica que el ID sea correcto
2. Confirma que la reunión pertenezca a tu organización
3. Usa `list_meetings` para obtener IDs válidos

### El servidor no aparece en Claude Desktop

**Solución**:

1. Verifica que el archivo de configuración esté en la ubicación correcta
2. Revisa que el JSON sea válido (sin errores de sintaxis)
3. Reinicia Claude Desktop completamente
4. Revisa los logs de Claude Desktop para errores

### Respuestas muy largas o timeouts

**Solución**:

1. Usa `maxSentences` para limitar transcripciones
2. Reduce el `limit` en búsquedas y listados
3. Usa `includeTranscript: false` si solo necesitas el resumen
4. Filtra por fechas para reducir el conjunto de datos

## Soporte

¿Necesitas ayuda con el servidor MCP?

* **Email**: <support@salescaling.com>
* **Documentación API**: <https://api.salescaling.com/api/docs>
* **Slack de la comunidad**: [Únete aquí](https://salescaling.com/slack)

## Recursos Adicionales

* [Especificación MCP Oficial](https://modelcontextprotocol.io)
* [API Pública de Salescaling](/api/introduction.md)
* [Gestión de API Keys](https://github.com/salescaling/web-platform/blob/main/apps/docs/configuraciones-de-la-plataforma/configuraciones-tecnicas/api-keys.md)
* [Webhooks](/api/webhooks.md)

***

**Última actualización**: Abril 2026


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.salescaling.com/api/mcp-server.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
