Skip to main content
Glama
Yasmine-Works

jobzyn-mcp

JobZyn MCP server

Connect JobZyn to Claude Desktop, Codex, and other Model Context Protocol clients. This TypeScript server exposes one tool for each of the five documented JobZyn API endpoints, through either stdio or an optional Streamable HTTP /mcp endpoint.

The distribution is an npm package running locally over stdio. No hosted service is planned. Streamable HTTP remains available as an optional capability for independently managed installations; both transports use the same tools and validation.

Claude Desktop: use the automatic npx setup. Claude downloads and launches the package for you—no npm install, repository checkout, or absolute package path required. Node.js 22+ must already be installed.

npm package: jobzyn-mcp, version 0.1.1.

Contents

Related MCP server: HireFrog MCP

Features and endpoint coverage

API base URL: https://www.jobzyn.com/api/integrations.

MCP tool

API method and path

Scope

Behavior

jobzyn_create_job

POST /job

write

Create a job; publishes immediately unless explicitly created as a draft

jobzyn_update_job

PUT /job/{externalJobId}

write

Change supplied fields; creates a missing job through an upsert

jobzyn_unpublish_job

DELETE /job/{externalJobId}

write

Remove public visibility while retaining job data

jobzyn_get_candidates

GET /job/{externalJobId}/candidates

read

Retrieve one page of applications, with date filters

jobzyn_link_external_ids

POST /job/link

write

Attach external IDs to existing JobZyn jobs

Coverage was checked against the JobZyn documentation on September 15, 2026. The site documents five method/path combinations. Authentication, accepted-values, and error pages describe those endpoints; they do not add API operations. There is no documented list-jobs endpoint or webhook registration endpoint to wrap.

Other features:

  • Typed, validated tool inputs, including all documented enums and query parameters.

  • Extra JSON fields inside job pass through, as allowed by JobZyn.

  • Tool annotations identify read operations, writes, and changes that can remove or replace data.

  • Responses include both readable JSON text and MCP structuredContent.

  • Request timeouts, cancellation, bounded responses, and no automatic retries.

  • Authenticated HTTP, exact host/origin allowlists, and stateless request handling.

  • A CLI, TypeScript library exports, Dockerfile, and CI for Node.js 22 and 24.

Requirements and authentication

  • Node.js 22 or newer and npm for local execution or building.

  • A JobZyn company API key. In the JobZyn backoffice, a Company Admin can open Settings → API Keys → Generate New Key. Copy the key when it is shown.

  • read scope to retrieve candidates; write scope to create, update, unpublish, or link jobs. JobZyn binds each key to a company.

Set the key as JOBZYN_API_KEY. The server sends it to JobZyn in the x-api-key header. Tools never ask the model to provide an API key.

HTTP mode also needs a separate MCP_AUTH_TOKEN of at least 32 characters. Generate a random token with:

openssl rand -hex 32

Use this token in the MCP client's Authorization: Bearer ... header. The server rejects a token that equals the JobZyn API key. The two credentials have different roles:

AI client ── MCP bearer token ──▶ JobZyn MCP server ── x-api-key ──▶ JobZyn

Quick start from source

git clone https://github.com/Yasmine-Works/jobzyn-mcp.git
cd jobzyn-mcp
npm ci
npm run build
cp .env.example .env

Edit .env and replace JOBZYN_API_KEY with your company key. Then:

# Local MCP process; stdin/stdout belong to the MCP client.
node --env-file=.env dist/cli.js

The stdio process waits for MCP messages, so a quiet terminal is normal. A client usually launches this process itself; you do not need to run a separate stdio server first.

.env is not loaded automatically. Use Node's --env-file option, set environment variables through your client, or have your hosting platform inject them. Never commit real credentials. npm start and npm run start:http use the current process environment.

Install from npm

npx downloads the pinned version into npm's cache and runs it. No separate npm install is needed. For Claude Desktop, skip the terminal commands and use the configuration below; Claude runs npx itself.

To launch it from a terminal:

export JOBZYN_API_KEY='YOUR_JOBZYN_API_KEY'
npx --yes jobzyn-mcp@0.1.1

Or install the CLI globally:

npm install --global jobzyn-mcp@0.1.1
jobzyn-mcp --transport stdio

To try the package locally before publishing:

npm pack
npm exec --yes --package=./jobzyn-mcp-0.1.1.tgz -- jobzyn-mcp --help

Pin reviewed releases in client configurations. Updating the package version requires updating and reviewing those pins as well.

Claude Desktop

  1. Install Node.js 22 or newer, which includes npm and npx, if it is not already installed.

  2. In Claude Desktop, open Settings → Developer → Edit Config.

  3. Add the configuration below, replace YOUR_JOBZYN_API_KEY with your key, and save. If you already have other MCP servers, add only the jobzyn entry inside the existing mcpServers object.

  4. Fully quit and reopen Claude Desktop. The five jobzyn_* tools should appear.

