Skip to main content
Glama
jnot807

Juicebox MCP

by jnot807

Juicebox MCP

Ein lokaler MCP-Server, der deine Juicebox-Sourcing-Daten in Claude einliest – gespeicherte Suchen und ihre bewerteten Ergebnisse – und dabei deine eigene angemeldete Juicebox-Sitzung verwendet.

Läuft vollständig auf deinem Rechner. Deine Sitzung verlässt ihn nie, und jeder Aufruf erfolgt als du, auf deinem eigenen Sitzplatz.

Lesevorgänge kosten keine Export-Credits. Alles, was die Lese-Tools zurückgeben, stammt von derselben freien Oberfläche, die auch die Suchergebnisseite bereits rendert. Ein Tool schreibt, und sagt das auch: jb_run_search erstellt eine echte gespeicherte Suche in deinem Workspace.


Installation

Option A – Desktop-Erweiterung (am einfachsten)

Lade juicebox-mcp.mcpb von Releases herunter und doppelklicke dann darauf, oder ziehe es in Claude Desktop → Einstellungen → Erweiterungen.

Es gibt keinen API-Schlüssel zum Einfügen. Nach der Installation führe die einmaligen Browser-Schritte unten aus.

Option B – aus dem Quellcode

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

Registriere es dann bei Claude Code:

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

-s user macht es in jeder Sitzung verfügbar; ohne diese Option ist die Registrierung auf das Verzeichnis beschränkt, in dem du es zufällig ausgeführt hast.

Der einmalige Browser-Download

Dies treibt ein echtes Chromium an, und diese Binärdatei ist nicht Teil von node_modules – es ist ein einmaliger Download von etwa 500 MB in einen gemeinsamen Cache (~/Library/Caches/ms-playwright auf macOS).

npm install lädt es automatisch über einen Postinstall-Schritt herunter. Benutzer der Desktop-Erweiterung müssen es einmal von Hand ausführen, da eine Erweiterung node_modules bündelt, aber nicht diesen Cache:

npx patchright install chromium

Wenn es fehlt, teilt dir der Server das in einfacher Sprache mit, anstatt einen Stack-Trace über eine fehlende ausführbare Datei zu werfen.

Anmelden

Die Authentifizierung ist eine echte Anmeldung, kein Schlüssel. npm run login öffnet ein Browserfenster; melde dich wie gewohnt bei Juicebox an. Die Sitzung wird dann in session/ gespeichert (gitignored, chmod 600) und headless wiederverwendet.

Melde dich erneut an, wenn npm run check fehlschlägt – Sitzungen laufen ab.


Related MCP server: JobSpy MCP Server

Tools

Tool

Was es tut

jb_list_searches(projectId?)

Gespeicherte Suchen auf einem Projekt (ID + Name).

jb_get_results(searchId, limit?, minMatchRate?)

Die bewerteten Kandidaten einer Suche – Name, LinkedIn-URL, Titel, Firma, Standort, matchRate, Kriterien-Bewertungen pro Kriterium und datierte experience[] + education, die von den gerenderten Karten abgelesen werden. Bis zu ~500 pro Aufruf.

jb_count(queryInput, searchId?)

Größe eines Filtersatzes bestimmen, ohne eine Suche auszuführen – die Abstimmungs-Primitive. queryInput ist ein PATCH über eine geerntete Vorlage; prüfe noEffect in der Antwort.

jb_run_search(prompt, need?)

SCHREIBT. Erstellt und führt eine neue Suche aus einer natürlichsprachlichen Eingabe aus und gibt dann deren Kandidaten zurück. Hinterlässt eine gespeicherte Suche, die für deinen gesamten Workspace sichtbar ist – bestätige, bevor du sie verwendest.

experience[] ist der einzige Weg, vergangene Arbeitgeber zu sehen: Die API-Payload enthält nur den aktuellen, daher sind Alumni eines Zielunternehmens ohne sie unsichtbar.


Welches Projekt es standardmäßig liest

Nichts ist fest verdrahtet. Bei der Anmeldung lädt eine Sonde /projects, was in ein Projekt umleitet, das dein Sitzplatz sehen kann, und diese ID wird als defaultProjectId in session/session-meta.json gespeichert.

Es wird einmal geschrieben und dann in Ruhe gelassen. Die Weiterleitung folgt dem Projekt, das die App zuletzt geöffnet hatte. Wenn man ihr bei jedem Lauf vertrauen würde, würde ein Tool-Aufruf ohne projectId ein anderes Projekt lesen als gestern.

