BlueAI株式会社BlueAI
カリキュラム/第8章: MCP 連携/8-3 Claude Code MCP で GitHub・DB・Slack をつなぐ

8-3 Claude Code MCP で GitHub・DB・Slack をつなぐ

無料

GitHub・PostgreSQL・Slack・Brave Search・Cloudflare を中心に、開発フロー直結の MCP 連携を実装パターンで体系化。自作 MCP サーバーの最小例と失敗パターンも収録した実践レッスン。

8章: MCP 連携60分
酒井歩乃加
監修: 酒井歩乃加

フリーランス編集者・ライター / 元マイベスト編集ディレクター

平原尚樹
監修: 平原尚樹

株式会社BlueAI 代表取締役CEO / ソフトウェアエンジニア

このレッスンで身につくこと

8-1 で MCP の地図、8-2 で 知識ベース系(Notion / Drive)を扱いました。このレッスンは 開発フローそのものを MCP で繋ぎ替える フェーズ。普段ターミナル・ブラウザ・Slack を往復している作業を、Claude Code から一発で終わらせます。

ポイント

このレッスンのゴール

  • MCP サーバー トップ 5(GitHub / PostgreSQL / Slack / Brave Search / Cloudflare)の使い分け
  • GitHub MCP で PR を自動作成する 1 プロンプトを自分のリポジトリで再現
  • PostgreSQL MCP読み取り専用ユーザー で安全に接続
  • Slack MCP でチャンネル限定の通知ボットを最小権限で運用
  • 自作 MCP サーバー の最小例(TypeScript SDK)を読み解く
  • 失敗パターン 3 種(権限過剰 / レート制限 / API キー露出)の予測と回避

所要時間 — 約 60 分 / 難易度 — ★★★★☆ / 前提 — 8-1 / 8-2 完了


なぜ「開発フローの MCP 化」が効くのか

Notion / Drive の MCP 化は 貼り替え作業 を消すのが本質でした。一方、GitHub / DB / Slack の MCP 化は 判断と実行のあいだに挟まる雑作業 を消します。「Issue を見て、関連 PR を読んで、ステージング DB のレコード数を確認して、結果を Slack に書け」が 1 プロンプトに圧縮されるのが要点です。

気づき

MCP の真の価値は、ツールを増やすことではなく アプリ切替の摩擦を消す ことにあります。アプリ切替は 1 回 20 秒・1 日 200 回。これが消えるだけで集中の深さが物理的に違ってきます。


連携対象トップ 5

サーバー主な用途おすすめ度
GitHubIssue / PR / Actions★★★★★
PostgreSQLDB スキーマ / 読み取り SQL★★★★★
Slack通知 / 監視 / 検索★★★★☆
Brave SearchWeb 検索の組み込み★★★☆☆
CloudflareWorkers / KV / R2 / D1★★★★☆

5 つ全部を一気に入れるのは アンチパターン。情報過多で Claude の判断が鈍り、応答速度も落ちます。コードを書く人は GitHub から / データを見る人は PostgreSQL から の順に、1 つずつ深く 入れていくのが安全です。


実例 1 — GitHub MCP で PR を自動作成

Step 1 — PAT を最小権限で発行

GitHub の Settings → Developer settings → Personal access tokens で発行。スコープは ==reporead:org だけ に絞ります。delete_repo は絶対に付けないFine-grained PAT ならリポジトリと操作を絞れて、社用ではこちらが推奨。Expiration は 90 日==、カレンダーにローテーション予定を入れておきます。

Step 2 — .mcp.json への登録

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}" }
    }
  },
  "permissions": {
    "allow": ["mcp__github__list_issues", "mcp__github__get_issue", "mcp__github__search_code"],
    "ask":   ["mcp__github__create_pull_request", "mcp__github__merge_pull_request"],
    "deny":  ["mcp__github__delete_repository"]
  }
}

「読み取りは自由 / 書き込みは確認 / 削除は禁止」 の 3 段構え。${GITHUB_TOKEN}環境変数 で渡し、ファイルには平文を残しません。

