Unified, multi-source job data aggregation server for recruiting AI agents. Searches live job listings across LinkedIn, Foundit, Shine, RemoteOK, BuiltIn, and WeWorkRemotely with deduplication and structured output.
RecruitData MCP has two tools with clear action verbs (search_jobs, get_pricing) and reasonable descriptions (194 and 48 chars respectively). search_jobs has a well-structured Zod schema with 5 parameters, all typed and described. However, output schemas are not formally documented, responses are JSON stringified text blocks rather than structured MCP content types. Error handling is minimal: no recovery guidance, no categorization of retryable vs fatal errors. The get_pricing tool has an empty input schema ({}), which is acceptable but offers no extensibility. Parameter descriptions are good (e.g., 'Max results (free tier capped at 15)'), but the tool lacks pagination support despite potentially returning large result sets. No tool annotations (readOnlyHint, idempotentHint) are present.
Pricing tiers and how recruiting-AI products subscribe.
Search live job listings across multiple boards (LinkedIn, Foundit, Shine, RemoteOK, BuiltIn, WeWorkRemotely) in one call — unified, deduplicated, structured. Built for recruiting/HR AI agents that need reliable hiring data. Returns title, company, location, salary, skills, url. LinkedIn is a premium source (paid tier).
Output schemas not formally documented. Responses are JSON-stringified text blocks (type: 'text') rather than structured MCP content with typed fields. LLMs cannot parse expected output structure or plan downstream tool calls.
No pagination support for search_jobs despite potentially large result sets. Tool description mentions 'free tier capped at 15' and 'paid tier up to 300', but no limit parameter validation or next_cursor/offset mechanism. Large responses risk context window exhaustion.
Error handling lacks recovery guidance. scrapeLinkedIn, scrapeFoundit, etc. return empty arrays on failure with no error message. LLM receives no signal about what failed or whether to retry. Promise.allSettled silently swallows errors.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 58 | 2026-07-28+ | v2 |
get_pricing has trivial description (48 chars, below 50-char baseline) and empty input schema. Tool is discoverable but provides minimal context for LLM selection. Description should explain when to call it (e.g., 'Show pricing tiers and subscription options to users considering upgrade').
No tool annotations (readOnlyHint, idempotentHint, destructiveHint). Both tools are read-only and idempotent, but this is not declared. LLMs cannot infer safety properties and may incorrectly reason about retry behavior or side effects.