Skip to main content
Glama

ticket-writer MCP

MagOneAI 用の MCP サーバーです。レポーターがフィーチャーリクエストを自由テキストとして投入すると、ワークフローはそれを実行可能にするために必要な数個の質問をし、問題、やるべきこと、受け入れ基準、アーキテクチャ上の決定を記載したチケットを発行します。

Jira、GitHub、GitLab、Linear は同じコードパスから生成されます。

サーバーはトラッカーを呼び出しません。 作成依頼をレンダリングして返すだけです。送信はワークフロー自身の HTTP ノードが行います。


ワークフローの実行方法

free text  ──▶  check_request  ──"needs_clarification"──▶  ask the reporter ──┐
                     │                                                        │
                     │◀──────────────────── answers ─────────────────────────┘
                  "ready"
                     │
                     ▼
                render_ticket  ──"possible_duplicate"──▶  human confirms ──┐
                     │                                                     │
                     │◀────────── confirm_not_duplicate ───────────────────┘
              "ready_to_send"
                     │
                     ▼
          HTTP node: POST request.url  ◀── the only write in the workflow
                     │
                     ▼
              issue key + url back to the reporter

WORKFLOW.md にはノードごとの契約が記載されています。正確な入力・出力 JSON と、チケットに載るすべてのフィールドです。


Related MCP server: refine-backlog-mcp

なぜ Jira 自体に接続しないのか

最初のドラフトには Jira REST クライアントが含まれていました。そのバージョンでは、このマシンに認証情報が必要で、チケットは正常にレンダリングされるが POST が失敗するという障害モードが発生し、ワークフローが 1 つのトラッカーに固定されていました。

代わりにリクエストをレンダリングするということは、次のことを意味します。

  • ここに認証情報は不要 — ヘッダーには {{PLACEHOLDER}} 名が含まれ、API ノードが MagOne のシークレットストアから置き換えます

  • 任意のトラッカー — 新しいトラッカーは src/targets.py の dict エントリです

  • MagOne が既に持っているものを再利用 — トラッカー MCP が接続されている場合は、target="generic" を使用してフィールドをその作成ツールに渡します

  • 承認ステップが適合 — レンダリング呼び出しの後まで何も書き込まれません

  • pytest だけでテスト可能 — リポジトリ全体にネットワークはありません

チケットの散文も書きません。ワークフローエージェントは言語モデルであり、支離滅裂な Slack メッセージを問題文に変換するのは、このリポジトリのどのルーブリックよりも得意です。このサーバーが担当するのは、毎回同じように動作しなければならない部分、つまりチェックリスト、質問の文言、本文形式、重複ガードです。


ツール

ツール

目的

check_request

これで発行できるか? できない場合、何を尋ねるか。

render_ticket

1 つのトラッカー用にフォーマットされた作成依頼。

list_targets

トラッカー、設定キー、API ノードが必要とする認証情報。

duplicate_search_query

任意。重複チェック用の検索クエリを構築します。

4 つすべて読み取り専用です。すべてのレスポンスには、キャンバスが切り替える status が含まれます。

status

ワークフローアクション

ready

render_ticket に進む

needs_clarification

questions を尋ね、ループする

possible_duplicate

candidates を表示し、人間の回答を得る

ready_to_send

request を API ノードに渡す

error

hint を読む — 通常は config キーが欠落している


チケットが完了する条件

check_request は 4 つのフィールドでブロックします。この順序で、1 ラウンドあたり最大 3 つ尋ねます。

  1. problem — 現在何が問題か、誰が影響を受けるか

  2. goal — 完了時に何が存在すべきか、動作として

  3. acceptance_criteria — レビュー担当者が受け入れるか拒否するか

  4. architecture_notes — 下した決定、尊重すべき制約 ("none known" は設計がまだ未確定の場合に有効)

affected_users と out_of_scope は提供された場合に収集されますが、ブロックはしません。25 文字未満の回答、または質問をそのまま繰り返す回答は、回答としてカウントされません。

チェックリストを変更するには、src/ticket.py の SLOTS を編集します。質問、ランキング、上限はすべてそのリストに従います。


ターゲット

target

config

API ノードが提供する認証情報

jira

base_url, project_key

{{JIRA_BASIC_AUTH}} — base64 email:api_token

github

owner, repo

{{GITHUB_TOKEN}} — Issues 読み取り/書き込み権限を持つ PAT

gitlab

project_id, host?

{{GITLAB_TOKEN}} — api スコープのトークン

