npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hornerosssp

v0.11.0

Published

SDK and CLI for HornerosSSP - integrate MCPs into any app

Downloads

1,435

Readme

HornerosSSP SDK

SDK oficial para integrar HornerosSSP en tu aplicacion. Permite conectar usuarios de tu app a integraciones como Kommo CRM, Chatwoot, NotebookLM, MercadoPago, TiendaNube, Correo Argentino y ARCA.

Instalacion

npm install hornerosssp

Inicio Rapido

import { HornerosSSP } from "hornerosssp";

// Inicializar cliente con tu API key
const client = new HornerosSSP({
  apiKey: "hsp_tu_api_key_aqui"
});

// Listar integraciones disponibles
const mcps = await client.mcps.list();
// [{ slug: "kommo-mcp", name: "Kommo CRM", ... }, ...]

// Crear conexion para un usuario de tu app
const conn = await client.connections.initiate({
  mcpSlug: "kommo-mcp",
  entityId: "user_123",  // ID del usuario en TU app
  credentials: {
    access_token: "token_del_usuario",
    base_domain: "empresa.kommo.com"
  }
});

// Ejecutar herramienta
const result = await client.tools.execute({
  mcpSlug: "kommo-mcp",
  entityId: "user_123",
  toolName: "get_leads",
  arguments: { limit: 10 }
});

Conceptos Clave

API Key

Tu API key (hsp_xxx) identifica a tu aplicacion. Obtenla desde el dashboard de HornerosSSP.

Entity ID

El entityId es el identificador del usuario final en TU aplicacion. Cada usuario puede tener sus propias conexiones a diferentes integraciones.

Conexiones

Una conexion almacena las credenciales de un usuario para una integracion especifica. Por ejemplo, si el usuario "user_123" conecta su cuenta de Kommo, las credenciales se guardan asociadas a ese entity.

API Reference

Listar MCPs Disponibles

const mcps = await client.mcps.list();

Retorna todas las integraciones disponibles. No requiere configuracion previa.

Respuesta:

[
  {
    slug: "kommo-mcp",
    name: "Kommo CRM",
    description: "Gestiona leads, contactos y mensajes...",
    requiredCredentials: ["access_token", "base_domain"],
    toolCount: 11,
    category: "CRM"
  },
  // ...
]

Obtener Detalle de un MCP

const mcp = await client.mcps.get("kommo-mcp");

Respuesta:

{
  slug: "kommo-mcp",
  name: "Kommo CRM",
  description: "...",
  requiredCredentials: ["access_token", "base_domain"],
  tools: [
    { name: "get_leads", description: "Obtiene lista de leads" },
    // ...
  ]
}

Crear Conexion

const conn = await client.connections.initiate({
  mcpSlug: "kommo-mcp",         // Requerido: slug del MCP
  entityId: "user_123",          // Requerido: ID del usuario en tu app
  credentials: {                 // Requerido: credenciales del usuario
    access_token: "xxx",
    base_domain: "empresa.kommo.com"
  },
  appName: "Mi App"              // Opcional: nombre descriptivo
});

Respuesta:

{
  id: "conn_abc123",
  mcpSlug: "kommo-mcp",
  entityId: "user_123",
  mcpUrl: "https://hornerosssp.com/api/mcp/kommo-mcp/conn_abc123",
  token: "tok_xxxxx",  // Solo se muestra una vez
  status: "active"
}

Listar Conexiones

// Todas las conexiones
const connections = await client.connections.list();

// Filtrar por entity
const userConns = await client.connections.list("user_123");

// Filtrar por entity y MCP
const specific = await client.connections.list("user_123", "kommo-mcp");

Buscar Conexion por Entity

const conn = await client.connections.getByEntity("user_123", "kommo-mcp");
if (conn) {
  // El usuario ya tiene conexion
}

Revocar Conexion

await client.connections.revoke("conn_abc123");

Ejecutar Herramienta

Hay dos formas de identificar la conexion:

Opcion 1: Por entityId (recomendado)

const result = await client.tools.execute({
  mcpSlug: "kommo-mcp",
  entityId: "user_123",      // Busca la conexion automaticamente
  toolName: "get_leads",
  arguments: { limit: 10 }
});

Opcion 2: Por connectionId

const result = await client.tools.execute({
  mcpSlug: "kommo-mcp",
  connectionId: "conn_abc123",
  toolName: "get_leads",
  arguments: { limit: 10 }
});

Respuesta:

{
  content: [
    { type: "text", text: "[{\"id\": 1, \"name\": \"Lead 1\"}, ...]" }
  ],
  isError: false
}

Listar Herramientas de un MCP

const tools = await client.tools.list("kommo-mcp");
// [{ name: "get_leads", description: "...", inputSchema: {...} }, ...]

Conexiones OAuth (Kommo, Google, etc.)

Para MCPs que soportan OAuth (como Kommo), puedes permitir que tus usuarios conecten sus propias cuentas sin que tengas que pedirles tokens manualmente.

Flujo OAuth

  1. Tu creas UNA integracion OAuth en el servicio (ej: Kommo)
  2. Multiples usuarios de tu app pueden conectar sus propias cuentas usando tus credenciales OAuth
  3. Cada usuario tiene su propia conexion con sus propios tokens

Es decir: con un solo client_id/client_secret, puedes conectar muchas cuentas de usuarios diferentes.

Configuracion Previa (IMPORTANTE)

Antes de usar OAuth, debes configurar el Redirect URI en tu integracion:

