CareerCompass AI
Inspiration
Career planning tools fail students in two opposite ways. Dashboards dump everything at once — majors, courses, internships, scholarships, research labs — and leave a 19-year-old to figure out which of forty things matters this semester. Chatbots do the reverse: they accept any free-text goal, including ones the system has no real data for, and generate confident advice on top of nothing.
We wanted a third shape. A student should make one supported choice at a time, and each choice should visibly narrow what comes next — the way a good advisor works through a conversation rather than handing over a catalog.
The WebMCP challenge gave us the other half of the idea. If a page can register its own tools with the browser, then an agent doesn't have to scrape our UI or guess at our data model. It can call explore_career_path or simulate_degree_plan directly, with real schemas, while the student stays in control of anything consequential. That's a much healthier division of labor than an agent clicking buttons on a student's behalf.
What it does
CareerCompass AI is a browser-native, agent-ready career planning journey with 33 WebMCP tools registered on the top-level page.
The student moves through nine dependent steps:
- Direction — pick 1 of 6 broad career areas (or browse all 20 supported fields)
- Role — pick a field, then a role that actually exists inside that field
- Priority — internship readiness, research, portfolio proof, or graduation protection
- Academic route — is the current degree direct, adjacent, or a real pivot?
- Next semester — pick a workload, review one prerequisite-safe term, approve it
- Skill sprint — choose one of at most three role-specific gaps
- Experience — internship, research, or portfolio proof (at most two options shown)
- Funding — optionally add one relevant funding lead
- Roadmap — milestones assembled only from the choices actually made
Nothing is preselected, and there is no free-text career box in the primary journey, so an unsupported entry like "singer" can never silently enter the planning engine. The catalog covers 20 fields and 54 roles, grouped so every role appears exactly once.
The six starting areas are: build software and digital products; work with AI, data, and advanced computing; protect and connect systems; build hardware, robots, and physical systems; design human and immersive experiences; and apply technology to health and biology.
Underneath, an agent connected through Chrome's WebMCP API can call any of the registered tools. The split is $25$ read/reason tools and $8$ approval-gated writes, so $25 + 8 = 33$ total:
- Read/reason —
list_career_fields,explore_career_path,recommend_career_paths,compare_career_paths,check_prerequisites,simulate_degree_plan,identify_skill_gaps,find_internships,find_scholarships,find_research_opportunities,build_personalized_pathway, and more - Approval-gated writes —
create_degree_plan,add_course_to_plan,save_internship,save_scholarship,save_research_opportunity,express_research_interest,update_internship_status,update_scholarship_status
The write boundary is the part we care most about: every write tool returns a pending approval, never a persisted change. An agent can propose a degree plan. Only the student pressing Approve plan in the interface applies it. Formally, for any agent-initiated write $w$, the applied state satisfies
$$S_{t+1} = \begin{cases} \text{apply}(S_t, w) & \text{if the student approves } w \ S_t & \text{otherwise} \end{cases}$$
Selections are not cosmetic. Area, field, and role set the career anchor used by every later step; priority changes how courses are ordered and which proof type is emphasized; the approved plan becomes the context for skill-gap and opportunity reasoning; and only the selected experience and funding survive into the final roadmap.
How we built it
Vanilla JavaScript, ES modules, no framework — a deliberate choice so the WebMCP registrations are plainly readable in the repository rather than buried in a build artifact.
Architecture:
src/webmcp.js— the 33 shared tool contracts (schemas, handlers, annotations) plus a local runtime for browsers without WebMCPsrc/site-tools.js— 33 literaldocument.modelContext.registerTool({ ... })calls, one per tool, each forwarding the browser-providedAbortSignalthrough to the shared handlersrc/app.js— top-level page startup, registration, and approval gatingsrc/buddy-journey.js— the nine-step state model and the six catalog-backed career groupssrc/career-catalog.js— JSON loading, normalization, exploration, and comparisonsrc/engine.js— prerequisite resolution, term planning, skill-gap matching, roadmap assemblysrc/store.js— student-controlled state and the pending-approval queuesrc/dom-patch.js— keyed in-place reconciliation, so re-rendering a step doesn't flicker or reset scroll
Data: the career catalog JSON holds the 20 fields, 54 roles, learning paths, scholarships, internships, universities, and research contacts. src/data.js holds curated demonstration student, degree, and course records. Where the catalog has url: null, we left it null and labeled the record Verify in the UI instead of inventing a link.
Registration: every tool is registered imperatively from the top-level page during startup — not from an iframe — with the browser's cancellation signal threaded into the shared handler:
await document.modelContext.registerTool({
name: "explore_career_path",
description: exploreCareerPath.description,
inputSchema: exploreCareerPath.inputSchema,
execute: async (input, options = {}) =>
exploreCareerPath.execute(input, { signal: options.signal }),
title: exploreCareerPath.title,
annotations: exploreCareerPath.annotations,
}, { signal });
Browsers without WebMCP run the exact same handlers through the local runtime, so the journey never depends on the agent being present.
Challenges we ran into
Proving registration instead of claiming it. Our first version generated the 33 registrations in a loop. It worked at runtime, but a reviewer reading site-tools.js couldn't see a single tool name. We rewrote it as 33 explicit literal calls, so the mapping from source to registry is one-to-one and visible on the page — because "trust the loop" isn't a submission.
Accomplishments that we're proud of
- 33 of 33 direct
document.modelContext.registerTool({ ... })registrations, literal and visible in source - A real write boundary, not a disclaimer — 8 write tools, zero of which can persist anything without a student action
- A refusal to fake coverage — unverified catalog URLs stay null and get labeled, and unsupported career fields simply cannot be entered
- Clean at $390 \times 844$ and on desktop, with no horizontal overflow
- Progressive disclosure enforced in code, not by convention: at most three skill gaps, at most two experience options, one active decision card, later steps locked until dependencies resolve
- Catalog coverage that partitions cleanly — six areas covering all 20 fields and 54 roles exactly once, with no duplicates and no orphans
What we learned
WebMCP rewards honest schemas. The moment tools are callable by an agent, vague inputs stop being a UI problem and start being a correctness problem. Writing strict inputSchema definitions forced us to sharpen the data model itself.
Cancellation is not optional. Forwarding options.signal into every handler seemed like boilerplate until an agent abandoned a long compare_career_paths call mid-flight. Plumbing the signal through from the start is far cheaper than retrofitting it.
Untrusted content needs a marker. Catalog-derived tools carry untrustedContentHint: true. Third-party records flowing into an agent's context are a prompt-injection surface, and labeling them is the minimum.
Constraint is a feature. We expected students to want more options. Testing the journey, the opposite held — cutting to at most three skill gaps and two experience options made the tool feel like advice instead of a search result.
Deterministic beats plausible for an MVP. Our reasoning engine is local and rule-based, not LLM-backed. Every recommendation traces back to a catalog record and a selection, which is exactly what a career tool ought to be able to show.
What's next for CareerCompass AI
Real institutional data. The biggest gap between demo and product: authenticated SIS integration and per-institution degree adapters, so prerequisite checks run against a student's actual transcript instead of curated records.
Verified, live opportunity feeds. Replace the null-URL entries with verified sources and freshness dates for scholarships, internships, and research postings — with an as-of timestamp on every record.
Server-side authorization and audit. Right now approval gating lives in the client. Production needs the same boundary enforced server-side, with an audit log of every agent-proposed change and every student decision.
Beyond the six technical areas. The catalog covers 20 technology-adjacent fields. The journey structure is domain-agnostic — health, trades, education, and public service are the natural next groups.
Advisor mode. A view where a human advisor sees the student's journey, the agent's proposals, and the pending approval queue, so CareerCompass AI augments advising instead of routing around it.
Log in or sign up for Devpost to join the conversation.