taiga-mcp-server について
taiga-mcp-serverは、AIエージェントからTaigaのプロジェクト作業を読み取り、管理するためのサーバーです。プロジェクト内の名前でステータスやメンバー、スプリントを解決し、期間を指定した活動履歴も扱えます。
主な機能
- 01担当作業とプロジェクトデータの取得
- 02ユーザーストーリー、タスク、課題、エピックの作成・更新
- 03担当者、見積もり、コメント、スプリントの管理
- 04名前によるカタログ値の解決
- 05期間内のプロジェクト活動の集約
活用シーン
- 01チームメンバーの担当項目を確認
- 02作業項目のステータスを変更
- 03Taigaの作業項目を作成して割り当て
- 04プロジェクトで先週起きた変更を確認
MCP 対応
このリポジトリにはtaiga-api-mcp-serverが含まれ、Taigaのプロジェクトデータと管理操作をMCPクライアント向けのツールとして公開します。Taiga APIクライアントを使用し、アカウントの権限範囲で動作します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
npx -y taiga-api-mcp-serverTAIGA_URLTaiga instance root, without /api/v1. Taiga Cloud: https://api.taiga.ioTAIGA_USERNAMETaiga username or email, used together with TAIGA_PASSWORDTAIGA_PASSWORDシークレットPassword for TAIGA_USERNAMETAIGA_APP_TOKENシークレットLong-lived Application token, instead of a username and passwordTAIGA_PROJECTDefault project (id, slug or name) for tool calls that omit oneTAIGA_MCP_READ_ONLYSet to 1 to register the read tools onlyTAIGA_MCP_ALLOW_DELETESet to 1 to also register taiga_delete_itemローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
taiga-api-client
🇬🇧 英語版 — 現在表示中 · 🇷🇺 ロシア語版
Taiga REST API 用の TypeScript クライアントです。実行時の依存関係はなく、ESM と CJS の両方に対応し、Node ≥18、Bun ≥1.0、およびグローバルな fetch が使えるあらゆる環境で動作します。
- 🔐 トークンの自動更新と同時更新の重複排除に対応した Bearer 認証
- 📦 完全な型付け:すべてのリソース、ペイロード、パラメーターの型を提供
- 🚫 実行時の依存関係はゼロ
- 🔄 ページネーション用の非同期イテレーター
- ⚠️ 型付きエラー(
TaigaApiError、TaigaAuthError、TaigaRateLimitError、TaigaNetworkError) - 🚀
.d.ts/.d.cts型マップを含む ESM + CJS の両対応ビルド
インストール
npm install taiga-api-client
# or
bun add taiga-api-client
# or
pnpm add taiga-api-client
クイックスタート
import { TaigaClient } from "taiga-api-client";
// baseUrl is the only required option.
const client = new TaigaClient({ baseUrl: "https://api.taiga.io" });
// Log in (the `username` field accepts both username and email).
await client.auth.login({ username: "[email protected]", password: "secret" });
// Fetch projects you are a member of.
const me = await client.users.me();
const projects = await client.projects.list({ member: me.id });
// Create a user story.
const story = await client.userStories.create({
project: projects[0].id,
subject: "Add OAuth login",
description: "Support GitHub OAuth in addition to password login",
});
// Iterate over every issue in the project (auto-pagination).
for await (const issue of client.issues.paginate({ project: projects[0].id })) {
console.log(`#${issue.ref} ${issue.subject}`);
}
🤖 MCP サーバー:AI エージェント向け Taiga
このリポジトリには、taiga-api-mcp-server も含まれています。このクライアントを基盤とする Model Context Protocol サーバーです。MCP クライアント(Claude Code、Claude Desktop、Cursor など)を Taiga アカウントに接続すると、あなたに割り当てられた項目の確認、項目のステータス変更、ユーザーストーリー、タスク、課題、エピックの作成、メンバーの割り当て、見積もり、コメント、スプリントの計画を行えます。権限はあなた自身のものに限られ、それ以上の権限はありません。
ステータス、メンバー、スプリントは名前で指定します。サーバーがプロジェクト固有のカタログから該当する項目を解決するため、エージェントが数値 ID を推測する必要はありません。
さらに、taiga_activity を 1 回呼び出すだけで、**「先週は何をしましたか」**という質問にも答えます。このツールはプロジェクトのタイムラインをたどり、期間内に変更されたカードごとに、実際に起きたこと(ステータスの変更、クローズ(数日後に入力されたものを含む)、コメント、スプリント間の移動、添付ファイル)を返します。Taiga の一覧エンドポイントには日付フィルターがないため、期間を指定して作業内容を取得するにはこれが唯一の方法です。ストーリーが完了したかどうかは、そのタスク(tasks_done と tasks_total)から判断し、クローズされたかどうかはプロジェクト固有のステータスから判断します。日付とクローズフラグは手動で入力され、入力されていないこともよくあります。カードが 3 日後に Done へ移動した場合、それは先週の作業ではないため、どちらの判定も今日時点と期間終了時点の両方で回答します。
claude mcp add taiga --env TAIGA_URL=https://api.taiga.io --env [email protected] --env TAIGA_PASSWORD=... -- npx -y taiga-api-mcp-server
📖 セットアップ、ツールリファレンス、使用例:mcp/README.md
💡 カタログ ID を調べるには?filters_data を使いましょう
書き込み操作の多くでは、プロジェクト固有のカタログ値(ステータス、タイプ、重要度、優先度、担当者など)の数値 ID が必要です。カタログを個別に取得する必要はありません。すべてのリソースには filters_data メソッドがあり、プロジェクトの範囲に限定されたカタログ値をすべて1 回のリクエストで返します。
const data = await client.issues.filtersData({ project: 42 });
const inProgress = (data.statuses as Array<{ id: number; name: string }>)
.find((s) => s.name === "In progress");
await client.issues.create({ project: 42, subject: "...", status: inProgress!.id });
📖 詳細ガイド:docs/filters-data.md — キャッシュ、リソースごとに利用できるエンドポイント、およびこの方法では不十分な場合について説明しています。
クライアントの作成
最小構成:
const client = new TaigaClient({ baseUrl: "https://api.taiga.io" });
baseUrl だけが必須のオプションです。それ以外はすべて省略できます。
完全な例:
const client = new TaigaClient({
baseUrl: "https://api.taiga.io", // ← required
// Authentication — pick one (or none, if you will call client.auth.login later):
token: "...", // a previously obtained bearer token (session restore)
refreshToken: "...", // its paired refresh token
applicationToken: "...", // a static Application token, used instead of bearer
// Behavior:
autoRefresh: true, // auto-refresh the bearer token on 401 (default true)
timeoutMs: 30000, // request timeout in ms (default 30000)
userAgent: "my-app/1.0",
acceptLanguage: "en",
apiPrefix: "/api/v1", // change only for self-hosted with a non-default prefix
fetch: customFetch, // dependency-injected fetch (proxies, mocks)
// Token persistence hook:
onTokenChange: async (tokens) => {
if (tokens) await db.saveTokens(tokens);
else await db.clearTokens();
},
});
TaigaClientOptions
| オプション | 必須? | 型 | デフォルト | 説明 |
|---|---|---|---|---|
baseUrl | ✅ はい | string | — | Taiga インスタンスのルート URL(/api/v1 を含めません)。Taiga Cloud の場合:https://api.taiga.io。 |
token | いいえ | string | null | null | ベアラートークンです。既存のセッションを復元するには、これを渡します。 |
refreshToken | いいえ | string | null | null | 対応するリフレッシュトークンです。 |
applicationToken | いいえ | string | null | null | 静的なアプリケーショントークンです(ベアラーとは相互排他です)。 |
autoRefresh | いいえ | boolean | true | 401 時にベアラートークンを自動的に更新します。 |
timeoutMs | いいえ | number | 30000 | リクエストごとのタイムアウト(ミリ秒)です。 |
userAgent | いいえ | string | — | User-Agent ヘッダーです。 |
acceptLanguage | いいえ | string | — | Accept-Language ヘッダーです(レスポンス文字列の i18n)。 |
apiPrefix | いいえ | string | /api/v1 | API パスのプレフィックスです。標準以外のセルフホスト環境の場合のみ変更してください。 |
fetch | いいえ | typeof fetch | global | カスタムの fetch 実装です(プロキシ、モック、MSW)。 |
onTokenChange | いいえ | (tokens | null) => void | Promise | — | login の後、および自動更新の成功後に呼び出されるコールバックです。トークンの永続化に使用します。 |
認証
次の 3 つのモードがサポートされています。
| モード | 使用する場面 | ヘッダー |
|---|---|---|
| ベアラー+リフレッシュ | 標準的な対話型ログイン | Authorization: Bearer X |
| セッションの復元 | プロセスの再起動時 — 保存済みトークンをコンストラクターに渡します | Authorization: Bearer X |
| アプリケーショントークン | インテグレーション/ボット、長期間有効な静的トークン | Authorization: Application X |
トークンの自動更新
autoRefresh: true(デフォルト)の場合、クライアントは 401 レスポンスを透過的にインターセプトし、POST /auth/refresh を呼び出して、元のリクエストを 1 回だけ再試行します。同時に発生した 401 は重複排除されます。10 件のリクエストが同時に失敗しても、/auth/refresh は 1 回だけ呼び出されます。リフレッシュ自体が失敗すると、トークンがクリアされ、TaigaAuthError がスローされます。
プロセスの再起動をまたいだトークンの永続化
const client = new TaigaClient({
baseUrl: "https://api.taiga.io",
token: await db.loadToken(),
refreshToken: await db.loadRefreshToken(),
onTokenChange: async (tokens) => {
if (tokens) await db.saveTokens(tokens);
else await db.clearTokens();
},
});
onTokenChange は次のタイミングで呼び出されます。
client.auth.login(...)の後 — 新しいトークンペアが渡されます。- 自動更新の成功後 — 新しいペアが渡されます。
client.auth.logout()の後 —nullが渡されます。
返された Promise はリクエストの再試行前に待機されるため、次のリクエストが送信される前にトークンの永続化が確実に完了します。
リソースとメソッド
すべてのリソースは BaseResource を継承し、標準的な CRUD を提供します。各リソースはさらに独自のメソッドを追加します。
BaseResource<T> — 共通の CRUD
| メソッド | HTTP | 戻り値 | 説明 |
|---|---|---|---|
list(params?) | GET /resource | T[] | 最初のページ(または disablePagination が有効な場合はレスポンス全体)。 |
paginate(params?) | GET /resource?page=N | AsyncIterable<T> | x-pagination-next リンクをたどる遅延評価の非同期イテレーター。 |
listPage(params?, page?) | GET /resource?page=N | { data, pagination } | 指定したページとページネーションのメタデータ。 |
get(id) | GET /resource/:id | T | ID で指定した単一のリソース。 |
create(payload) | POST /resource | T | 作成します。 |
update(id, payload) | PUT /resource/:id | T | 全体を置き換えます。必須フィールドをすべて指定する必要があります。 |
patch(id, payload, version?) | PATCH /resource/:id | T | 部分更新します。version を指定すると、楽観的同時実行制御が有効になります。 |
delete(id) | DELETE /resource/:id | void | 削除します。 |
client.auth — 認証
| メソッド | 戻り値 | 説明 |
|---|---|---|
login({ username, password }) | Promise<AuthResponse> | POST /auth。username にはユーザー名とメールアドレスの両方を指定できます。 |
refresh() | Promise<string> | 手動で更新します。通常は 401 の発生時に自動的に呼び出されます。 |
logout() | Promise<void> | トークンをローカルで消去し、onTokenChange(null) を呼び出します。 |
setTokens(tokens | null) | Promise<void> | トークンを手動で設定します(例:データベースから復元した後)。 |
getTokens() | AuthTokens | null | メモリ上にある現在のトークン。 |
getCurrentUser() | AuthUser | null | 最後に成功した login() で取得したユーザープロフィール。 |
onTokenChange(handler) | void | 実行時に永続化コールバックを置き換えます。 |
const auth = await client.auth.login({ username: "u", password: "p" });
console.log(auth.auth_token, auth.refresh, auth.full_name);
client.users — ユーザー
基本 CRUD に加えて、次の機能があります。
| メソッド | HTTP | 説明 |
|---|---|---|
me() | GET /users/me | 現在認証されているユーザー。 |
updateMe(payload) | PUT /users/:id (own id) | update(me.id, …) を簡単に呼び出すためのメソッド。 |
changePassword(currentPassword, newPassword) | POST /users/change_password | パスワードを変更します。 |
stats(id) | GET /users/:id/stats | ユーザーの統計情報。 |
⚠️
users.create()は意図的に例外をスローします。登録には専用のエンドポイントを使用します(v0.1 の対象外)。
const me = await client.users.me();
await client.users.updateMe({ bio: "TypeScript fan", lang: "en" });
await client.users.changePassword("oldPwd!", "newPwd!");
client.projects — プロジェクト
基本的なCRUDに加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
getBySlug(slug) | GET /projects/by_slug?slug=... | idの代わりにスラッグでプロジェクトを取得します。 |
stats(id) | GET /projects/:id/stats | プロジェクトの統計情報(ポイント、マイルストーン)。 |
modulesConfig(id) | GET /projects/:id/modules | インテグレーション設定(GitHub、GitLab、Bitbucket、Gogs)。 |
setModulesConfig(id, config) | PATCH /projects/:id/modules | インテグレーション設定を更新します。 |
const proj = await client.projects.create({ name: "Demo", description: "" });
const sameProj = await client.projects.getBySlug(proj.slug);
const updated = await client.projects.patch(proj.id, { description: "Updated" }, /* version */ 1);
const stats = await client.projects.stats(proj.id);
await client.projects.delete(proj.id);
client.memberships — プロジェクトのメンバーシップ
基本的なCRUDに加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
bulkCreate(payload) | POST /memberships/bulk_create | 1回の呼び出しで複数のユーザーを招待します。 |
resendInvitation(id) | POST /memberships/:id/resend_invitation | 招待メールを再送します。 |
await client.memberships.bulkCreate({
project_id: proj.id,
bulk_memberships: [
{ role_id: 1, username: "[email protected]" },
{ role_id: 2, username: "[email protected]" },
],
invitation_extra_text: "Welcome to the team",
});
client.userStories — ユーザーストーリー
基本的なCRUDに加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
bulkCreate(payload) | POST /userstories/bulk_create | 改行区切りの文字列から複数のストーリーを作成します。 |
bulkUpdateBacklogOrder(payload) | POST /userstories/bulk_update_backlog_order | バックログ内のストーリーの順序を変更します。 |
bulkUpdateKanbanOrder(payload) | POST /userstories/bulk_update_kanban_order | カンバンボード上のストーリーの順序を変更します。 |
bulkUpdateSprintOrder(payload) | POST /userstories/bulk_update_sprint_order | スプリント内のストーリーの順序を変更します。 |
filtersData({ project }) | GET /userstories/filters_data?project=... | UIで利用可能なフィルター:ステータス、タグ、担当者。 |
const story = await client.userStories.create({
project: proj.id,
subject: "User can log in via GitHub",
description: "OAuth flow",
});
// Bulk create from a multi-line string (the way the Taiga UI does it):
await client.userStories.bulkCreate({
project_id: proj.id,
bulk_stories: "Story 1\nStory 2\nStory 3",
});
// Iterate over every story in the project:
for await (const s of client.userStories.paginate({ project: proj.id })) {
console.log(s.subject);
}
client.tasks — タスク
基本的なCRUDに加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
bulkCreate(payload) | POST /tasks/bulk_create | 複数のタスクを一度に作成します。 |
filtersData({ project }) | GET /tasks/filters_data?project=... | 利用可能なフィルター。 |
const task = await client.tasks.create({
project: proj.id,
subject: "Implement OAuth callback",
user_story: story.id, // link to a user story
});
client.issues — 課題
基本的な CRUD に加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
filtersData({ project }) | GET /issues/filters_data?project=... | 利用可能なフィルター(タイプ、重大度、優先度)。 |
voters(id) | GET /issues/:id/voters | 課題に賛成票を投じたユーザー。 |
upvote(id) | POST /issues/:id/upvote | 課題に賛成票を投じます。 |
downvote(id) | POST /issues/:id/downvote | 自分の賛成票を取り消します。 |
watchers(id) | GET /issues/:id/watchers | 課題をウォッチしているユーザー。 |
watch(id) | POST /issues/:id/watch | 通知を購読します。 |
unwatch(id) | POST /issues/:id/unwatch | 購読を解除します。 |
const issue = await client.issues.create({
project: proj.id,
subject: "Login button doesn't work in Safari",
description: "Reproduces on macOS Safari 17.x",
});
await client.issues.upvote(issue.id);
await client.issues.watch(issue.id);
client.epics — エピック
基本的な CRUD に加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
bulkCreate(payload) | POST /epics/bulk_create | 改行区切りの文字列から複数のエピックを作成します。 |
filtersData({ project }) | GET /epics/filters_data?project=... | UI で利用可能なフィルター。 |
relatedUserStories(id) | GET /epics/:id/related_userstories | エピックに関連付けられたユーザーストーリー。 |
addRelatedUserStory(id, { user_story }) | POST /epics/:id/related_userstories | 既存のユーザーストーリーをエピックに関連付けます。 |
removeRelatedUserStory(id, usId) | DELETE /epics/:id/related_userstories/:usId | ユーザーストーリーとエピックの関連付けを解除します。 |
voters(id) | GET /epics/:id/voters | エピックに賛成票を投じたユーザー。 |
upvote(id) | POST /epics/:id/upvote | エピックに賛成票を投じます。 |
downvote(id) | POST /epics/:id/downvote | 自分の賛成票を取り消します。 |
watchers(id) | GET /epics/:id/watchers | エピックをウォッチしているユーザー。 |
watch(id) | POST /epics/:id/watch | 通知を購読します。 |
unwatch(id) | POST /epics/:id/unwatch | 購読を解除します。 |
const epic = await client.epics.create({
project: proj.id,
subject: "Q1 roadmap",
color: "#ff8800",
});
await client.epics.addRelatedUserStory(epic.id, { user_story: story.id });
for (const link of await client.epics.relatedUserStories(epic.id)) {
console.log(link.user_story);
}
ℹ️ これらのエンドポイントを使用するには、プロジェクトでエピックを有効にする必要があります(
is_epics_activated: true)。
client.milestones — スプリント
基本的な CRUD に加えて:
| メソッド | HTTP | 説明 |
|---|---|---|
stats(id) | GET /milestones/:id/stats | バーンダウンデータとポイント単位の完了進捗。 |
const sprint = await client.milestones.create({
project: proj.id,
name: "Sprint 1",
estimated_start: "2026-01-01",
estimated_finish: "2026-01-14",
});
const burndown = await client.milestones.stats(sprint.id);
ページネーション
list() は常にレスポンスの最初のページを返します。全データを取得するには、次の 3 つの方法があります。
// 1. Async iterator (recommended): lazy, walks the next links.
for await (const story of client.userStories.paginate({ project: 42 })) {
await processStory(story);
}
// 2. A specific page plus metadata.
const page = await client.userStories.listPage({ project: 42 }, 3);
console.log(page.data, page.pagination); // { count, perPage, current, next, prev }
// 3. Disable pagination entirely (returns the full set as one array).
const all = await client.http.get("/userstories", {
query: { project: 42 },
disablePagination: true,
});
⚠️
disablePaginationはx-disable-pagination: Trueヘッダーを送信します。小規模なコレクションでのみ使用してください。大規模なコレクションの場合、Taiga がエラーを返すか、タイムアウトする可能性があります。
エラー
すべてのエラーは抽象クラス TaigaError を継承します。
| クラス | 発生する状況 | 役立つフィールド |
|---|---|---|
TaigaApiError | 4xx/5xx の失敗 | status、code、detail、body |
TaigaAuthError | 401 / 403 | TaigaApiError のすべてのフィールドに加えて |
TaigaRateLimitError | 429 | retryAfter(Retry-After から解析された秒数) |
TaigaNetworkError | ネットワーク障害、中断、タイムアウト | cause(基となる fetch / AbortError) |
import {
TaigaApiError,
TaigaAuthError,
TaigaRateLimitError,
TaigaNetworkError,
} from "taiga-api-client";
try {
await client.projects.get(99999);
} catch (err) {
if (err instanceof TaigaRateLimitError) {
await sleep((err.retryAfter ?? 1) * 1000);
} else if (err instanceof TaigaAuthError) {
// Session is dead — log in again
} else if (err instanceof TaigaApiError) {
console.error(`Taiga ${err.status}: ${err.detail ?? err.message}`);
} else if (err instanceof TaigaNetworkError) {
// Network / timeout
}
}
楽観的同時実行制御(OCC)
Taiga は version フィールドを使って、複数ユーザーによる同時更新で変更が失われるのを防ぎます。patch() を呼び出す際は、オブジェクトとともに受け取ったバージョンを渡してください。先に誰かが更新していた場合、Taiga は 400 / 412 を返し、競合が発生したことがわかります。
const story = await client.userStories.get(42);
const updated = await client.userStories.patch(
story.id,
{ subject: "Renamed" },
story.version, // ← OCC
);
低レベルアクセス
まだリソースとしてラップされていないエンドポイントには、client.http を直接使用してください。
const result = await client.http.get<{ id: number }[]>("/wiki", {
query: { project: 1 },
});
console.log(result.data, result.pagination, result.headers);
利用可能なメソッドは get、post、put、patch、delete です。すべて同じ RequestOptions を受け取ります:{ query, body, headers, signal, disablePagination, skipAuth }。
対応範囲
実装済み:
- 認証:ログイン、更新、ログアウト、アプリケーショントークン、セッション復元、重複排除による自動更新
- ユーザー:プロフィール、一覧、更新、パスワード変更、統計
- プロジェクト:CRUD、by_slug、統計、モジュール設定
- メンバーシップ:CRUD、bulk_create、招待の再送信
- ユーザーストーリー:CRUD、bulk_create、すべてのボードでの bulk_update_order、filters_data
- タスク:CRUD、bulk_create、filters_data
- イシュー:CRUD、filters_data、投票者、ウォッチャー、賛成票/反対票、ウォッチ/ウォッチ解除
- マイルストーン:CRUD、統計
- エピック (v0.2 で新規追加):CRUD、bulk_create、filters_data、関連するユーザーストーリー(一覧/追加/削除)、投票者、ウォッチャー、賛成票/反対票、ウォッチ/ウォッチ解除
未実装(今後のリリースで対応予定): wiki、webhooks、添付ファイル、カスタム属性、履歴/コメント、インポーター(Trello/Jira/GitHub)、プロジェクトテンプレート、GitHub OAuth フロー。
必要なエンドポイントが対応範囲に含まれていない場合は、client.http にフォールバックするか、イシューを作成してください。
互換性
| ランタイム | 最小バージョン | 備考 |
|---|---|---|
| Node.js | 18 | グローバルの fetch は Node 18 で導入されました。 |
| Bun | 1.0 | 完全にサポートされています。 |
| Deno | 1.x | 動作するはずです(グローバルの fetch を利用できます)。 |
| ブラウザー | 最新のモダンブラウザー | Taiga 側で CORS の設定が必要です。 |
ライセンス
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。