Metadata-Version: 2.4
Name: orkestrr-mcp
Version: 0.2.0
Summary: MCP server exposing the Orkestrr project-management hierarchy (Bundles, Goals, Tasks) to AI agents
Project-URL: Homepage, https://github.com/cafadev/orkestrr
Project-URL: Repository, https://github.com/cafadev/orkestrr
Project-URL: Issues, https://github.com/cafadev/orkestrr/issues
Author-email: Christopher Flores <christopherflores@moxie-link.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,claude,mcp,model-context-protocol,orkestrr,project-management
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: mcp>=1.2.0
Description-Content-Type: text/markdown

# orkestrr-mcp

An [MCP](https://modelcontextprotocol.io) server that lets an AI agent (e.g. Claude Code)
**create, reuse, and manage** the Orkestrr project-management hierarchy — Bundles, Goals, and
Tasks — through the existing Orkestrr REST API.

It is a standalone process that talks to Orkestrr over HTTP, so once registered at **user scope**
it works from **any** project/repo you open, against **local or production** Orkestrr.

## What it exposes

Hierarchy tools (read + write):

| Area | Tools |
| --- | --- |
| Projects | `list_projects`, `get_project`, `list_project_members` |
| Bundles | `list_bundles`, `create_bundle`, `update_bundle` (incl. status & archive) |
| Goals | `list_goals`, `create_goal`, `update_goal` (incl. status) |
| Tasks | `list_tasks`, `create_task`, `update_task` (incl. status & assignment) |

Task details:

| Area | Tools |
| --- | --- |
| Status | `set_task_status` |
| Estimation | `list_estimation_values`, `set_task_estimation` |
| Labels | `list_labels`, `create_label`, `add_task_labels`, `remove_task_labels` |

Status changes propagate up the hierarchy automatically (Task → Goal → Bundle → Project),
handled by the Orkestrr backend. `add_task_labels` reads the task's current labels and sends
the union (the API replaces the label set on update), so existing labels are preserved.

### Backend quirks worked around (candidates for a future backend fix)

* `POST /labels/` does not return the new label's `id` — `create_label` resolves it by
  re-querying labels by name.
* A task's `estimation_label` is null in list/update payloads (only the nested `estimation`
  object on the detail payload carries the label) — `set_task_estimation` re-fetches the detail
  so it can confirm the value.

## Authentication

You sign in **once**, interactively, in the browser with your EVOHEIM SSO (Authentik):

```bash
okr login     # opens the browser (OAuth device flow); approve the code
okr status    # shows who you're logged in as + token validity
okr logout    # clears the stored session
```

`okr login` uses the OAuth 2.0 **Device Authorization Flow** against the public
`orkestrr-cli` Authentik provider. The issued JWT carries your real identity, so tasks and
status changes stay attributed to you. Tokens are stored in
`~/.config/orkestrr-mcp/tokens.json` (mode `0600`) and **auto-refresh** — the MCP server
never needs an interactive prompt. No secrets go into the MCP registration.

If a tool ever fails with *"Not logged in"* or *"Session expired"*, just run `okr login` again.

## Configuration

| Variable | Example | Notes |
| --- | --- | --- |
| `ORKESTRR_BASE_URL` | `http://localhost:9000` | The only required var. `/api` is appended automatically if absent. |
| `ORKESTRR_MCP_HOME` | `~/.config/orkestrr-mcp` | Optional. Override the directory where the session is stored. |

## Install

From PyPI (recommended — no repo checkout needed):

```bash
uv tool install orkestrr-mcp        # or: pipx install orkestrr-mcp
# installs the `okr` command on your PATH; upgrade with `uv tool upgrade orkestrr-mcp`
```

From source (for development on the server itself):

```bash
git clone git@github.com:cafadev/orkestrr.git
uv tool install --editable ./orkestrr/orkestrr-mcp
```

## Register with Claude Code (user scope = available in every project)

No credentials in the registration — the server command is `okr mcp`, and it uses your
`okr login` session.

```bash
# Local Orkestrr
claude mcp add --scope user orkestrr-local \
  --env ORKESTRR_BASE_URL=http://localhost:9000 \
  -- okr mcp

# Production Orkestrr
claude mcp add --scope user orkestrr \
  --env ORKESTRR_BASE_URL=https://<prod-domain> \
  -- okr mcp
```

Then run `okr login` once (it works for both environments — same Authentik). Restart Claude
Code and run `/mcp` to confirm the tools are listed.

## Develop

```bash
uv sync          # install deps + this package (editable)
uv run pytest    # run the test suite
```

## Publishing to PyPI (maintainers)

Publishing is automated by GitHub Actions
([`.github/workflows/orkestrr-mcp-publish.yml`](../.github/workflows/orkestrr-mcp-publish.yml))
using **PyPI Trusted Publishing (OIDC)** — no API token is stored anywhere.

**One-time setup on PyPI** (do this before the first release): on
<https://pypi.org/manage/account/publishing/> add a *pending* trusted publisher:

| Field | Value |
| --- | --- |
| PyPI Project Name | `orkestrr-mcp` |
| Owner | `cafadev` |
| Repository name | `orkestrr` |
| Workflow name | `orkestrr-mcp-publish.yml` |
| Environment | *(leave blank)* |

**Each release:**

1. Bump `version` in `pyproject.toml` (PyPI never lets you re-upload the same version) and merge it.
2. Create a GitHub Release whose **tag starts with `orkestrr-mcp-v`** (e.g. `orkestrr-mcp-v0.1.0`).
   The tag prefix is what triggers the workflow (and keeps it monorepo-safe).

The workflow builds the sdist + wheel and publishes them. Teammates then `uv tool install orkestrr-mcp`.

**Manual fallback** (if Actions is unavailable) — needs an API token from
Account settings → API tokens:

```bash
rm -rf dist && uv build
uvx twine check dist/*
UV_PUBLISH_TOKEN=pypi-XXXX uv publish
```

## Out of scope (for now)

Acceptance criteria, action items, comments, blockers, and estimation-scale configuration
(creating/editing the scale itself — only assigning existing values is supported). A dedicated
API-key / OAuth2 machine-to-machine auth layer is also deferred — token auth covers current needs.