linear

team_id, project_id?

{{LINEAR_API_KEY}}

generic

—

なし — fields をそのトラッカーの独自 MCP に渡す

レンダラーが吸収する違い(エージェントが処理する必要はありません):

  • Jira は description にマークダウンではなく ADF を要求します。マークダウン文字列を渡すことは、手動で配線された Jira ノードが失敗する最も一般的な原因です。

  • GitLab はラベルを カンマ区切り文字列 として要求します。GitHub と Jira はリストを要求します。

  • GitHub には優先度フィールドがないため、優先度は priority-* ラベルになります。

  • Linear は GraphQL です。エンドポイントは 1 つで、ミューテーションはボディに含まれます。

トラッカーを追加するには: (url, headers, body) を返す build() を持つ TARGETS エントリを 1 つ追加します。それが変更のすべてです。


重複ガード

このサーバーは検索できないため、ワークフローが供給します。duplicate_search_query がクエリを構築し、検索ノードがそれを実行し、ヒットは existing_issues=[{key, summary, url}] として render_ticket に戻されます。トークン重複率 ≥ 0.6 のサマリーは possible_duplicate として返されます。

検索ノードがなくてもチェックは行われず、チケットはレンダリングされます。それが、トラッカーごとに検索クライアントを持たないこととのトレードオフです。


実行方法

python -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/python -m pytest -q          # 47 tests, no network, no account

Claude Desktop 用のローカル MCP(stdio 経由):

MCP_TRANSPORT=stdio .venv/bin/python -m src.server

デプロイ:

docker build -t ticket-writer .
docker run -p 8000:8000 -e TICKET_WRITER_TOKEN=$(openssl rand -hex 32) ticket-writer
curl localhost:8000/health

MagOneAI で https://your-host/mcp をヘッダー Authorization: Bearer $TICKET_WRITER_TOKEN とともに登録します。Outlook MCP とまったく同じように構成します。TICKET_WRITER_TOKEN はサーバーが要求する唯一の環境変数です。MCP_TRANSPORT、HOST、PORT、LOG_LEVEL には動作するデフォルトがあります。max_iterations は約 12 に設定します。


実際のチケットを発行して確認する

scripts/send.py は API ノードとまったく同じことを行います。レンダリングし、同じ名前の環境変数からプレースホルダーを置き換え、POST します。

.venv/bin/python scripts/send.py --target jira \
  --config base_url=https://you.atlassian.net project_key=KAN --dry   # payload only

export JIRA_BASIC_AUTH=$(printf '%s' 'you@mail.com:API_TOKEN' | base64)
.venv/bin/python scripts/send.py --target jira \
  --config base_url=https://you.atlassian.net project_key=KAN         # 201 + issue key

TESTING.md には、各スイートが証明する内容、Jira Cloud に対するライブ実行、エラーテーブルが記載されています。


セキュリティ

  • ベアラートークンは環境変数から取得し、ワークフローノードを経由しません。キャンバスを通過するトークンは実行ログに残ります。

  • トラッカーの認証情報がこのサーバーに到達することはありません。 ヘッダーはプレースホルダーです。config はシークレットではなく場所を受け取ります。テストがそれを検証します。

  • /health はプラットフォームのプローブ用に認証なしですが、それ以外はすべて認証が必要です。サーバーはトークンが設定されていない HTTP での起動を拒否します。

  • 非 root コンテナユーザー。

  • レポーターのテキストはデータであり、命令ではありません。 引用ブロックにそのまま保存され、解釈されることはありません。ツールの docstring にその旨が記載されています。なぜなら、それがエージェントが読むものだからです。

  • 重複ガードと完全性チェックは、おしゃべりな Slack チャンネルと何百ものジャンクチケットの間に立ちはだかるものです。両方をスキップするフラグを追加しないでください。


レイアウト

src/server.py    MCP surface: tool defs, transport, auth
src/ticket.py    pure: rubric, questions, body in markdown + ADF, dup scoring
src/targets.py   pure: what each tracker's API wants — one entry per tracker
tests/           47 tests: the rules, the tool surface, HTTP and auth
scripts/send.py  stands in for the API node, for end-to-end checks
WORKFLOW.md      node-by-node input/output contract
TESTING.md       what is covered, what is not

ticket.py はどのトラッカーについても知りません。targets.py は良いチケットの条件について知りません。必須フィールドを追加するために targets.py を編集する必要がある場合、分割が漏れています。

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers