# TMS MCP Server

Connect Claude to your [1WLF Task Management System](https://tms.1wlf.com) account. Manage tasks, projects, and organizations directly from Claude Code.

## Quick Install

**Step 1 — Install `uv`** (one-time)

| Platform | Command |
|----------|---------|
| Windows | `winget install astral-sh.uv` |
| macOS | `brew install uv` |
| Linux | `curl -LsSf https://astral.sh/uv/install.sh \| sh` |

**Step 2 — Add to your Claude Code MCP config**

Edit `~/.claude/mcp.json` (global, works in all projects):

```json
{
  "mcpServers": {
    "tms": {
      "command": "uvx",
      "args": ["tms-mcp"]
    }
  }
}
```

**Step 3 — Restart Claude Code**

That's it. `uvx` downloads and runs the server automatically — no Python setup required.

## Usage

Start any Claude Code session and authenticate first:

> _"Log into TMS as user@example.com"_

Then interact naturally:

- _"What organizations do I belong to?"_
- _"List all tasks in project 5 that are blocked"_
- _"Create a bug task 'Fix login redirect' in project 3, high priority"_
- _"Show me task 42 with its subtasks and audit history"_
- _"Move task 42 to in-progress"_
- _"Search for users named 'sarah' in org 1"_

## Available Tools

### Authentication

| Tool | Description |
|------|-------------|
| `tms_login` | Authenticate with email and password. Must be called first — caches the JWT token in-memory for the session. |
| `tms_whoami` | Return the current authenticated user's info. |

### Organizations

| Tool | Description |
|------|-------------|
| `tms_list_organizations` | List all organizations you belong to. Set `include_stats=True` to get task counts per org. |

### Projects

| Tool | Description |
|------|-------------|
| `tms_list_projects` | List projects, optionally filtered by `organization_id`. |
| `tms_get_project` | Get project details and member list. |

### Tasks

| Tool | Description |
|------|-------------|
| `tms_list_tasks` | List tasks in a project. Filter by `status`, `priority`, `assigned_to_id`, `parent_task_id`. |
| `tms_get_task` | Get a task with its subtasks. Set `include_audit_log=True` for change history. |
| `tms_create_task` | Create a task with full field support. |
| `tms_update_task` | Partial update — only provide the fields you want to change. |
| `tms_delete_task` | Delete a task and all its subtasks. |

### Users

| Tool | Description |
|------|-------------|
| `tms_search_users` | Search for users by name or email (min 2 characters). |

### Field Reference

**Status:** `backlog` · `todo` · `in-progress` · `blocked` · `testing` · `in-review` · `done`

**Priority:** `low` · `medium` · `high` · `critical`

**Task type:** `task` · `story` · `feature`

**Category:** `feature` · `bug` · `improvement` · `maintenance`

**Difficulty:** `1` to `5`

## Self-Hosted Instances

If you're running your own TMS backend, override the API URL:

```json
{
  "mcpServers": {
    "tms": {
      "command": "uvx",
      "args": ["tms-mcp"],
      "env": {
        "TMS_API_URL": "https://your-tms-instance.com"
      }
    }
  }
}
```

---

## Developer Setup

For local development or contributing to this server:

### 1. Create virtual environment and install dependencies

```bash
cd TMS-MCP
python -m venv .venv

# Windows
.venv\Scripts\activate
# Linux/macOS
source .venv/bin/activate

pip install -e .
```

### 2. Run locally

```bash
python -m tms_mcp
```

Or point `.mcp.json` at your venv directly:

```json
{
  "mcpServers": {
    "tms": {
      "command": "<path-to>/TMS-MCP/.venv/Scripts/python.exe",
      "args": ["-m", "tms_mcp"],
      "env": {
        "TMS_API_URL": "http://localhost:8000"
      }
    }
  }
}
```

### Publishing to PyPI

```bash
pip install build twine
python -m build
twine upload dist/*
```

Bump `version` in `pyproject.toml` before each release.

### Architecture

```
TMS-MCP/
├── pyproject.toml
└── tms_mcp/
    ├── __main__.py      # Entry point: python -m tms_mcp
    ├── server.py        # FastMCP app, registers tools and resources
    ├── api_client.py    # Async httpx client — auth header injection, error translation
    ├── resources.py     # MCP resource handlers
    └── tools/
        ├── auth.py          # tms_login, tms_whoami
        ├── organizations.py # tms_list_organizations
        ├── projects.py      # tms_list_projects, tms_get_project
        ├── tasks.py         # tms_list_tasks, tms_get_task, tms_create_task, tms_update_task, tms_delete_task
        └── users.py         # tms_search_users
```

### Authentication flow

- `tms_login` calls `POST /auth/login`, receives a JWT, and caches it in-memory
- Token is attached to all subsequent requests as a Bearer header
- Token has a 24-hour TTL — if it expires, Claude will see a 401 and suggest re-authenticating
- Token is never persisted to disk; it dies when the MCP process exits

### Error handling

API errors are returned as readable strings so Claude can reason about failures:

| HTTP Status | Message |
|-------------|---------|
| 401 | Authentication failed — re-authenticate with `tms_login` |
| 403 | Permission denied: {detail} |
| 404 | Not found: {detail} |
| 409 | Conflict: {detail} |
| 422 | Validation error: {field}: {message} |
| 5xx | TMS API server error — is the backend healthy? |
| Connection refused | Cannot connect to TMS API at {url} |