{
  "mcpServers": {
    "jobzyn": {
      "command": "npx",
      "args": ["--yes", "jobzyn-mcp@0.1.1"],
      "env": {
        "JOBZYN_API_KEY": "YOUR_JOBZYN_API_KEY"
      }
    }
  }
}

Claude launches npx, which downloads the package when needed and starts the local MCP server. --yes accepts npm's download prompt so startup can proceed without a terminal. Internet access is required for the first download and for calls to JobZyn. The version stays pinned until you change it in the configuration.

On Windows, use "command": "cmd" and "args": ["/c", "npx", "--yes", "jobzyn-mcp@0.1.1"] if launching npx directly fails.

This setup follows the official MCP local-server guide and npm's npx behavior. Protect the configuration file because it contains your API key. Standard locations are:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Run a source checkout (for development)

After building from source, you can run that checkout instead. Use this configuration with absolute executable and checkout paths:

{
  "mcpServers": {
    "jobzyn": {
      "command": "/absolute/path/to/node",
      "args": ["/absolute/path/to/jobzyn-mcp/dist/cli.js"],
      "env": {
        "JOBZYN_API_KEY": "YOUR_JOBZYN_API_KEY"
      }
    }
  }
}

On Windows, use an absolute node.exe path and escape backslashes in JSON. Fully quit and reopen Claude Desktop after saving.

Remote connections

For a client that supports custom authorization headers, configure the hosted HTTPS /mcp URL and the separate MCP bearer token. This server does not implement OAuth discovery, browser login, or dynamic client registration. If a Claude remote connector requires OAuth or cannot supply a custom bearer header, it needs a compatible authentication gateway in front of this server. Local stdio remains available without that gateway. Remote availability and authentication options depend on the client's managed configuration.

Codex

Local checkout

Add this entry to ~/.codex/config.toml, replacing the absolute paths:

[mcp_servers.jobzyn]
command = "/absolute/path/to/node"
args = ["/absolute/path/to/jobzyn-mcp/dist/cli.js"]
env_vars = ["JOBZYN_API_KEY"]

Start Codex with JOBZYN_API_KEY available in its environment. If your desktop launcher does not inherit shell variables, use an absolute protected env-file path instead:

[mcp_servers.jobzyn]
command = "/absolute/path/to/node"
args = ["--env-file=/absolute/path/to/jobzyn-mcp/.env", "/absolute/path/to/jobzyn-mcp/dist/cli.js", "--transport", "stdio"]

Choose one configuration for mcp_servers.jobzyn; do not duplicate the table.

Pinned npm package

Use the pinned npm package:

[mcp_servers.jobzyn]
command = "npx"
args = ["--yes", "jobzyn-mcp@0.1.1"]
env_vars = ["JOBZYN_API_KEY"]

Hosted HTTP

The remote client does not need Node.js or the npm package:

[mcp_servers.jobzyn]
url = "https://mcp.example.com/mcp"
bearer_token_env_var = "JOBZYN_MCP_TOKEN"

Set JOBZYN_MCP_TOKEN in Codex's environment to the server's MCP_AUTH_TOKEN. The client variable name is independent from the server variable name. You can also register the URL with the CLI:

codex mcp add jobzyn --url https://mcp.example.com/mcp --bearer-token-env-var JOBZYN_MCP_TOKEN
codex mcp list

The official Codex MCP documentation describes environment forwarding and bearer-token configuration. codex mcp login is for OAuth-enabled servers and is not the login mechanism for this static-token endpoint.

Streamable HTTP

This is an optional capability for independently managed installations. The planned npm distribution uses stdio and includes no hosted endpoint.

The implementation follows the SDK's Streamable HTTP guidance, using its stateless JSON-response mode. Each HTTP request receives its own MCP server and transport instance. There are no session IDs, in-memory client sessions, standalone SSE streams, or resumable event history.

Route

Access

Purpose

POST /mcp

MCP bearer token

Initialize, discover tools, call tools, send notifications

OPTIONS /mcp

No bearer token; origin validation applies

Browser CORS preflight

GET /mcp

MCP bearer token

Returns 405; no standalone SSE subscription

DELETE /mcp

MCP bearer token

Returns 405; no sessions to delete

GET /healthz

No bearer token; host validation applies

Liveness only; returns {"status":"ok"}

Requests include Content-Type: application/json and Accept: application/json, text/event-stream. Responses use JSON; valid notifications receive 202. The SDK handles protocol negotiation and rejects unsupported protocol-version headers. Returning 405 for an unsupported standalone GET stream is permitted by the MCP transport specification.

