Metadata-Version: 2.5
Name: timemanager-mcp
Version: 0.1.1
Summary: User-scoped TimeManager tasks for MCP coding assistants
License-Expression: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27
Requires-Dist: mcp<2,>=1.12.4
Requires-Dist: pydantic<3,>=2.8
Provides-Extra: dev
Requires-Dist: build<2,>=1.2; extra == 'dev'
Requires-Dist: mypy<2,>=1.15; extra == 'dev'
Requires-Dist: pytest-asyncio<2,>=0.24; extra == 'dev'
Requires-Dist: pytest<10,>=8; extra == 'dev'
Requires-Dist: ruff<1,>=0.11; extra == 'dev'
Description-Content-Type: text/markdown

# timemanager-mcp

A standalone stdio MCP server exposing your TimeManager tasks to a
coding assistant. It uses the official MCP Python SDK (stable v1), Python 3.11+,
and HTTPS requests to your hosted TimeManager API. It imports no TimeManager
application code and needs no access to the private application repository.

## Availability

Published to PyPI as `timemanager-mcp`; `uvx timemanager-mcp` works as shown
below. This directory is still the package's source of truth — it has not
yet been extracted into its own public repository (see "Independent
development and release").

## Configure

1. Open your TimeManager bot and run `/dev_token`. Generate a token and save
   it immediately; it is shown once. Rotation invalidates the previous token.
2. Set `TIMEMANAGER_API_URL` to the API origin (for example,
   `https://your-timemanager.example`) or its `/api/v1` root.
3. Set `TIMEMANAGER_TOKEN` to your `tm_pat_...` token in the environment
   inherited by the MCP process. Keep it out of version-controlled files.
4. Register the command `uvx` with arguments `["timemanager-mcp"]` in your
   assistant's MCP server configuration.

There is no required task category: point the assistant at any task by ID
and use your own judgment about which ones make sense to hand off.

A generic `mcpServers` configuration for clients using that format:

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

The parent process must pass both environment variables to this server. If a
client uses its own `env` settings, place credentials only in its private local
configuration. Variable interpolation syntax depends on the MCP client.

## Tools

| Tool | Arguments | Behavior |
|---|---|---|
| `list_tasks` | optional `status`, `category` | List up to 100 tasks |
| `get_task` | `task_id` | Read full task detail |
| `fetch_task_attachment` | `task_id`, `attachment_id` | Fetch one listed image or file, up to 20 MiB |
| `start_task` | `task_id` | Mark a pending task in progress |
| `finish_task` | `task_id` | Finish a pending/in-progress task |

IDs accept Mongo ObjectIds or short IDs such as `12` or `#12`. Status accepts
`pending`, `scheduled`, `in_progress`, `completed`, `cancelled`, or `blocked`.
Without a status, the API lists all statuses up to its default 100-task limit;
the API currently has no offset pagination. Use status filters to narrow results.

Results retain API task details, source metadata, and lifecycle effects. A
recurring task can reopen after finishing; inspect the `completion` field.
Lifecycle restrictions (including blocked or scheduled tasks) remain API-owned.
There are no create, edit, delete, or progress-note tools in this release.

`get_task` includes `task.attachments` with opaque `attachment_id`, kind,
filename, MIME type, and optional size. It does not download attachments.
Call `fetch_task_attachment` explicitly for an ID from that list. PNG, JPEG,
WebP, and GIF responses are native MCP image content; other files are embedded
binary resources with base64 content and their response MIME type. Client support
determines how files are displayed. The bridge writes no local files and follows
no attachment URLs. Downloads use the same authenticated API, with a 20 MiB
decoded-byte limit checked while streaming. Telegram file IDs and bot credentials
remain on the backend. Older tasks without captured attachment references have
an empty list; opening their original Telegram message remains available in the bot.

Every detail or lifecycle tool performs an authenticated task GET before its
task-ID operations, then uses the canonical ID from that GET. Mutations use a
fresh `Idempotency-Key` for each invocation. Reinvoking a tool starts a new
operation; inspect the task first if a previous request's outcome is
uncertain. The API enforces ownership using the token's identity: the same
token can access other external-client API endpoints directly, so keep it as
guarded as your account password.

## License

MIT — see [LICENSE](LICENSE).

## Errors and transport

Expired, revoked, or invalid tokens produce `/dev_token` guidance. Other API
errors (including rate-limit responses) retain their HTTP status and JSON body
in the tool error, with token strings redacted. Network failures name
`TIMEMANAGER_API_URL` without printing secrets or raw exception details. There
are no retries: after an uncertain mutation, call `get_task` before trying again.

HTTPS is required except for `localhost` and literal loopback IPs. URLs with
credentials, query strings, or fragments are rejected. Redirects are never
followed, and environment proxy settings are disabled. Standard output is
reserved for MCP; configuration failures go to standard error.

## Independent development and release

This package's tests are separate from the application's test suite:

```sh
uv run --extra dev pytest
uv run --extra dev ruff check src tests
uv run --extra dev mypy src
uv run --extra dev python -m build
```

When developing within the Dockerized application checkout, use the app's
Docker workflow instead of installing dependencies on the host.

`0.1.0` and `0.1.1` were published manually (`uv publish` with a personal API
token) from this staging directory, still inside the private application
repository. Remaining before treating this as a stable, fully authorized
release process:

1. Extract this directory into a public repository (the license already
   travels with it — see [LICENSE](LICENSE)).
2. Configure PyPI trusted publishing for that repository's release workflow,
   so future versions don't require a manually-held API token.
3. Point this README's project URLs at the public repository once it exists.

No remote repository or publishing workflow is created by this staging
directory yet.
