Skip to content

Connect Ashby to Claude: Automate Hiring Pipelines via MCP

Learn how to connect Ashby to Claude using a managed MCP server. Automate your hiring pipeline, candidate sourcing, and offer generation workflows without writing integration boilerplate.

Uday Gajavalli Uday Gajavalli · · 9 min read
Connect Ashby to Claude: Automate Hiring Pipelines via MCP

Just 3% of talent teams report advanced AI adoption, according to Forrester [1]. Yet the engineering pressure to automate hiring workflows is at an all-time high. Ashby has emerged as a dominant Applicant Tracking System (ATS) for high-growth companies, centralizing everything from sourcing to offer letters. If you want to build custom AI agents that interact with your Ashby data - or simply want to query candidate profiles directly from Claude (if you use OpenAI, see our guide on connecting Ashby to ChatGPT) - you hit a wall.

There is no native Claude connector for Ashby. Connecting Anthropic's Large Language Model (LLM) to Ashby's REST API requires an integration layer. You either spend weeks building and hosting a custom Model Context Protocol (MCP) server, or you use a managed infrastructure layer that handles the boilerplate for you.

This guide breaks down exactly how to use Truto to generate a managed MCP server for Ashby, connect it natively to Claude Desktop, and execute complex recruiting workflows using natural language.

The Engineering Reality of Custom ATS Connectors

A custom MCP server is a self-hosted integration layer that translates an LLM's natural language tool calls into structured REST API requests.

Anthropic's rollout of Custom Connectors gave engineers a standardized way to connect models to external systems. The protocol itself is elegant. The reality of implementing it against vendor APIs is entirely different.

If you decide to build a custom MCP server for Ashby, you are responsible for the entire API lifecycle. You have to write and maintain massive JSON schemas for every endpoint you want the LLM to access. When the LLM requests a list of candidates, you have to write the logic to handle pagination cursors. LLMs are notoriously bad at managing pagination state on their own (a challenge we also highlighted when connecting Kandji to ChatGPT). If you build a custom server, you must explicitly instruct the LLM to pass the cursor value back exactly as received. If the model modifies the cursor string, the pagination breaks.

Handling Rate Limits and Authentication

When an API token expires, your MCP server needs a mechanism to detect the 401 Unauthorized error, refresh the token, and retry the request without crashing the LLM's context window.

Truto handles this proactively. Before making any API request on behalf of an integrated account, the proxy layer checks if the OAuth token is expired (using a 30-second buffer). If it is, the system automatically calls the provider to refresh the token, updates the database, and proceeds with the request. For high-volume scenarios, a Durable Object alarm fires 60 - 180 seconds before expiry to refresh the credentials asynchronously. The LLM never sees an authentication error.

The Managed Approach: Zero Integration-Specific Code

Truto approaches this differently. Instead of writing integration-specific code for Ashby, Truto's architecture relies on a generic execution pipeline driven by JSON configuration.

When you connect an Ashby account, Truto dynamically generates a set of MCP tools from the integration's resource definitions and documentation records. These tools are served over a JSON-RPC 2.0 endpoint that any MCP client can connect to.

Because tool generation is dynamic and documentation-driven, a tool only appears in the MCP server if it has a corresponding documentation entry. This acts as a quality gate, ensuring only well-documented endpoints are exposed to Claude. When Ashby updates their API, the documentation records update, and your MCP server automatically inherits the new schemas. No code deployment required.

How to Create the Ashby MCP Server

You can generate a secure, self-contained MCP server URL for Ashby in two ways.

Method 1: Via the Truto Interface

  1. Navigate to the integrated account page for your connected Ashby instance.
  2. Click the MCP Servers tab.
  3. Click Create MCP Server.
  4. Select your desired configuration (e.g., restrict to read-only methods, apply specific tags, or set an expiration date).
  5. Copy the generated MCP server URL.

Method 2: Via the API

For programmatic provisioning, you can issue a POST request to generate the server. The API validates that the integration has tools available, generates a secure token, and returns a ready-to-use URL.

POST /integrated-account/:id/mcp
{
  "name": "Ashby Recruiting Agent",
  "config": {
    "methods": ["read", "write"]
  },
  "expires_at": null
}

The response includes the URL you will feed to Claude:

{
  "id": "abc-123",
  "name": "Ashby Recruiting Agent",
  "url": "https://api.truto.one/mcp/a1b2c3d4e5f6..."
}

Adding Extra Authentication

