career-scout-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., "@career-scout-mcpscore my resume for senior data scientist roles"
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.
career-scout-mcp
A production-grade Model Context Protocol (MCP) server demonstrating the wrapping pattern for AI-augmented data pipelines. Built as a standalone artifact: one LXC container, one Cloudflare Tunnel, one repo. Self-hosted via Ollama + LiteLLM SDK.
This server demonstrates the pattern I would apply to wrap Career Scout — my private job-search scoring pipeline. Synthetic data committed here for portability and reproducibility.
Documentation
Full architecture and design decisions: career-scout-mcp.stojadinovic.at
Related MCP server: jobjourney-claude-plugin
Stack
Python 3.13 (mypy strict)
MCP SDK with decorator-based primitive registration
LiteLLM SDK — provider-agnostic LLM routing, model-swappable via env
Ollama + Qwen 2.5 3B (default) — self-hosted, biomedical-research-portable
Pydantic for config + tool schemas
loguru structured JSON logging with secret redaction
Debian 13 LXC, cloudflared edge termination, nginx static docs
Prerequisites
Python 3.13 (uv manages this automatically)
uv — dependency and environment management
Ollama — default local LLM provider for
qwen2.5:3b
Memory: Ollama's headroom calc for qwen2.5:3b requires ~6 GiB of available memory (it counts buff/cache as unavailable). A 4 GiB system may fail to load the model even though it's 1.9 GB on disk.
Debian 13
sudo apt-get update && sudo apt-get install -y curl ca-certificates zstd
curl -LsSf https://astral.sh/uv/install.sh | sh
curl -fsSL https://ollama.com/install.sh | sh
ollama pull qwen2.5:3bNote:
zstdis required by the Ollama installer for archive extraction on minimal Debian; not all base images include it.
macOS
brew install uv ollama
ollama serve &
ollama pull qwen2.5:3bWindows
uv installer · Ollama installer, then ollama pull qwen2.5:3b.
Quick start (local stdio)
uv sync
uv run python -m career_scout_mcpThe server exposes 4 tools, 5 resources (6 URIs), and 2 prompts via stdio. Connect from Claude Desktop, Claude Code, or OpenCode by pointing them at this binary.
Try it out
The fastest way to exercise the server is via MCP Inspector:
npx @modelcontextprotocol/inspector uv run python -m career_scout_mcpOpens a browser UI at localhost:6274 where you can list resources, render prompts, and invoke tools end-to-end against your local Ollama.
Development
Dev workflow uses OpenCode + standard Python tooling. See CONTRIBUTING.md.
Security
See SECURITY.md for reporting. Key posture:
All SQL parameterized (never f-string)
Pydantic input validation on every tool entry
Path traversal prevention on resource URIs
systemd hardening (non-root, ProtectSystem=strict, etc.)
MCP server NEVER publicly exposed (stdio default, HTTP bound 127.0.0.1 only)
TLS via Cloudflare edge — no local cert management surface
Docs deploy via manual
scripts/deploy_docs.sh. MCP server is never publicly exposed — stdio default; HTTP transport loopback-only behind Bearer auth (hmac.compare_digest).
License
MIT — see LICENSE.
Built by Stefan Stojadinovic, Vienna. Contact: stefan@stojadinovic.at
Available Tools
4 toolsquery_postingsB
List postings matching the filter criteria, with their latest score.
Returns only postings that have at least one score (the JOIN excludes never-scored ones). Empty result is valid output.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| min_score | No | ||
| date_after | No | ||
| role_anchor | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals a key behavior: the tool only returns postings with at least one score, and that an empty result is valid. However, since there are no annotations, the description should also disclose aspects like idempotency, side effects, or required permissions, but it does not. The disclosed behaviors are useful but incomplete.
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?
The description is extremely concise: two sentences with no redundant words. It states the core action, a critical behavioral detail, and a note about empty results. Every sentence adds value, achieving high efficiency.
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?
Despite having an output schema (reducing the need to describe return values), the description still leaves gaps. It does not elaborate on the filter criteria parameters, nor does it explain the output beyond 'latest score'. The tool has 4 parameters, all undocumented in schema descriptions; the description fails to compensate adequately. The behavioral note is good but insufficient for a complete understanding.
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%, meaning the input schema lacks any explanatory text for parameters. The description only mentions 'filter criteria' generically, without explaining how each parameter (limit, min_score, date_after, role_anchor) works. The parameter names offer some clues, but for an AI agent, more explicit guidance is needed to ensure correct invocation.
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 clearly states the tool lists postings with filter criteria and includes the latest score. The verb 'List' and resource 'postings' are specific. Although it doesn't explicitly differentiate from siblings, the sibling tools (rescore_posting, tag_mismatched_score, regenerate_digest) are obviously different in function, so no confusion.
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 explicit guidance on when to use this tool versus alternatives. The description mentions a behavioral constraint (only postings with at least one score) but doesn't explain under what circumstances an agent should choose this over other list or search tools. Absence of usage context or exclusions limits its helpfulness.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
regenerate_digestA
Render a digest HTML of the current top-20 postings.
Output path is settings.digest_output_path (operator-controlled, not user-input — no path traversal vector). Writes a single self-contained HTML file with minimal inline styling.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| path | Yes | |
| bytes_written | Yes | |
| postings_included | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It discloses output path safety and file style, but lacks details on side effects (e.g., overwrites existing file?), rate limits, or required permissions. Not comprehensive for a mutation tool.
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?
Three efficient sentences, each adding distinct information: purpose, output path safety, and file styling. No fluff, front-loaded.
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?
Adequate for a 0-param tool with output schema, but missing guidance on when regeneration is appropriate and how 'current' top-20 is defined. Could mention if it replaces an existing file.
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?
No parameters in schema, so description adds value by explaining output path security and file characteristics, which the empty schema cannot convey. Baseline is 4 for 0-param tools.
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?
Clearly states the tool renders a digest HTML of the current top-20 postings. The action 'render' and resource 'digest HTML' are specific and distinguish it from sibling tools like query_postings or rescore_posting.
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 guidance on when to use this tool vs alternatives. Does not mention prerequisites, timing, or comparison with query_postings or other siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rescore_postingA
Re-score one posting against the current rubric via the configured LLM.
Loads the posting, loads the current rubric, scores it via LiteLLM, persists the new score row, and returns the structured result. Raises ValueError if posting not found; ScoringError on LLM/parse failure.
| Name | Required | Description | Default |
|---|---|---|---|
| posting_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| model | Yes | |
| score | Yes | |
| rationale | Yes | |
| score_band | Yes | |
| rubric_version | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It details the steps (load posting, load rubric, score via LiteLLM, persist result) and error conditions (ValueError for missing posting, ScoringError for LLM failure). This provides good transparency into side effects and behaviors.
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?
The description is concise, with four sentences front-loaded by the purpose. It efficiently covers purpose, steps, and errors without unnecessary words. Slightly more conciseness could be achieved by combining steps, but it is well-structured.
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?
Given the existence of an output schema and single parameter, the description is nearly complete. It covers the main actions and errors, though it could mention idempotency or implications of re-scoring (e.g., overwriting previous score). Overall, it provides sufficient context for correct invocation.
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 description does not elaborate on the posting_id parameter beyond its use. However, the single parameter is self-explanatory from the context. The description could add value by explicitly stating the meaning of posting_id.
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 clearly states it re-scores a posting using the configured LLM, with a specific verb (re-score), resource (posting), and method (via LLM). It is distinct from sibling tools like tag_mismatched_score, query_postings, and regenerate_digest.
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 description implies when to use (when needing to rescore a posting) but does not provide explicit guidance on when not to use or contrast with alternative tools. The sibling tools are different in function, but no exclusions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tag_mismatched_scoreB
Record that a stored score does not match operator judgment.
Writes to tagged_mismatches.db. The tune_rubric prompt aggregates these for rubric refinement workflows. Reason must be non-empty.
| Name | Required | Description | Default |
|---|---|---|---|
| reason | Yes | ||
| posting_id | Yes | ||
| expected_band | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | |
| ok | Yes | |
| message | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Reveals the tool writes to a database (side effect) and that reason must be non-empty (constraint). However, without annotations, it omits idempotency, rate limits, error behavior, and what happens on duplicate calls. The output schema is present but not referenced.
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?
Three concise sentences; each adds value: purpose, database context, constraint. No redundancy. Slightly better front-loading would help, but acceptable.
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?
Fails to cover return values (despite output schema), error conditions, expected_band format, or duplicate handling. With 3 required params and no schema descriptions, the description is too sparse to support confident invocation.
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?
Only reason is given a constraint (non-empty). posting_id and expected_band are not described at all, leaving their semantics unclear. With 0% schema coverage, the description should explain all parameters.
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?
Clearly states the tool records mismatches between stored scores and operator judgment, with specific side effects (writing to a database) and intended use (rubric refinement). The purpose is distinct from siblings like rescore_posting.
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?
Implies usage when an operator disagrees with a stored score, and mentions downstream aggregation by tune_rubric. However, no explicit guidance on when not to use it vs. alternatives like rescore_posting, and no prerequisites or trigger conditions are stated.
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.
4 tool updates
v0.1.0- First observed
query_postings - First observed
regenerate_digest - First observed
rescore_posting - First observed
tag_mismatched_score
TDQS
Scored across 4 tools
Each tool targets a distinct action: re-scoring, tagging mismatches, querying postings, and generating a digest. No overlap in purpose.
All tool names follow the verb_noun pattern in snake_case, providing a predictable and consistent naming convention.
With 4 tools, the server is well-scoped for focused tasks like scoring, mismatch recording, querying, and digest generation without being too heavy or too thin.
The set covers scoring, discrepancy tracking, and reporting but lacks tools for CRUD operations on postings or rubric management, leaving notable gaps in a typical career management workflow.
Maintenance
Related MCP Connectors
MCP server for VC pitch-deck scoring, thesis-fit matching, and deal-flow management.
MCP Hub: AI service discovery, per-user OAuth, and multi-service workflow orchestration
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
MCP Server for an Agent Task Marketplace
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA production-grade MCP server designed for multi-tenant, authenticated, and observable AI agent systems, enabling secure tool execution across heterogeneous data sources.65MIT
- AlicenseCqualityDmaintenanceAn MCP server that enables AI-assisted job search workflows including job discovery, application tracking, resume evaluation, and cover letter generation, with support for multiple job sources and scheduled scraping.8325 npm1AGPL 3.0
- AlicenseNot gradedqualityDmaintenanceA custom MCP server that exposes a jobs database to any MCP-compatible LLM client, allowing users to ask in plain English to search, filter, and match job openings.MIT
- AlicenseNot gradedqualityCmaintenanceMCP server that aggregates and deduplicates job listings from multiple public sources, ranks them against a user's resume, and exposes tools for searching, viewing details, explaining fit, and tracking applications.MIT