Local HTTP startup:

export JOBZYN_API_KEY='YOUR_JOBZYN_API_KEY'
export MCP_AUTH_TOKEN='YOUR_SEPARATE_RANDOM_MCP_TOKEN'
node dist/cli.js --transport http

Then check liveness and discovery from a second terminal with the token in its environment:

curl --fail http://127.0.0.1:3000/healthz

curl --fail http://127.0.0.1:3000/mcp \
  -H "Authorization: Bearer $MCP_AUTH_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"manual-check","version":"1.0.0"}}}'

curl --fail http://127.0.0.1:3000/mcp \
  -H "Authorization: Bearer $MCP_AUTH_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

These checks do not create or modify jobs. /healthz does not verify your JobZyn credentials or upstream connectivity. The stateless server also accepts independent discovery requests; SDK clients perform the normal initialization exchange.

Hosting and Docker

No service will be hosted for this release. The following reference is only for operators choosing to host their own copy.

Deploy the Node process or container behind an HTTPS reverse proxy or security gateway. A typical configuration is:

JOBZYN_API_KEY=YOUR_JOBZYN_API_KEY
MCP_AUTH_TOKEN=YOUR_SEPARATE_RANDOM_MCP_TOKEN
MCP_TRANSPORT=http
HOST=0.0.0.0
PORT=3000
MCP_ALLOWED_HOSTS=mcp.example.com,127.0.0.1,localhost

Replace mcp.example.com with the real hostname. MCP_ALLOWED_HOSTS validates the incoming Host hostname, ignoring its port. If the proxy rewrites Host to an internal service name, add that exact hostname. Forwarded host headers are not trusted. Do not use wildcards.

For browser-based clients that send an Origin header, add only the origins that should connect:

MCP_ALLOWED_ORIGINS=https://your-client.example.com

Origins include the scheme and optional port, with no trailing slash. Use the actual Origin sent by your client. Requests with an Origin header are rejected unless it is explicitly allowed; server-to-server requests without that header work with an empty list.

Build and run:

docker build -t jobzyn-mcp:0.1.1 .
docker run --rm --init --name jobzyn-mcp \
  -p 127.0.0.1:3000:3000 \
  --env-file .env \
  -e HOST=0.0.0.0 \
  -e MCP_TRANSPORT=http \
  -e MCP_ALLOWED_HOSTS=mcp.example.com,localhost,127.0.0.1 \
  jobzyn-mcp:0.1.1

The container runs as the non-root node user. The example publishes the port only on the host's loopback interface for a local reverse proxy. Use your platform's private networking when the proxy runs elsewhere. The client URL is the public HTTPS address ending in /mcp, not the container address.

At the proxy/gateway:

  • Terminate TLS, authenticate callers, and forward the server's bearer token securely.

  • Preserve Authorization, Accept, Content-Type, and MCP-Protocol-Version; do not log authorization headers or bodies.

  • Allow MCP POST and any required CORS preflight. Set request timeouts above JOBZYN_REQUEST_TIMEOUT_MS.

  • Apply rate and concurrency limits appropriate to your JobZyn account. The package does not provide a distributed rate limiter.

  • Restrict network access so an organization gateway cannot be bypassed by connecting directly to the origin.

  • Use /healthz for liveness. Supply an allowed Host header for platform health probes.

Stateless replicas need no session affinity. Each deployment is configured for one JobZyn company. Run separately configured deployments for different companies, or build an authenticated tenant-to-credential mapping before offering a shared service.

No hosting provider or public hostname is provisioned by this repository. The Dockerfile is supplied for deployment; validate the image in your target environment.

Configuration reference

Variable

Default

Meaning

JOBZYN_API_KEY

Required

Company API key, forwarded only as JobZyn's x-api-key

JOBZYN_BASE_URL

https://www.jobzyn.com/api/integrations

Upstream integration root; HTTPS required, except HTTP on loopback for tests

JOBZYN_REQUEST_TIMEOUT_MS

30000

Deadline for headers and response body, 1–300000 milliseconds

MCP_TRANSPORT

stdio

stdio or http; overridden by --transport

MCP_AUTH_TOKEN

Required in HTTP mode

Separate bearer token, at least 32 characters; use a random value

HOST

127.0.0.1

HTTP listen address; use 0.0.0.0 in containers

PORT

3000

HTTP listen port, 1–65535

MCP_ALLOWED_HOSTS

Loopback hosts when bound to loopback

Comma-separated exact hostnames/IPs, no scheme or port; required for non-loopback binding

MCP_ALLOWED_ORIGINS

Empty

Comma-separated exact browser origins; empty rejects all requests that include Origin

