Employee MCP Server
README.md
# Employee MCP Server
A small [Model Context Protocol](https://modelcontextprotocol.io) server that
exposes an employee directory — backed by SQLite, validated with Pydantic —
as a set of MCP tools and resources. Includes an interactive CLI client for
exercising it without a full MCP-aware host.
## Contents
- [server.py](server.py) — the MCP server: tools, resources, database access
- [models.py](models.py) — Pydantic schemas that validate every tool's input and shape its output
- [seed_db.py](seed_db.py) — one-time script that creates and populates `employees.db`
- [client.py](client.py) — interactive REPL client for calling the server by hand
- [tests/](tests) — pytest suite for the server and models
## Requirements
- Python 3.11+ (developed against 3.14)
- A virtual environment (the project expects one at `.venv`)
## Setup
Create a virtual environment and install dependencies:
```bash
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
```
For running the test suite, install the dev dependencies instead (this
includes everything in `requirements.txt` plus `pytest`):
```bash
.venv/bin/pip install -r requirements-dev.txt
```
Create and seed the database (run once per checkout — it creates
`employees.db` next to `server.py`):
```bash
.venv/bin/python seed_db.py
```
`employees.db` is gitignored, so every fresh checkout needs this step. To
wipe and reseed an existing database:
```bash
.venv/bin/python seed_db.py --force
```
## Data model
Two tables, one employee record per `id`:
- `employees(id, name, role)`
- `skills(id, employee_id, skill)` — many rows per employee, cascade-deleted
with the employee
Input to every write tool is validated by a Pydantic model in `models.py`
before it reaches the database: `name`/`role` can't be blank, `skills` must
contain at least one non-empty entry, and `employee_id` must be a positive
whole number. A tool called with bad input gets back a clear error message
(e.g. `employee_id must be a positive whole number, got 'abc'`) instead of a
stack trace or a silent failure.
## Running the server
The server speaks MCP over stdio and isn't meant to be run standalone in a
terminal — it's launched as a subprocess by an MCP client. `client.py` does
this for you via `StdioServerParameters`, spawning `server.py` with the
venv's Python interpreter.
To use it from an MCP-aware host (e.g. Claude Desktop, Claude Code), point
the host's MCP config at:
```json
{
"mcpServers": {
"employees": {
"command": "/absolute/path/to/mcp_tool/.venv/bin/python",
"args": ["/absolute/path/to/mcp_tool/server.py"]
}
}
}
```
## Tools
| Tool | Arguments | Description |
|---|---|---|
| `list_employees` | — | List all employees |
| `get_employee` | `employee_id` | Get one employee by ID |
| `search_employees` | `name` | Case-insensitive partial name match |
| `find_employees_by_skill` | `skill` | Case-insensitive exact skill match |
| `add_employee` | `name`, `role`, `skills`, `employee_id?` | Add an employee; ID auto-assigned if omitted |
| `update_employee` | `employee_id`, `name?`, `role?`, `skills?` | Update one or more fields |
| `delete_employee` | `employee_id` | Delete an employee |
Every tool also declares an output schema (an `Employee` or `DeleteResult`
shape), so a schema-aware client sees structured results, not just text.
## Resources
| URI | Description |
|---|---|
| `employees://all` | All employee records as JSON |
| `employees://{employee_id}` | A single employee record as JSON |
## Using the interactive client
`client.py` opens one MCP session and gives you a REPL to call tools and
read resources by hand:
```bash
.venv/bin/python client.py
```
```
> list
> get 101
> search an
> byskill AWS
> add Zara Khan | Data Scientist | Python,SQL
> update 122 | role=Senior Data Scientist | skills=Python,SQL,Spark
> delete 122
> resource employees://all
> resource employees://101
> resources
> tools
> help
> quit
```
- `add` fields are pipe-separated: `name | role | comma,separated,skills [| employee_id]`
- `update` takes `employee_id`, then one or more `field=value` pairs
(`name=`, `role=`, or `skills=`), pipe-separated
- Tool errors (e.g. validation failures) print inline and drop you back to
the prompt — the session stays open
## Running tests
```bash
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest tests/
```
Tests point the server at a temporary SQLite database (via `tmp_path` +
`monkeypatch`) and never touch the real `employees.db`.
## Project layout
```
server.py MCP server: tools, resources, DB access
models.py Pydantic input/output schemas
seed_db.py Creates and seeds employees.db
client.py Interactive REPL client
employees.db SQLite database (generated, gitignored)
requirements.txt Runtime dependencies
requirements-dev.txt Runtime + test dependencies
tests/test_server.py Server/tool tests
tests/test_models.py Pydantic model tests
```
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues