1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI駆動開発で個人開発ツールを作ってみた〜Claude Code × Spec-Kit × MCP実践記〜

1
Posted at

この記事について

個人開発で「リモートチーム協業プラットフォーム」というWebアプリを作っています。プロジェクト管理・チケット管理・チャット・バーチャルオフィス・会議室・通知・検索・ファイル添付を1つにまとめた、社内向け協業ツールです。

  • PHP 8.3 + Laravel 13 + MySQL 8.0 + Blade(SPAフレームワークは使わないMPA構成)
  • Laravel Reverb(WebSocket)でオンライン状態・チャット・通知をリアルタイム反映
  • WebRTCによるバーチャルオフィス・会議室の音声/映像

設計から実装まで、要所要所でClaude Codeを開発フローに組み込んで進めています。この記事では、Spec-Kitによる設計プロセスMCPサーバーの自作を中心に、実際にどう使っているかをまとめます。

規模感としては、機能追加のたびにspecを1本切る運用をしていて、現時点で26機能分のspecが溜まっています。コントローラーは53本、Bladeビューは67枚です。

対象読者:

  • Claude CodeやAIエージェントを使った開発フローに興味がある人
  • Spec-Kitを試してみたいが実際の運用イメージが湧かない人
  • MCPサーバーを自作する具体例を知りたい人

1. 開発フロー全体像

大まかな役割分担はこうなっています。

フェーズ 主体 使うツール
要件定義・仕様策定 人間 + Claude Code Spec-Kit(speckit-specify)
設計(技術選定・データモデル) 人間 + Claude Code Spec-Kit(speckit-plan)
タスク分解 Claude Code Spec-Kit(speckit-tasks)
実装 Claude Code(人間はレビューと方針判断) speckit-implement、通常のClaude Codeセッション
テスト Claude Code(実行はDocker経由) PHPUnit(php artisan test)

スクリーンショット 2026-09-06 141001.png

ポイントは、「何を作るか」を曖昧なまま実装に入らないことです。Spec-Kitを使い始める前は、思いついた機能をそのままClaude Codeに指示して実装してもらうことが多かったのですが、要件の揺れがそのままコードの手戻りに直結していました。今は機能追加のたびにspecs/NNN-feature-name/ディレクトリが1つ増える運用に統一しています。

2. Spec-Kitでの設計プロセス

Spec-Kitは「仕様→計画→タスク→実装」を段階的に固めていくワークフローです。実際に021番(マルチテナント機能)を例に、流れを見てみます。

2-1. speckit-specify:仕様の言語化

まず自然言語で機能概要を渡すと、User Story単位で仕様書(spec.md)が生成されます。実際の021番の冒頭はこうなっています。

# Feature Specification: マルチテナント機能(組織単位のデータ分離)

**Feature Branch**: `021-multi-tenant-organizations`
**Status**: Draft

## User Scenarios & Testing

### User Story 1 - 組織をまたいだデータが一切見えないことを保証する (Priority: P1) 🎯 MVP

複数の組織(会社)が同じシステムを共有していても、あるユーザーが所属していない組織の
プロジェクト・チケット・チャット・ファイル・メンバー一覧・検索結果に一切アクセスできない。

**Why this priority**: マルチテナント機能の存在意義そのものであり、これが破られると
機能全体が意味を成さない(セキュリティ上のNON-NEGOTIABLE要件)。

**Independent Test**: 2つの組織にそれぞれ所属するユーザーを用意し、一方のユーザーが
他方の組織のプロジェクトURL・チケットURL・検索キーワードでアクセスを試みて、
すべて拒否されるか結果に含まれないことを確認する。

「Priority」「Why this priority」「Independent Test」が各User Storyに必ずセットで付くのが特徴です。優先度付けの理由と、そのUser Storyが単体で検証可能な形になっているかを、仕様段階で強制的に言語化させられます。曖昧なまま次のフェーズに進めない設計になっているのが、Spec-Kitを使ってみて一番効果を感じた部分です。

2-2. speckit-plan:技術判断を固める

仕様が固まったら、技術スタックやデータモデルの判断をplan.mdに書き出します。ここで初めて「どう実装するか」が具体化されます。Constitution(後述)との整合性チェックもこの段階で行われます。

2-3. speckit-tasks:実装単位への分解

plan.mdをもとに、実装可能な粒度のタスクリスト(tasks.md)が生成されます。021番では44個のタスクに分解されました。タスクはUser Story単位でグルーピングされ、複数のUser Storyが共通して必要とする基盤部分(テーブル定義や認可基盤)は「Foundational」フェーズとして独立させる設計になっています。

3. Skill機能の実践活用

「Skill機能をカスタマイズした」と書きたいところですが、正直に書くと、.claude/skills/配下にあるのはGitHub公式のspec-kit標準スキル(speckit-specifyspeckit-planspeckit-tasksspeckit-implementspeckit-clarifyspeckit-analyzespeckit-checklistspeckit-constitutionなど)で、自作のSkillは今のところありません。