HTTP-specific configuration is only required in HTTP mode. Base URLs may not include embedded credentials, query parameters, or fragments. Changing the base URL changes where the API key is sent; configure only trusted JobZyn environments. Tool inputs cannot change it.

CLI options:

jobzyn-mcp [--transport stdio|http]
jobzyn-mcp --help
jobzyn-mcp --version

The HTTP request-body limit is 1 MiB. Upstream responses are limited to 10 MiB. Reduce candidate pageSize or split mapping batches if needed. Upstream API limits still apply.

Tool reference

Examples below are tool argument objects, used with the named MCP tool. A raw MCP call wraps them in {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"TOOL_NAME","arguments":{...}}}.

jobzyn_create_job

Required: job.id and job.title.

{
  "job": {
    "id": "REQ-2026-001",
    "title": "Software Engineer",
    "description": "<p>Build recruiting tools with our team.</p>",
    "city": ["Casablanca", "Rabat"],
    "country": "Maroc",
    "languages": ["fr", "en"],
    "contractType": "CDI",
    "educationLevel": "BAC +5",
    "workMode": "HYBRID",
    "minSalary": 8000,
    "maxSalary": 12000,
    "displaySalary": true,
    "minExperience": 0,
    "maxExperience": 5,
    "status": "UNPUBLISHED",
    "recruitmentProcess": ["Screening", "Technical interview"],
    "atsDepartment": "Engineering"
  }
}

This example creates a draft. Omitting status lets JobZyn default to PUBLISHED, so the job goes live immediately. A duplicate company/external-ID combination returns 409; use the update tool when appropriate.

All job fields

Field

Type

Notes

id

string

Required for create; your ATS identifier, used in later operations

title

string

Required for create

description

string

HTML supported; JobZyn sanitizes it

responsibilities

string

HTML supported

qualifications

string

HTML supported

benefits

string or string[]

Text or a list

city

string or string[]

One or multiple city names

country

string

JobZyn creation default: Maroc

languages

string[]

fr, en, ar

contractType

string

CDI, CDD, Stage, Alternance, Freelance, VIE, Autre

educationLevel

string

Non défini, Niveau BAC, BAC, BAC +1, BAC +1/2, BAC +3/4, BAC +5, BAC +5 et plus

workMode

string

REMOTE, HYBRID, ONSITE

minSalary, maxSalary

number

Net monthly salary bounds

displaySalary

boolean

JobZyn creation default: false

minExperience, maxExperience

number

Each between 0 and 20 years

status

string

PUBLISHED or UNPUBLISHED

recruitmentProcess

string[]

Ordered interview/recruitment steps

Additional fields

JSON values

Preserved inside job, including nested objects and arrays

Enums are case- and space-sensitive. The documentation's create example uses Bac+5, but the accepted-values page explicitly requires BAC +5; this server follows the accepted-values list. It does not normalize or silently substitute values. Unknown top-level tool arguments are rejected; custom fields belong inside job.

jobzyn_update_job

Required: externalJobId and a job object. Job fields are optional and only supplied fields are forwarded, so defaults do not overwrite existing data. false, 0, empty strings, and arrays are preserved.

{
  "externalJobId": "REQ-2026-001",
  "job": {
    "title": "Senior Software Engineer",
    "displaySalary": false,
    "status": "PUBLISHED"
  }
}

This example publishes the job. The endpoint is an upsert: it updates an existing job (200) or creates a missing one (201). Include enough creation data, including a title, if the job may not exist. JobZyn accepts all create fields on update, including optional job.id; normally omit that field and use externalJobId to identify the target. The server forwards supplied values without rewriting the ID.

jobzyn_unpublish_job

{ "externalJobId": "REQ-2026-001" }

The server sends DELETE with no body. Job data is retained, but candidates can no longer see the job publicly. To republish, call the update tool with job.status set to PUBLISHED.

jobzyn_get_candidates

{
  "externalJobId": "REQ-2026-001",
  "from": "2026-07-01T00:00:00Z",
  "to": "2026-07-31T23:59:59Z",
  "page": 1,
  "pageSize": 50
}

Parameter

Meaning

externalJobId

Required; your ATS job ID

since

Applications after this date; JobZyn gives it priority over from

from

Applications on or after this date

to

Applications on or before this date

page

Integer starting at 1; JobZyn defaults to 1

pageSize

Integer 1–100; JobZyn defaults to 50

Dates accept ISO calendar dates such as 2026-07-01 or ISO timestamps with Z or a UTC offset. Prefer UTC timestamps for polling. All supplied filters are forwarded, including both since and from; JobZyn applies precedence.

Each call retrieves one page. Use the top-level data.total and your effective pageSize to determine how many pages remain. Candidate records may include application ID, name, email, phone, application date, status, cover message, LinkedIn URL, CV URL, and job/company references. CV URLs are returned as data; this server does not download resumes or open links.

For polling, keep a checkpoint in your own application, retrieve every page in a fixed date window, and advance the checkpoint only after processing that window successfully. A small overlap with deduplication by application id can protect against timestamp boundary or arrival-order issues. The documentation does not promise snapshot-stable pagination. The server does not retain polling state or run a scheduler. JobZyn documents polling as the current alternative to webhooks.

{
  "links": [
    { "jobzynJobId": 2625, "externalJobId": "REQ-2026-001" },
    { "jobzynJobId": 2626, "externalJobId": "REQ-2026-002" }
  ]
}

jobzynJobId is JobZyn's internal numeric job ID, available in the backoffice job URL. externalJobId is your external ATS ID. This is the only tool that needs internal IDs.

Each result has one of three documented statuses:

  • linked: mapping was created.

  • already_linked: the job already has an external ID; no change was made. This does not prove that the existing ID equals the one requested.

  • not_found: the job does not exist or is outside the API key's company.

Inspect every result. A batch can partly succeed even with HTTP 200. The MCP result sets isError: true if any mapping is not_found, while retaining all successes and statuses. Existing mappings are not overwritten.

Results and errors

A successful call returns the upstream HTTP status and JobZyn response body:

{
  "httpStatus": 200,
  "data": {
    "jobId": 1234,
    "jobUrl": "https://www.jobzyn.com/fr/companies/example/jobs/example-job",
    "error": null
  }
}

This object appears in MCP structuredContent and is serialized in a text content block. Upstream response fields remain available; an accidental echo of the configured API key is redacted.

API failures retain httpStatus and the response body and set MCP isError: true. Application-level error fields and partial link failures also set isError. If present, the upstream Retry-After header appears as retryAfter. An HTTP MCP request can return 200 while the enclosed tool result reports a JobZyn error: check isError and httpStatus.

JobZyn status

Typical action

400

Correct required fields, dates, or enum values

401 / 403

Check key, scopes, company ownership, and external job ID

404

Check the job ID; unpublish documents this for missing jobs

409

Job exists; consider update instead of create

429

Respect any retry guidance; reduce request rate

500

Investigate upstream failure; verify write outcome before repeating

JobZyn's authentication page describes missing credentials as 403, while its error guide lists 401; the server preserves the actual upstream status. Candidate lookup can also return 403 for an unknown or inaccessible job.

Transport failures use a safe local error envelope:

{
  "error": {
    "code": "TIMEOUT",
    "message": "JobZyn request timed out.",
    "outcomeUnknown": true,
    "guidance": "The write may have completed. Verify the job in JobZyn before repeating the request."
  }
}

Other codes include CANCELLED, NETWORK_ERROR, INVALID_RESPONSE, RESPONSE_TOO_LARGE, and INTERNAL_ERROR. An outcomeUnknown warning accompanies failed write transport/response handling. The server never retries automatically. Cancellation or timeout cannot roll back a request that JobZyn already applied.

Security and operating model

  • Single company per process/deployment. Every bearer-token holder can use the configured company's API scopes. The static token is not a user identity or tenant selector.

  • Gateway authentication. The bearer token is a shared deployment secret, not a complete MCP OAuth authorization service. Add the authentication and authorization gateway your managed client requires.

  • Secret separation. MCP authorization headers are not forwarded to JobZyn. Incoming x-api-key headers cannot select a different upstream account.

  • Restricted outbound requests. Only the five fixed endpoint shapes can be called. External job IDs are URL-encoded; . and .. path segments are rejected. Redirects are not followed, and production upstream URLs require HTTPS.

  • Browser protections. Exact Host and Origin checks apply as documented above. CORS is not authentication; bearer authentication is still required for actual MCP calls.

  • Tool policy. Only candidate retrieval is marked read-only. Annotation hints help clients present approvals; they do not replace JobZyn scopes or gateway enforcement. Use a read-scoped JobZyn key and client/gateway tool restrictions for candidate-only access. All five tools remain discoverable.

  • Candidate privacy. Tool responses can contain personal information. Control who can invoke candidate retrieval and where your client retains responses. The server has no persistent application database and does not log tool bodies, but client/gateway infrastructure may retain them.

  • Untrusted content. Treat returned candidate text and job HTML as data, not instructions. The server does not execute returned content or follow resume links.

  • Shutdown. SIGINT/SIGTERM closes the transport/listener; HTTP gets up to 10 seconds to drain before forced exit. A process termination may leave an upstream write outcome uncertain.

Development, testing, and releases

npm ci
npm run check
npm test
npm run verify:package

