Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,5 @@ debian/files
debian/python-taiga*
debian/python3-taiga*
.ruff_cache
.venv
*.egg-link
112 changes: 112 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Agent instructions

This file gives coding agents (Claude Code and similar) step-by-step
instructions for tasks specific to this repository. Human-facing docs live in
``README.rst`` and ``docs/``.

## Registering the Taiga MCP server in the user's global Claude config

This repo ships an MCP server (`taiga/mcp_server/`) that exposes the Taiga
REST API as tools over stdio, via the `taiga-mcp-server` console script
(installed by the `mcp` extra: `pip install -e .[mcp]` from this repo, or
`pip install python-taiga[mcp]` from PyPI).

When asked to "add the Taiga MCP server to Claude" / "register taiga-mcp
globally" / "add it to my user-wide config", follow this procedure:

1. **Confirm before acting.** Registering at user scope changes the user's
global Claude Code config (`~/.claude.json`), applying to every project,
not just this repo. Confirm the target Taiga instance and scope with the
user before running the command, unless they've already given explicit
go-ahead in this conversation.

2. **Get a stable `taiga-mcp-server` binary.** Don't point the MCP config at
a project-local `.venv` — Claude Code launches MCP server commands without
inheriting an activated venv, and the binary disappears if that venv is
ever recreated. Install it somewhere durable instead. There are several
equally valid ways to do this; pick whichever fits the user's toolchain,
asking if it's unclear, and default to `pip install --user` since it needs
nothing beyond a reasonably modern Python:
```bash
# default: pip install --user (works with any modern Python/pip)
pip install --user "python-taiga[mcp]" # from PyPI
pip install --user -e ".[mcp]" # from this checkout

# pipx (isolated venv per tool, one binary on PATH)
pipx install "python-taiga[mcp]" # from PyPI
pipx install --editable ".[mcp]" # from this checkout

# uvx (no persistent install; uv manages an ephemeral/cached env)
# here the *registered command* becomes `uvx --from "python-taiga[mcp]" taiga-mcp-server`
# instead of a resolved path — see the uvx example in step 4.
```
After a `pip --user`/`pipx` install, resolve the resulting path and use it
verbatim in step 4:
```bash
command -v taiga-mcp-server
```

3. **Collect credentials.** Ask the user for:
- `TAIGA_HOST` — the Taiga site root, e.g. `https://my.taiga.com`.
For self-hosted instances this is *not* an `api.` subdomain and has no
`/api` suffix — the client appends `/api/v1` itself.
- Either `TAIGA_TOKEN` (pre-issued API token), or both
`TAIGA_USERNAME` and `TAIGA_PASSWORD`. A token takes precedence if both
are configured.
- Optional: `TAIGA_TOKEN_TYPE` (default `Bearer`), `TAIGA_TLS_VERIFY`
(default `true`).

Never pass `--token`/`--password` as CLI arguments — they'd be visible in
the process list. Always pass credentials as environment variables.

**Default to username/password over a token, unless the instance has a
real personal-access-token feature.** Stock Taiga (checked against
`https://my.taiga.com`) has no self-service PAT: the only tokens it
issues are (a) short-lived JWTs from `POST /api/v1/auth` — on that
instance, a 24h access token / 8-day refresh token — and (b) OAuth-style
"Application" tokens, which require an admin-registered app and a
consent/`auth_code` flow (`client.auth_app()`), not something a regular
user can self-serve. This server's `auth.py`/CLI has no refresh-token
support, so a manually-generated `TAIGA_TOKEN` will just silently stop
working after ~24h with no renewal — worse than username/password, which
re-authenticates fresh on every server start. Only reach for `TAIGA_TOKEN`
when the target instance genuinely offers a durable personal token (e.g.
a Taiga Enterprise/hosted deployment with PAT support) — verify that
before recommending it, don't assume it exists.

4. **Register at user scope** with `claude mcp add`, using `-e` for every
credential env var and the resolved binary (or `uvx` invocation) from
step 2:
```bash
claude mcp add --scope user taiga \
-e TAIGA_HOST=https://my.taiga.com \
-e TAIGA_USERNAME=<username> \
-e TAIGA_PASSWORD=<password> \
-- /absolute/path/to/taiga-mcp-server
```
or, with a token instead of username/password:
```bash
claude mcp add --scope user taiga \
-e TAIGA_HOST=https://my.taiga.com \
-e TAIGA_TOKEN=<token> \
-- /absolute/path/to/taiga-mcp-server
```
With `uvx` there's no path to resolve — pass the `uvx` invocation itself
as the command:
```bash
claude mcp add --scope user taiga \
-e TAIGA_HOST=https://my.taiga.com \
-e TAIGA_TOKEN=<token> \
-- uvx --from "python-taiga[mcp]" taiga-mcp-server
```
`--scope user` (not `local`/`project`) is what makes it "user-wide" —
available in every project for that user, stored outside this repo.

5. **Verify** with `claude mcp list` (look for `taiga` ... `✔ Connected`) and
`claude mcp get taiga`. If it fails to connect, re-check the resolved
binary/command from step 2 and that `TAIGA_HOST` is the site root, not an
API subdomain.

6. **Don't persist secrets in the repo.** Credentials belong only in the
`claude mcp add -e ...` invocation (stored in the user's own
`~/.claude.json`) — never write them into files inside this repository.
3 changes: 2 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
include AGENTS.md
include AUTHORS
include LICENSE
include README.rst
include CONTRIBUTING.rst
include HISTORY.rst
include requirements.txt
include requirements-tests.txt
include requirements-test.txt
recursive-include taiga *.html *.png *.gif *js *jpg *jpeg *svg *py *mo *po
1 change: 1 addition & 0 deletions changes/14020.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add MCP server exposing Taiga projects, user stories, tasks, issues, epics, milestones and wiki pages as tools for AI agents
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Welcome to python-taiga's documentation!
:maxdepth: 3

usage
mcp
api
models
development
Expand Down
177 changes: 177 additions & 0 deletions docs/mcp.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
.. :mcp:

==========
MCP Server
==========

Contents:

python-taiga ships a `Model Context Protocol <https://modelcontextprotocol.io/>`_
(MCP) server that exposes Taiga projects, user stories, tasks, issues, epics,
milestones and wiki pages as tools an LLM-based assistant (Claude, or any
other MCP-compatible client) can call directly, without you writing any glue
code.

.. note:: The MCP server wraps the same ``TaigaAPI`` documented in
:doc:`the usage guide <usage>` and :doc:`the API reference <api>` -
if you need to script against Taiga from Python yourself, use
``TaigaAPI`` directly instead.

****************
Installation
****************

The server is an optional extra, since it pulls in `fastmcp
<https://pypi.org/project/fastmcp/>`_ as a dependency:

.. code:: shell

pip install "python-taiga[mcp]"

Any of the following also work, depending on your toolchain:

.. code:: shell

pip install --user "python-taiga[mcp]" # no virtualenv management needed
pipx install "python-taiga[mcp]" # isolated venv, one command on PATH
uvx --from "python-taiga[mcp]" taiga-mcp-server # no persistent install at all

Any of these makes a ``taiga-mcp-server`` console script available.

****************
Configuration
****************

Credentials are read from environment variables, or from equivalent
command-line flags (flags take precedence over the environment):

.. list-table::
:header-rows: 1
:widths: 20 25 55

* - Environment variable
- CLI flag
- Meaning
* - ``TAIGA_HOST``
- ``--host``
- Taiga instance root, e.g. ``https://taiga.example.com``. Defaults to
``https://api.taiga.io``.
* - ``TAIGA_TOKEN``
- ``--token``
- A pre-issued auth token. Takes precedence over username/password if
both are set.
* - ``TAIGA_TOKEN_TYPE``
- ``--token-type``
- Type of the token above. Defaults to ``Bearer``.
* - ``TAIGA_USERNAME``
- ``--username``
- Username, used together with the password below.
* - ``TAIGA_PASSWORD``
- ``--password``
- Password, exchanged for a session token at startup.
* - ``TAIGA_TLS_VERIFY``
- ``--tls-verify`` / ``--no-tls-verify``
- Verify TLS certificates. Defaults to ``true``.

.. warning:: Prefer the environment variables over the CLI flags for
``--token``/``--password``: command-line arguments are visible
to other processes on the same machine (e.g. via ``ps``),
environment variables set for the server's own process are not.