Step 3 — PR を作るプロンプト

> 今のローカル変更(git status で見える分)から PR を作って。
> ・ブランチ名: feat/lesson-8-3
> ・ベース: main
> ・タイトル: feat(claudecode): expand lesson 8-3
> ・本文: 変更内容と背景を箇条書き
> ・レビュアー: @teammate

Claude は内部で Bash で git 操作(status / diff / branch / commit / push)→ ==mcp__github__create_pull_request で PR 作成 → mcp__github__request_pull_request_reviewers== でレビュアー指定 → PR URL を返す、という流れを自分で組み立てます。書き込み系の各ステップで (y/n) 確認が挟まるので、最初は 1 個 1 個読みましょう。

ポイント

コミットメッセージ規約は CLAUDE.md に書く のが正解。「Conventional Commits 形式」とだけ書いておけば、Claude はそれに従います。MCP の挙動より手前の CLAUDE.md が効くケースは意外と多い。


実例 2 — PostgreSQL MCP でデータ参照

なぜ DB MCP が効くのか

スキーマを知らない Claude はテーブル名・カラム名を 推測 でしか書けません。DB MCP を入れると、==mcp__postgres__schema でリアルタイムにスキーマを取得 → 正確なカラム名で SQL を組み立て → mcp__postgres__query で結果を返します。カラム名取り違え事故が体感 1/10 以下== に減ります。

Step 1 — 読み取り専用ユーザーを作る

CREATE USER claude_readonly WITH PASSWORD 'changeme';
GRANT CONNECT ON DATABASE app TO claude_readonly;
GRANT USAGE ON SCHEMA public TO claude_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO claude_readonly;

PII カラムを除外 したい場合は、ビューを切ってそこにだけ SELECT を許可します。users 本体ではなく users_safe ビュー(メール・電話を除外)を読ませる発想です。

Step 2 — .mcp.json への登録

{
  "mcpServers": {
    "db": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-postgres",
        "postgresql://claude_readonly:${DB_PASSWORD}@localhost:5432/app"
      ]
    }
  }
}

Step 3 — 使い方

最初の 1 回は スキーマ把握 のクエリを叩いておくと、以降の対話で Claude が正しい構造をコンテキストに保持します。

> このプロジェクトの主要テーブル 5 つ、カラム・型・外部キーを表でまとめて。
> 続けて、users テーブルから過去 7 日の新規登録を日別・プラン別で集計して。

書き込み系の扱い

答えは「読み取り MCP のまま、別経路で書く」。Claude に SQL を 生成 させて、人間が 別クライアントで実行 するか、マイグレーションファイルとして書き出させる

> users テーブルの `plan` を 'free' から 'starter' に rename する
> マイグレーション SQL を作って migrations/20260519_rename_plan.sql に保存して。

Claude が SQL を書き、人間が実行のタイミングを握る。破壊的変更を AI に任せない最後の砦が残ります。


実例 3 — Slack MCP で通知

Step 1 — Bot 用 Slack App を作成

https://api.slack.com/apps で Create New App → From scratch。Bot Token Scopes は最小権限。

  • ==chat:write== — 投稿
  • ==channels:history== — public 履歴読み取り
  • ==channels:read== — チャンネル一覧

==files:write / im:write は付けない==。Install to Workspace → Bot Token(xoxb-...)をコピー。

Step 2 — .mcp.json への登録

{
  "mcpServers": {
    "slack": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-slack"],
      "env": {
        "SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
        "SLACK_TEAM_ID": "T0XXXXXXX"
      }
    }
  },
  "permissions": {
    "allow": ["mcp__slack__list_channels", "mcp__slack__get_channel_history"],
    "ask":   ["mcp__slack__post_message", "mcp__slack__reply_to_thread"]
  }
}

Step 3 — Bot をチャンネルに招待

9 割の人が踏むワナ。Bot を作っただけでは投稿できません。投稿したいチャンネルで /invite @claude-bot を実行して招待します。

使い方