By default, the MCP server URL contains a cryptographic token that acts as the sole authentication mechanism. Anyone with the URL can call the tools. For higher-security scenarios, you can pass "require_api_token_auth": true in the configuration. This forces the MCP client to also provide a valid Truto API token in the Authorization header, adding a second layer of security.

Connecting Ashby to Claude Desktop

Once you have your MCP server URL, connecting it to Claude takes seconds.

  1. Open Claude Desktop.
  2. Navigate to Settings -> Connectors -> Add custom connector.
  3. Paste your Truto MCP URL.
  4. Click Add.

Claude immediately discovers the available Ashby tools via the MCP handshake. No additional configuration is needed.

Tool Execution: What You Can Do With Ashby

When Claude connects to the Truto MCP server, it gains access to 33 distinct tools mapped directly to Ashby's API. You can view the full capabilities on the Ashby integration page.

Here is the complete inventory of tools your AI agent can now execute:

Candidate Management

  • list_all_ashby_candidates: List candidates in Ashby. Returns candidate id, createdAt, updatedAt, name, primaryEmailAddress, and emailAddresses.
  • get_single_ashby_candidate_by_id: Get a single candidate by externalMappingId in Ashby. Returns candidate details including id, name, and email address.
  • create_a_ashby_candidate: Create a new candidate profile.
  • update_a_ashby_candidate_by_id: Update an existing candidate by candidateId in Ashby. Returns updated candidate fields including id, name, and primaryEmailAddress.
  • ashby_candidates_tag: Add a tag to a candidate in Ashby using candidateId and tagId. Returns candidate details including id and name.
  • ashby_candidates_project: Add a candidate to a project in Ashby. Requires candidateId and projectId. Returns candidate details.
  • ashby_candidates_anonymize: Anonymize a candidate by id in Ashby. Requires candidateId. This action cannot be reversed and requires high-level permissions.

Application & Pipeline Tracking

  • list_all_ashby_applications: Get all applications in the organization in Ashby. Returns application id, createdAt, updatedAt, status, and candidate details.
  • get_single_ashby_application_by_id: Fetch application details by id in Ashby. Requires applicationId. Returns id, createdAt, updatedAt, status, and candidate info.
  • create_a_ashby_application: Create an application by considering a candidate for a job in Ashby. Requires candidateId and jobId.
  • update_a_ashby_application_by_id: Update an application by id in Ashby. Requires applicationId. Returns updated application fields including id, status, and candidate info.
  • ashby_applications_change_stage: Change the stage of an application by applicationId and interviewStageId in Ashby. Returns updated application details.
  • ashby_applications_change_source: Change the source of an application in Ashby. Requires applicationId and sourceId. Returns updated application details.
  • ashby_applications_transfer: Transfer an application with applicationId to a different job with jobId, interviewPlanId, and interviewStageId.

Job & Requisition Management

  • list_all_ashby_jobs: List all jobs in Ashby with optional filtering by status. Returns job id, title, status, and employmentType.
  • get_single_ashby_job_by_id: Get information about a specific job in Ashby. Returns fields including id, title, status, and location.
  • create_a_ashby_job: Create a new job in Ashby with required parameters title, teamId, and locationId. Returns job id, title, and status.
  • update_a_ashby_job_by_id: Update an existing job in Ashby by jobId. Returns updated job fields including id, title, status, and locationId.
  • ashby_jobs_set_status: Set the status of a job by id in Ashby. Requires jobId and status. Returns updated job fields.

Interviews & Offers

  • list_all_ashby_interviews: List all interviews in Ashby. Returns id, title, isArchived, isDebrief, and instructionsHtml.
  • get_single_ashby_interview_by_id: Fetch interview details by id in Ashby. Requires id. Returns id, title, isArchived, isDebrief, and instructions.
  • list_all_ashby_offers: Get a list of all offers with their latest version in Ashby. Returns id, decidedAt, and status.
  • get_single_ashby_offer_by_id: Get details about a single offer by id in Ashby. Requires offer id. Returns fields including id, decidedAt, and applicationId.
  • create_a_ashby_offer: Create a new offer with offerProcessId, offerFormId, and offerForm containing fieldSubmissions in Ashby.
  • update_a_ashby_offer_by_id: Update an existing offer by providing offerId and offerForm with fieldSubmissions in Ashby.

