Use AI to manage your job board with Cavuno MCP

Connect Claude, Cursor, Codex, and other MCP clients to your Cavuno job board.

The Cavuno MCP server is a hosted Cloudflare Worker at mcp.cavuno.com. It lets AI agents like Claude, Cursor, and Codex drive the Cavuno API without any per-endpoint MCP tool registration — there is no npm package to install, just an HTTPS URL. The public Cavuno MCP repository contains connection examples and issue tracker details, plus registry metadata; the hosted server implementation is not published there.

The authenticated Operator MCP endpoint at mcp.cavuno.com/mcp exposes exactly two tools, regardless of how many REST endpoints exist:

  • search — runs JavaScript against the Cavuno OpenAPI spec for endpoint and schema discovery.
  • execute — runs JavaScript that calls the Cavuno API via a sandboxed loopback binding. Multiple calls can be chained in one execution; the final return value and captured console output flow back to the model.

This follows Cloudflare's “code mode” pattern. In Cloudflare's implementation, code-based discovery and execution reduced the tool context needed for a large API. Cavuno applies the same pattern with a two-tool surface; results still depend on the client, model, and task.

Choose a job board resource

Use the resource references when you need exact discovery prompts, write patterns, and safety boundaries:

  • Jobs — create, update, publish, pause, expire, duplicate, delete, and review job listings.
  • Companies — find, create, update, and delete company records.
  • Blog posts — audit, draft, update, and publish job board articles.
  • Blog authors and tags — manage article ownership and organization.
  • Taxonomies — manage categories, skills, and markets, and read canonical remote permits and timezones.
  • Settings — inspect and change supported job board configuration.
  • Domains — inspect domain state and verification data.
  • Google Search Console — query finalized search performance and inspect Google's indexed version of Board URLs.
  • Media — understand media metadata and the upload boundary.
  • Operations — follow asynchronous work to completion.
  • API keys — list key metadata without exposing plaintext secrets.
  • Audit logs — verify who changed what and when.
  • Usage and limits — inspect quotas before bulk work.
  • Authentication and security — choose OAuth or API keys and protect credentials.
  • Limitations — understand outbound network, files, and execution constraints.

See what you can do with it

The MCP cookbook starts with the outcome rather than API paths. Use it to post a job, publish or refresh blog content, research a content strategy, sync jobs from a careers page, or build a custom job scraper. The agent discovers the relevant endpoints and record IDs from Cavuno for you.

When a task also needs a browser, scraper, spreadsheet, or an unsupported third-party platform, that access comes from your AI client or another connector. Google Search Console is the exception documented above: after it is connected in Cavuno, MCP can use its native Board-bound performance and URL Inspection reads.

Connect a client

Add Cavuno to your MCP-aware editor. Clients that support remote MCP OAuth can open a browser so you can sign into Cavuno and approve access. Cavuno currently grants the single full_access scope. Configuration, token storage, and refresh behavior vary by client.

Claude Desktop

Remote MCP servers cannot be added directly through claude_desktop_config.json. In Claude Desktop, open Settings → Connectors, choose Add custom connector, and enter https://mcp.cavuno.com/mcp. Availability can depend on your Claude plan. See Anthropic's remote connector guide for the current interface.

Cursor

Edit ~/.cursor/mcp.json:

json
{
"mcpServers": {
"cavuno": {
"url": "https://mcp.cavuno.com/mcp"
}
}
}

Codex

Add the server to ~/.codex/config.toml (or the project-level .codex/config.toml for a trusted project):

toml
[mcp_servers.cavuno]
url = "https://mcp.cavuno.com/mcp"

Claude Code

bash
claude mcp add --transport http cavuno https://mcp.cavuno.com/mcp

Authentication

Two paths are supported. OAuth is the right choice for interactive use; an API key is the right choice for CI / automation that doesn't have a browser.

OAuth 2.1 (default)

The MCP spec runs the standard OAuth authorization-code flow with PKCE. On first connect, the client:

  1. Fetches https://mcp.cavuno.com/.well-known/oauth-protected-resource/mcp and discovers the authorization server (api.cavuno.com/v1/oauth).
  2. Uses dynamic registration at /v1/oauth/register when the client supports that flow, or uses client credentials configured by the client.
  3. Opens a browser to /v1/oauth/authorize for user consent. The minted JWT is bound to the Cavuno MCP resource (aud=https://mcp.cavuno.com/mcp).
  4. Sends every subsequent request with Authorization: Bearer <jwt>.

The worker verifies the JWT’s issuer, audience, and signature through the authorization server’s JWKS before invoking a tool.

Cavuno's dynamic registration endpoint accepts client_secret_basic, client_secret_post, and public clients using none, matching its authorization-server metadata. The client decides which supported registration and token-authentication method to use.

API key (CI / scripts)

Mint a key in the Cavuno dashboard at Settings → Developer → API keys. Pass it as the bearer token — MCP clients that support custom request headers can attach it directly:

json
{
"mcpServers": {
"cavuno": {
"url": "https://mcp.cavuno.com/mcp",
"headers": {
"Authorization": "Bearer cavuno_live_xxxxxxxxxxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
}
}
}
}

API keys beginning with cavuno_live_ skip the OAuth flow entirely—the worker passes them through unchanged.

The two tools

Both tools take a single argument: code, the source of an async () => … arrow function. The function runs in a fresh Cloudflare Dynamic Worker isolate per call — there is no shared state across invocations.

search

javascript
// Tool: search
// Args: { code: string } // an async arrow function as a string
//
// Globals available inside the sandbox:
// spec — the full Cavuno OpenAPI document with $refs pre-resolved
//
// Network access: blocked. Use `spec` for everything.
async () => Object.keys(spec.paths).slice(0, 10)

execute

javascript
// Tool: execute
// Args: { code: string } // an async arrow function as a string
//
// Globals available inside the sandbox:
// cavuno.request({ method, path, body?, query?, headers? })
// -> { status: number, ok: boolean, data: unknown }
//
// Network access: only the loopback binding above. The agent's bearer
// token is held by the parent worker and injected on every call —
// never include an Authorization header in the code you write.
async () => {
const r = await cavuno.request({ method: 'GET', path: '/usage' });
return r.data;
}

The spec object that search sees is the same OpenAPI document published at api.cavuno.com/v1/openapi.json — also visible in the interactive API reference. execute can call authenticated Operator API endpoints that accept JSON. Multipart uploads and endpoints that require a different authentication context are outside this MCP surface.

Sandbox & limits

  • Outbound network from inside the sandbox is blocked (globalOutbound: null). The only way out is cavuno.request(…); calling fetch(…) throws.
  • No access to environment variables, file system, or persistent storage. Each invocation starts in a fresh isolate.
  • console.log/warn/error is captured and returned alongside the function's return value, so multi-step scripts can print intermediate state for debugging.
  • CPU and wall-clock budgets are bounded by the underlying Cloudflare Workers limits — keep individual execute calls under a few seconds.
  • File uploads (POST /v1/companies/{id}/logo and POST /v1/media/upload) are not exposed via MCP today—they require multipart bodies. Use the Cavuno CLI, dashboard, or direct REST API for those uploads.

Errors

When user code throws (or returns a rejected promise), the response is a structured error envelope rather than a tool failure. The captured console output is included so the agent can self-diagnose without re-running:

json
{
"ok": false,
"error": "TypeError: Cannot read properties of null (reading 'id')",
"stack": "TypeError: Cannot read properties of null...",
"logs": [
{ "level": "log", "args": ["company:", null] }
]
}

API-level errors (4xx / 5xx) come back from cavuno.request as { status, ok: false, data: { error: { code, message, requestId, details? } } } — the agent can branch on data.error.code rather than parsing strings.