npm test builds the executable and runs tests against a local mock API using the actual MCP SDK clients. The suite verifies all five endpoints through both stdio and Streamable HTTP, custom-field preservation, input validation, request encoding, authorization/origin/host checks, concurrent clients, errors, partial successes, redaction, redirect refusal, and timeouts. It does not require credentials or mutate live JobZyn data. Live account behavior must be validated separately.

For source development, use npm run dev with credentials in the process environment. CLI diagnostics go to stderr so stdout remains valid MCP traffic.

Project layout

src/
  cli.ts        CLI, transport selection, shutdown
  config.ts     Environment parsing and configuration validation
  schemas.ts    All job fields and endpoint input schemas
  client.ts     Fixed JobZyn API operations and bounded HTTP requests
  server.ts     Five MCP tool registrations and result handling
  http.ts       Authenticated stateless HTTP app and listener
  index.ts      Public library exports
test/           Local API, MCP transport, validation, and error tests
examples/       Client configuration examples

Library usage

The package exports the MCP server factory, HTTP app/listener, typed API client, input schemas, and configuration readers. For example:

import { createJobzynServer, readApiConfig } from 'jobzyn-mcp';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = createJobzynServer(readApiConfig());
await server.connect(new StdioServerTransport());

createHttpApp(apiConfig, httpConfig) lets an existing Express host mount the application. Keep its authentication and validation middleware intact. The JobzynClient methods are typed API wrappers; MCP input validation occurs in the server, so direct JavaScript callers should validate payloads with the exported schemas.

Live validation without stored credentials in code

Use an ignored local .env file containing JOBZYN_API_KEY, then run:

npm run build
npm run test:live -- --job-id YOUR_EXTERNAL_JOB_ID

The helper uses stdio, makes one read-only candidate lookup, and prints only status and counts. It never writes jobs, persists candidate records, or prints the API key or candidate details. No credentials are needed for CI or release preparation. See the live-test instructions.

Release process

Create the reviewed npm artifact with:

npm run release:prepare

This produces .release/jobzyn-mcp-0.1.1.tgz and an integrity manifest after checking the package allowlist, credentials, clean installation, TypeScript exports, and all five stdio tools. .release/, local .env* files, and .npmrc are excluded from Git. Only explicitly listed public files enter the package.

Follow the npm publication guide for the dry run, maintainer login, publication of the exact reviewed tarball, and registry verification. The npm examples for Claude Desktop and Codex are pinned to 0.1.1.

  1. Confirm npm ownership/availability of jobzyn-mcp, or change the package name and all client examples to your organization's scope.

  2. Update package.json, src/config.ts's version, and client examples together. Commit the lockfile.

  3. Run the checks above. Inspect the tarball to confirm it contains compiled runtime files and declarations, README, examples, and LICENSE, with no secrets.

  4. Test the tarball in a clean installation. Confirm the CLI works without source files or development dependencies.

  5. Publish the reviewed version using your organization's npm release process. When publishing from the source directory, prepublishOnly runs the full release preparation gate and prepack builds the runtime.

  6. Record the published release metadata:

npm view jobzyn-mcp@0.1.1 version dist.integrity dist.tarball --json

Publishing and hosting are separate actions. A public npm package has no public /mcp endpoint until someone deploys the HTTP server. No CI job in this repository publishes or deploys automatically.

Troubleshooting

Symptom

Check

stdio appears to do nothing

It is waiting for a client; configure Claude/Codex to launch it

JSON parsing errors in a local client

Launch the CLI directly; keep banners and logs off stdout

JOBZYN_API_KEY missing

.env is not automatic; use --env-file, client env settings, or hosting secrets

npx says package/version not found

Publish the intended version first, or use the built checkout/tarball

Claude cannot find npx

Install Node.js 22+ and fully restart Claude. If Node is installed through a version manager, ensure its executables are available to desktop apps; on Windows, try the cmd configuration above

Desktop cannot find Node

Set an absolute Node executable path; verify Node 22+

HTTP 401 from /mcp

Supply the separate MCP token, not the JobZyn API key

HTTP 403 before a tool runs

Check allowed Host and Origin; your proxy may rewrite Host

HTTP 405 on GET /mcp

Expected; this endpoint uses Streamable HTTP POST and has no standalone SSE stream

HTTP 413

Reduce the request below 1 MiB, e.g. split a link batch

MCP tool returns JobZyn 403

Check API scopes, company ownership, and the external job ID

BAC +5 validation error

Use the exact accepted value with spaces and capitalization

Missing candidates

Check date filters, since precedence, total, and additional pages

Timeout while writing

Verify the job in the JobZyn backoffice before retrying

HTTP startup fails on 0.0.0.0

Set explicit MCP_ALLOWED_HOSTS and a separate MCP_AUTH_TOKEN

OAuth login fails

This server uses a static bearer token; configure headers or a compatible gateway

Documentation sources

License