Auflösungsreihenfolge:

  1. JUICEBOX_PROJECT_ID (Umgebungsvariable – das ist es, was das optionale Feld „Standardprojekt“ der Desktop-Erweiterung setzt)

  2. JUICEBOX_VALIDATOR_PROJECT (Umgebungsvariable – pinnt auch die Authentifizierungsprüfung auf dieses Projekt)

  3. defaultProjectId in session/session-meta.json, durch Erkennung gesetzt

Jedes Tool akzeptiert auch eine explizite projectId, die immer gewinnt.

Juicebox-Projekt-IDs sind ~20 Zeichen lange Schlüssel wie c5PheL2fANnX6uBQVUdo – der /project/<id>/-Teil einer URL. Wenn du eine UUID übergibst, lehnt der Server sie mit einer Erklärung ab, anstatt still zu einem Projekt zu navigieren, das nicht existiert.


Zwei Regeln, die die Tools mit sich tragen

  • verdictFound: false → unknown, niemals eine Verneinung. „Keine Beweise gefunden“ und „Beweise sagen nein“ sind unterschiedliche Bewertungen. Sie zusammenzufassen bewertet einen Kandidaten für ein Kriterium schlechter, das niemand tatsächlich prüfen konnte.

  • Breite Skill-Begriffe verwässern das Ranking. Skills sind ODER-gewichtet; ein bevölkerungsweiter Begriff wie „Account Management“ bei einer Customer-Success-Suche bläht den Pool um etwa das 3,4-fache auf. Entferne die generischen Begriffe und befördere die eine harte Anforderung zu einem Skill-Filter.


Skripte ausführen, während der Server läuft

Du kannst das Browserprofil nicht teilen: session/profile/ ist Single-Writer, und der MCP-Server hält es, wann immer er läuft. Ein zweiter Prozess, der es öffnen will, schlägt bei der Authentifizierungsprüfung fehl – die sich selbst als „Sitzung abgelaufen“ meldet und dich im Kreis herum zum erneuten Anmelden schickt.

Für Diagnosen erstelle stattdessen einen frischen Kontext aus dem Checkpoint. Keine Sperre, dieselbe Sitzung:

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

Wie es funktioniert und die Fallstricke

Die Ergebnisseite wird beim ersten Laden serverseitig gerendert, daher feuert /api/profiles/results nur bei Interaktion. Der Client stößt den Pager an, damit die App ihre eigene Anfrage auslöst, und erfasst dann die Antwort – die den gesamten bewerteten Satz enthält, nicht nur die sichtbare Seite.

Drei Dinge, die jeden beißen werden, der client.js bearbeitet:

  1. Verwende niemals addInitScript. Patchright ignoriert es still als Anti-Erkennungsmaßnahme – kein Fehler, das Skript läuft einfach nie. Verwende page.on('response').

  2. Die linkedin_url der API ist verschlüsselt (hex:hex), ebenso wie profiles[].url und profileDetails.id. Echte URLs kommen von den gerenderten Karten und werden über normalisiertes full_name verknüpft – gemessen bei 100 % bei einer Live-Suche.

  3. Die Liste wird mitten in der Paginierung leer. Ein null-Pager-Wert bedeutet „bewegt sich noch“, nicht „fehlgeschlagen“. Etwas an die Pager-Änderungserkennung während eines Übergangs zu koppeln, ist die Ursache für zwei frühere Fehler.


Wenn es kaputtgeht

Dies reitet auf der internen API von Juicebox. Es gibt keinen Stabilitätsvertrag, und sie kann sich ohne Vorankündigung ändern.

  • npm run check schlägt fehl → Sitzung abgelaufen: npm run login.

  • Der Server sagt, Chromium fehlt → npx patchright install chromium.

  • jb_get_results gibt source: "dom-fallback" zurück → die API-Erfassung ist kaputt; du verlierst matchRate und Kriterien. Prüfe, ob RESULTS_PATH noch übereinstimmt.

  • jb_get_results meldet joinedLinkedInUrls: 0 → das Karten-Markup hat sich geändert; überarbeite harvestCards / rewindToFirstPage.

  • Leere Suchliste → das Projektseiten-Markup hat sich geändert; siehe listSavedSearches.


Anforderungen

  • Node.js 18 oder neuer

  • Ein Juicebox-Konto, bei dem du dich anmelden kannst

  • ~500 MB freier Speicherplatz für den Chromium-Download

Lizenz

MIT. Nicht verbunden mit oder unterstützt von 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
    B
    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