Organizational Structure & Users

  • list_all_ashby_departments: List all departments in Ashby. Returns id, name, isArchived, and parentId fields for each department.
  • get_single_ashby_department_by_id: Fetch department details by id in Ashby. Requires departmentId. Returns id, name, isArchived, and parentId.
  • create_a_ashby_department: Create a department with name and optional parentId in Ashby. Returns id, name, isArchived, and parentId.
  • update_a_ashby_department_by_id: Update a department using departmentId and name in Ashby. Returns id, name, isArchived, and parentId.
  • ashby_departments_move: Move a department by departmentId to another parent using parentId in Ashby. Returns id, name, and isArchived status.
  • delete_a_ashby_department_by_id: Archive a department by departmentId in Ashby. Returns the department's id, name, and isArchived status.
  • ashby_departments_restore: Restore a department by departmentId in Ashby. Returns the department's id, name, isArchived status, and parentId.
  • list_all_ashby_users: Get a list of all Ashby users. Returns id, firstName, lastName, email, and globalRole.
  • get_single_ashby_user_by_id: Get an Ashby user by id. Requires userId. Returns id, name, email, globalRole, and enabled status.

Architecting the AI Workflow

The Flat Input Namespace Problem

When an MCP client like Claude calls a tool, all arguments arrive as a single flat JSON object. This presents a unique challenge for REST APIs, which expect parameters to be strictly segregated into path variables, query strings, and request bodies.

Truto's MCP router solves this by extracting the tool's query_schema and body_schema from the documentation records. It inspects the incoming flat object and routes each parameter to its correct destination based on property keys. If a query schema and a body schema both define a property with the exact same name, the query schema takes precedence. This mapping layer is invisible to the LLM, allowing it to interact with complex APIs without understanding their underlying HTTP transport mechanics.

Tool Tags and Method Filtering

Exposing an entire ATS to an LLM is a massive security risk if not properly scoped. You rarely want an AI agent to have unrestricted delete access to your candidate database.

When generating the MCP server, you can restrict access using method filtering. By passing methods: ["read"] in the configuration, Truto filters out any create, update, or delete operations at the generation stage. The LLM simply won't know those tools exist.

You can also filter by functional area using tool tags. If you only want an agent to manage job postings, you can apply a tag filter so the server only exposes tools related to the jobs and departments resources, completely isolating candidate data.

Here is an architectural view of how a tool call flows from Claude to Ashby:

sequenceDiagram
    participant Claude as Claude Desktop
    participant MCP as Truto MCP Server
    participant Proxy as Proxy Layer
    participant Ashby as Ashby API

    Claude->>MCP: Call ashby_applications_change_stage(applicationId, interviewStageId)
    MCP->>MCP: Validate token & extract schemas
    MCP->>MCP: Split flat arguments into query & body
    MCP->>Proxy: Delegate to proxy API handler
    Proxy->>Proxy: Refresh OAuth token (if expired)
    Proxy->>Ashby: POST /applications/{applicationId}/stage
    Ashby-->>Proxy: 200 OK (Updated Application)
    Proxy-->>MCP: Parse response via JSONata
    MCP-->>Claude: Return JSON-RPC result

This architecture allows you to build highly autonomous recruiting workflows. You can ask Claude: "Find the candidate named Jane Doe, check her current application stage, and if she passed the technical screen, draft an offer letter based on the standard engineering template." Claude will chain list_all_ashby_candidates, get_single_ashby_application_by_id, and create_a_ashby_offer together, handling the data mapping automatically.

Strategic Next Steps

Building custom MCP servers for enterprise Applicant Tracking Systems is a massive time sink. You end up maintaining schemas, fighting pagination cursors, and writing boilerplate authentication logic instead of actually building AI agents.

By using a managed MCP infrastructure, you offload the entire integration lifecycle. Your AI agents get immediate, secure access to Ashby's full API surface, allowing you to automate pipeline management, candidate sourcing, and offer generation in minutes.

FAQ

Does Claude have a native connector for Ashby?
No. To connect Claude to Ashby, you must use a Model Context Protocol (MCP) server. You can either build one from scratch or use a managed MCP infrastructure like Truto.
How does the MCP server handle Ashby's API authentication?
Truto's managed MCP server handles the entire OAuth lifecycle automatically. It proactively refreshes access tokens before they expire, ensuring Claude never encounters a 401 Unauthorized error.
Can I restrict what Claude can do in my Ashby account?
Yes. When creating the MCP server, you can use method filtering to restrict Claude to read-only actions, or use tool tags to limit access to specific resources like jobs and departments.
How do I create an MCP server for Ashby?
You can create it via the Truto interface under the 'MCP Servers' tab of your integrated account, or programmatically by sending a POST request to the /integrated-account/:id/mcp endpoint.

More from our Blog