An AI-powered job recommendation system that uses FAISS vector search, BERT embeddings, and Claude for personalized job matching based on user profiles and preferences
Static source inference · medium confidence · detected: Logging
Deprecated protocol patterns detected
Summary
This MCP server exhibits significant definition quality gaps across multiple dimensions. While tool names generally follow verb_noun conventions and most tools have descriptions, the descriptions are often generic and lack specificity. Input schemas are present for most tools but vary in completeness. Critical issues include: (1) Missing output schema documentation for all 21 tools, agents cannot plan downstream calls without knowing what fields will be returned; (2) No parameter validation hints (ranges, enums, formats) in descriptions despite numeric/string parameters that could accept invalid values; (3) Generic descriptions that fail to answer WHEN to use each tool vs. similar alternatives (e.g., 'fetch_from_jooble' vs 'fetch_from_careerjet', why choose one?); (4) No error handling guidance in any tool description; (5) Database tools (add_user, get_user, save_chat_message, get_chat_history) lack descriptions of data structures and validation rules; (6) Embedding/FAISS tools expose low-level details (numpy arrays, L2 distance, 'pooling_strategy' enum) that violate the abstraction boundary, agents need high-level intent, not ML infrastructure; (7) Job fetching tools do not document API rate limits, failure modes, or fallback behavior despite calling external services. Average description length is ~100 chars (below the 194-char baseline), suggesting brevity at the cost of clarity.
No output schemas documented for any of the 21 tools. Agents cannot plan downstream tool calls or extract structured data without knowing what fields will be returned. This is a critical blocker for multi-step agent reasoning.
Redundant tool composition: four per-API fetch tools (fetch_from_jooble, fetch_from_careerjet, fetch_from_greenhouse, fetch_from_web3career) exist alongside a generic fetch_jobs_from_apis tool. This creates ambiguity, when should an agent pick one vs. the other? No tool description explains the distinction. This forces agents to reason about tool selection without clarity, increasing error rates.
Recommendations
Document complete output schemas for all 21 tools using JSON Schema. For example, get_recommendations should document: {type: 'object', properties: {recommendations: {type: 'array', items: {type: 'object', properties: {title, company, location, description, url}}}, claude_analysis: {type: 'string'}, error?: {type: 'string'}}}. This enables agents to plan downstream tool usage.
Consolidate redundant API fetch tools. Choose ONE primary tool (fetch_jobs_from_apis) that internally tries all APIs. Document which APIs are tried in what order and fallback behavior. Remove or deprecate the per-API fetch tools (fetch_from_jooble, etc.) or clearly document when an agent should choose one over fetch_jobs_from_apis.
Raise the abstraction level for embedding/FAISS tools. Instead of exposing get_embedding with pooling_strategy, offer a single high-level tool: 'compute_job_relevance(user_preferences: string, jobs: list) -> list[{job_id, relevance_score}]'. Hide numpy, BERT, L2 distance, and pooling from the agent, these are implementation details.
Add parameter validation constraints to all numeric/enum fields. Examples: (1) Add to fetch_jobs_from_apis description: 'limit must be 1 - 100; defaults to 20.' (2) Add to search_similar_jobs: 'k must be 1 - 50; higher values increase latency.' (3) Add to batch_get_embeddings: 'batch_size must be 1 - 256; defaults to 32.' (4) Encode enums in the JSON Schema type field, not just descriptions (e.g., pooling_strategy: {type: 'string', enum: ['mean', 'cls', 'max']}).
Add error handling guidance to all tool descriptions. Examples: (1) get_user: 'If user is not found, return a 404 and suggest using search_users() with a partial name.' (2) fetch_jobs_from_apis: 'If an API fails, return partial results from other sources. If all APIs fail, return error: "Job search unavailable; please try again in a few minutes."' (3) add_user: 'If a user with this ID already exists, return 409 conflict and suggest update_user() instead.'
Spec posture evidence
Inferred effective spec: <=2025-11-25.
Relies on Logging (deprecated) - log to stderr or use OpenTelemetry
Low-level ML abstractions exposed to agents: tools like get_embedding, batch_get_embeddings, search_similar_jobs, and calculate_similarity expose numpy arrays, BERT pooling strategies, L2 distance metrics, and dimensionality details. Agents operate at the intent level (e.g., 'find similar jobs'), exposing infrastructure (numpy, BERT, L2) violates the abstraction boundary and forces agents to reason about implementation rather than user needs.
Generic parameter types without validation constraints. Multiple tools accept numeric parameters (limit, k, batch_size) or string enums (pooling_strategy, role) without documented ranges or valid values in the schema. Example: 'limit' in fetch_jobs_from_apis has no min/max (can agent pass 1,000,000?); 'pooling_strategy' enum is only in description text, not in schema; 'batch_size' has no bounds. This invites invalid agent inputs and API errors.
Missing error handling guidance for all tools. No tool description explains what to do when an error occurs. Example: 'User not found' from get_user should guide the agent ('Try search_users() or ask the user for clarification'), but no such guidance exists. External API calls (job fetchers) have no error guidance (rate limit? timeout? retry?). Database tools lack conflict-resolution hints (user already exists?).
Generic object parameters without field specifications. Tools like add_user (user_data), generate_recommendation_message (user_context, job_listings), and get_personalized_recommendations (user_context, job_listings) accept objects with no schema specification. Agents cannot know which fields are required, which are optional, or what types they should be. This forces trial-and-error and failed calls.
External API integration tools lack critical metadata. Job fetchers (fetch_jobs_from_apis, scrape_jobs_from_public_sites) do not document: rate limits, expected latency, API failure modes, fallback behavior, or compliance considerations (robots.txt, ToS). Agents cannot plan for failures or understand performance characteristics.
Descriptions are often too brief or generic, lacking WHEN/WHY context. Examples: 'Standardize job data format from different sources and remove duplicates' does not explain the algorithm (exact match? fuzzy match?) or output format. 'Reset the FAISS index and job list' does not warn about destructiveness. Average description length is ~100 chars vs. 194-char baseline, indicating insufficient detail for LLM reasoning.
Add field specifications to generic object parameters. Examples: (1) add_user should document 'user_data must contain: {user_id (string, required), skills (array of strings, optional), experience (string, optional), location (string, optional), preferences (string, optional)}.' (2) generate_recommendation_message should document the exact shape of user_context and job_listings expected.
Document external API characteristics. For fetch_jobs_from_apis and scrape_jobs_from_public_sites, add: (1) Rate limits (e.g., '10 requests/minute per IP'). (2) Expected latency (e.g., '3 - 10 seconds for full API set'). (3) Failure handling (e.g., 'If an API is unavailable, attempts other sources and returns partial results'). (4) Compliance notes (e.g., 'Web scraping respects robots.txt and includes User-Agent header').
Expand descriptions to include WHEN/WHY and consequences. Examples: (1) clear_index: 'Deletes all indexed job data. This is destructive and cannot be undone. Call only when rebuilding the index with fresh data or resetting the system.' (2) standardize_job_data: 'Converts job listings from multiple sources into a canonical format and removes duplicates using exact-match title+company+location. Returns normalized jobs with consistent fields: title, company, location, description, url, source, posted_date (ISO 8601).' (3) get_embedding: 'Converts text to a 768-dimensional vector for similarity comparison. Used internally by search_similar_jobs and calculate_similarity, agents typically do not call this directly.'
Add pagination and limit parameters to list-returning tools. get_chat_history and get_recommendations should accept offset/limit or cursor parameters. Document default limits (e.g., 'Returns up to 20 results by default; use limit parameter to retrieve more, up to 100.').
Separate read-only and write tools more clearly in descriptions. Tools like save_user_context, save_chat_message, and add_user should explicitly state 'This tool modifies the database' or 'This operation is irreversible.' Tools like get_user and get_recommendations should state 'This tool is read-only and safe to retry.'
Remove or clarify the purpose of get_embedding, batch_get_embeddings, and calculate_similarity. These are low-level utilities that duplicate FAISS functionality. Document whether agents should ever call these directly, or if they are internal-only. If internal, move them out of the exposed tool set.