https://hornerossp.vercel.app/api/v1/oauth/callback

Para Kommo:

  1. Ve a Settings → Integrations → Tu Integracion
  2. En "Redirect URI", agrega: https://hornerossp.vercel.app/api/v1/oauth/callback
  3. Guarda los cambios

Para Google (NotebookLM):

  1. Ve a Google Cloud Console → APIs & Services → Credentials
  2. En tu OAuth Client, agrega el URI de redireccion autorizado
  3. Guarda los cambios

Ejemplo OAuth con Kommo

// 1. Obtener info de campos requeridos (opcional pero util)
const info = await client.connections.getOAuthInfo("kommo-mcp");
console.log(info.fields.initiationData.required);
// [{ name: "subdomain", description: "Solo el subdominio, ej: 'miempresa'" }]

// 2. Iniciar flujo OAuth
const oauth = await client.connections.initiateOAuth({
  mcpSlug: "kommo-mcp",
  entityId: "user_123",  // El usuario en TU app
  authConfig: {
    client_id: "tu_kommo_client_id",
    client_secret: "tu_kommo_client_secret",
  },
  initiationData: {
    subdomain: "miempresa"  // SOLO el subdominio, no la URL completa
  }
});

// 3. Redirigir al usuario al popup de autorizacion
window.open(oauth.redirectUrl, '_blank', 'width=600,height=700');

// 4. Escuchar cuando el usuario complete la autorizacion
window.addEventListener('message', (event) => {
  if (event.data?.type === 'hornerossp-oauth-callback') {
    if (event.data.success) {
      console.log('Conectado!', event.data.connectionId);
      // Ahora puedes usar client.tools.execute() con este usuario
    } else {
      console.error('Error:', event.data.error);
    }
  }
});

Campo subdomain para Kommo

El campo subdomain debe contener SOLO el subdominio, no la URL completa:

| Tu cuenta Kommo | Valor correcto de subdomain | |-----------------|----------------------------| | miempresa.kommo.com | miempresa | | ventas.kommo.com | ventas | | https://demo.kommo.com | demo |

Incorrecto: https://miempresa.kommo.com, miempresa.kommo.comCorrecto: miempresa

Integraciones Disponibles

| MCP | Descripcion | Auth | Credenciales | |-----|-------------|------|--------------| | kommo-mcp | CRM Kommo | OAuth2 / Token | subdomain (OAuth) o access_token, base_domain | | chatwoot-mcp | Soporte Chatwoot | API Key | chatwoot_url, api_token, account_id | | notebooklm-mcp | Google NotebookLM | OAuth2 | Google OAuth | | mercadopago-mcp | Pagos MercadoPago | Bearer | access_token | | tiendanube-mcp | E-commerce TiendaNube | Bearer | access_token, store_id | | correoargentino-mcp | Envios Correo Argentino | API Key | api_key, environment | | arca-mcp | Facturacion AFIP | Certificate | cuit, certificate, private_key, environment |

Ejemplo Completo

import { HornerosSSP } from "hornerosssp";

const client = new HornerosSSP({ apiKey: process.env.HORNEROS_API_KEY });

async function connectUserToKommo(userId: string, kommoToken: string, domain: string) {
  // Verificar si ya existe conexion
  const existing = await client.connections.getByEntity(userId, "kommo-mcp");
  if (existing) {
    console.log("Usuario ya conectado a Kommo");
    return existing;
  }

  // Crear nueva conexion
  const conn = await client.connections.initiate({
    mcpSlug: "kommo-mcp",
    entityId: userId,
    credentials: {
      access_token: kommoToken,
      base_domain: domain
    }
  });

  console.log("Conexion creada:", conn.id);
  return conn;
}

async function getLeadsForUser(userId: string) {
  const result = await client.tools.execute({
    mcpSlug: "kommo-mcp",
    entityId: userId,
    toolName: "get_leads",
    arguments: { limit: 50 }
  });

  const leads = JSON.parse(result.content[0].text);
  return leads;
}

// Uso
await connectUserToKommo("user_123", "kommo_token", "empresa.kommo.com");
const leads = await getLeadsForUser("user_123");
console.log(`Found ${leads.length} leads`);

Manejo de Errores

import { HornerosError, HORNEROS_SDK_ERROR_CODES } from "hornerosssp";

try {
  await client.tools.execute({...});
} catch (error) {
  if (error instanceof HornerosError) {
    switch (error.errorCode) {
      case HORNEROS_SDK_ERROR_CODES.COMMON.CONNECTION_NOT_FOUND:
        console.log("El usuario no tiene conexion. Crear una primero.");
        break;
      case HORNEROS_SDK_ERROR_CODES.COMMON.TOOL_NOT_FOUND:
        console.log("Herramienta no existe");
        break;
      case HORNEROS_SDK_ERROR_CODES.COMMON.RATE_LIMITED:
        console.log("Limite de requests alcanzado");
        break;
      default:
        console.log("Error:", error.message);
    }
  }
}

Variables de Entorno

El SDK puede leer configuracion de variables de entorno:

HORNEROS_API_KEY=hsp_xxx        # API key
HORNEROS_BASE_URL=https://...   # URL base (opcional)
// Si las variables estan configuradas, no necesitas pasarlas
const client = new HornerosSSP();

TypeScript

El SDK incluye tipos TypeScript completos:

import type {
  McpInfo,
  McpDetail,
  ConnectionInfo,
  ToolDefinition,
  ToolResult,
  InitiateConnectionParams,
  ExecuteToolParams
} from "hornerosssp";