.. note:: Most Taiga instances don't offer a durable personal-access-token
feature - the token obtained from a username/password login is a
short-lived JWT (often expiring within a day), and this server
doesn't refresh it once started. Unless you know your instance
issues long-lived tokens, configure ``TAIGA_USERNAME``/
``TAIGA_PASSWORD`` rather than a fixed ``TAIGA_TOKEN`` - the server
re-authenticates fresh every time it starts.

******************************
Running the server standalone
******************************

.. code:: shell

TAIGA_HOST=https://taiga.example.com \
TAIGA_USERNAME=myuser \
TAIGA_PASSWORD=mypassword \
taiga-mcp-server

The server speaks MCP over stdio and is meant to be launched by an MCP
client, not used interactively - the command above will sit and wait for a
client to connect over stdin/stdout.

*****************************
Connecting an MCP client
*****************************

Any MCP client that supports the stdio transport can launch
``taiga-mcp-server`` as a subprocess. For `Claude Code
<https://docs.claude.com/en/docs/claude-code>`_, register it once and it's
available in every project:

.. code:: shell

claude mcp add --scope user taiga \
-e TAIGA_HOST=https://taiga.example.com \
-e TAIGA_USERNAME=myuser \
-e TAIGA_PASSWORD=mypassword \
-- taiga-mcp-server

``--scope user`` stores the registration in your own Claude configuration,
not in any particular project. Check it went through with:

.. code:: shell

claude mcp get taiga

****************
Available tools
****************

``whoami``
Return the Taiga user currently authenticated.

``list_projects`` / ``get_project``
List projects visible to the user, or fetch one project's full detail
(numeric id or slug) - including the statuses/priorities/severities/points
ids needed to create or update entities in it.

``search``
Search user stories, tasks, issues, epics and wiki pages in a project.

``add_comment``
Add a comment to a user story, task, issue or epic.

``list_user_stories``, ``get_user_story``, ``create_user_story``, ``update_user_story``, ``delete_user_story``
Manage user stories.

``list_tasks``, ``get_task``, ``create_task``, ``update_task``, ``delete_task``
Manage tasks, optionally scoped to a project and/or a user story.

``list_issues``, ``get_issue``, ``create_issue``, ``update_issue``, ``delete_issue``
Manage issues.

``list_epics``, ``get_epic``, ``create_epic``, ``update_epic``, ``delete_epic``
Manage epics.

``list_milestones``, ``get_milestone``, ``create_milestone``, ``delete_milestone``
Manage milestones (sprints).

``list_wiki_pages``, ``get_wiki_page``, ``create_wiki_page``, ``update_wiki_page``
Manage wiki pages.

.. tip:: Call ``get_project`` first when creating or updating an entity - it
returns every status/priority/severity/points id valid for that
project, which the ``create_*``/``update_*`` tools expect.

****************
Security notes
****************

The MCP server has the same permissions as the account it authenticates
with, and the create/update/delete tools above are destructive: an assistant
with access to this server can create, modify or delete real data in your
Taiga projects. Review what an MCP client proposes to do before approving
write operations, and consider a dedicated Taiga account with restricted
project membership if you want to limit the blast radius.
13 changes: 12 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,32 @@ install_requires =
six>=1.9
python-dateutil>=2.4
pyjwkest>=1.0
packages = taiga
packages = find:
python_requires = >=3.7
setup_requires =
setuptools
zip_safe = False
test_suite = tests

[options.packages.find]
include =
taiga
taiga.*

[options.package_data]
* = *.txt, *.rst
taiga = *.html *.png *.gif *js *jpg *jpeg *svg *py *mo *po

[options.entry_points]
console_scripts =
taiga-mcp-server = taiga.mcp_server.cli:main

[options.extras_require]
docs =
sphinx
sphinx-rtd-theme
mcp =
fastmcp>=3.0

[sdist]
formats = zip
Expand Down
7 changes: 7 additions & 0 deletions taiga/mcp_server/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# python-taiga
# Copyright 2015 Nephila
# See LICENSE for details.

"""
MCP server exposing python-taiga as a set of tools for LLM clients.
"""
Loading
Loading