Employee Management MCP Server

Employee Management MCP Server

Enables employee management operations including listing, searching, creating, updating, and deactivating employees, as well as generating organizational summaries, using a synthetic JSON dataset.

Category
访问服务器

README

Employee Management MCP Server (EMP-MCP-2026)

An MCP server exposing 6 employee-management tools over stdio, backed by a synthetic JSON employee dataset.

Tools

Tool Purpose
list_employees Filter/search employees (department, status, location, free-text query).
get_employee Fetch one employee's full profile by employee_id.
get_org_summary Headcount aggregation by department / status / location.
create_employee Onboard a new hire.
update_employee Partial update of an existing employee's mutable fields.
deactivate_employee Soft-delete (sets status to inactive; record stays retrievable).

Setup

Requires Python 3.10+.

python -m venv .venv
.venv\Scripts\activate        # Windows
pip install -e .

Copy .env.example to .env and adjust if needed (no secrets live in either file — only paths and mode flags). Note: the server does not auto-load .env — nothing in config.py calls load_dotenv(). python-dotenv is listed as a dependency but isn't wired in. .env is documentation of what to set; to make it take effect you either export those variables in your shell before running, set them directly in the env block of your MCP host's server config (the common case — see "Host configuration" below), or run dotenv run -- python -m employee_mcp.server yourself if you want the file loaded.

Running the server

python -m employee_mcp.server

On first run, if EMP_MCP_DATA_PATH doesn't exist yet, the server copies the committed seed (data/employees.seed.json, 14 synthetic employees across all 5 departments) to that path and treats it as the mutable working dataset. Delete that file to reset to a clean seed on the next run.