> #engineering の過去 24 時間のメッセージを要約。
> 質問が未回答のままになっているものを別枠で挙げて。

「収集系」と「投稿系」を別 Bot に分ける のが上級者の運用。1 つは read-only 監視 Bot、もう 1 つは投稿用 Bot で漏洩リスクを分離。


自作 MCP サーバー の最小例(TypeScript SDK)

公式 MCP が対応していない 社内ツール は、自作 MCP で Claude に喋らせます。最小例は 50 行 で動きます。

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const server = new Server(
  { name: "internal-time-mcp", version: "0.1.0" },
  { capabilities: { tools: {} } },
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [{
    name: "now",
    description: "Return the current time in ISO 8601",
    inputSchema: {
      type: "object",
      properties: { timezone: { type: "string", default: "Asia/Tokyo" } },
    },
  }],
}));

server.setRequestHandler(CallToolRequestSchema, async (req) => {
  const tz = (req.params.arguments?.timezone as string) ?? "Asia/Tokyo";
  const value = new Date().toLocaleString("ja-JP", { timeZone: tz });
  return { content: [{ type: "text", text: value }] };
});

await server.connect(new StdioServerTransport());

.mcp.json への登録は "command": "node" / "args": ["/path/to/server.ts"]。==bun / tsx でも動きます。Claude Code 自身にひな形を書かせる== のが一番速い手段です。

> 社内の在庫管理 API(OpenAPI: ./openapi.yaml)に接続する MCP サーバーを
> TypeScript SDK で書いて。Tools は list_inventory / get_item / search_items。
> 認証は API_KEY 環境変数で渡す。

社内パッケージ化 すれば npx -y @your-org/internal-mcp で全社員がすぐ使えます。


失敗パターン — 現場で踏む 3 大事故

失敗 1 — 権限過剰(最多)

症状 — 意図しない範囲まで触れる。「PR を作ってと言っただけなのにブランチが消えた」。根本原因認可元に広すぎる権限 を与えていること。対処permissionsdeny ではなく 認可元 を絞ること。GitHub は Fine-grained PAT で リポジトリ単位 / 操作単位、PostgreSQL は 読み取り専用ユーザー、Slack は Bot Token Scopes を最小、Cloudflare は API Token で対象リソースを絞る。==permissions は最後の砦、本物の防御は認可元==。

失敗 2 — レート制限

症状 — 突然の 429 Too Many Requests

サーバー制限
GitHub API5,000 req/h(PAT)/ Search は 30 req/min
Slack APITier 3 で 50 req/min
Brave Search無料枠 1 req/s / 2,000 req/月
Cloudflare KV1,000 req/s(namespace 単位)

対処プロンプトで指示。「100 件処理してほしいけど 1 秒に 1 件ずつ」と書くと Claude は素直に従います。それでも頻発するなら、書き込み系を ==ask permission== に降ろすと、人間が「次へ」を押すタイミングで間隔が空きます。

失敗 3 — API キー露出

露出パターン は ==.mcp.json 平文コミット / .envrc.gitignore 漏れ / ログへの印字 / プロンプト本文への混入 / スクショ流出== の 5 つ。

事故ったときの正しい対応 は次の通り。まず Revoke(管理画面で 30 秒)→ 新しい鍵を Expiration 付き で発行 → 履歴削除は ==git filter-repo== → 再発防止に pre-commit hook で ghp_ / xoxb- の検出を入れる。

Bad

悪手 — 気づかれないことを願って放置 / パスワード使い回し / .gitignore だけ追加して push(履歴に残っているので無効)

Good

鉄則${VAR_NAME} で外部参照、ファイルに鍵を書かない / Expiration を必ず設定 / .envrc.gitignore


プロンプトテンプレート 3 つ

テンプレ 1 — Issue ベースの実装着手

