Use AI to manage your job board with Cavuno MCP
Connect Claude, Cursor, Codex, and other MCP clients to your Cavuno job board.
A
JThe 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:
1234567{"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):
12[mcp_servers.cavuno]url = "https://mcp.cavuno.com/mcp"
Claude Code
1claude 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:
- Fetches
https://mcp.cavuno.com/.well-known/oauth-protected-resource/mcpand discovers the authorization server (api.cavuno.com/v1/oauth). - Uses dynamic registration at
/v1/oauth/registerwhen the client supports that flow, or uses client credentials configured by the client. - Opens a browser to
/v1/oauth/authorizefor user consent. The minted JWT is bound to the Cavuno MCP resource (aud=https://mcp.cavuno.com/mcp). - 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:
12345678910{"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
123456789// 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
123456789101112131415// 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 iscavuno.request(…); callingfetch(…)throws. - No access to environment variables, file system, or persistent storage. Each invocation starts in a fresh isolate.
console.log/warn/erroris 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
executecalls under a few seconds. - File uploads (
POST /v1/companies/{id}/logoandPOST /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:
12345678{"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.