MODEL CONTEXT PROTOCOL — PORTFOLIO

MCP Portfolio

自作 MCP サーバー 8本 — 設計と実装の記録
非エンジニアのビジネス職が
自分の業務の不便を
自分で MCP サーバーを書いて解いた記録
8
SERVERS
7
実運用中
3,815
LINES (実装)
0
外部DB依存
石塚 一樹 / Kazuki Ishizuka
QuackShift インサイドセールス(ビジネス職)
2026
Overview

これは何か

私はエンジニアではなく/AIスタートアップのインサイドセールス(営業)として展示会の運営や追客を担当している
日々の業務を Claude Code(AIエージェント)に任せる中で/既製のコネクタでは届かない不便がいくつも出てきた
そのたびに「ならば自分で MCP サーバーを書く」という形で解いてきた成果物が この8本

MCP(Model Context Protocol)= AIエージェントに外部のツールやデータを安全につなぐためのプロトコル
各サーバーは stdio 経由で Claude Code 本体と通信し/エージェントから呼べる「道具」を公開する

Design Principles

8本に共通する設計思想

Lineup

8本の一覧

サーバー役割状態規模外部API / 基盤
qs-ragローカル知識ベースの意味検索(grep の代替)日次運用753行Ollama(ローカル埋め込み)
qs-gmail複数 Gmail を識別子で一元操作日次運用673行Gmail API
qs-slidesブランド適用済み Google Slides を自動生成日次運用625行Slides / Drive API
qs-crm-gasスプレッドシート CRM を安全に読み書き日次運用570行Apps Script Web App
qs-docsGoogle Docs 本文の構造的な読み書き日次運用542行Docs / Drive API
qs-formsフォームの構造と回答を読む(read only)運用中308行Forms / Drive API
qs-driveDrive のファイル操作(探す・作る・移す・上げる)日次運用192行Drive API
qs-firm会社名 → 売上 → 企業ランク自動判定実装完了 / 投入準備中152行なし(Web調査はホスト側)

規模 = index.js + src/(+ bin / hooks / authorize / GAS)の実装行数 / node_modules・生成物・lock・使い捨てスクリプトは除外 / 合計 3,815行

qs-rag ローカル知識ベースの意味検索サーバー 日次運用
課題 数百件の Markdown メモ・同期ドキュメント・過去セッションログを エージェントに参照させたい
だが grep はキーワード一致しか拾えず「あれ何だっけ」系の曖昧な問いに弱い / かといってクラウドのベクトルDBはコストと秘匿性が問題
→ 埋め込み・ストア・検索を全部ローカルに閉じた RAG を MCP として実装した
Design Decisions

設計上の判断(なぜ そうしたか)

Tools

公開している MCP ツール

ツール引数戻り値
search_knowledgequery / limit? / exclude? / domain?domain・見出し・score・id・抜粋の一覧
get_detailidチャンク本文 + 同一ファイル内の隣接チャンク一覧
reindex_now差分 reindex の結果(scanned / changed / total)

+ 常駐運用 Claude Code の UserPromptSubmit フックとして毎ターン自動検索しコンテキストに注入 / Ollama 不通やタイムアウト(2.5s)でも無言終了し エージェントを絶対にブロックしない設計 / セッション終了フックで差分 reindex を走らせ 次の起動時には最新の索引になっている

スタック Node.js (ESM) / @modelcontextprotocol/sdk / zod / node:sqlite / Ollama / SQLite FTS5 実装規模 753行 外部npm依存 2個のみ(sdk / zod)
qs-rag
qs-gmail 複数 Gmail アカウントを 1サーバーで識別子管理 日次運用
課題 既製の Gmail コネクタは基本「1ユーザー = 1アカウント」前提
業務では用途別の共有メールボックス(展示会用 exhibition@ など)を複数扱いたいが それを1つのエージェントから区別して操作する手段がなかった
→ 複数アカウントを 1DB・1サーバーで識別子管理する Gmail MCP を実装した
Design Decisions

