「Claude Codeから直接データベースを操作できたら便利なのに」と思ったことはありませんか。
この記事では、MCP(Model Context Protocol)を使って自作のSQLiteデータベースをClaude Codeに接続し、チャットだけでCRUD操作を完結させる方法を解説します。実際に僕が運用している自作MCPサーバーのコードをベースに、設計から実装、運用まで一気通貫で紹介します。
こんな方に向けた記事です。
- Claude CodeやClaude Desktopの「MCPサーバー」に興味があるけど、自作したことがない
- 既存のSQLiteデータベースをAIアシスタントから操作したい
- TypeScriptでMCPサーバーを作る具体的な手順を知りたい
僕はますさんといいます。福祉事業のIT全般を担当するCTOとして働きつつ、フリーランスエンジニアとしても活動しています。Mac mini M4 Proで24時間AIエージェントシステムを運用しており、その中核にあるのが今回紹介する自作MCPサーバーです。
MCPとは何か
**MCP(Model Context Protocol)**は、Anthropicが2024年11月に発表したオープンスタンダードです。AIモデルと外部ツール・データソースを接続するための共通規格で、現在はOpenAIやGoogle DeepMindも採用しています。
ざっくり言うと、「AIアシスタントが外部のツールやデータベースを安全に操作できるようにする仕組み」です。
MCPが登場する前は、AIに外部ツールを使わせたければ自前でAPIラッパーを書き、プロンプトにJSON Schemaを埋め込み、レスポンスをパースして……という作業が必要でした。MCPはこの「接続部分」を標準化し、一度サーバーを作れば、Claude Code・Claude Desktop・VS Codeなど、どのMCPクライアントからでも使い回せるようにしてくれます。
Claude Code / Desktop] -->|MCPクライアント| B[MCPサーバー
自作 or 公開] B --> C[SQLite] B --> D[外部API] B --> E[ファイルシステム]
MCPのアーキテクチャは3層構造です。
- MCPホスト — Claude CodeやClaude Desktopなど、AIが動作するアプリケーション
- MCPクライアント — ホスト内部でサーバーとの通信を担当するコンポーネント
- MCPサーバー — ツールやデータソースを公開する軽量サーバー(今回自作する部分)
通信方式は主にstdio(標準入出力)で、MCPホストがサーバーを子プロセスとして起動し、JSONでやり取りします。HTTPベースのSSE方式もありますが、ローカル運用ならstdioが手軽です。
なぜ自作MCPサーバーが必要なのか
「公式のSQLite MCPサーバーがあるのに、わざわざ自作する意味あるの?」という疑問はもっともです。
公式の汎用SQLite MCPサーバーは、任意のSQLクエリを実行できます。ただし、それは裏を返すとAIが自由にSQLを組み立てて実行するということです。
- 操作を限定できる: 「目標の作成」「アイデアの更新」など、ビジネスロジックに沿った操作だけを公開する
- 入力バリデーション: Zodスキーマでパラメータを検証し、不正な値を弾ける
- ツール名が意味を持つ:
create_goal、list_ideasなど、AIが自然に理解できる名前で公開される - セキュリティ: DROP TABLEやDELETEの無差別実行を防止できる
僕のシステムでは、Goals(目標)、Ideas(アイデア)、Deliverables(成果物)、Knowledge(ナレッジ)、Projects(プロジェクト)など13エンティティ・60以上のツールをMCP経由で公開しています。
全体アーキテクチャ
僕の自作MCPサーバーは、以下のような構成で動いています。
Discord Bot / 手動セッション] end subgraph MCPサーバー MCP["mcp-db-server
(stdio, @modelcontextprotocol/sdk v1)"] end subgraph データ層 DB["Database クラス
(agent-core)"] SQLite[(SQLite
masu-agent.db)] end CC -->|"mcp__masu_db__*"| MCP MCP --> DB DB --> SQLite
ポイントは、MCPサーバー自体にはビジネスロジックを持たせないこと。データベース操作はDatabaseクラス(別パッケージ)に集約し、MCPサーバーはその「薄いラッパー」として機能します。
技術スタックはこうです。
| 要素 | 技術 |
|---|---|
| 言語 | TypeScript(ESModules) |
| MCP SDK | @modelcontextprotocol/sdk v1 |
| バリデーション | Zod |
| データベース | SQLite(better-sqlite3) |
| パッケージ管理 | npm workspaces(モノレポ) |
実装ステップ
ここからは、実際のコードを見ながら実装手順を追っていきます。
Step 1: プロジェクトのセットアップ
mkdir mcp-db-server && cd mcp-db-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
package.jsonのポイントは"type": "module"を指定すること。MCP SDKはESModules前提です。
{
"name": "mcp-db-server",
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.26.0",
"zod": "^4.3.6"
}
}
Step 2: エントリポイント(index.ts)
MCPサーバーの起動部分は驚くほどシンプルです。
#!/usr/bin/env node
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { Database } from './database.js'; // 自前のDBクラス
// DBパスをCLI引数から取得
const dbPath = process.argv[2] || 'my-app.db';
const server = new McpServer({
name: 'my-db',
version: '0.1.0',
});
const db = new Database(dbPath);
// ツール登録(後述)
registerGoalTools(server, db);
// stdio トランスポートで起動
const transport = new StdioServerTransport();
await server.connect(transport);
McpServerを作って、ツールを登録して、StdioServerTransportで接続する。これだけです。
Step 3: Zodスキーマの定義(schemas.ts)
MCP SDK v1では、ツールの入力パラメータをZodの「raw shape」(z.object()で包まない形)で渡します。各フィールドに.describe()を付けると、AIがパラメータの意味を理解しやすくなります。
import { z } from 'zod';
// 共通の IDスキーマ
export const IdSchema = {
id: z.number().int().describe('レコードID'),
};
// 目標の作成パラメータ
export const CreateGoalSchema = {
title: z.string().describe('目標のタイトル'),
description: z.string().optional().describe('詳細説明'),
status: z.enum(['active', 'cleared']).optional()
.describe('ステータス'),
};
// 目標の更新パラメータ
export const UpdateGoalSchema = {
id: z.number().int().describe('目標ID'),
title: z.string().optional().describe('タイトル'),
description: z.string().optional().describe('詳細説明'),
status: z.enum(['active', 'cleared']).optional()
.describe('ステータス'),
};
- 必須
string→z.string() - オプショナル →
.optional()を追加 - enum型 →
z.enum([...]) - nullable →
.nullable() - すべてのフィールドに
.describe('日本語説明')を付ける
Step 4: ツール登録(tools/goals.ts)
ここが自作MCPサーバーの核心部分です。server.tool()で1つずつツールを登録します。
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import type { Database } from './database.js';
import { IdSchema, CreateGoalSchema, UpdateGoalSchema } from './schemas.js';
export function registerGoalTools(server: McpServer, db: Database): void {
// 作成
server.tool(
'create_goal',
'新しい目標を作成する',
CreateGoalSchema,
async (params) => {
const goal = db.createGoal(params);
return {
content: [{ type: 'text', text: JSON.stringify(goal) }],
};
}
);
// 取得
server.tool(
'get_goal',
'IDで目標を取得する',
IdSchema,
async ({ id }) => {
const goal = db.getGoal(id);
if (!goal) {
return {
content: [{ type: 'text', text: `Goal id=${id} not found` }],
isError: true,
};
}
return {
content: [{ type: 'text', text: JSON.stringify(goal) }],
};
}
);
// 一覧(引数なし)
server.tool(
'list_goals',
'全目標を一覧する',
async () => {
const goals = db.listGoals();
return {
content: [{ type: 'text', text: JSON.stringify(goals) }],
};
}
);
// 更新
server.tool(
'update_goal',
'目標を更新する',
UpdateGoalSchema,
async ({ id, ...params }) => {
db.updateGoal(id, params);
const updated = db.getGoal(id);
return {
content: [{ type: 'text', text: JSON.stringify(updated) }],
};
}
);
}
server.tool()のシグネチャは以下の4パターンです。
| 操作 | シグネチャ | 戻り値 |
|---|---|---|
| create | server.tool('create_*', '説明', CreateSchema, handler) |
作成したレコードのJSON |
| get | server.tool('get_*', '説明', IdSchema, handler) |
レコードJSON / isError: true |
| list | server.tool('list_*', '説明', handler) |
配列のJSON(引数なし) |
| update | server.tool('update_*', '説明', UpdateSchema, handler) |
更新後レコードJSON |
このパターンさえ覚えれば、新しいテーブルが増えてもコピペ + 修正で対応できます。実際、僕のシステムでは13エンティティすべてがこのパターンで実装されています。
Step 5: ビルド
npx tsc
これでdist/index.jsが生成されます。MCPサーバーは単なるNode.jsプロセスとして動作するので、特別なランタイムは不要です。
Claude Codeへの接続設定
ビルドしたMCPサーバーをClaude Codeに接続するには、プロジェクトルートの.mcp.jsonに設定を書きます。
{
"mcpServers": {
"my_db": {
"type": "stdio",
"command": "node",
"args": [
"/absolute/path/to/dist/index.js",
"/absolute/path/to/my-app.db"
]
}
}
}
設定後、Claude Codeを起動すると自動的にMCPサーバーが子プロセスとして立ち上がります。接続確認は以下のコマンドで。
claude mcp list
# my_db: Connected
「Connected」と表示されれば成功です。
これ以降、Claude Codeのチャットで「今の目標一覧を見せて」と言うだけで、AIがmcp__my_db__list_goalsツールを呼び出し、SQLiteからデータを取得して表示してくれます。
関連記事: Claude Codeのセキュリティ設定ガイド ではMCPツールのパーミッション管理について詳しく解説しています。
運用してみた感想
自作MCPサーバーを3ヶ月ほど運用してみて、一番変わったのは**「データベースを触るハードル」が激減した**ことです。
以前はSQLiteのデータを確認するたびにターミナルでsqlite3コマンドを叩き、テーブル名やカラム名を思い出しながらSELECT文を書いていました。今は、Discord上のBot(内部でClaude Codeが動いている)に「今週のタスク一覧見せて」と送るだけです。
具体的にこう変わりました。
Before: MCPなし
1. ターミナルを開く
2. sqlite3 masu-agent.db
3. .tables でテーブル確認
4. SELECT * FROM deliverables WHERE status = 'in_progress';
5. 結果を読む
After: MCP経由
1. チャットで「進行中のタスク一覧を見せて」と送る
2. 結果が整形されて返ってくる
たった2ステップ。しかも、AIが結果を整形してくれるので、生のJSONを自分でパースする必要もありません。
create_goal、update_deliverable、list_ideas——ツール名を見れば何ができるかわかる。新しいエンティティを追加しても、AIは自動的にツールの存在を認識し、適切に使い分けてくれます。
関連記事: Mac mini M4 ProでAIエージェントを24時間運用する方法
手動SQL運用を続けた1年後、あなたはこうなる
MCPを使わずに、AIとデータベースの連携をこのまま放置したらどうなるでしょうか。
パターン1: 毎回SQLを書かせる
AIにSQLを生成させて、Bashツールで実行する方法です。動くには動きますが、テーブルの構造をプロンプトに毎回含める必要があり、コンテキストウィンドウを圧迫します。DROP TABLEのような危険なクエリを生成するリスクもあります。
パターン2: REST APIを挟む
Express等でAPIサーバーを立て、AIにHTTPリクエストを送らせる方法です。まともに動きますが、APIサーバーの起動・管理が必要になり、認証の仕組みも自前で用意しなければなりません。運用コストが跳ね上がります。
パターン3: MCPサーバー(この記事の方法)
MCPサーバーはClaude Codeが自動で起動・管理してくれます。認証も不要(ローカルstdio通信)。ツールの入力バリデーションはZodが担当。インフラ管理のオーバーヘッドがほぼゼロです。
関連記事: Claude Code生産性ガイド2026
この記事を書いている理由
僕がMCPサーバーを自作しようと思ったきっかけは、「AIにタスク管理を任せたいけど、データベースへのアクセス方法がイマイチだった」という経験です。
最初はBashツールでsqlite3コマンドを実行させていました。でも、テーブル名を間違えたり、WHERE句の条件がズレたり、小さなミスが頻発しました。MCPサーバーに切り替えてからは、操作がツール単位で限定されるので、こういったミスがほぼなくなりました。
MCPの概念自体は2024年末に登場しましたが、2026年現在ではOpenAIやGoogleも対応し、事実上の業界標準になりつつあります。つまり、今MCPサーバーの作り方を覚えておけば、この先どのAIプラットフォームに乗り換えても使い回せるということです。
「AIエージェント」というとハードルが高く聞こえますが、MCPサーバーの実装自体はシンプルです。この記事が「自分でも作ってみようかな」と思うきっかけになれば嬉しいです。
この記事が参考になったら、ぜひSNSでシェアしてください。 MCPサーバーの自作について質問があれば、コメント欄やX(@mamamasu_3)のDMでお気軽にどうぞ。
この記事の裏話や実装の苦労話は、noteでも公開しています。
→ noteアカウント: mamamasu_3
また、X(@mamamasu_3)では日々のAI運用のTipsやハマりどころをリアルタイムで発信しています。フォローしておくと、次のAIツール導入時に役立つかもしれません。