Inspiration
Job applications often fail before a candidate can make their case. A promising role becomes a relay of unfamiliar portals, repeated resume uploads, and long forms asking for information that already exists in the resume. By the last page, the candidate has spent their attention on administration instead of the opportunity. We wanted to show how WebMCP changes that: the candidate keeps the consequential decisions, and the agent does the repetitive work between them.
What it does
Jobly turns a resume into a completed application. The candidate gives Codex their resume and preferences. Codex identifies relevant roles on Jobly (an Indeed-style job board), the candidate chooses which opportunity is worth pursuing, and Codex uses each employer portal's explicit WebMCP tools to carry the application forward across two simulated ATS sites:
- Greenhold — a Greenhouse-style ATS with a five-step application wizard
- Leverly — a Lever-style ATS with a single-page form
The journey: Codex uses Jobly's list_jobs / get_job tools to build a shortlist with each role's applyUrl. For each approved role it opens the ATS, signs in, inspects the real form via get_application_form / get_page_fields, fills it from the resume with fill_fields, attaches files, validates, pauses for human approval, and finally submit_application returns a confirmation ID — verifiable under My applications.
The WebMCP surface
This is not a UI-scraping demonstration. Jobly exposes structured search and job-detail tools (get_filter_options, list_jobs, get_job); the two ATS sites expose their jobs, form schemas, page state, file attachment, validation, and submission actions directly (sign_in, start_application, fill_fields, attach_resume, attach_cover_letter, goto_page, next_page, prev_page, validate_application, submit_application).
Greenhold and Leverly expose the same agent contract but render structurally different forms. That difference is intentional: the agent must inspect and adapt to each application experience instead of replaying a hardcoded sequence of clicks.
How we built it
- Monorepo (npm workspaces): three Vite + React + TypeScript apps and three shared packages.
packages/webmcp— WebMCP registration glue, tool helpers, and anOrigin-Agent-ClusterVite plugin (WebMCP requires origin isolation).packages/convex— one shared Convex backend (jobs+applications) that all three apps point at.packages/ats-core— a config-driven form engine (store, validation, submit mapping, WebMCP tools, React renderer) shared by both ATS sites.- WebMCP tools call Convex imperatively (
convex.query/mutation), so the agent path and the React UI share one backend and, in the ATS apps, one in-page form store — the visible human view stays in sync with the agent's progress.
Challenges we ran into
- Designing one tool contract that works for both a multi-page wizard and a single-page form, so the agent adapts by inspection rather than memorized flows.
- Keeping the human UI and the agent's mutations in perfect sync through a single in-page form store.
- Origin isolation requirements for WebMCP, solved with a reusable
Origin-Agent-ClusterVite plugin.
What we learned
WebMCP is at its best when the site tells the agent what it can do instead of the agent guessing at the UI. Structured form schemas plus validation tools let the agent complete real multi-step workflows safely, while explicit human approval before submit_application keeps the person in control of the consequential choices.
What's next for Jobly
Richer candidate profiles, more ATS form archetypes (Workday-style multi-section forms), and employer-side WebMCP tools for reviewing incoming applications.
Built With
- codex
- convex
- react
- typescript
- vercel
- vite
- webmcp
Log in or sign up for Devpost to join the conversation.