Job Assistant MCP
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Job Assistant MCPFind Python + AI jobs posted this week and tell me which three fit me best."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Job Assistant MCP
An MCP server that turns Claude into a job-search assistant. It pulls real postings from public job boards, scores them against your own stored profile (skills, experience, projects) and tracks your applications in SQLite.
"Find remote Python + AI jobs posted this week and tell me which three fit me best."
What it does
Tool | Purpose |
| Store your skills, years of experience, target roles, summary and projects (merged, so you can update one field at a time). |
| Query all boards concurrently, filter by keywords / remote / recency, dedupe, cache. If a profile exists every result gets a 0-100 fit score and the list is sorted best-first. |
| Explainable breakdown for one posting: matched & missing skills, seniority fit, which of your projects to mention. |
| Full posting text + your application status. |
| Application tracker ( |
Also exposed: resources profile://me and jobs://pipeline, and prompts find_best_jobs and
prepare_application (tailored cover letter + talking points).
Job sources
Source | Access | Notes |
official public RSS | Ukrainian IT jobs | |
official public RSS | Ukrainian / European IT jobs |
The scope is intentionally limited to these two Ukrainian IT job boards. LinkedIn is not supported: it has no public job API and scraping it violates its Terms of Service. New sources are easy to add, see Adding a source.
A failing board never breaks a search; its error is reported in errors and the rest still return.
Related MCP server: job-search-mcp
Quick start
You need Docker and an MCP client such as Claude Code.
1. Start the server
git clone https://github.com/kaidashova/job-assistant-mcp.git && cd job-assistant-mcp
docker compose up -d --buildThe MCP endpoint is now at http://localhost:8000/mcp. If port 8000 is taken, pick another one:
HOST_PORT=8765 docker compose up -d --build (use the same port in step 2).
2. Connect your MCP client
claude mcp add --transport http job-assistant http://localhost:8000/mcp
claude mcp list # job-assistant should show as connectedThen start claude and type /mcp to see the 8 tools. Any other MCP client that supports
Streamable HTTP can use the same URL.
3. Day-to-day
docker compose logs -f # watch the server
docker compose down # stop (your data is kept)
docker compose down -v # stop and delete all data (profile, applications)The container restarts automatically with Docker. Your profile and applications live in the
job-data Docker volume, so they survive restarts and rebuilds.
The port is bound to 127.0.0.1 only. There is no authentication, so don't expose it publicly
without a reverse proxy in front.
Try it
Tell Claude about yourself once:
Save my profile: skills Python, FastAPI, PostgreSQL, Docker, LLM, RAG, MCP; 3 years of experience; I want Python Developer or AI Engineer roles. Projects: "Job Assistant MCP" (MCP server, tech: python, sqlite, mcp), "Docs Q&A bot" (tech: python, rag, postgresql).
Use the
find_best_jobsprompt, or just ask:Find remote Python + AI jobs posted this week and tell me which three fit me best.
Save the first one and mark it as applied. → later: "What's in my pipeline?"
How scoring works
Deterministic and explainable, so Claude can reason over the parts instead of a black box:
score = 65 × skill coverage + 20 × role fit + 15 × seniority fit
Skill coverage: skills are extracted from the posting using a vocabulary of ~90 technologies with aliases (
k8s → kubernetes,postgres → postgresql; ambiguous words like go only match asgolang). Skills in the title/tags count double. Umbrella skills are implied (LLM/RAG ⇒ AI, PostgreSQL ⇒ SQL). Skills outside the vocabulary that you list in your profile are still searched for.Role fit: word overlap between your target roles and the job title.
Seniority fit: level from the title (junior … lead) vs. your years of experience.
Architecture
Layered, with dependencies pointing downward only:
server/ MCP adapters: tools, resources, prompts (validate input -> call service -> typed output)
↓
services/ business logic: SearchService, TrackerService, ProfileService, MatchingService
↓
repositories/ SQLite access only: Database, JobRepository, ApplicationRepository, ProfileRepository
sources/ one module per job board, all behind the same JobSource protocol
matching/ pure scoring engine + skill extraction (no I/O)
utils/ small stateless helpers (HTML to text, date parsing)
schemas/ Pydantic models shared by every layer; tool results are typed, so the server
publishes JSON output schemas for each tool
constants/ all module-level constants (skill vocabulary, scoring weights, feed URLs, SQL schema…)
config.py Settings (pydantic BaseSettings, read from env / .env)
container.py composition root: builds the repositories and services and wires them together
errors.py JobAssistantError, surfaced to the model as a clean tool errorapp/
config.py container.py errors.py
constants/ skills, matching, sources, search, database, server
schemas/ job, application, profile, search, matching, source
repositories/ database, jobs, applications, profile
services/ search, tracker, profile, matching, filters
matching/ scoring, skills
sources/ base, rss, dou, djinni
utils/ text (HTML cleanup, remote detection), dates
server/ app, tools, resources, prompts
tests/ offline: mocked HTTP + fixtures, one test module per layer, plus end-to-end over MCPServices never import MCP and the server never touches SQL, so each layer is testable on its own.
Development
make install # local .venv with dev tools (uv)
make test # offline tests, no network needed
make lint # ruff + mypyCI (GitHub Actions) runs lint + tests on Python 3.11-3.13 and builds the Docker image.
Adding a source
Create app/sources/mysource.py with a class that has a name and an
async fetch(client, query) -> list[Job], then register it in sources/__init__.py. Filtering by
keyword / remote / date is done centrally in services/filters.py, so a source only needs to fetch and map
fields. Add a fixture and a test in tests/.
Configuration
Variable | Default | Meaning |
|
| SQLite file |
|
|
|
|
| HTTP bind address inside the container |
|
| Seconds before a job-board request times out |
To change one, add it under environment: in docker-compose.yml and run docker compose up -d again.
Notes
Built on the official MCP Python SDK (v2,
MCPServer).Be a good citizen: only public feeds/APIs are used, with a descriptive User-Agent and one request per board per search.
Your profile and applications never leave your machine; only the search keywords go to the boards.
MIT licensed.
Available Tools
8 toolsget_jobARead-only
Full details (description, tags, application status) of a job from search results.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| url | Yes | |
| tags | No | |
| title | Yes | |
| remote | No | |
| salary | No | |
| source | Yes | |
| company | No | |
| location | No | |
| posted_at | No | |
| application | No | |
| description | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds the fields that come back, but that is largely duplicated by the output schema, and it says nothing about error behavior for invalid/expired job IDs or whether saved-job state is included.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with the resource and scope front-loaded; every clause carries information. The parenthetical field list is somewhat redundant with the output schema but is not wasteful enough to hurt.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool with an output schema, the description covers what is returned and where the ID comes from. Missing pieces are minor: no mention of failure modes or that application status may be stale relative to update_status.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the schema itself gives no meaning for job_id. The description partially compensates by indicating the ID originates from search results, but it does not state the expected format or whether IDs expire, leaving a real gap for the single required parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (a job) and scope (full details: description, tags, application status), and the phrase 'from search results' distinguishes it from search_jobs. It does not, however, explicitly separate itself from match_job_to_profile or save_job, which also operate on a single job.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'From search results' implies the job_id comes from search_jobs, giving an implied usage context. There is no explicit when-to-use statement, no exclusion ('do not use to fetch multiple jobs'), and no mention of alternatives such as match_job_to_profile.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_profileARead-only
Return the stored profile (empty if none has been set yet).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| skills | No | |
| summary | No | |
| projects | No | |
| target_roles | No | |
| years_experience | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds non-obvious behavioral context: the return is empty if no profile has been set, which tells the agent how to interpret a null/blank result.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short sentence with the main behavior front-loaded and the edge case parenthetically appended. Zero waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-shape explanation is not required, and the empty-state caveat covers the main ambiguity. The only shortfall is the absence of any relationship to sibling tools.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, which is the baseline-4 case. There is nothing for the description to disambiguate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Return) and resource (stored profile), so the operation is unambiguous. It does not explicitly differentiate itself from the sibling set_profile (the write counterpart), leaving the read-vs-write routing to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the verb 'Return' but there is no explicit when-to-use statement or named alternative (e.g., 'use set_profile to create one'). Adequate but with a clear gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_applicationsBRead-only
Your tracked jobs (optionally filtered by status) plus counts per pipeline stage.
| Name | Required | Description | Default |
|---|---|---|---|
| status | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| counts | Yes | Number of applications per status |
| applications | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds that results include per-stage counts, which is useful context, but says nothing about pagination, ordering, or how the counts are scoped. With annotations doing the heavy lifting, a 3 is appropriate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with zero padding. The core resource is front-loaded and the optional filter and supplementary counts are appended parenthetically, which is efficient and readable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and annotations cover the safety profile. Still, for a list tool the description leaves the valid status vocabulary and any result-ordering behavior undocumented, which is a meaningful gap given the 0% schema coverage on the only parameter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the single 'status' parameter is a bare string with no enum, so the schema tells the agent nothing about valid values. The description only repeats that filtering by status is optional ('optionally filtered by status') and does not enumerate the accepted status values, so it fails to compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource ('Your tracked jobs') plus an aggregation ('counts per pipeline stage'), so an agent can tell this is a personal application-list tool rather than a search tool. It lacks an explicit verb and does not name a sibling, but the resource is distinctive enough to distinguish it from search_jobs or get_job.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Your tracked jobs' implies this is for the user's saved pipeline rather than the global job corpus, hinting at divergence from search_jobs. However, there is no explicit when-to-use statement and no exclusions or named alternatives, leaving routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
match_job_to_profileBRead-only
Compare a posting with the stored profile: score, matched/missing skills, seniority fit and which of your projects are most relevant to mention.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | |
| notes | Yes | |
| score | Yes | |
| title | Yes | |
| job_id | Yes | |
| company | Yes | |
| verdict | Yes | |
| breakdown | Yes | |
| matched_skills | Yes | |
| missing_skills | Yes | |
| relevant_projects | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds that the result is an analysis (scores, matched/missing skills, seniority fit), which is useful, but with an output schema present the return-content detail is largely redundant and no preconditions (e.g. stored profile requirement) are disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence that leads with the action and then lists the outputs. Efficient, with no filler, though the enumerated outputs make it slightly list-heavy rather than prose-tight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read-only tool with an output schema, the description is adequate about what is produced, but it omits how to source job_id and any precondition that a stored profile must exist — gaps that matter given 0% parameter documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single job_id parameter is undocumented in both schema and description. The phrase 'a posting' hints that an identifier is needed, but the description never explains what job_id is, its format, or where to obtain it (get_job/search_jobs), leaving the only parameter under-specified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (compare) and both resources (posting, stored profile), then enumerates the analysis produced: score, matched/missing skills, seniority fit, relevant projects. This clearly separates it from siblings like get_job/get_profile, which merely fetch, though it does not name them explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied — the agent can infer 'use this to evaluate fit' — but there is no explicit when-to-use guidance, no prerequisites (e.g. a profile must be set first), and no named alternatives among the siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
save_jobBIdempotent
Add a job to your application tracker with status 'saved'.
| Name | Required | Description | Default |
|---|---|---|---|
| notes | No | ||
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| application | Yes | |
| already_saved | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true and destructiveHint=false, so safety and repeat-call behavior are covered. The description adds one useful bit of context beyond them: the record is created with status 'saved'. It says nothing about duplicate job_ids, required fields, or what happens if the job is already tracked.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single tight sentence with zero filler, and the key effect (status 'saved') is placed up front. Nothing is padded or restated from the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained. However, for a mutation tool with a required undocumented parameter and no usage routing, the description is thin; it covers the action and its state effect but not the inputs or alternatives an agent needs to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the required 'job_id' parameter is never mentioned in the description, leaving no guidance on its format or provenance (e.g. from search_jobs). The optional 'notes' parameter is likewise unexplained. This is a clear case where the description should compensate for the empty schema and does not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Add a job') plus the resulting state ('status saved'), so an agent understands the effect without opening the schema. It does not, however, contrast itself with siblings like update_status or list_applications, which is where a 5 would come from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use or when-not-to-use guidance. With siblings such as update_status, list_applications and get_job present, the description never says whether this is for first-time tracking versus status changes, leaving the agent to infer intent from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_jobsA
Search live job boards concurrently. If a profile is stored, each result carries a 0-100 fit score and results are sorted best-first; otherwise newest-first.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| sources | No | Subset of boards to query. Available: dou, djinni. | |
| keywords | Yes | Terms to look for, e.g. ['python', 'AI']. | |
| remote_only | No | Only remote positions. | |
| match_all_keywords | No | Require every keyword (AND) instead of any (OR). | |
| posted_within_days | No | Only postings from the last N days. |
Output Schema
| Name | Required | Description |
|---|---|---|
| jobs | Yes | |
| errors | Yes | Boards that failed, with the reason |
| returned | Yes | |
| by_source | Yes | |
| total_found | Yes | |
| scored_against_profile | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (destructiveHint=false, openWorldHint=true) and match the 'live job boards' framing, so the description is free to spend its words elsewhere, which it does: it discloses that boards are queried concurrently, that a stored profile adds a 0-100 fit score per result, and that ordering flips between best-first and newest-first. This is genuinely additive context. It does not explain the readOnlyHint=false flag, i.e. what the non-read-only side effect of a search actually is.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, with the core action front-loaded and the conditional scoring/sorting behavior immediately after. Every clause carries information an agent would otherwise have to guess.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be described, and the description covers the two behaviors that the schema cannot express: concurrency across boards and the profile-dependent scoring/ordering. Parameter-level filtering is left entirely to the schema, which is acceptable given 83% coverage but is the one remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 83%, so keywords, sources, remote_only, match_all_keywords and posted_within_days are already documented in the schema. The description adds nothing about any parameter (not even the fact that the remote/freshness defaults are applied), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Search live job boards') plus a scope detail ('concurrently', i.e. multiple boards queried in parallel), which an agent can hold apart from get_job or save_job. It stops short of naming a sibling or ruling one out, so it is clear but not fully differentiated from the sibling set.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the reader infers 'call this when you want to find postings', and the mention that a stored profile changes scoring hints at why one might set a profile first. There is no explicit when-to-use/when-not statement and no alternative (e.g. match_job_to_profile) named for the scoring case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_profileBIdempotent
Create/update your profile. Only the fields you pass are changed.
| Name | Required | Description | Default |
|---|---|---|---|
| skills | No | ||
| summary | No | ||
| projects | No | ||
| target_roles | No | ||
| years_experience | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| skills | No | |
| summary | No | |
| projects | No | |
| target_roles | No | |
| years_experience | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds genuine value with merge semantics ('Only the fields you pass are changed'), clarifying partial-update behavior that annotations do not express. It says nothing about permissions or overwrite edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two brief sentences, tightly front-loaded with the action and immediately followed by the key semantic. No filler; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, but the definition leaves 5 undocumented parameters ambiguous (e.g. what 'projects' objects expect, null vs omitted) and offers no usage context for a mutation tool. It is under-specified for a five-parameter profile upsert.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
All 5 parameters (skills, summary, projects, target_roles, years_experience) have 0% schema description coverage, so the description carries the full burden — yet it names no parameter and gives no format or type guidance. The only relevant clue is the generic note that unpassed fields are unchanged.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Create/update your profile') with clear upsert semantics that distinguish it from get_profile. It does not explicitly name or contrast with siblings like get_profile or match_job_to_profile, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No when-to-use or when-not-to-use guidance, and no mention of alternatives such as get_profile for reads. The only usage signal is implicit in 'Create/update'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_statusBIdempotent
Move a job through the pipeline; every change is kept in its history.
| Name | Required | Description | Default |
|---|---|---|---|
| notes | No | ||
| job_id | Yes | ||
| status | Yes | saved | applied | screening | interview | offer | rejected | withdrawn |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | |
| notes | No | |
| title | Yes | |
| job_id | Yes | |
| status | Yes | |
| company | Yes | |
| history | No | |
| saved_at | Yes | |
| updated_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true and destructiveHint=false, so the safety profile is covered. The description adds a genuinely new behavioral fact not derivable from any structured field: every change is retained in the job's history, telling the agent that status moves are auditable and recoverable. It still omits any permission or error behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; the core action is stated before the behavioral footnote. Nothing is wasted or buried.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be explained, and annotations cover the mutation safety profile. Still, for a write tool with two undocumented parameters, the description is thin — it omits transition validity, notes semantics, and failure behavior, leaving the agent to guess at invocation details.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 33% (only 'status' carries an inline description listing the pipeline values); job_id and notes are undocumented. The description adds no meaning to any parameter — it does not say what notes are for or whether job_id must reference an existing application — so it fails to compensate for the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The verb+resource are clear: 'Move a job through the pipeline' identifies this as a job-status transition tool, which is distinct from read-oriented siblings like get_job or search_jobs. It does not, however, explicitly name or contrast itself with save_job or list_applications, so sibling differentiation is left to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to use this tool versus alternatives such as save_job, nor any precondition (e.g., job must already exist, allowed transitions). Usage is only implied by the phrase 'move a job through the pipeline'.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
8 tool updates
v0.1.0- First observed
get_job - First observed
get_profile - First observed
list_applications - First observed
match_job_to_profile - First observed
save_job - First observed
search_jobs - First observed
set_profile - First observed
update_status
TDQS
Scored across 8 tools
Each tool targets a distinct resource and action: profile (get/set), jobs (search/get/save/match), and applications (update_status/list_applications). The fit-scoring overlap between search_jobs and match_job_to_profile is intentional and clearly separated by scope. An agent can reliably pick the right tool for any task.
All tools use a consistent snake_case verb_noun pattern (get_profile, search_jobs, save_job, list_applications, set_profile, update_status). Naming is predictable and self-describing throughout.
8 tools is well-scoped for a job-assistant domain covering profile management, job discovery, matching, and application tracking. No redundant or filler tools; each earns its place.
Covers the core lifecycle: profile get/set, job search/get/match/save, and application tracking with status updates and counts. Minor gaps exist (no way to remove/unsave a job or delete a profile), but agents can work around them.
Maintenance
Related MCP Connectors
Manage job applications — jobs, companies, boards, notes, and profile — from your AI client.
- jobwyreOAuthapp.jobwyre
Track job applications on a board: let Claude or ChatGPT read and update jobs, interviews, notes.
Analyze job listings against your resume, track applications, and generate cover letters.
AI job search MCP — fact-checked jobs, application tracker, alerts. ChatGPT, Claude, Cursor.
Related MCP Servers
- FlicenseAqualityDmaintenanceTransforms Claude into an AI job-hunting assistant that searches remote job boards, scores roles against your CV, generates tailored cover letters, and logs everything to a Notion tracker.11-
- FlicenseBqualityDmaintenanceEnables searching justjoin.it for job listings and tracking applications locally with status updates, all via natural language in Claude.4-
- FlicenseNot gradedqualityCmaintenanceEnables Claude to parse CVs, search job boards (Remotive, Arbeitnow, Adzuna, Greenhouse/Lever), tailor resumes and cover letters, and prepare application packages with direct apply links—without ever auto-submitting. It runs 100% locally and free, storing jobs and applications as JSON files.-
- FlicenseNot gradedqualityBmaintenanceEnables Claude Desktop to manage a job search end-to-end: find and score job listings, tailor resumes, generate application messages, and track application history, while leaving final external actions to the user.-