MIT, copyright 2026 Yasmine Works and Agenz.

Available Tools

5 tools
jobzyn_create_jobCreate JobZyn jobA

Create a job (POST /job, write scope). Requires job.id and job.title. Defaults to PUBLISHED: the job becomes public immediately. Set status UNPUBLISHED for a draft. Duplicate external IDs return 409. Additional job fields are preserved.

ParametersJSON Schema
NameRequiredDescriptionDefault
jobYes

TDQS

A4.6/5.0
Behavior5/5

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

Beyond the annotations, the description reveals key write behavior: immediate publication by default, the UNPUBLISHED draft path, 409 on duplicate external IDs, and preservation of additional fields. This is substantial behavioral disclosure for annotations that only provide generic hints.

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 compact and front-loaded: endpoint and scope first, then requirements and behavior. Every sentence earns its place by stating a requirement or a behavioral consequence.

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 creation tool with no output schema, te description covers endpooint, required subfields, default status, draft option, duplicate behavior, and open-world field handling. It omits the response shape, but an agent has enough to invoke the tool correctly and understand common failures.

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 top-level job parameter has no schema description, so the description compensates by identifying required id/title subfields and adding status and duplicate-ID semantics. It does not enumerate every optional field, but the nested schema already documents those details.

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 states a specific verb and resource: 'Create a job (POST /job, write scope).' It also clarifies required fields and creation defaults, which clearly distinguishes it from siblings like jobzyn_update_job or jobzyn_get_candidates.

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 gives clear usage context: job.id and job.title are required, and the caller must choose between PUBLISHED (immediate public) and UNPUBLISHED (draft). It does not explicitly name update_job as the alternative for existing IDs, but the duplicate-external-ID 409 behavior implies the boundary.

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

jobzyn_get_candidatesGet JobZyn candidatesA
Read-onlyIdempotent

Retrieve one page of applications for an external job ID (GET /job/{externalJobId}/candidates, read scope). Supports since/from/to ISO dates and page/pageSize (1-based; default 50, max 100). since takes priority over from. Use total to fetch remaining pages. Contains personal information and resume URLs; no files are downloaded.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoApplications on or before this date.
fromNoApplications on or after this date; ignored by JobZyn when since is supplied.
pageNoPage number, starting at 1. JobZyn defaults to 1.
sinceNoApplications after this date; takes priority over from when both are supplied.
pageSizeNoResults per page, at most 100. JobZyn defaults to 50.
externalJobIdYesYour external job ID from your ATS, not the internal numeric JobZyn job ID.

TDQS

A4.4/5.0
Behavior5/5

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

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false. The description adds meaningful behavioral context: it mentions the read scope, clarifies that 'since takes priority over from', explains pagination via 'Use total to fetch remaining pages', and warns about personal information and that no files are downloaded. This goes well beyond the annotations and provides actionable operational insights.

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 three sentences, front-loaded with the core purpose, followed by essential operational details. Every sentence adds value: the purpose, the supported options, and the pagination/data-sensitivity note. No redundancy or filler.

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?

With six parameters but only one required, the schema covers all parameter meanings, and annotations cover safety. Since there is no output schema, the description provides some guidance on response usage ('Use total to fetch remaining pages') and alerts to personal information. It does not describe the candidate object structure, but for a paginated read tool that is likely sufficient for an agent to invoke correctly. Minor gap: no explicit mention of the response format beyond pagination.

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

Parameters3/5

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

Schema coverage is 100% – every parameter has a description. The tool description repeats some schema details (default pageSize, 1-based page, priority rules) but adds little new parameter-level meaning. It does introduce the concept of using 'total' for pagination, which is output-related, not parameter-specific. Since the schema already documents each parameter thoroughly, the description does not significantly enhance parameter understanding.

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: 'Retrieve one page of applications for an external job ID' – a specific verb, resource, and scope. It also names the HTTP endpoint and read scope, distinguishing it from sibling tools like jobzyn_create_job or jobzyn_unpublish_job, which are mutations. The purpose is unambiguous.

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 conveys when to use this tool (to fetch candidate applications) and provides operational details (pagination, date filters, priority rules). It does not explicitly contrast it with alternatives, but the sibling names (create, update, unpublish, link) make the read-only distinction obvious. There is no misleading guidance; the context is clear but lacks an explicit 'use this instead of X' statement.

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

jobzyn_unpublish_jobUnpublish JobZyn jobA
DestructiveIdempotent

Unpublish a job by external ID (DELETE /job/{externalJobId}, write scope). Removes public visibility while retaining the job data. Does not permanently delete the job.

ParametersJSON Schema
NameRequiredDescriptionDefault
externalJobIdYesYour external job ID from your ATS, not the internal numeric JobZyn job ID.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already signal write/destructive behavior, so the description adds value by clarifying the exact effect: 'Removes public visibility while retaining the job data' and 'Does not permanently delete the job.' It also includes 'write scope' and the HTTP method, giving the agent a clearer behavioral picture.

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?

Three short sentences, each earning its place: the first states the operation and endpoint, the second describes the state change, and the third clarifies what it does not do. There is no redundant or filler text.

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?

For a one-parameter tool with 100% schema coverage and annotations covering idempotency, read-only-ness, and destructiveness, the description is complete enough for an agent to invoke it correctly. It clarifies the non-destructive nature of unpublishing and does not need an output schema to explain return values.

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

Parameters3/5

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

The single parameter is fully documented in the schema with a clear description of externalJobId, including the warning that it is not the internal numeric JobZyn job ID. The description's 'external ID' phrasing adds little beyond the schema, so the baseline score of 3 is appropriate.

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 states a specific verb and resource ('Unpublish a job by external ID') and gives the exact endpoint and scope. It is clearly distinct from the sibling tools (create, update, get, link), and it disambiguates 'unpublish' from permanent deletion.

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 gives clear context: use this when you need to remove public visibility while retaining data, and it explicitly says this does not permanently delete the job. It does not name alternative tools or state when to prefer update_job instead, but the intended usage is evident.

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

jobzyn_update_jobUpdate or upsert JobZyn jobA
DestructiveIdempotent

Update a job by external ID (PUT /job/{externalJobId}, write scope). Only supplied fields change. If the job does not exist, JobZyn creates it (201); include a title for creation. Can publish/unpublish through status. Job fields including optional id and custom fields are forwarded as supplied.

ParametersJSON Schema
NameRequiredDescriptionDefault
jobYes
externalJobIdYesYour external job ID from your ATS, not the internal numeric JobZyn job ID.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already mark this as read-write, destructive, idempotent, and open-world. The description adds valuable behavioral details beyond those flags: partial-update semantics, 201 creation on missing job, status-based publish/unpublish, and forwarding of custom fields. No contradiction with the annotations.

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?

Three tight sentences front-load the core operation and scope, then add the essential upsert, partial-update, and custom-field behavior. No filler or repetition of schema details.

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 mutation tool with a nested job object and no output schema, the description covers the key call semantics: identification, partial update, creation fallback, title requirement, status effect, and custom fields. It stops short of describing response/error behavior, but the annotations and detailed input schema carry the rest.

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?

Schema coverage is about 50%, and the description adds useful conditional semantics not explicit in schema: the external ID is the lookup key, title is required for creation, and unknown/custom job fields are passed through. It doesn't enumerate every parameter, but the schema already documents most 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 names a specific operation ('Update a job by external ID'), the HTTP method/resource (PUT /job/{externalJobId}), and the write scope. It also distinguishes itself from create by stating the upsert behavior: if the job does not exist, JobZyn creates it (201).

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 gives clear context: use external ID, only supplied fields change, creation requires title, and status can publish/unpublish. It does not explicitly name when to prefer sibling tools like jobzyn_create_job or jobzyn_unpublish_job, so it falls just short of full routing guidance.

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. 5 tool updatesv0.1.1
    • First observedjobzyn_create_job
    • First observedjobzyn_get_candidates
    • First observedjobzyn_link_external_ids
    • First observedjobzyn_unpublish_job
    • First observedjobzyn_update_job

TDQS

A4.4/5.0

Scored across 5 tools

Disambiguation4/5

Each tool has a distinct primary purpose: create, update, unpublish, fetch candidates, and link IDs. The only mild ambiguity is that update_job can also publish/unpublish via status, which overlaps with unpublish_job, but the dedicated unpublish action is still clearly differentiated.

Naming Consistency5/5

All tools follow a consistent verb_noun snake_case pattern with the jobzyn_ prefix (create_job, update_job, unpublish_job, get_candidates, link_external_ids). No mixed conventions or vague verbs.

Tool Count5/5

Five tools is well-scoped for a focused job-posting and candidate-retrieval MCP server. Each tool earns its place, and the count is neither too thin nor bloated.

Completeness3/5

The set covers create, update, unpublish, and candidate retrieval, but lacks a get_job or list_jobs operation, making it impossible to read or verify a job's current details or status through the MCP surface. This is a notable gap for a job-management server.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to recommend jobs, parse candidate profiles, compute semantic skill match scores, and filter opportunities by location through standardized MCP tools.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP-compatible AI assistants to securely access a user's job-search account, letting them search and save jobs, analyze job fit, and retrieve job queue and profile summaries with links back to the web app.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI clients to serve as a personal career analyst by searching, matching, and explaining job recommendations, managing job applications, and syncing public job boards through standardized MCP tools.
    MIT