設計上の判断(なぜ そうしたか)

Tools

公開している MCP ツール

地味だが効く実装 外部メールライブラリを使わず RFC822 を手組み / 件名は RFC2047 Base64・本文は base64url に自前変換 / In-Reply-ToReferences を付与して Gmail のスレッドに正しく連結

スタック Node.js (ESM) / @modelcontextprotocol/sdk / googleapis / zod / node:sqlite 実装規模 673行
qs-gmail
qs-slides ブランド適用済み Google Slides を自動生成 日次運用
課題 提案資料や振り返りスライドを エージェントから直接 作りたい
PowerPoint 変換を挟むと Drive 上で即共同編集できない / Slides API は座標を EMU で手指定する必要があり 生では扱いにくい
→ スライド「型」を宣言するだけで ブランド適用済みのネイティブ Slides が Drive 直下に出る MCP を実装した
Design Decisions

設計上の判断(なぜ そうしたか)

Tools

公開している MCP ツール

地味だが効く実装 raw_batch_update を逃げ道として並置し 宣言型で届かない細工も同じ分割ロジックを通す(二重実装なし)/ get_thumbnails は生成直後の視覚確認を 1コールで完結

スタック Node.js (ESM) / @modelcontextprotocol/sdk / googleapis (slides v1 / drive v3) / zod / node:sqlite 実装規模 625行(うち約45%が型→APIリクエスト変換)
qs-slides
qs-crm-gas スプレッドシート CRM を安全に読み書き 日次運用
課題 CRM は Google スプレッドシート上にある / エージェントから Sheets API を直叩きすると認証も権限管理も重い
一方「任意コードを実行できる GAS Web App」はスプレッドシートに対して危険すぎる
→ 呼べる関数を許可リストに限定し 共有トークンで認証する GAS Web App を立て その薄い RPC クライアントを MCP 化した
Design Decisions

設計上の判断(なぜ そうしたか)— セキュリティが主題

Tools

公開している MCP ツール

ツールは gas_call_function(fn, args)1本のみ / 呼べるのは許可リストの関数だけ(先頭引数は常に spreadsheetId)

スタック MCP側: Node.js (ESM) / sdk / zod / fetch ・ GAS側: Apps Script (V8) / SpreadsheetApp / PropertiesService 実装規模 570行(MCP 39 + GAS 531)
qs-crm-gas
qs-docs Google Docs 本文の構造的な読み書き 日次運用
課題 既製の Drive コネクタは 読み取りとメタデータ更新まで / 本文そのものを直す経路が無い
かといって Docs API の編集は「文書先頭からの文字位置(index)」で範囲を指定する方式で 人にもエージェントにも生では扱えない / しかも1回編集するたび後続の index がズレる
→ 構造を index 付きで返し 名前で操作する(この見出しの節を消す 等)層をかぶせた MCP を実装した
Design Decisions

設計上の判断(なぜ そうしたか)

Tools

公開している MCP ツール(12本)

スタック Node.js (ESM) / @modelcontextprotocol/sdk / googleapis (docs v1 / drive v3) / zod / node:sqlite 実装規模 542行 外部npm依存 3個(sdk / googleapis / zod)
qs-docs
qs-forms フォームの構造と回答を読む(read only) 運用中
課題 展示会・ウェビナーの申し込みフォームの回答を CRM と突き合わせたい
だが Forms API の回答は設問IDがキーで返るため 生では人もエージェントも読めない / 回答者メールも別枠にあり 突合の前に毎回整形が要る
→ 設問タイトルと回答者メールを join した形で返す 読み取り専用の MCP を実装した
Design Decisions

設計上の判断(なぜ そうしたか)

Tools

公開している MCP ツール(4本)