ただ、これらを素の状態で使い続けているわけではなく、実務でよく使うのは以下の組み合わせです。

  • speckit-specifyspeckit-clarify(仕様の曖昧点を対話形式で潰す) → speckit-planspeckit-tasksspeckit-implement
  • 機能追加後、既存のconstitution.md(後述)との矛盾がないかをspeckit-analyzeでチェック

公式Skillをフルセットで導入し、機能追加のたびに同じworkflowを型として繰り返す、という運用が今のところの実践内容です。将来的には自社の業務knowledge(Laravel特有の実装パターンなど)をSkill化する構想もありますが、現状はまだそこまで手が回っていません。

4. MCPサーバー自作:ReportServer

Spec-Kit以外に、このアプリ自体にMCPサーバーを2つ実装しています(TicketServerReportServer)。ここではReportServerを掘り下げます。

4-1. 設計思想:材料集めと文章化を分離する

ReportServerは週報・クライアント向けレポート・リスクダイジェスト・スプリントレトロ要約の4つのMCP Promptを提供します。

#[Name('Team Collab Platform - Reports')]
#[Instructions('プロジェクトの稼働・進捗・成果物・リスク・変更履歴・レトロボード・
課題/リスク台帳の内容を、レポート作成や記録のために取得・作成・更新する。
すべての操作は、このトークンを発行したユーザー本人が所属するプロジェクトの範囲に限定される。')]
class ReportServer extends Server
{
    protected array $tools = [
        ListProjectsTool::class,
        ListSprintsTool::class,
        GetTimeEntriesTool::class,
        GetDailyStandupHoursTool::class,
        GetSprintProgressTool::class,
        GetVelocityMetricsTool::class,
        GetCompletedTicketsTool::class,
        GetRiskTicketsTool::class,
        GetScopeChangesTool::class,
        GetHolidaysTool::class,
        // ...
    ];

    protected array $prompts = [
        ClientReportPrompt::class,
        WeeklyReportPrompt::class,
        RiskDigestPrompt::class,
        SprintRetroSummaryPrompt::class,
    ];
}

設計上こだわったのは、MCP Promptが「完成したレポート文章」を返さないことです。ClientReportPromptのコード冒頭にはこうコメントしています。

/**
 * 018-client-report-mcp US1, FR-011, FR-016, FR-017: 稼働・進捗・成果物・課題とリスク・
 * 今後の予定・変更管理の6区分を1つの標準フォーマットでまとめる。契約形態(準委任/請負)に
 * よる出し分けロジックは持たない汎用フォーマット1本(research.md、spec.md 対象範囲5)。
 * 金額計算(billing-summary)・KPI評価は一切含めない(FR-017)。
 */

ReportMaterialAssemblerというサービスクラスが、権限チェック済みの生データ(進捗・課題・リスクなど)を構造化して返すところまでを担当し、それを自然な文章のレポートに仕上げるのはMCPクライアント側(Claude)の役割、という分業にしています。

スクリーンショット 2026-09-06 141020.png

理由は2つあります。

  1. 認可の一貫性:既存のWeb画面と同じTicketPolicy/ProjectPolicyで認可するため、「このユーザーがどこまで見えるべきか」のロジックを1箇所に保てる
  2. 監査可能性:MCPサーバー側が返すのは検証可能な構造化データなので、「なぜこの数字が出たか」を後から追える。文章化(要約・言い回し)はLLM側の仕事として明確に切り離す

4-2. 4つのPromptの役割分担

Prompt 用途 入力
ClientReportPrompt クライアント向け標準レポート(稼働・進捗・成果物・課題とリスク・予定・変更管理) project, from, to
WeeklyReportPrompt 社内向け軽量週報(月〜日で期間固定) project, week
RiskDigestPrompt 期限超過・優先度High未着手・直近ブロッカーだけの抽出 project
SprintRetroSummaryPrompt レトロボード(付箋・アクションアイテム)の要約材料 sprint_id

同じReportMaterialAssemblerを呼び出しつつ、Promptごとに取得範囲を絞り込むことで、用途別に4つのエントリポイントを用意しています。Claude Code(または他のMCPクライアント)側からは、これらを叩くだけで「今週の進捗どう?」「このプロジェクトのリスクをまとめて」といった依頼にすぐ答えられる状態です。

5. 深掘りエピソード:マルチテナント化という大手術

個人開発を続けていて一番手応えがあったのが、021番(マルチテナント機能)の実装です。

5-1. なぜ大手術だったか

このアプリはもともと「1つの会社が使う」前提で設計していました。ユーザー・プロジェクト・チケット・チャットなど、すべてが単一の名前空間に存在します。それを「複数の組織(会社)が同じシステムを共有しても互いのデータが一切見えない」構成に拡張するのが021番です。

