Coding agent documentation index Fetch the complete documentation index at: https://docs.worklittle.com/docs-agent-manifest.json Use this file to discover all available pages before exploring further.

Search and apply in your AI app

Let your users find jobs and apply without leaving your agent, career coach, or chat app. More than 7.5 million open jobs, and every one can be applied to.

Install the agent skill

Paste this into your coding agent (Claude Code, Cursor, Codex, and others):

set up worklittle.com/SKILL.md

Pick a path

| You want | Do this |
| --- | --- |
| Job search in your agent, fast | [Connect the MCP server](#connect-the-mcp-server) |
| Results as a scrollable job list in the chat, not plain text | [Display the MCP app](#display-the-mcp-app) |
| Your users apply as themselves | [Build your own tools](#build-your-own-tools) |
| Your own cards and Apply button | [Build your own UI](#build-your-own-ui) |

Most agents combine two: the MCP server for search, your own tools for applying.

Connect the MCP server

Connect from your server with your API key, then give the tools to your model.

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const worklittle = new Client({ name: "my-agent", version: "1.0.0" });
await worklittle.connect(
  new StreamableHTTPClientTransport(new URL("https://mcp.worklittle.com/"), {
    requestInit: { headers: { Authorization: `Bearer ${process.env.WORKLITTLE_API_KEY}` } },
  })
);

const { tools } = await worklittle.listTools(); // give these to your model

// Run each tool call your model makes:
const result = await worklittle.callTool({
  name: "search_jobs",
  arguments: { query: "data analyst", remote: true },
});

Give your model search_jobs, get_job_details, and search_companies. See all MCP tools.

The MCP apply tools apply as you, the key owner. To apply for your users, [build your own tools](#build-your-own-tools).

Display the MCP app

By default your model answers in text. Jobs is a small interactive window that search_jobs can show in the chat instead: a scrollable list of jobs, each with the company logo, title, location, pay, and an Apply button. It is an MCP app, a web page an MCP server sends for the chat to display.

To show it, your agent's chat has to be able to display MCP apps:

1. Read _meta.ui.resourceUri on search_jobs from tools/list. It changes between releases, so don't hard-code it. 2. Fetch it with resources/read. 3. Render it in a sandboxed iframe with @modelcontextprotocol/ext-apps or @mcp-ui/client.

Its Apply button applies as you. For your users, [build your own UI](#build-your-own-ui). More: Jobs (MCP app).

Build your own tools

Run your own MCP server with two tools: one searches jobs, one applies for the signed-in user. Your server fills in that user's applicant_id itself, so the AI can never apply as someone else. To create one, see Save the user's profile once.

<!-- tab: TypeScript -->

npm install worklittle @modelcontextprotocol/sdk zod
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { createWorklittle } from "worklittle";

const wl = createWorklittle({ apiKey: process.env.WORKLITTLE_API_KEY });
const currentApplicantId = () => process.env.APPLICANT_ID!; // from your signed-in user

const server = new McpServer({ name: "my-job-tools", version: "1.0.0" });

server.registerTool(
  "find_jobs",
  {
    description: "Search open jobs. Every result can be applied to with apply_to_job.",
    inputSchema: { role: z.string(), location: z.string().optional() },
  },
  async ({ role, location }) => {
    const page = await wl.jobs.search({ q: role, location, limit: 10 });
    const jobs = (page.data as Array<Record<string, any>>).map((j) => ({
      id: j.id,
      title: j.title,
      company: j.company?.name,
      location: j.locations?.[0],
      pay: j.salary?.display ?? null,
    }));
    return { content: [{ type: "text", text: JSON.stringify(jobs) }] };
  }
);

server.registerTool(
  "apply_to_job",
  {
    description: "Apply the signed-in user to one job by its id from find_jobs. Ask the user first.",
    inputSchema: { job_id: z.string() },
  },
  async ({ job_id }) => {
    const started = await wl.apply.create({ job_id, applicant_id: currentApplicantId() });
    return {
      content: [{ type: "text", text: JSON.stringify({ session_id: started.session_id, next_step: started.next_step }) }],
    };
  }
);

await server.connect(new StdioServerTransport());

<!-- tab: Python -->

pip install worklittle mcp
import json
import os

from mcp.server.mcpserver import MCPServer
from worklittle import Worklittle

wl = Worklittle(api_key=os.environ["WORKLITTLE_API_KEY"])
mcp = MCPServer("my-job-tools")


def current_applicant_id() -> str:
    return os.environ["APPLICANT_ID"]  # from your signed-in user


@mcp.tool()
def find_jobs(role: str, location: str | None = None) -> str:
    """Search open jobs. Every result can be applied to with apply_to_job."""
    page = wl.jobs.search(q=role, location=location, limit=10)
    jobs = [
        {
            "id": j["id"],
            "title": j["title"],
            "company": (j.get("company") or {}).get("name"),
            "location": (j.get("locations") or [None])[0],
            "pay": (j.get("salary") or {}).get("display"),
        }
        for j in page["data"]
    ]
    return json.dumps(jobs)


@mcp.tool()
def apply_to_job(job_id: str) -> str:
    """Apply the signed-in user to one job by its id from find_jobs. Ask the user first."""
    started = wl.apply.create(job_id=job_id, applicant_id=current_applicant_id())
    return json.dumps({"session_id": started["session_id"], "next_step": started["next_step"]})


if __name__ == "__main__":
    mcp.run()

<!-- /tabs -->

Not using MCP? Register the same two functions as tools in your agent framework.

Build your own UI

The model picks what to search. Your app draws the results and owns the Apply button.

| Step | Your app | API |
| --- | --- | --- |
| Search | Your `find_jobs` tool runs the model's filters | `GET /jobs` |
| Show | Draw cards or a [map](/use-cases/interactive-job-map) from the job rows | Rows with `id`, title, company, pay |
| Apply | The user taps Apply; your server sends `job_id` and their `applicant_id` | `POST /v1/apply` |
| Track | Update the card: Applying, Applied, Needs answers | Webhook or `GET /v1/apply/{session_id}` |

Full walkthrough with requests and responses: Apply on your job board.

Before you ship

- Use a Business organization. Your app gets far higher free limits (3,000,000 jobs a month instead of 1,000) and a monthly spend cap. Create an organization, then make your key in API keys. - Keep the key on your server. Don't put it in a browser or mobile app. - Ask before applying. Let the user confirm each application, and send an Idempotency-Key so a retry never applies twice. - Show jobs from the API. Use the title and pay from the job rows rather than the AI's summary. See Grounding. - Cost. Search is free within your monthly limits. Each application is $0.20. See Pricing.