ツール引数戻り値
get_formformIdタイトル・設定・設問一覧(構造)
list_responsesformId / pageSize? / filter?回答一覧(回答者メール + 設問タイトルで join 済み)
get_responseformId / responseId回答1件(同上)
list_accounts認証済みアカウント一覧
スタック Node.js (ESM) / @modelcontextprotocol/sdk / googleapis (forms v1 / drive v3) / zod / node:sqlite 実装規模 308行
qs-forms
qs-drive Drive のファイル操作(探す・作る・直す・移す・上げる) 日次運用
課題 qs-docs で本文は触れるようになったが 置き場所(フォルダを作る・名前を直す・移す・アップロードする)はエージェントから触れないままだった
ただし Drive はファイルが親フォルダを複数持てる仕様で 移動を雑に実装すると 所在不明のファイルを量産する
→ 変更系を全部 dryRun 既定にし 削除を最初から持たない 薄いサーバーとして実装した
Design Decisions

設計上の判断(なぜ そうしたか)

Tools

公開している MCP ツール(8本)

スタック Node.js (ESM) / @modelcontextprotocol/sdk / googleapis (drive v3) / zod 実装規模 192行(8本で最小)
qs-drive
qs-firm 会社名 → 売上 → 企業ランクを自動判定 実装完了 / 投入準備中

※ 正直な状態表示 — コードは完成しユニットテストも通っているが 追客リストへの本番投入はこれから(8本のうちこれだけが日次で動いていない)

課題 展示会のリードリストには「会社名の生テキスト」しか無いことが多く 株式会社 / (株) / 全角 / 支店名 の表記ゆれで名寄せが難しい / 売上を手で調べると数百件で破綻する
最初は公的DB(gBizINFO)に問い合わせる実装にしたが API 申請とトークン管理が要る上に 非上場企業の売上はそもそも載っていない
2026年8月に方針を変えた: 探すのはホスト側のWeb検索に任せ MCP は「調べ方の設計」と「根拠の解釈・判定」だけを持つ / 外部APIキーがゼロになった
Design Decisions

設計上の判断(なぜ そうしたか)— 役割分割が主題

Tools

公開している MCP ツール(3本)

ツール引数戻り値
plan_firm_researchname正規化名・検索クエリ・確認順・完了条件
classify_firm_from_webname / listed? / evidence[]売上(値・年度・連結単体・ソース・根拠)/ 企業ランク / 信頼度 / 代替根拠
classify_firm_batch_from_webcompanies[]調査済み企業を一括判定(件数 + 結果配列)

企業ランクは売上規模で4段階(300億+ / 100–300億 / 50–100億 / 50億未満)/ 円で受け 1億で割って億換算してから閾値判定

スタック Node.js (ESM) / @modelcontextprotocol/sdk / zod / node:test 実装規模 152行(外部API依存を外し 判定に専念して 251行から縮小) 外部API なし
qs-firm
Summary

技術スタックと姿勢

観点共通の選択
言語 / ランタイムNode.js(ES Modules)— 全8本
MCP 実装@modelcontextprotocol/sdk + StdioServerTransport / 引数は zod でスキーマ定義
永続化node:sqlite(Node 22+ 組み込み)— 外部DBドライバ依存ゼロ
外部 APIOllama(ローカル)/ Gmail / Slides / Docs / Drive / Forms / Apps Script Web App
認証OAuth クライアント1つを5サーバーで共有 / トークンDB はスコープ単位で分離 / 最小権限(qs-forms は readonly のみ)
秘密情報環境変数 または リポジトリ外ファイル — コードにもリポジトリにも置かない
配布各リポジトリに README / LICENSE(MIT) を整備

この8本から伝えたいこと

石塚 一樹 / Kazuki Ishizuka — kazukiishizuka.marinos@gmail.com
各サーバーのソースは個別リポジトリ(README / MIT License 付き)として整備済み
本編ポートフォリオ — kazuki-ishizuka.pages.dev

MCP Portfolio — 2026