Skip to main content
Glama

Openings

Recommend jobs from a resume

recommend_jobs
Read-onlyIdempotent

Rank jobs against a resume, quoting the evidence for each match, and separate direct matches from hidden title-family and stretch roles. Use it when the candidate has chosen to share a resume and wants matching; prefer search_jobs for plain filtering, which needs no resume and answers faster. The resume is parsed in memory for this call and never stored. When matches are thin it may refresh the local snapshot once, per the refresh policy.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoHow many ranked matches to return
intentYesWhat the candidate is actually looking for, stated explicitly rather than guessed from the resume. Every field is optional; the ones given narrow the result, and the excluded* fields remove roles the candidate does not want to see.
resumeYesThe resume itself, passed inline. It is parsed in memory for this call and never written to disk, logged, or sent anywhere else.
rankingNoHow matches are scored and how weak a match may be before it is dropped
refreshNoWhether this call may crawl employer boards before ranking. Crawling costs seconds; the default only does it when the result would otherwise be thin

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
windowNoWhich age windows were walked and which one the results came from
matchesYesRanked matches, each carrying the job, its scores, and the resume text that supports them
outcomeYeswidened means the date window had to open up to find anything; no_matches means say so rather than searching again silently
profileNoWhat was read from the resume. It is returned so claims can be checked, and is not stored
rankingNo
refreshNoWhether this call crawled, and what it found
coverageNo
snapshotNoAge and size of the index these matches came from
nextMovesNoWhat to try next when the result is thin; relay these instead of inventing advice
shortfallNoPresent when fewer matches came back than asked for
assumptionsNoAnything inferred rather than stated; worth repeating to the candidate
explanationYesWhy the result looks the way it does, in words meant for the candidate
explorationNoDirect, hidden title-family and stretch groupings
filteredOutNoCounts by reason, with a small sample, for roles the intent excluded
nextActionsNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed21 schema fields changed
    • addedInput schema / properties / intent / description
      Added value: +"What the candidate is actually looking for, stated explicitly rather than guessed from the resume. Every field is optional; the ones given narrow the result, and the excluded* fields remove roles the candidate does not want to see."
    • addedInput schema / properties / intent / properties / countries / description
      Added value: +"Two-letter codes the candidate may work in, such as IN or US. This is eligibility to work, not where the office is"
    • addedInput schema / properties / intent / properties / excludedCountries / description
      Added value: +"Two-letter codes to drop even when a role is otherwise eligible"
    • addedInput schema / properties / intent / properties / excludedLocations / description
      Added value: +"Cities or regions to drop, matched like locations"
    • addedInput schema / properties / intent / properties / excludedRoles / description
      Added value: +"Role titles to drop, matched like roles"
    • addedInput schema / properties / intent / properties / excludedTerms / description
      Added value: +"Words that disqualify a role, matched as whole words in the title, such as \"intern\" or \"sales\""
    • addedInput schema / properties / intent / properties / locations / description
      Added value: +"Cities or regions to keep, matched as case-insensitive substrings of the job's location, such as \"Bengaluru\" or \"Delhi NCR\""
    • addedInput schema / properties / intent / properties / remote / description
      Added value: +"True to keep only remote roles, false to drop them; omit to keep both"
    • addedInput schema / properties / intent / properties / requiredSkills / description
      Added value: +"Skills a role must state to be kept, such as \"kubernetes\". Each is matched as a whole word"
    • addedInput schema / properties / intent / properties / roles / description
      Added value: +"Role titles the candidate is looking for, in their own words, such as \"backend engineer\" or \"data analyst\". Matched against the job title"
    • addedInput schema / properties / intent / properties / seniority / description
      Added value: +"Levels to keep, in the posting's own vocabulary, such as \"senior\" or \"lead\". Not a years-of-experience filter: use experienceYears in search_jobs for that"
    • addedInput schema / properties / limit / description
      Added value: +"How many ranked matches to return"
    • addedInput schema / properties / ranking / description
      Added value: +"How matches are scored and how weak a match may be before it is dropped"
    • addedInput schema / properties / ranking / properties / mode / description
      Added value: +"evidence scores a match only on requirements the resume text supports; keyword scores on term overlap alone"
    • addedInput schema / properties / refresh / description
      Added value: +"Whether this call may crawl employer boards before ranking. Crawling costs seconds; the default only does it when the result would otherwise be thin"
    • addedInput schema / properties / refresh / properties / minimumMatches / description
      Added value: +"With auto, the match count below which a refresh is worth the wait"
    • addedInput schema / properties / refresh / properties / policy / description
      Added value: +"auto crawls once only when matches are thin and the snapshot is stale; never keeps the snapshot as it is; always crawls first"
    • addedInput schema / properties / refresh / properties / staleDays / description
      Added value: +"With auto, how old the snapshot must be before a refresh is considered"
    • addedInput schema / properties / resume / description
      Added value: +"The resume itself, passed inline. It is parsed in memory for this call and never written to disk, logged, or sent anywhere else."
    • addedInput schema / properties / resume / properties / format / description
      Added value: +"How content is encoded: plain text, markdown, or base64 of a PDF or DOCX file"
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "additionalProperties": true,
      +  "properties": {
      +    "assumptions": {
      +      "description": "Anything inferred rather than stated; worth repeating to the candidate",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "coverage": {
      +      "additionalProperties": true,
      +      "properties": {
      +        "countries": {
      +          "description": "Per-country live and recent role counts",
      +          "items": {
      +            "additionalProperties": true,
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "snapshotUpdatedAt": {
      +          "description": "When the index this answer came from was last refreshed",
      +          "type": "string"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "explanation": {
      +      "description": "Why the result looks the way it does, in words meant for the candidate",
      +      "type": "string"
      +    },
      +    "exploration": {
      +      "additionalProperties": true,
      +      "description": "Direct, hidden title-family and stretch groupings",
      +      "type": "object"
      +    },
      +    "filteredOut": {
      +      "additionalProperties": true,
      +      "description": "Counts by reason, with a small sample, for roles the intent excluded",
      +      "type": "object"
      +    },
      +    "matches": {
      +      "description": "Ranked matches, each carrying the job, its scores, and the resume text that supports them",
      +      "items": {
      +        "additionalProperties": true,
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    "nextActions": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "nextMoves": {
      +      "description": "What to try next when the result is thin; relay these instead of inventing advice",
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "outcome": {
      +      "description": "widened means the date window had to open up to find anything; no_matches means say so rather than searching again silently",
      +      "enum": [
      +        "matches",
      +        "widened",
      +        "no_matches"
      +      ],
      +      "type": "string"
      +    },
      +    "profile": {
      +      "additionalProperties": true,
      +      "description": "What was read from the resume. It is returned so claims can be checked, and is not stored",
      +      "type": "object"
      +    },
      +    "ranking": {
      +      "additionalProperties": true,
      +      "type": "object"
      +    },
      +    "refresh": {
      +      "additionalProperties": true,
      +      "description": "Whether this call crawled, and what it found",
      +      "type": "object"
      +    },
      +    "shortfall": {
      +      "additionalProperties": true,
      +      "description": "Present when fewer matches came back than asked for",
      +      "type": "object"
      +    },
      +    "snapshot": {
      +      "additionalProperties": true,
      +      "description": "Age and size of the index these matches came from",
      +      "type": "object"
      +    },
      +    "window": {
      +      "additionalProperties": true,
      +      "description": "Which age windows were walked and which one the results came from",
      +      "type": "object"
      +    }
      +  },
      +  "required": [
      +    "outcome",
      +    "matches",
      +    "explanation"
      +  ],
      +  "type": "object"
      +}
  2. First observed

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already signal readOnly, openWorld, idempotent, and non-destructive behavior. The description adds meaningful behavioral context beyond those hints: the resume is parsed in memory and never stored, and the tool may refresh the local snapshot once when matches are thin. This is useful extra transparency about side effects and data handling, though the description could have been even more explicit about output behavior if the output schema were absent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three dense sentences with no filler. It front-loads the core behavior and output style first, then gives usage guidance, then notes privacy and refresh behavior. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the rich input schema, the presence of an output schema, and annotations covering safety and open-world behavior, the description is complete for an agent to select and invoke the tool correctly. It covers what the tool does, when to use it, the no-resume alternative, and the two non-obvious runtime behaviors (in-memory resume handling and snapshot refresh).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the input schema already documents every parameter in detail, including nested fields like intent, ranking, and refresh. The description adds high-level context about the resume being parsed in memory, but it does not need to repeat parameter-level semantics. Baseline 3 is appropriate because the schema carries the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Rank jobs against a resume, quoting the evidence for each match,' and it names the distinctive output categories (direct matches, hidden title-family, stretch roles). It also differentiates from search_jobs by noting that recommend_jobs requires a resume while search_jobs does plain filtering without one.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool ('Use it when the candidate has chosen to share a resume and wants matching') and when to prefer the alternative ('prefer search_jobs for plain filtering, which needs no resume and answers faster'). This gives an agent clear selection criteria rather than leaving the choice to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.