影響範囲は多岐に渡りました。

  • 組織(Organization)エンティティの新設
  • 既存の全ユーザー・全プロジェクトを、マイグレーションで自動的にデフォルト組織へ移行
  • オンライン状態・バーチャルオフィス・会議室・全社チャット・検索・ラベル・会社休日・ステータスプリセットなど、「全社」を対象にしていた機能をすべて組織単位に分離
  • 管理者権限を自組織内に限定(かつ組織を横断できる「プラットフォーム管理者」ロールを新設)

5-2. Constitutionの改定を伴った

このアプリでは.specify/memory/constitution.mdという、プロジェクトの憲法(不変の設計原則)を定義したファイルを運用しています。021番の実装は、この憲法のメジャーバージョンを上げる規模の変更でした。

Version change: 2.0.0 → 3.0.0
Modified principles:
  - I. プロジェクト境界とデータ分離 (NON-NEGOTIABLE)
    → I. 組織境界とプロジェクト境界のデータ分離 (NON-NEGOTIABLE)
    (マルチテナント化に伴い、組織〈企業〉境界を最上位のデータ境界として追加。
    プロジェクト境界はその内側の下位境界として維持)
  - IV. 権限モデルの明確化・承認フローなし (NON-NEGOTIABLE)
    → 同名、ロール種別を3種類から4種類へ拡張
    (組織を横断できる「プラットフォーム管理者」を、既存の管理者/リーダー/一般に追加)
Rationale: 「管理者はシステム全体の全ユーザー・全プロジェクトを管理できる」という
既存原則IVの前提、および「プロジェクト境界が最上位の境界である」という既存原則Iの
前提がともに後方互換性なく再定義されるため、MAJORバージョンとした。

スクリーンショット 2026-09-06 141037.png

「既存の前提が後方互換性なく壊れる変更かどうか」をバージョニングの基準にしている点が、このConstitutionの運用で気に入っている部分です。機能追加のたびにこのファイルを見返すことで、「今回の変更は本当に原則レベルの話か、それとも実装の詳細か」を都度立ち止まって考える癖がつきました。

5-3. タスクの構成

speckit-tasksによって44個のタスクに分解され、以下のような優先度構成になりました。

  • Foundational: organizationsテーブル、既存テーブルへのorganization_id付与、認可基盤(Gate::before)の修正 — 全User Storyが依存する土台
  • US1(P1・MVP): 組織をまたいだデータの不可視性の保証
  • US2(P1・MVP): 既存データの自動移行、既存ユーザーへの無影響
  • US3(P1): オンライン状態・バーチャルオフィス・全社チャット等、組織単位機能群の分離
  • US4・US5(P2): 管理者権限のスコープ限定、プラットフォーム管理者ロール

PolicyBoundaryTestMultiTenantOrganizationsTestといった専用のFeatureテストを用意し、「組織Aのユーザーが組織Bのデータに一切到達できない」ことを機械的に保証する形にしました(仕様書段階でIndependent Testとして明記していた内容が、そのままテストケースに落ちています)。

6. つまずいたポイント

Windows + Docker Desktop環境で開発しているため、環境起因のハマりどころがいくつもありました。実際に.claude/settings.jsonに残っている許可コマンド履歴から、実体験ベースで振り返ります。

  • パス変換問題: Git BashやMSYS環境だと、Dockerコマンドに渡すパスが勝手にWindows形式に変換されてしまうことがあり、MSYS_NO_PATHCONV=1を頭につけて回避するのが定型パターンになりました
  • PowerShellとBashの混在: Spec-Kitのスクリプト(check-prerequisites.ps1など)はPowerShell、Dockerコマンドの多くはBash(Git Bash)経由と、シェルが混在する場面が多く、pwsh -Filepowershell -Fileのどちらが通るか都度確認する必要がありました
  • php artisan tinkerでのデバッグ: MCPツールやマルチテナント境界の検証で、一時的な確認スクリプトを/tmpに置いてtinker経由で実行し、確認後に消す、というサイクルを繰り返しました
  • コンテナ再起動忘れ: opcache.validate_timestamps=0を設定している関係で、PHPファイルを編集してもdocker compose restart web(またはapache2ctl graceful)を忘れると変更が反映されず、「直したのに動かない」を何度か経験しました

7. まとめ

  • Spec-Kitの「Priority」「Why this priority」「Independent Test」を仕様段階で強制させる設計は、曖昧なまま実装に入ることを防ぐ効果が大きかった
  • Skill機能は今のところ公式spec-kit標準スキルの実践活用に留まっている。自社ドメイン知識のSkill化は今後の課題
  • MCPサーバーは「材料集め(認可統制込み)」と「文章化(LLM側)」を分離する設計にすることで、監査可能性を保ったままレポート生成のような曖昧なタスクをAIに任せられる
  • Constitutionのバージョニングによって、機能追加のたびに「これは原則レベルの変更か」を立ち止まって考える運用が定着した
  • 環境起因のハマりどころ(Windows Docker Desktop特有の問題)は、AI駆動開発がどれだけ進んでも変わらず人間が向き合う部分だった
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?