Windows note: make sure python resolves to the interpreter with mcp installed (or point a host's command at the venv's absolute python.exe). Prefer an absolute EMP_MCP_DATA_PATH when a host launches this as a subprocess — a relative path combined with a host-chosen working directory is the most common cause of "connected but no tools" / "connection closed" on Windows. In this codebase, relative EMP_MCP_DATA_PATH values are resolved against the repo root (not the process's cwd) specifically to avoid that trap, but an absolute path is still the most robust choice for host configs.

Data storage

Employees live in a single JSON array file (data/employees.json), loaded in full at startup into an employee_id -> Employee dict (store.py) for O(1) lookups. Every write (create_employee / update_employee / deactivate_employee) re-serializes the whole in-memory set and persists it atomically — write to a .tmp file, then os.replace() over the target — so a crash or kill mid-write can't leave a half-written, corrupt data file.

JSON (rather than a real database) is a deliberate choice for this project's scale: the seed is 14 employees, and this design targets small in-memory datasets on the order of hundreds to low thousands of records, not enterprise HRIS volumes. At that size, loading the entire file into memory on every server start has no meaningful cost, and JSON buys a human-readable, git-diffable store with zero schema migrations, no separate database process to run, and no driver to install — appropriate for a synthetic-data assignment/demo, not a claim that this approach would scale past that ceiling (see "Known limitations" for what would need to change if it did — e.g. real pagination, an actual DB engine, and finer-grained locking than the current "rewrite the whole file" strategy allows for concurrent writers).

Configuration (environment variables)

Env var Default Meaning
EMP_MCP_DATA_PATH ./data/employees.json Mutable working data file.
EMP_MCP_READ_ONLY false When true, all write tools refuse with a READ_ONLY error and make no changes.
EMP_MCP_DEBUG false When true, unexpected-error messages include a traceback. Keep false in normal/demo use.
EMP_MCP_AUDIT_PATH ./logs/audit.log Path to the audit log file (one JSON line per tool call).

No secrets are configured anywhere — these are mode flags and paths only.

Host configuration

{
  "mcpServers": {
    "employee-mcp": {
      "command": "<ABSOLUTE-PATH-TO-YOUR-python.exe>",
      "args": ["-m", "employee_mcp.server"],
      "env": {
        "PYTHONPATH": "<ABSOLUTE-PATH-TO-THIS-REPO-ROOT>",
        "EMP_MCP_DATA_PATH": "<ABSOLUTE-PATH-TO-THIS-REPO-ROOT>\\data\\employees.json",
        "EMP_MCP_AUDIT_PATH": "<ABSOLUTE-PATH-TO-THIS-REPO-ROOT>\\logs\\audit.log",
        "EMP_MCP_READ_ONLY": "false",
        "EMP_MCP_DEBUG": "false"
      }
    }
  }
}

Fill in the two placeholders for your own machine (every path must be absolute — a relative path combined with a host-chosen working directory is the most common cause of "connected but no tools" / "connection closed" on Windows):

  • <ABSOLUTE-PATH-TO-YOUR-python.exe> — the interpreter you installed this project into. If you used a venv (python -m venv .venv per Setup above), activate it and run (Get-Command python).Source in PowerShell, then paste that path, e.g. C:\Users\you\...\Employee_management_MCP_server\.venv\Scripts\python.exe.
  • <ABSOLUTE-PATH-TO-THIS-REPO-ROOT> — the folder containing this README on your machine, e.g. C:\Users\you\Documents\Employee_management_MCP_server. It's used four times above: once for PYTHONPATH, and as the prefix for both data-file paths — replace all of them consistently.

PYTHONPATH matters specifically when command points at a bare interpreter that this project was never pip install -e .'d into — without it, python -m employee_mcp.server can't locate the employee_mcp package and the host will show the server as failed/disconnected. If command points at a venv's python.exe where you already ran pip install -e ., PYTHONPATH is unnecessary — the editable install makes the package importable from anywhere — but it doesn't hurt to leave it set.

Debugging with MCP Inspector

npx @modelcontextprotocol/inspector python -m employee_mcp.server

This opens a local web UI (http://localhost:6274/...) where you can run tools/list, inspect each tool's JSON Schema, and call tools interactively with a form built from that schema. To test read-only mode, set EMP_MCP_READ_ONLY=true in the Inspector's "Environment Variables" panel before connecting.

Human-in-the-loop (HITL) expectation

This server does not gate write tools on its own confirmation step — it expects the MCP host to show the user the write tool's resolved input (the employee fields about to be created/updated/deactivated) before actually calling it, the way most MCP-aware chat hosts do for consequential tool calls. EMP_MCP_READ_ONLY=true is the hard backstop for hosts/contexts where that isn't available.

Email-uniqueness interpretation

The requirement is "email unique across active employees." This server enforces it as: on create, and on update that changes email, reject with DUPLICATE_EMAIL if any other employee whose status == "active" already holds that email (case-insensitive compare). Two inactive/on_leave records may share an email with each other or with what later becomes an active employee's old email — the constraint only looks at currently-active holders at the moment of the write.

Other documented interpretations

  • list_employees limit > 100: clamped to 100, not rejected.
  • Deactivating an already-inactive employee: succeeds idempotently; the response reports previous_status == new_status == "inactive" rather than erroring.
  • update_employee and manager_id: omitting manager_id means "no change." There's currently no way to explicitly clear an employee's manager back to null via update_employee (the tool can't distinguish "field omitted" from "field explicitly set to null" with this parameter shape) — reassign to a different manager, or edit manager_id at creation time. A future iteration could resolve this with a sentinel/"unset" value if that gap matters for real usage.
  • SDK-level argument validation: FastMCP validates each tool's arguments (types, enums) against its generated JSON Schema before our tool code runs. Such failures are non-crashing and surfaced as isError: true with a message starting VALIDATION_ERROR: invalid arguments for <tool>: ..., and are still recorded as one logs/audit.log line with status: "error", code: "VALIDATION_ERROR" — a thin server-level wrapper (_AuditedFastMCP in server.py) exists specifically to guarantee that, since it doesn't happen for free.

Audit logging

Every tool call appends exactly one JSON line to logs/audit.log (created at startup if missing) with timestamp, tool, args_summary (PII-light — email local-part masked, full names omitted), status (ok/error), latency_ms, and on failure a taxonomy code. Nothing is ever written to stdout — stdout is reserved for JSON-RPC frames; all logging goes to this file and/or stderr.

Error taxonomy

VALIDATION_ERROR, DUPLICATE_EMAIL, NOT_FOUND, MANAGER_CYCLE, READ_ONLY, INTERNAL_ERROR — see employee_mcp/errors.py. Every domain failure message has the shape CODE: human-readable detail, e.g. NOT_FOUND: no employee with id EMP-999.

Tests

python -m pytest tests/test_smoke.py -v

Spins up the real server as a subprocess per test and drives it over stdio with an mcp.ClientSession, exercising protocol discovery, all 6 tools' success/failure paths, read-only mode, malformed-argument robustness, and audit-log completeness. This — not "the LLM said it worked" — is the evidence that the transport contract holds.

Demo

See demo/demo_transcript.md for a captured run of three flows (search/list, create, org summary) plus one intentional failure path (duplicate email), against the seed dataset, with the corresponding logs/audit.log lines shown alongside each call.

Known limitations

  • No pagination cursor for list_employees beyond limit/clamp — fine at the small, in-memory scale this project targets (low thousands of records at most), would need revisiting at larger scale.
  • update_employee can't clear manager_id back to null (see above).
  • Audit log location defaults to logs/audit.log and is configurable via EMP_MCP_AUDIT_PATH, but nothing enforces a 1:1 pairing with EMP_MCP_DATA_PATH — server instances that don't override it share the same default file.
  • Out of scope by design: no HTTP/SSE transport, no auth/OAuth provider, no frontend UI, no real HRIS/payroll integration, no stretch tools (search_by_skill, get_direct_reports, export_employees_csv, MCP Resources).

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选