> リポジトリ {owner/repo} の Issue #{番号} を実装する。
> 1. Issue を読んで要件を箇条書きで整理
> 2. 実装方針を 3 行で提示(同意なら「進んで」と返す)
> 3. ブランチ feat/issue-{番号} を切って実装
> 4. テストを通す
> 5. PR 作成(Closes #{番号} を含める)、レビュアー @{user}

Step 2 で一度止まる ように指示するのがコツ。間違った方向に走り出すのを止められます。

テンプレ 2 — DB → Slack 通知

> 1. db MCP で「今週の {テーブル名}」の指標を集計
>    - 新規レコード数(日別 + 合計)
>    - {主要カラム} 別の内訳(上位 5)、前週比
> 2. 結果を Markdown レポートに整形
> 3. slack MCP で #{channel} に投稿

週次の人手作業がそのまま消えます。

テンプレ 3 — 自作 MCP を生やす

> {サービス名} の REST API(OpenAPI: {URL})に接続する MCP を
> TypeScript SDK で。Tool は list / get / create の {N} 個。
> 認証は {SERVICE}_API_KEY、各 Tool に description と inputSchema を。
> README も付けて、最小動作確認の手順まで書いて。

社内 API を MCP 化する第一歩。30 分後には動くベースが出てきます。


まとめ

  1. 開発フロー系 MCP の本質は アプリ切替の摩擦を消す こと
  2. 連携対象は GitHub / PostgreSQL / Slack / Brave Search / Cloudflare1 つずつ深く
  3. GitHub MCP — PAT は最小スコープ、書き込みは askdelete_repo 禁止
  4. PostgreSQL MCP — 読み取り専用ユーザー、機微カラムはビューで隠す、書き込みは SQL ファイル経由
  5. Slack MCP — Bot Token Scopes 最小、招待を忘れない、収集系と投稿系を別 Bot に
  6. 自作 MCP は TypeScript SDK で 50 行 から。Claude にひな形を書かせるのが最速
  7. 失敗の 9 割は 権限過剰 / レート制限 / API キー露出permissions は最後の砦、本物の防御は認可元
気づき

外部ツール接続は、設定ではなく「設計」。何を読ませ、何を書かせ、どこを人間が握るか — この設計が、3 年後も事故らない MCP 運用の正体です。

章末演習

章末演習 — 所要時間 45〜60 分。

  1. GitHub PAT を Fine-grained で発行 — 検証用リポジトリだけにアクセスを限定
  2. ==/mcp✓ github== — permissionsallow / ask / deny に分類
  3. Issue → PR — 「Issue #X を実装して PR」を 1 プロンプトで完走
  4. 読み取り専用 DB ユーザー — 機微カラムを除外したビューを 1 つ作る
  5. Slack Bot 通知 1 件chat:write だけで投稿、招待 → 投稿ログ確認
  6. 自作 MCP 最小例now ツールだけの MCP を 30 分で完走
  7. 事故対応シミュレーション — PAT を一度 revoke → 再発行 → .envrc 更新を通しでやる

<Quiz question="GitHub MCP を .mcp.json に登録する際、最も推奨される運用はどれですか?" options={["Fine-grained PAT を最小スコープで発行し、書き込み系を ask permission にする","classic PAT で repo / delete_repo / admin:org を含む全スコープを付けておく","PAT を .mcp.json に平文で書いてチームに共有する"]} answer={0} />

<Quiz question="PostgreSQL MCP で本番 DB を扱うときの最も安全なアプローチは?" options={["読み取り専用ユーザーを作って機微カラムはビューで隠し、書き込みはマイグレーションファイル経由で人間が実行する","管理者ユーザーで接続し、すべての SQL を Claude に自由に実行させる","本番 DB の admin パスワードを .mcp.json に直書きしてチームで共有する"]} answer={0} />

<Quiz question="MCP の API キーを誤って公開リポジトリに push してしまったときの正しい第一歩は?" options={["管理画面で対象トークンを即時 Revoke する",".gitignore に追加してから push する","気づかれていないことを願って放置する"]} answer={0} />


次のレッスン 9-1: API コストの仕組み では、第 9 章「コスト管理」に入ります。MCP を入れるほどトークン消費が増える側面もあるので、/cost/compact の節約術を体系化していきます。