Skip to main content
Glama
jnot807

Juicebox MCP

by jnot807

Juicebox MCP

Un servidor MCP local que lee tus datos de Juicebox para Claude — búsquedas guardadas y sus resultados puntuados — usando tu propia sesión de Juicebox iniciada.

Se ejecuta por completo en tu máquina. Tu sesión nunca sale de ella, y cada llamada se realiza como tú, en tu propio asiento.

Leer no cuesta créditos de exportación. Todo lo que devuelven las herramientas de lectura proviene de la misma superficie libre que la página de resultados de búsqueda ya renderiza. Una herramienta escribe, y lo dice: jb_run_search crea una búsqueda guardada real en tu espacio de trabajo.


Instalación

Opción A — Extensión de escritorio (la más fácil)

Descarga juicebox-mcp.mcpb desde Releases, haz doble clic, o arrástralo a Claude Desktop → Ajustes → Extensiones.

No hay ninguna clave de API que pegar. Tras instalar, haz los pasos del navegador de una sola vez que vienen abajo.

Opción B — desde el código fuente

git clone https://github.com/jnot807/juicebox-mcp.git
cd juicebox-mcp
npm install          # also downloads the Chromium build (see note)
npm run login        # a real browser opens — sign in to Juicebox yourself
npm run check        # proves the session works headless

Después regístralo con Claude Code:

claude mcp add -s user juicebox -- node "$(pwd)/server.js"

-s user lo hace disponible en cada sesión; sin él, el registro se limita al directorio desde el que lo hayas ejecutado.

La descarga única del navegador

Esto maneja un Chromium real, y ese binario no forma parte de node_modules — es una descarga única de unos 500MB a una caché compartida (~/Library/Caches/ms-playwright en macOS).

npm install la consigue automáticamente mediante un paso post-instalado. La extensión de escritorio necesita ejecutarlo una vez a mano, porque una extensión incluye node_modules pero no esa caché:

npx patchright install chromium

Si falta, el servidor te lo dice en lenguaje normal en lugar de lanzar un stack trace sobre un ejecutable que falta.

Iniciar sesión

La autenticación es un inicio de sesión de verdad, no una clave. npm run login abre una ventana del navegador; inicia sesión en Juicebox como harías normalmente. La sesión queda entonces almacenada en session/ (gitignored, chmod 600) y se reutiliza sin cabeza.

Vuelve a iniciar sesión siempre que npm run check empiece a fallar.


Related MCP server: JobSpy MCP Server

Herramientas

Herramienta

Qué hace

jb_list_searches(projectId?)

Búsquedas guardadas en un proyecto (id y nombre).

jb_get_results(searchId, limit?, minMatchRate?)

Candidatos clasificados de una búsqueda: nombre, URL de LinkedIn, título, empresa, ubicación, matchRate, veredictos por criterio, y experience[] + education[] fechados leídos de las tarjetas renderizadas. Hasta ~500 por llamada.

jb_count(queryInput, searchId?)

Tamaño de un filtro sin ejecutar la búsqueda: la primitiva de ajuste. queryInput es un PATCH sobre una plantilla segmentada; comprueba noEffect en la respuesta.

jb_run_search(prompt, need)

ESCRIBE. Crea y ejecuta una nueva búsqueda desde una solicitud en lenguaje natural, devuelve sus candidatos. Deja una búsqueda guardada visible a todo tu espacio de trabajo — confirma antes de usarla.

experience[] es la única forma de ver empleadores anteriores: el payload de la API lleva solo el mayor actual, sin él los exalumnos de una empresa objetivo son invisibles.


Qué proyecto lee por defecto

Nada está fijo. Al iniciar sesión, una sonda carga /projects, que redirige a un proyecto que tu asiento puede ver, y ese id se guarda como defaultProjectId en session/session-meta.json.

Se escribe una vez y luego se deja. La redirección sigue al proyecto que la aplicación tuvo abierto más recientemente, así que confiar en él cada vez haría una llamada a herramienta con el projectId que leer un proyecto distinto del que leyó ayer.

Orden de resolución:

  1. JUICEBOX_PROJECT_ID (env — esto es lo que la opción "proyecto por defecto" opcional de la extensión de escritorio fija)

  2. JUICEBOX_VALIDATOR_PROJECT (env — también fija la verificación de auth a ese proyecto)

  3. defaultProjectId en session/session-meta.json, fijada por descubrimiento

Cada herramienta tambien admite un projectId explícito, que siempre gana.

Los id de proyecto de Juicebox son claves de ~20 caracteres como c5PheL2fANnXu6BQVUdo — la parte /project/<id>/ de una URL. Si pasas un UUID, el servidor lo rechaza con una explicación en lugar de navegar en silencio a un proyecto que no existe.


