Skip to main content
Glama
CaseyTTS

Bullhorn MCP Agent

by CaseyTTS

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
connection_statusA

Check whether Bullhorn API credentials are configured and connectivity is available.

list_jobsA

List and filter job orders from Bullhorn CRM.

Args: query: Lucene search query (e.g., "title:Engineer AND isOpen:1") status: Filter by job status limit: Maximum number of results (1-500, default 20) fields: Comma-separated fields to return

Returns: JSON array of job orders

Examples: - list_jobs() - Get recent jobs - list_jobs(query="isOpen:1") - Get open jobs - list_jobs(query="title:Software AND employmentType:Direct Hire", limit=10) - list_jobs(status="Accepting Candidates")

get_jobA

Get details for a specific job order by ID.

Args: job_id: The JobOrder ID fields: Comma-separated fields to return (default: all common fields)

Returns: JSON object with job details

list_candidatesA

List and filter candidates from Bullhorn CRM.

Args: query: Lucene search query (e.g., "lastName:Smith" or "skillSet:Python") status: Filter by candidate status limit: Maximum number of results (1-500, default 20) fields: Comma-separated fields to return

Returns: JSON array of candidates

Examples: - list_candidates() - Get recent candidates - list_candidates(query="skillSet:Python") - Find Python developers - list_candidates(query="lastName:Smith AND status:Active") - list_candidates(status="Active", limit=50)

get_candidateA

Get details for a specific candidate by ID.

Args: candidate_id: The Candidate ID fields: Comma-separated fields to return (default: all common fields)

Returns: JSON object with candidate details

get_candidate_filesB

List file attachments for a Bullhorn Candidate.

upload_candidate_resumeA

Upload a local resume file to a Bullhorn Candidate.

Args: candidate_id: The Candidate ID file_path: Local filesystem path to the resume file file_type: Bullhorn file type classification (default: "SAMPLE") external_id: Bullhorn external ID for the file (default: "Portfolio") dry_run: If True, validate inputs and return a preview of what would be uploaded without performing the upload

Returns: JSON object with the upload result, or - when dry_run is True - a preview of what would have been uploaded.

get_recent_placementsC

Get recent Bullhorn placements from the last X days.

search_entitiesA

Search any Bullhorn entity type using Lucene query syntax.

Args: entity: Entity type (JobOrder, Candidate, Placement, ClientCorporation, ClientContact, etc.) query: Lucene search query limit: Maximum number of results (1-500, default 20) fields: Comma-separated fields to return

Returns: JSON array of matching entities

Examples: - search_entities(entity="Placement", query="status:Approved") - search_entities(entity="ClientCorporation", query="name:Acme*") - search_entities(entity="JobSubmission", query="jobOrder.id:12345")

query_entitiesA

Query Bullhorn entities using SQL-like WHERE syntax.

Args: entity: Entity type (JobOrder, Candidate, etc.) where: WHERE clause (e.g., "salary > 100000 AND status='Active'") limit: Maximum number of results (1-500, default 20) fields: Comma-separated fields to return order_by: Sort order (e.g., "-dateAdded" for newest first)

Returns: JSON array of matching entities

Examples: - query_entities(entity="JobOrder", where="salary > 100000") - query_entities(entity="Candidate", where="status='Active'", order_by="-dateAdded")

setup_statusA

Report the tenant setup state, missing requirements and per-capability readiness.

Args: check_connection: Also log in to Bullhorn to confirm connectivity and the REST URL fingerprint (default true).

Returns: JSON with state, missing_requirements, capabilities, active_version, open_proposals and last_validation.

discover_schemaA

Discover the tenant's Bullhorn field metadata (metadata only; no record data, no samples).

Writes the local discovery snapshot and drift report; never changes mappings and never writes to Bullhorn.

Args: entities: Canonical or Bullhorn entity names to discover (default: every catalog entity).

Returns: JSON with per-entity summaries and the drift report.

get_mapping_profileA

Read the tenant mapping profile, its history, a version diff, or a proposal.

Args: view: One of "active", "version", "history", "diff", "proposal". version: The version for view="version"; the first version for view="diff". other_version: The second version for view="diff" (default: the active version). entity: Only show mappings of this canonical entity (views "active"/"version"). search: A substring filter; for view="proposal" it is the proposal ID (omit it to list open proposals).

Returns: JSON for the requested view.

propose_mapping_changesA

Propose mapping changes (the dry-run): validate, diff, hash and store a proposal.

Nothing is activated; only a local proposal file is written. Commit it with commit_mapping_changes using the returned proposal_id and diff_hash.

Args: changes: Change operations, each an object with an "op": init_tenant, apply_verified_defaults, set_field_mapping, deactivate_field_mapping, remove_field_mapping, set_value_mapping, deactivate_value_mapping, remove_value_mapping, set_setting, rollback_to, import_document. base_version: The version the change is built on (default: the active version).

Returns: JSON with proposal_id, diff_hash, expires_at, diff, conflicts, dependencies, validation.

commit_mapping_changesA

Approve or reject a stored proposal. The actor comes from BULLHORN_MCP_ACTOR.

Args: proposal_id: The proposal_id returned by propose_mapping_changes. diff_hash: The diff_hash returned by propose_mapping_changes. decision: "approve" or "reject".

Returns: JSON with status (committed, rejected or refused), version (on commit) and correlation_id.

manage_mapping_profileA

Validate or export the active mapping profile.

Import and rollback are proposals (propose_mapping_changes with import_document / rollback_to), so nothing is ever activated silently.

Args: action: "validate" (fresh metadata discovery + validation of the active version, recorded locally) or "export" (write the active profile to a new file). path: For "export": a new .yaml/.yml file outside the setup store. format: For "export": "v2" (default) or "v1".

Returns: JSON describing the result.

get_notesA

Read canonical notes (and their note_created events) for one record.

Exactly one primary scope is required: target_type + target_id, or one of candidate_id, job_id, client_corporation_id, client_contact_id, placement_id, submission_id. Only verified Bullhorn mechanisms are used; a scope or filter without one returns status "unsupported_filter" with the supported filters (it is never approximated).

Args: target_type: "candidate", "job", "client_contact", "client_corporation", "placement" or "submission". target_id: The record id for target_type. candidate_id: Primary scope: a candidate id. job_id: Primary scope: a job id. client_corporation_id: Primary scope: a client corporation id. client_contact_id: Primary scope: a client contact id. placement_id: Primary scope: a placement id. submission_id: Primary scope: a submission id. action_type: A tenant note action value (validated; never substituted). author: A Bullhorn user id or name. date_from: Inclusive ISO-8601 date or datetime with offset (a date means midnight in the reporting timezone). date_to: Exclusive ISO-8601 date or datetime with offset. include_deleted: Include deleted notes (default false). limit: Page size, 1 to 50 (default 20). start: Offset of the page (default 0).

Returns: JSON with status, notes, events, next_start, truncated and warnings.

create_noteA

Create a Bullhorn note through the safe-write pipeline (preview by default).

With dry_run=True (the default) nothing is written to Bullhorn: the result holds operation_id and preview_hash. Execute exactly that preview with confirm_write(operation_id, preview_hash, "approve"). dry_run=False is accepted only when BULLHORN_NOTE_CREATE_MODE=direct. Writing requires the note.create scope (BULLHORN_ENABLED_WRITE_SCOPES) and BULLHORN_MCP_ACTOR.

Args: target_type: The person the note is about: "candidate" or "client_contact". target_id: The record id of the target. action_type: A tenant note action value (exact; never substituted). comments: The note text (1 to 10,000 characters; stored unchanged). associations: Additional records, each {"type": ..., "id": ...} (at most 10). idempotency_key: Optional caller key (kept 7 days) that prevents a duplicate write. dry_run: Preview only (default true).

Returns: JSON with operation, status, entity_type, record_id, associations, targets, activity, correlation_id, and operation_id/preview_hash for a preview.

confirm_writeA

Approve or reject a previewed write. The approver comes from BULLHORN_MCP_ACTOR.

The write runs only if the preview_hash matches, the preview has not expired or been used, the actor is allowed, the scope and setup gate still hold, and nothing previewed has changed (otherwise: refused, e.g. stale_preview).

Args: operation_id: The operation_id returned by the preview. preview_hash: The preview_hash returned by the preview. decision: "approve" or "reject".

Returns: JSON with the normalized write result (status committed, partially_committed, failed, failed_orphan, rejected or refused).

bullhorn_sessionA

Show, start, complete or end your own Bullhorn sign-in for this workspace.

Sign-in happens in your browser through Bullhorn (including SSO/MFA); never give passwords or MFA codes to the assistant. After the browser step, the page shows a one-time code: the user enters it here with action="complete_link".

Args: action: "status" (default), "login" (returns a sign-in link), "complete_link" (finish linking with the code from the browser page) or "logout". confirmation: The one-time code from the browser page; only for "complete_link".

Returns: JSON with the session status, the sign-in link, {"linked": true} or {"logged_out": true}.

find_recordsA

Find canonical records of one entity with structured, AND-combined filters.

Only canonical names are accepted (never Bullhorn field names or query text). Every filter is applied exactly; a filter, operator or sort without a verified Bullhorn mechanism returns status "unsupported" and nothing is read.

Args: entity: candidate, job, submission, placement, client_corporation, client_contact, appointment or user. filters: 0 to 10 objects {"field": , "op": , "value": ...}. Operators by type: id/reference eq, in; string eq, in, is_null; boolean eq; integer/number eq, in, gt, gte, lt, lte; datetime gte, lt, is_null (ISO-8601 with offset, or a date = midnight in the reporting timezone). "in" takes 1 to 50 values. concept: Optional tenant concept (e.g. client_submission, interview_completed, offer_extended): only records whose current value matches the tenant's mapping. fields: 1 to 30 canonical field names to return (default: a standard set). sort: {"field", "direction"}; no sort is verified yet (returns "unsupported"). include_deleted: Include deleted records (default false; not verified, returns "unsupported"). limit: 1 to 100 (default 25). cursor: The next_cursor of a previous call with the same arguments.

Returns: JSON with status, entity, records, count, truncated, complete, next_cursor, consistency, reporting_timezone, provenance and warnings.

get_activityA

Read recruiting activity events, one independent block per concept.

Needs scope_type + scope_id, or both date_from and date_to (an unscoped range is at most 366 days). Business concepts (client_submission, interviews, offers) come only from the tenant's configured mappings; a missing definition returns "definition_missing", an unverified mechanism "unsupported" (never guessed).

Args: concepts: 1 to 8 concept IDs (e.g. job_created, submission_created, client_submission, interview_scheduled, interview_completed, placement_created, note_created). scope_type: candidate, job, client_corporation, client_contact, placement or submission. scope_id: The record id for scope_type (required with it). recruiter_id: A user id; filters on each concept's attribution field. date_from: Inclusive ISO-8601 date or datetime with offset. date_to: Exclusive ISO-8601 date or datetime with offset. limit: 1 to 200 events per concept (default 50). cursor: The next_cursor of a previous call with the same arguments.

Returns: JSON with status, concepts (per-concept blocks), next_cursor, reporting_timezone, provenance and warnings.

get_recruiting_metricsA

Recruiting metrics per calendar period: counts and same-period stage ratios.

Counts come from the tenant's configured activity concepts; a metric whose concept is not configured returns its status (e.g. "definition_missing") and no numbers. A count that could not be enumerated completely returns "incomplete" (never a partial number).

Args: metrics: 1 to 8 of jobs_created, client_submissions, interviews_scheduled, offers_extended, placements_created, submission_to_interview, interview_to_offer, offer_to_placement. date_from: Inclusive date (YYYY-MM-DD) in the reporting timezone, on a period boundary. date_to: Exclusive date (YYYY-MM-DD) on a period boundary; at most 12 months or 4 quarters. period: "month" (default) or "quarter".

Returns: JSON with status, tier, period, reporting_timezone, definition and per-metric cells.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

B3.4/5.0

Scored across 23 tools

Disambiguation3/5

There is substantial overlap between the generic search tools (search_entities Lucene, query_entities SQL-like, find_records structured filters) and the specific ones (list_jobs, list_candidates, get_recent_placements), so an agent can easily pick the wrong path to the same data. get_notes versus get_activity (which includes note_created) and connection_status versus setup_status versus bullhorn_session also blur together. The very detailed descriptions do help differentiate them, keeping this from being worse than a 3.

Naming Consistency3/5

Most tools follow a verb_noun snake_case pattern (list_jobs, get_candidate, propose_mapping_changes, confirm_write), which is readable and predictable. However several tools break the pattern with noun or non-standard verb forms (connection_status, setup_status, bullhorn_session, manage_mapping_profile). The mix is understandable but not fully consistent.

Tool Count3/5

23 tools is on the heavy side and sits in the borderline range where redundancy costs appear. The breadth (CRM reads, mapping-profile governance, safe-write pipeline, activity and metrics) justifies many tools, but the generic search trio overlaps with the resource-specific list tools, suggesting some could be consolidated.

Completeness3/5

The server has strong read coverage (jobs, candidates, placements, notes, activity, metrics) and a well-governed write path, but it lacks create/update for the core CRM entities (no candidate/job/submission/placement creation). For a Bullhorn agent the only real writes are notes and resume upload, a notable lifecycle gap.

Maintenance

ActivityMaintained
ResponsivenessNo issues