Dos reglas que llevan las herramientas

  • verdictFound → false→unknown`, nunca un negativo. "No hay evidencia" y "la evidencia dice que no" son veredictos distintos. Colapsarlos puntúa a un candidato por un criterio que nadie podía comprobar.

  • Los términos de aptitud amplios diluyen la clasificación. Las aptitudes se ponderan con OR; un término amplio como "Gestión de cuentas" en una búsqueda de éxito de clientes infla el grupo por ~3.4×. Retira los términos genéricos y promueve contenido enduro el requisito a un filtro de aptitud.


Scripts mientras el servidor está en marcha

No se puede compartir el perfil del navegador: perfil de sesión/ es de un solo escritor y es el servidor MCP lo mantiene cuando se está ejecutando. Otro proceso que intente abrirlo falla el control de autenticación — que se reporta como "sesión expirada" y te hace volver a iniciar sesión.

Para diagnosticar, construye un contexto reciente desde el punto de control. Misma cerradura, misma sesión:

const { chromium } = require('patchright');
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ storageState: 'session/storage-state.json' });

Cómo funciona, y las trampas

La página de resultados se renderiza del lado del servidor en la primera carga, así que /api/profiles/results solo se dispara en interacción. El cliente empuja la página para que la app haga su propia solicitud, y entonces captura la respuesta — que incluye el conjunto clasificado completo, no solo la página visible.

Tres cosas que morderán a cualquería que edite client.js:

  1. No uses nunca addInitScript. Oculta en silencio no-op como medida anti-detección: sin error, el script no se ejecuta. Usa page.on('response').

  2. linkedin_URL del API está cifrada (hex:hex), como perfiles[].url y detalles de url. Las URLs reales vienen de las tarjetas renderizadas y se unen en full_name normalizado. — medido al 100% en una búsqueda en vivo.

  3. La lista se vacía en medio de la paginación. Un paginador nulo significa "sigue moviéndote", no "fallaste". Depender del cambio de paginador durante la transición es cómo sucedieron dos bugs anteriores.


Cuándo se rompe

Esto va sobre el API interna de Juicebox. No hay un contrato de estabilidad, y puede cambiar sin previo aviso.

  • npm run diff falla → sesión expirada: npm run diff.

  • El servidor dice que falta Chromium → npx patchright install chromium.

  • jb_get_results devuelve source: "dom-fallback" → la captura de la API se rompió; pierde matchRate y criteria.

Comprueba que RESULTS todavía coincide con el caché.

  • jb_get_results informa de joinedLinkedInUrls: 0 → el marcado de la tarjeta cambió; revisa harvest / rewindToFirstPage.

  • La lista de búsqueda vacía → el marcado de la página del proyecto cambió; ver listSavedSearches.


Requisitos

  • Node.js 18 o más nuevo

  • Una cuenta de Juicebox en la que puedas iniciar sesión

  • ~500MB de disco libre para la descarga de Chromium

Licencia

MIT. No asociado a Juicebox.# Juicebox MCP

Un servidor MCP local que lee los datos de Juicebox para Claude Code: búsquedas guardadas y resultados puntuados mediante tu propia sesión de Juicebox.

Se ejecuta completamente en tu máquina. Tu sesión nunca sale de ella, y cada llamada se hace como tú, en tu propio asiento.

Leer no cuesta créditos de exportación. Todo lo que devuelven las herramientas de lectura proviene de la misma superficie libre que la página de resultados de búsqueda ya renderiza. Una herramienta escribe, y lo dice: jb_run_search crea una búsqueda guardada real en tu área de trabajo.


Instalación

Opción A: extensión de escritorio (la más fácil)

Descarga juicebox-mcp.mcpb desde Releases, haz doble clic o arrástralo a Ayuda de Claude → Configuración.

No hay ninguna API key que pegar. Después de instalar, haz los pasos del navegador una sola vez aquí abajo.

Opción B: desde la fuente

git clone https://github.com/jnot807/juicebox-mcp.git
cd juicebox-mcp
npm install          # also downloads the Chromium build (see note)
npm run login        # a real browser opens — sign in to Juicebox yourself
npm run check        # proves the session works headless

Regístralo con Claude Code:

claude mcp add -s user juicebox -- node "$(pwd)/server.js"

-s user lo hace disponible en cada sesión; sin él, el alta estáá limitado al directorio desde el que lo ejecutes.

La descarga única del navegador

Esto controla un Chromium real, y ese binario no forma parte de node_modules — es una descarga única de unos 500 MB en una caché compartida (~/Library/Caches/ms-playwright en macOS).

npm install la obtiene automáticamente mediante un paso de post-instalación. Los usuarios de la extensión de escritorio necesitan ejecutarla manualmente una vez ; una extensión incluye node_modules pero no esa caché:

npx patchright install chromium

Si falta, el servidor te lo dice en lenguaje plano y no te lanza un stack trace por un binario ausente.

Iniciar sesión

La autenticación es un inicio de sesión real, no una clave. npm run login abre una ventana del navegador; inicia sesión en Juicebox como harías normalmente. La sesión se guarda en session/ (en gitignore, chmod 600) y se reutiliza de forma ciega.

Vuelve a iniciar sesión siempre que npm run check empiece a fallar.


Herramientas

Herramienta

Qué hace

jb_list_searches(projectId?)

Búsquedas guardadas de un proyecto (id + nombre).

jb_get_results(search, limit, minMatchRate?)

Candidatos clasificados de una búsqueda: nombre, LinkedIn URL, cargo, empresa, ubicación, matchRate, veredictos por criterio, y experience[] + education[] con fecha de las tarjetas renderizadas. Hasta ~500 por llamada.

jb_count_query(query, searchId?)

Tamaño de un conjunto de filtros sin ejecutar la búsqueda — la primilla de ajuste. queryInput es un PATCH sobre una plantilla cosechada; comprueba noEffect en la respuesta.

jb_run_search(prompt, need?)

ESCRIBE. Crea y ejecuta una nueva búsqueda desde un prompt en lenguaje natural, luego devuelve sus candidatos. Deja una búsqueda guardada visible para todo tu espacio de trabajo: confirma antes de usarla.

experience[] es la única forma de ver empleadores anteriores: el payload de la API lleva solo el actual, por lo que exalumnos de la misma empresa son invisibles si no.


Qué proyecto lee por defecto

Nada está fijo incrustado. Al iniciar sesión, un probe carga /projects, que redirige a un proyecto que tu asiento puede ver, y ese id se guarda como defaultProjectId en session/session-meta.json.

Se escribe una sola vez y luego se deja. La redirección sigue al proyecto que más recientemente tenía la app abierta, así que un intento con cada projectId distinto leería un proyecto distinto del que leyó ayer.

Orden de resolución:

  1. odio de proyecto (env — esto es lo que la extensión de escritorio "proyecto por defecto" fija)

  2. validación de proyecto (env — también fija la comprobación de auth a ese proyecto)

  3. defaultProjectId en session/session-meta.json, fijado por descubrimiento

Cada herramienta también acepta un projectId explícito, que siempre gana.

Los ids de proyecto de son claves tipo ~20 caracteres como c5eP4fANnXU6oBQVUabs — el /project/<id>/ de una URL. Si pasas un UUID, el servidor te lo rechaza con una explicación en lugar de navegar en silencio a un proyecto que no existe.


Dos reglas que llevan las herramientas

  • verdictFound: false → unknown, nunca negativo. "No hay evidencia" y "la evidencia dice que no" son veredictos distintos. Colapsarlos puntúa a una candidata por un criterio que nadie pueede comprobar en realidad.

  • Los términos de aptitud amplios diluyen el ranking. Los términos son ponderados con OR; una búsqueda de éxito de clientes con el término "Accounts" como el éxito de Gestión de cuentas pública infla el grupo por ~2×. Descarta los términos genéricos y promueve el requisito difícil a un filtro de aptitud.


Ejecutar scrpts mientras el servidor está en marcha

No puedes compartir el perfil de la sesión: perfiles/sesión/ es de un único escritor, el servidor MCP lo mantiene siempre que se está ejecutando. Un segundo proceso que intenta abrirlo falla la comprobación de auth — que se reporta como "sesión caducada" y te hace dar vueltas al iniciar sesión.

Para diagnóstico, construye un contexto nuevo desde el punto de control. Mismo candado, misma sesión:

const { chromium } = require('patchright');
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ storageState: 'session/storage-state.json' });

Cómo funciona, y las trampas

La página se muestra desde el servidor en la primera carga, así que /api/profiles/results solo se dispara en la interacción. El cliente conduce la página para que la app haga su propia request, y el resultado capturarespuesta — que lleva la conjugada completa, no solo la página visible.

Tres cosas que muerden a cualquiera que edite client.js:

1: Nunca uses addInitScript. Juicio silencion se no-op como mediate anti-detección: sin script, no hay error. Usa page.on('response'). 2: La URL de linkedin está cifrada (hex:hex), como los url de perfiles[].url y perfil.detalles URL. Las URL reales vienen de las tarjetas renderizados y por full_name normalizado — medido al 100% en una búsqueda en vivo. 3: La lista se blanca a mitad de paginación. Un pager nula significa "sigues en el medio", no "falló". Bloquear cualquier cosa en pager-change durante una transición es cómo pasaron dos errores anteriores. 4. Si jb_get_results devuelve src: "dom-fallback": la captura de API se rompió; pierdes matchRate y criteria. Comprueba que RESULTS sigue haciendo.

Cuenta la aplicación

Esto monta el interno API de Juicebox. No hay ningún estabilidad puede cambiar sin previo aviso.

  • npm run diff falló → sesión caducada: npm run diff.

  • El servidor dice Chromium falta → npx patchright install chromium.

  • jb_get_results returns source: "dom-fallback" de la captura API se rompió; pierdes matchRate y criteria. Comprueba RESULTS todavía coincide con la caché.

  • jb_get_results reporta joinedLinkedInUrls: 0 el marcado de la tarjeta cambió; revisa harvest / rewindToFirstPage.

  • Lista de búsqueda vacía → el marcado de la pagina del proyecto cambió; revisa listSearches.


Requisitos

  • Node.js 18 o más reciente

  • Una cuenta de Juicebox donde puedes iniciar sesión

  • hédes~ké500MB libres de disco para la descarga de Chromium

Licencia

MIT. No afiliado a Juicebox.# Juicebox MCP

Un servidor MCP local que lee sus datos de Juicebox en Claude Code — búsquedas guardadas y resultados puntuados— mediante su propia sesión de Juicebox iniciada.

Se ejecuta enteramente en su máquina. Su sesión nunca sale de ella, y cada llamada se hace como usted, en su propio asiento.

Leer no cuesta créditos de exportación. Todo lo que devuelven las herramientas de lectura proviene de la misma superficie lisa y libre que la página de resultados de búsqueda ya renderizada. Una herramienta escribe, y lo dice: jb_run_search crea una búsqueda guardada real en su espacio de trabajo.


Instalación

Opción A: Extensión de escritorio (la más fácil)

  1. Descargue juicebox-mcp.mcpb desde Releases, haga doble clic o arrástrelo a Claude Desktop → Settings.

No hay ninguna clave API que pegar. Después de instalar, realice los pasos de navegador únicos que aparecen abajo.

Opción B: desde la fuente

git clone https://github.com/jnot807/juicebox-mcp.git
cd juicebox-mcp
npm install          # also downloads the Chromium build (see note)
npm run login        # a real browser opens — sign in to Juicebox yourself
npm run check        # proves the session works headless

Regístrelo con Claude Code:

claude mcp add -s user juicebox -- node "$(pwd)/server.js"

-s user lo hace disponible en cada sesión; sin él, el registro se limita al directorio desde el que lo execute.

La descarga única del navegador

Esto conduce a un Chromium real, y ese binario no forma parte de node_modules: es una descarga única de unos 500 MB en una caché compartida (~/Library/Caches/ms-playwright en macOS).

npm install lo obtiene automáticamente mediante un paso de post-instalación. Los usuarios de la extensión de escritorio deben ejecutarlo una vez a mano, porque una extensión incluye node_modules pero no esa caché:

npx patchright install chromium

Si falta, el servidor se lo dice en lenguaje sencillo en lugar de lanzar un stack trace sobre un binario que falta.

Iniciar sesión

La autenticación es un inicio de sesión real, no una clave. npm run login abre una ventana del navegador; inicie sesión en Juicebox como lo haría normalmente. La sesión se almacena entonces en session/ (gitignored, chmod 600) y se reutiliza sin cabeza.

Vuelva a iniciar sesión cada vez que npm run check empiece a fallar.


Herramientas

Herramienta

Qué hace

jb_list_searches(projectId?)

Búsquedas guardadas en un proyecto (id + nombre).

jb_get_results(search, limit, minMatchRate?)

Candidatos clasificados de una búsqueda: nombre, URL de LinkedIn, título, empresa, ubicación, matchRate, veredictos por criterio y experience[] + education[] con fecha de las tarjetas renderizadas. Hasta ~500 por llamada.

jb_count(query, searchId?)

Tamaño de un filtro sin ejecutar la búsqueda — la primilla de ajuste. queryInput es un PATCH sobre una plantilla cosechada; comprueba noEffect en la respuesta.

jb_run_search(prompt, need?)

ESCRIBE. Crea y ejecuta una nueva búsqueda desde un prompt en lenguaje natural, luego devuelve sus candidatos. Deja una búsqueda guardada visible en todo tu espacio de trabajo: confirma antes de usarla.

experience[] es la única forma de ver empleadores anteriores: el payload de la API lleva solo el actual, así que los alumni de una empresa sin ella son invisibles.


Qué proyecto lee por defecto

Nada está fijo incrustado. Al iniciar sesión, una sonda carga /projects, que redirige a un proyecto que tu asiento pueda ver, y ese id se guarda como defaultProjectId en session/session-meta.json.

Se escribe una vez y luego se deja. El redirige sigue al proyecto sobre el que la app estuvo más recientemente abierto, por lo que confiar en él cada ejecución haría una llamada de herramienta con projectId distinta del que leyó ayer.

Orden de resolución:

  1. JUICEBOX_PROJECT_ID (env — es lo que el "campo de proyecto por defecto" de la extensión de escritorio fijó)

  2. JUICEBOX_VALIDATOR_PROJECT (env — también fija la comprobación de auth a ese proyecto)

  3. defaultProjectId en session/session-meta.json, fijado por descubrimiento

Cada herramienta también toma un projectId explícito, que siempre gana.

Los ids de proyecto de Juicebox son claves tipo ~20 caracteres como c5TuB7nJWuVdo9LpPg1 — la parte /proyecto/<id>/ de una URL. Si pasa un UUID, el servidor lo rechaza con una explicación en lugar de aterrizar a un proyecto que no existe.


Dos reglas que llevan las herramientas

  • candidatoEncontrado: false → desconocido, nunca un negativo. "No se encontró evidencia" y "la evidencia dice que no" son veredictos distintos. Colapsarlos infravalora una candidata a un criterio que nadie realmente pudo chequear.

  • Los términos de aptitud anchos diluyen la clasificación. Las aptitudes son ponderadas OR; una búsqueda de customer success con el término amplio term como "Account Management" en una búsqueda de management infla el pool por ~3.4×. Descarta los términos de gen y promueve en la correo the one hard requirement a un filtro de aptitud.


Ejecutar scripts mientras el servidor está activo

No se puede compartir el perfil de la sesión: session/ es de una sola escritora, el servidor MCP lo mantiene abierto solo cada vez que se ejecuta. Un segundo proceso que lo intente falla la comprobación de auth — que se reporta a sí misma como "sesión expirada" y te hace dar vueltas iniciando sesión.

Para el diagnóstico, construya un contexto nuevo desde el punto de control. El mismo bloqueo, misma sesión:

const { chromium } = require('patchright');
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ storageState: 'session/storage-state.json' });

Cómo funciona, y las trampas

La ficha de la sesión se renderiza desde servidor en la primera carga, así que /api/profiles/results solo se dispara en la interacción. El cliente empuja a la página para que la aplicación emita su solicitud, y entonces capta la respuesta — que lleva el resultado clasificado completo, no solo la página visible.

Tres cosas que muerden cualquiera que edite client.js:

  1. Nunca uses addInitScript.* Patches de forma sulfonosa lo ignora como si no pasara nada — no script; no error. Usa page.on('response').

  2. linkedin_url del API está cifrado (hex:hex), búscalos urls[].url y profileDetails.url. Las URLs reales provienen de las tarjetas y se unen en full_name normalizado—medido al 100% en una búsqueda en vivo.

  3. La lista corta en medio de la paginación. Un paginador "no está trayendo" significa "sigue en movimiento", no "no resultado". El golpe de estado en la transición de la página es cómo pasaron dos bugs anteriores.


Cuándo se rompe

Está montado en la Juicebox API interna del jugo. No hay un contrato de estabilidad, puede cambiar sin aviso.

  • npm run lint falla → sesión caducada: npm run login.

  • El server dice que falta Chromium → npx patchright install chromium.

  • jb_get_results devuelve src: "dom-fallback" → la captura del API se rompió; pierdes matchRate + criteria. Comprueba que RESULTS todavía coinciden con la ruta caché.

  • jb_get_results reporta joinedLinkedInUrls: 0 → el marcado de la tarjeta cambió; revisa harvest / rewindToFirstPage.

  • La lista de búsqueda vacía → el marcado de la página del proyecto cambió; revisa listStoredSearches.


Requisitos previos

  • Node.js 18 o más nuevo

  • lock Una cuenta de Juicebox en la que puedas into iniciar sesión

  • ~500MB de disco libre para descarga de Chromium

Licencia

MIT. No asociado con Juicebox.# Juicebox MCP

Un servidor MCP local que lee tus datos de Juicebox en Claude Code — búsquedas guardadas y resultados puntuados— mediante tu propia sesión de Juicebox iniciada.

Se ejecuta enteramente en tu máquina. Tu sesión nunca sale de ella, y cada llamada se hace como tú, en tu propio asiento.

Leer no cuesta créditos de exportación. Todo lo que devuelven las herramientas de lectura proviene de la misma superficie libre que la página de resultados de búsqueda ya renderizada. Una herramienta escribe, y lo dice: jb_run_search crea una búsqueda guardada real en tu espacio de trabajo.


Instalación continuada de la extensión de escritorio (la más fácil)

  1. Descarga juicebox-mcp.mcpb desde Releases, haz doble clic o arrástralo a Claude Desktop → Configuración.

No hay ninguna clave API que pegar. Después de instalar, haz tos pasos de navegación que van abajo.

Opcional: desde la fuente

git clone https://github.com/jnot807/juicebox-mcp.git
cd juicebox-mcp
npm install          # also downloads the Chromium build (see note)
npm run login        # a real browser opens — sign in to Juicebox yourself
npm run check        # proves the session works headless

Regístralo con Claude Code:

claude mcp add -s user juicebox -- node "$(pwd)/server.js"

-s user lo hace disponible en cada sesión; si no, el registro está restringido al directorio desde el que lo ejecutes.

La descarga única del navegador

Esto maneja un Chromium real, y ese binario no forma parte de node_modules — es una descarga única de unos 500MB de caché compartida (~/Library/caches/ms-playwright en macOS).

npm install lo obtiene automáticamente mediante un paso de post-instalado. Los usuarios de la extensión de escritorio necesitan ejecutarlo una vez a mano, porque una extensión incluye node_modules pero no ese caché:

npx patchright install chromium

Si no, el servidor te lo dice en lenguaje honesto en lugar de lanzar un stack trace sobre un binario que falta.

Iniciar sesión

La autenticación es un inicio de sesión real, no una clave. npm run login abre una ventana del navegador; inicia sesión en Juicebox como harías tú normalmente. La sesión se almacena en session/ (gitignored, chmod 700) y se reutiliza de forma invisible.

Vuelve a iniciar sesión siempre que npm run check empiece a fallar.


Herramientas

Herramienta

Qué hace

jb_list_searches(projectId?)

Búsquedas guardadas en de (id + nombre).

jb_get_results(search, limit, minMatchRate?)

Resultados clasificados de una búsqueda — nombre, URL de LinkedIn, cargo, empresa, ubicación, matchRate, veredictos por criterio, y experience[] + education[] con fechas de las tarjetas renderizadas. Hasta ~500 por llamada.

jb_count(query, searchId?)

Tamaño de un filtro sin ejecutar la búsqueda — la primilla de ajuste. queryInput es un PATCH a plantilla cosechada; comprueba noEffect en la respuesta.

jb_run_search(prompt, need?)

ESCRIBE. Crea y ejecuta una nueva búsqueda desde un prompt en lenguaje natural, luego devuelve sus candidatos. Deja una búsqueda guardada visible a todo tu espacio de trabajo: confirma antes de usarla.

experience[] es la única manera de ver empleadores antiguos: el payload de la API lleva solo data tual, así que los alumnos de una empresa son invisibles sin.


Qué proyecto lee por defecto

Nada está fijo de incrustado. En el inicio de la sesión, una sonda del carga /projects, que redirects a un proyecto que tu asiento pueda ver, y ese id se guarda como defaultProjectId en session/session-meta.json.

Se escribe una vez y se deja en paz. La redirección sigue al proyecto que la app tenía más recientemente abierto, así que confiar en él en cada ejecución haría una llamada de herramienta con el projectId que no fuese que ayer.

Orden de resolución:

  1. JUICEBOX_PROJECT_ID (env — esto es lo que el campo "proyecto por defecto" opcional de la extensión de escritorio fija)

  2. VALIDATION_PROJECT_ID (env — también incrusta el cheque de auth contra ese proyecto)

  3. defaultProjectId en session/session.json, fijado por el descubrimiento

Cada herramienta también toma un projectId explícito, que siempre gana.

Los ids de proyectos de Juicebox son claves tipo ~20 caracteres como c5Phe2fANnXu6BQVdo — la parte /proyecto/<id>/ de una URL. Si pasas un UUID, el servidor lo rechaza con una explicación en lugar de silenciosamente a un proyecto que no existe.


Dos normas que las herramientas ifferencias

  • verdictFound: false → unknown, nunca un negativo. "No hay evidencia" y "la evidencia dice que no" son veredictos diferentes. (Colapsarlos baja a una candidata a una producción de un criterio que nadie podría realmente comprobar.)

  • Los términos de aptitud amplios (amplio) diluyen el ranking. Los términos de aptitud se ponderan conOR; un término de población / la industria como "Gestión de cuentas" en una búsqueda de gestión de clientes infla el grupo en ~3.4×. Quita los genéricos y subebe el requisito duro a un filtro de aptitud.


Cuando se ejecutan scripts mientras el servidor está en marcha

No puedes compartir perfil de sesión: session/ es un solo escritor, el servidor MCP lo mantiene cuando quiera que se ejecuta. Un segundo proceso que lo intente falla el cheque de auth — que se reporta a sí mismo como "sesión expirada" y te pone dando vueltas reiniciando sesión.

Para diagnosticar, construye un contexto fresco desde el checkpoint. Misma cerradura, misma sesión:

const { chromium } = require('patchright');
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ storageState: 'session/storage-state.json' });

Cómo funciona, y las trampas

La página se renderiza desde el servidor en la primera carga, así que /api/profiles/results solo se dispara en la interacción. El cliente empuja la página a la aplicación para que emita su propia solicitud, y luego captura la respuesta — que lleva todo el conjunto clasificado, no solo la página visible.

Tres cosas que muerden a quienquiera que edite client.js:

  1. Nunca addInitScript. Parchea silenciosamente como un sinónimo contra-detección — no, solo el script, no error. Usa page.on('response').

  2. la url del API está cifrado (hex:hex) igual urls[].url y profile.url los. Las URLs reales vienen de los tarjetas y se applied con en full_name normalizada — medida al 100% en una búsqueda en vivo.

  3. La lista en blanco a mitad de una paginación. Un paginador nullo que significa "sigue adelante", no "fallido". El golpe a la transición de paginación es cómo cómo fueron dos errores anteriores.


Cuándo se rompe

Esto monta la interna API de Juicebox. No hay contrato de estabilidad, y puede cambiar sin aviso.

  • npm run check fallo → sesión expirada: npm run login.

  • El servidor dice que falta Chromium → npx patchright install chromium.

  • jb_get_results devuelve source: "dom-fallback" → la captura del API se rompió; pierdes matchRate y criteria. Comprueba que RESULTS sigue coincidiendo con la ruta.

  • jb_get_results reporta joinedLinkedInUrls: 0 → el marcado de la tarjeta de tablero cambió; revisa harvest / rewindToFirstPage.

  • La lista de búsqueda vacía → el marcado de la página del proyecto cambió; revisa listStoredSearches.


Requisitos

  • Node.js 18 o más nuevo* Una cuenta de Juicebox que pueda iniciar sesión

  • ~500MB de espacio libre en disco para la descarga de Chromium

Licencia

Permitida MT. No afiliada a Juicebox.

Available Tools

4 tools
jb_countA

Size a filter set WITHOUT running a search — the tuning primitive. Free and side-effect free, so permute filters and compare before committing to a run. The endpoint is VERIFIED DETERMINISTIC (same body, same count on repeat), which is what makes the comparisons below trustworthy.

queryInput is a PATCH, not a whole body. It is merged over a ~164-key template harvested live from a saved search, because a PARTIAL body does not error — it returns result:0, which reads exactly like "nobody matches your filters". Pass only the keys you want to change. Use searchId to choose which saved search supplies the template; the response echoes baseline (the unpatched count).

ALWAYS CHECK noEffect IN THE RESPONSE. Unrecognised keys and wrong value shapes are dropped SILENTLY, so an unchanged count means the key name is probably wrong, NOT that the filter does not matter. Measured example: coSizes (company headcount) is ignored in all eight shapes tried, including [{name:"51-200"}], ["51-200"], [{title,tag}] and [{min,max}]. Its real shape is still unknown — set the filter in the Juicebox UI and capture the request before trusting it.

SOME FILTERS EXPAND RATHER THAN RESTRICT, which is the opposite of the intuition and was measured on one search (baseline 1413): dropping industries gives 1387 and dropping coTags gives 1247 — REMOVING them SHRINKS the pool, so they act as OR-expanders and cannot be used to narrow onto a category. An unrecognised industry ("mining & metals") returns the same 1387 as an empty list. What actually restricts: skills (removing all four widened 1413 to 4526), yearsOfExp (20 gives 881), selectedLocs, and criteria. Note this REVISES the older claim that broad skill terms widen the pool — specific skills restrict hard, broad ones merely fail to restrict. The practical rule is unchanged: drop skill terms that describe the whole population, and promote the ONE hard requirement to a skill (e.g. "AI Agents", not prose about being AI-first).

NameRequiredDescriptionDefault
searchIdNoSaved search to harvest the template from (from jb_list_searches). Defaults to the first saved search on the project. Pick the one whose titles/locations you want as your starting point.
projectIdNoJuicebox project id — a ~20-character key like c5PheL2fANnX6uBQVUdo, taken from the /project/<id>/ part of a Juicebox URL. Optional: omit it to use the default project discovered at sign-in.
queryInputYesPATCH over the harvested template — only the keys you are changing. Verified keys: jobTitles[{title,tag}], pastJobTitles, skills[{title,tag}], industries[{name}], coTags[{title,name,tag}], selectedLocs[{name,country,continent,type,...}], selectedCos, timezones, revenueRanges, fundingStages, yearsOfExp (number), criteria[{text,id}], excludeDncCountries (bool), coSizes (present but IGNORED in every shape tried).

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the entire behavioral burden, and it excels. It reveals that the endpoint is deterministic, that partial bodies are silently merged over a template, that unrecognized keys are dropped silently, and that filter behavior can be counterintuitive (some expand rather than restrict). It even provides measured examples showing how to detect silent failures via the noEffect flag. This is exemplary transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but every sentence carries critical, non-redundant information. It front-loads the core purpose and safety properties, then layers in warnings and measured data. No filler or repetition exists; each paragraph adds actionable knowledge an agent needs to use the tool correctly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (nested objects, no output schema) and the absence of annotations, this description is remarkably complete. It covers expected behavior, failure modes (silent drops, noEffect), practical examples, and even guidance on filter semantics that only become apparent through experimentation. An agent has everything it needs to call this tool correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already describes each parameter, the description adds value by clarifying that queryInput is a PATCH over a template, enumerating the verified key shapes (e.g., 'skills[{title,tag}]'), and explicitly flagging coSizes as ignored in every tested shape. It also explains how searchId selects the template and the meaning of the echoed 'baseline.' This goes well beyond the schema definitions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb and object: 'Size a filter set WITHOUT running a search — the tuning primitive.' This immediately distinguishes it from running a search and states its role as a sizing/measurement tool. It also explicitly contrasts with the sibling jb_run_search by saying 'before committing to a run,' leaving no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance ('permute filters and compare before committing to a run') and explains the side-effect-free nature that makes this safe for experimentation. It also instructs on selecting the saved search template via searchId and warns about the partial-body PATCH semantics. This is far more than typical usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jb_get_resultsA

Pull a saved search's ranked candidates — up to ~500 in one call. Returns name, LinkedIn URL, title, company, location, a numeric matchRate (0-100, banded) and per-criterion verdicts. Costs NO export credits: this is the same free surface the results page renders.

READING THE RESULTS: at the top of a ranked list every candidate meets every criterion, so criteria-met count does NOT discriminate up there — use matchRate and depth. A criterion with verdictFound=false is reported as result "unknown": that means no evidence was found, NOT that the candidate fails it. Never treat an unknown as a negative.

If the search has never been executed, this errors — open it in the app and press "Run search" once.

NameRequiredDescriptionDefault
limitNoMax candidates to return (default 50, max 500).
searchIdYesSaved search id from jb_list_searches.
projectIdNoJuicebox project id — a ~20-character key like c5PheL2fANnX6uBQVUdo, taken from the /project/<id>/ part of a Juicebox URL. Optional: omit it to use the default project discovered at sign-in.
minMatchRateNoOnly return candidates at or above this matchRate.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses the free/costless nature, the exact return data, the significance of verdictFound=false ('not a negative'), and the error condition for unexecuted searches. It also notes that matchRate is 'banded' and that criteria-met count doesn't discriminate at the top of a ranked list. This is rich behavioral detail well beyond structured fields, giving the agent a clear understanding of what happens when calling the tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but every sentence earns its place: the first line states the action and output, the cost note is critical, the 'READING THE RESULTS' section is indispensable for correct interpretation, and the final error note is essential. It's well-structured with clear sections (purpose, cost, interpretation, error condition). No fluff or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description enumerates the return fields and explains the semantic meaning of matchRate and verdicts (including the crucial 'unknown ≠ negative' nuance). It covers error behavior, limits, and the relationship to search execution. With four parameters fully documented in the schema and the description adding inter-tool references, an agent has everything necessary to correctly invoke and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers all parameters with descriptions at 100% coverage, so the baseline is 3. The description adds meaningful context: it tells the agent that searchId comes from jb_list_searches, that projectId is a specific format and can be omitted to use a default project, and that limit has a default of 50 and max of 500. These references connect the tool to its ecosystem and clarify usage, exceeding the schema's raw field meanings.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description begins with a specific verb ('Pull') and a specific resource ('a saved search's ranked candidates'), and details the exact fields returned (name, LinkedIn URL, title, company, location, matchRate, per-criterion verdicts). This clearly distinguishes it from siblings like jb_list_searches (which lists searches) and jb_count (counts). The scope is precise and non-tautological.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states that this costs no export credits and is the same surface as the results page, giving context on when it's appropriate. It also provides a prerequisite: 'If the search has never been executed, this errors — open it in the app and press Run search once.' It doesn't explicitly name sibling alternatives, but the distinct purposes of siblings (list, count, run) make the usage boundary clear. The 'READING THE RESULTS' section adds interpretive guidance, though it's more about reading the output than choosing when to use the tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

jb_list_searchesA

List the saved searches on a Juicebox project (searchId + name). Saved searches are stable and re-runnable, so this is the entry point for pulling existing sourcing work. Defaults to the configured project.

NameRequiredDescriptionDefault
projectIdNoJuicebox project id, or a /project/{id} URL. Optional.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses that saved searches are stable and re-runnable (reassuring the agent that reuse is safe), and that it defaults to the configured project. This adds useful behavioral context beyond the raw schema. It doesn't mention pagination or error behavior, but for a simple list operation this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences: the first states the purpose and output, the second adds context and default behavior. No wasted words, and the most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter list tool with no output schema, the description is nearly complete: it explains what is returned, the stability, and the default. It could mention whether an empty list is returned when none exist, but that is minor. It doesn't need to explain return values since it already says 'searchId + name'. Missing details are negligible.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already describes projectId as optional and as a URL or ID (100% coverage). The description adds value by stating it defaults to the configured project, which is not in the schema. That's meaningful extra guidance for when an agent can omit the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action (list), the resource (saved searches on a Juicebox project), and the output (searchId + name). It also situates the tool as an entry point for pulling existing sourcing work, distinguishing it from siblings like jb_run_search or jb_get_results without needing to inspect them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It says this is the entry point for pulling existing sourcing work, implying you should use this before running or fetching results. It also notes the default-project behavior, which helps an agent decide when explicitly passing projectId is unnecessary. It doesn't explicitly say 'don't use this if you want results' or name alternatives, but the use case is implied clearly enough.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv1.0.0
    • First observedjb_count
    • First observedjb_get_results
    • First observedjb_list_searches
    • First observedjb_run_search

TDQS

A4.6/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: list saved searches, fetch ranked results, tune filter counts, and create/run a new search. No two tools overlap in function, making misselection unlikely.

Naming Consistency5/5

All tools follow the consistent pattern of 'jb_' prefix + verb_noun (list_searches, get_results, run_search) with count as a concise verb. This is predictable and uniform.

Tool Count5/5

Four tools is well-scoped for a talent sourcing server. Each tool earns its place and covers the core workflow without redundancy or bloat.

Completeness4/5

The surface covers the essential lifecycle: listing existing searches, retrieving results, tuning filters without execution, and creating new searches. Minor gaps like deleting or updating saved searches exist but are not critical for the primary use case.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables Claude to perform actions on X, LinkedIn, and Reddit via a Chrome extension, such as connecting with recruiters, finding threads, and replying to posts.
    36
    38 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables job search and scraping across multiple job boards (LinkedIn, Indeed, Glassdoor, etc.) with advanced filtering, directly from Claude Desktop or other MCP clients.
    6
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables searching and evaluating job postings from LinkedIn and freehire.me directly through Claude Desktop. Provides tools to search jobs, fetch full posting details, and assess candidate fit using eligibility scans and a scoring rubric.
    MIT