mcp-database-serverを使用してSQL Server を自然言語で操作してみる
はじめに
最近、「データベース開発をAIを使って行いたい、、」と思うことがよくありまして。
アプリ開発界隈では、MCPの活用事例などをよく伺うのですが、データベース開発界隈ではMCPを活用した開発事例はあまり聞かない?イメージなので、何かないものかと探しておりました。
そんななか、mcp-database-serverに出会いましたのでご紹介をば、と本記事作成に至ります。
mcp-database-serverとは
このMCP(Model Context Protocol)サーバーは、Claudeへのデータベースアクセス機能を提供し、SQLite、SQL Server、PostgreSQL、およびMySQLデータベースをサポートします。
MCP データベースサーバーは、次のツールを提供します。
ツール名 | 説明 | 必須パラメータ |
---|---|---|
read_query |
データを読み取るためのSELECTクエリを実行します |
query : SQLのSELECT文 |
write_query |
データを挿入・更新・削除するためのINSERT、UPDATE、DELETEクエリを実行します |
query : SQLの変更系文 |
create_table |
データベースに新しいテーブルを作成します |
query : CREATE TABLE文 |
alter_table |
既存のテーブルのスキーマを変更します |
query : ALTER TABLE文 |
drop_table |
データベースからテーブルを削除します |
table_name : テーブル名confirm : 安全確認フラグ(trueである必要あり) |
list_tables |
データベース内のすべてのテーブルを一覧表示します | なし |
describe_table |
指定したテーブルのスキーマ情報を表示します |
table_name : テーブル名 |
export_query |
クエリ結果をCSVまたはJSON形式でエクスポートします |
query : SQLのSELECT文format : "csv" または "json" |
append_insight |
ビジネスインサイトをメモに追加します |
insight : インサイトの内容 |
list_insights |
すべてのビジネインサイトを一覧表示します | なし |
上記の通り、一通りのデータベース操作は可能です。自然言語でこれだけのことができれば、申し分ないです。素敵すぎる。
Create Databaseはできなさそうなので、先に作成しておく必要がありそうです。
Githubのreadmeでは、「Claudeで」、と記載されてますが、今回はVS Codeを使用します。
環境
VS Codeをmcpクライアントとして、mcp-database-serverを使用します。
- VS Code (V1.103.2)
- Github Copilot
- Mode : Agent Mode
- Model : GPT-5(Preview)
- Github Copilot
- node.js (v22.14.0)
- SQL Server 2022 (オンプレミス)
今回はSQL Serverへの接続を想定とします。
mcp-database-serverのセットアップ
まずは、任意の作業フォルダにmcp-database-serverを展開します。
git clone https://github.com/executeautomation/mcp-database-server.git
cd mcp-database-server
npm install
npm run build
その後、以下コマンドでnpmグローバルインストールを行います。
npm install -g @executeautomation/database-server
VS Codeのmcp.jsonには接続するデータベースの設定を行います。
mcpサーバーの名称はsqlserver_mcpとしています。
{
"servers": {
"sqlserver_mcp": {
"command": "npx",
"args": [
"-y",
"@executeautomation/database-server",
"--sqlserver",
"--server", "YourDatabaseServer",
"--port", "1433",
"--database", "YourDatabase",
"--user", "YourDatabaseUser",
"--password", "YourPassword"
]
}
},
"inputs": []
}
mcpサーバーが無事に追加起動できていれば、VS Code上では以下のようにmcp-datdabase-serverがチャットに使用できるツールに表示されているかと思います。
実験
いざいざmcp-database-serverを使用してデータベースを操作してみます。
今回はDBサーバー(192.168.5.7)上のTEST_DB_2というデータベースに接続するとして、TEST_DB_2は作成済みを想定しています。
テーブルを作成する
まずはテーブルがないと始まりませんので、テキトーにテーブルを作成してもらうことにします。
超簡素なショッピング(ECサイト)データベースを作成するとします。
テーブル:
- Users(ユーザー情報)
- Products(商品情報)
- Orders(注文)
- OrderDetails(注文内の商品詳細)
TEST_DB_2は、ショッピング(ECサイト)データベースとして活用したく考えています。
以下のようなテーブルをTEST_DB_2に作成してください。
テーブル:
- Users(ユーザー情報)
- Products(商品情報)
- Orders(注文)
- OrderDetails(注文内の商品詳細)
各カラムの属性や主キー、制約はお任せします。一般的なテーブル設計に基づいてテーブルを作成してください。
何度かSQL実行は失敗してますが、実行結果を読み取ってテーブル作成を実行しています。
以下は実行結果サマリです。
実際に実行されたSQL
以下は実際に実行されたCreate Table のSQLです。
- Users(ユーザー情報)テーブル
CREATE TABLE TEST_DB_2.dbo.Users(
UserID INT IDENTITY (1, 1) NOT NULL CONSTRAINT PK_Users PRIMARY KEY
, Email NVARCHAR(320) NOT NULL
, PasswordHash VARBINARY(256) NOT NULL
, FirstName NVARCHAR(50) NOT NULL
, LastName NVARCHAR(50) NOT NULL
, Phone NVARCHAR(30) NULL
, IsActive BIT NOT NULL CONSTRAINT DF_Users_IsActive DEFAULT 1
, CreatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_Users_CreatedAt DEFAULT SYSUTCDATETIME()
, UpdatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_Users_UpdatedAt DEFAULT SYSUTCDATETIME()
, CONSTRAINT UQ_Users_Email UNIQUE (Email)
);
- Products(商品情報)テーブル
CREATE TABLE TEST_DB_2.dbo.Products(
ProductID INT IDENTITY (1, 1) NOT NULL CONSTRAINT PK_Products PRIMARY KEY
, SKU NVARCHAR(50) NOT NULL
, Name NVARCHAR(200) NOT NULL
, Description NVARCHAR(MAX) NULL
, Price DECIMAL (19, 4) NOT NULL
, Currency CHAR (3) NOT NULL CONSTRAINT DF_Products_Currency DEFAULT 'JPY'
, StockQuantity INT NOT NULL CONSTRAINT DF_Products_Stock DEFAULT 0
, IsActive BIT NOT NULL CONSTRAINT DF_Products_IsActive DEFAULT 1
, CreatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_Products_CreatedAt DEFAULT SYSUTCDATETIME()
, UpdatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_Products_UpdatedAt DEFAULT SYSUTCDATETIME()
, CONSTRAINT UQ_Products_SKU UNIQUE (SKU)
, CONSTRAINT CK_Products_Price CHECK (Price >= 0)
, CONSTRAINT CK_Products_Stock CHECK (StockQuantity >= 0)
);
- Orders(注文)テーブル
CREATE TABLE TEST_DB_2.dbo.Orders(
OrderID BIGINT IDENTITY (1, 1) NOT NULL CONSTRAINT PK_Orders PRIMARY KEY
, OrderNumber NVARCHAR(30) NOT NULL
, UserID INT NOT NULL
, OrderDate DATETIME2(0) NOT NULL CONSTRAINT DF_Orders_OrderDate DEFAULT SYSUTCDATETIME()
, Status VARCHAR (20) NOT NULL CONSTRAINT DF_Orders_Status DEFAULT 'Pending'
, Subtotal DECIMAL (19, 4) NOT NULL CONSTRAINT DF_Orders_Subtotal DEFAULT 0
, Tax DECIMAL (19, 4) NOT NULL CONSTRAINT DF_Orders_Tax DEFAULT 0
, ShippingFee DECIMAL (19, 4) NOT NULL CONSTRAINT DF_Orders_ShippingFee DEFAULT 0
, Discount DECIMAL (19, 4) NOT NULL CONSTRAINT DF_Orders_Discount DEFAULT 0
, Total AS (Subtotal + Tax + ShippingFee - Discount) PERSISTED
, Currency CHAR (3) NOT NULL CONSTRAINT DF_Orders_Currency DEFAULT 'JPY'
, ShippingAddress NVARCHAR(500) NULL
, BillingAddress NVARCHAR(500) NULL
, CreatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_Orders_CreatedAt DEFAULT SYSUTCDATETIME()
, UpdatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_Orders_UpdatedAt DEFAULT SYSUTCDATETIME()
, CONSTRAINT UQ_Orders_OrderNumber UNIQUE (OrderNumber)
, CONSTRAINT CK_Orders_Subtotal CHECK (Subtotal >= 0)
, CONSTRAINT CK_Orders_Tax CHECK (Tax >= 0)
, CONSTRAINT CK_Orders_ShippingFee CHECK (ShippingFee >= 0)
, CONSTRAINT CK_Orders_Discount CHECK (Discount >= 0)
, CONSTRAINT CK_Orders_Status CHECK (
Status IN (
'Pending'
, 'Paid'
, 'Shipped'
, 'Completed'
, 'Cancelled'
, 'Refunded'
)
)
, CONSTRAINT FK_Orders_Users FOREIGN KEY (UserID) REFERENCES TEST_DB_2.dbo.Users(UserID)
);
- OrderDetails(注文内の商品詳細)テーブル
CREATE TABLE TEST_DB_2.dbo.OrderDetails(
OrderDetailID BIGINT IDENTITY (1, 1) NOT NULL CONSTRAINT PK_OrderDetails PRIMARY KEY
, OrderID BIGINT NOT NULL
, LineNumber INT NOT NULL
, ProductID INT NOT NULL
, Quantity INT NOT NULL
, UnitPrice DECIMAL (19, 4) NOT NULL
, UnitDiscount DECIMAL (19, 4) NOT NULL CONSTRAINT DF_OrderDetails_UnitDiscount DEFAULT 0
, LineTotal AS (
CONVERT(DECIMAL (19, 4), Quantity) * (UnitPrice - UnitDiscount)
) PERSISTED
, CreatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_OrderDetails_CreatedAt DEFAULT SYSUTCDATETIME()
, UpdatedAt DATETIME2(0) NOT NULL CONSTRAINT DF_OrderDetails_UpdatedAt DEFAULT SYSUTCDATETIME()
, CONSTRAINT UQ_OrderDetails_Order_Line UNIQUE (OrderID, LineNumber)
, CONSTRAINT CK_OrderDetails_Qty CHECK (Quantity > 0)
, CONSTRAINT CK_OrderDetails_Price CHECK (UnitPrice >= 0)
, CONSTRAINT CK_OrderDetails_Discount CHECK (UnitDiscount >= 0 AND UnitDiscount <= UnitPrice)
, CONSTRAINT FK_OrderDetails_Orders FOREIGN KEY (OrderID) REFERENCES TEST_DB_2.dbo.Orders(OrderID)
ON
DELETE CASCADE
, CONSTRAINT FK_OrderDetails_Products FOREIGN KEY (ProductID) REFERENCES TEST_DB_2.dbo.Products(ProductID)
);
テストデータ作成する
テーブルにテストデータを作成してもらいます。
作成した各テーブルにデモ用、テスト用にサンプルデータを10レコードずつ程度で作成してください。
実行結果サマリ:
10~20件のテストデータが無事作成されました。
実際に実行されたSQL
INSERT
INTO TEST_DB_2.dbo.Users(
Email
, PasswordHash
, FirstName
, LastName
, Phone
, IsActive
) VALUES (
'user1@example.com'
, 0x01020304
, 'Taro'
, 'Yamada'
, '090-0000-0001'
, 1
)
, (
'user2@example.com'
, 0x01020305
, 'Hanako'
, 'Sato'
, '090-0000-0002'
, 1
)
, (
'user3@example.com'
, 0x01020306
, 'Ken'
, 'Suzuki'
, '090-0000-0003'
, 1
)
, (
'user4@example.com'
, 0x01020307
, 'Mika'
, 'Tanaka'
, '090-0000-0004'
, 1
)
, (
'user5@example.com'
, 0x01020308
, 'Daichi'
, 'Kobayashi'
, '090-0000-0005'
, 1
)
, (
'user6@example.com'
, 0x01020309
, 'Akira'
, 'Kato'
, '090-0000-0006'
, 1
)
, (
'user7@example.com'
, 0x0102030A
, 'Rina'
, 'Yoshida'
, '090-0000-0007'
, 1
)
, (
'user8@example.com'
, 0x0102030B
, 'Sota'
, 'Yamamoto'
, '090-0000-0008'
, 1
)
, (
'user9@example.com'
, 0x0102030C
, 'Ayaka'
, 'Nakamura'
, '090-0000-0009'
, 1
)
, (
'user10@example.com'
, 0x0102030D
, 'Kenta'
, 'Watanabe'
, '090-0000-0010'
, 1
);
INSERT
INTO TEST_DB_2.dbo.Products(
SKU
, Name
, Description
, Price
, StockQuantity
, IsActive
) VALUES (
'SKU-1001'
, 'Coffee Beans 250g'
, 'Arabica blend'
, 980.00
, 200
, 1
)
, (
'SKU-1002'
, 'Green Tea 100g'
, 'Shizuoka sencha'
, 720.00
, 150
, 1
)
, (
'SKU-1003'
, 'Black Tea 50 bags'
, 'Assam blend'
, 850.00
, 180
, 1
)
, (
'SKU-1004'
, 'Drip Bags 10pcs'
, 'Single origin'
, 650.00
, 300
, 1
)
, (
'SKU-1005'
, 'Espresso Roast 250g'
, 'Dark roast'
, 1080.00
, 120
, 1
)
, (
'SKU-1006'
, 'Mug Cup'
, 'Ceramic 350ml'
, 1200.00
, 80
, 1
)
, (
'SKU-1007'
, 'Thermos Bottle'
, '500ml, stainless'
, 2980.00
, 60
, 1
)
, (
'SKU-1008'
, 'Cookie Set'
, 'Butter cookies'
, 540.00
, 250
, 1
)
, (
'SKU-1009'
, 'Chocolate Bar'
, '70% cacao'
, 390.00
, 400
, 1
)
, (
'SKU-1010'
, 'Gift Box S'
, 'Wrap included'
, 300.00
, 500
, 1
);
INSERT
INTO TEST_DB_2.dbo.Orders(
OrderNumber
, UserID
, OrderDate
, Status
, Subtotal
, Tax
, ShippingFee
, Discount
)
SELECT
CONCAT(
'ORD-'
,
RIGHT (
'00000' + CAST(
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS VARCHAR (5)
)
, 5
)
) AS OrderNumber
, u.UserID
, DATEADD(
DAY
, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) * - 1
, SYSUTCDATETIME()
) AS OrderDate
, CASE (ROW_NUMBER() OVER (ORDER BY (SELECT 1)) % 5)
WHEN 0 THEN 'Pending'
WHEN 1 THEN 'Paid'
WHEN 2 THEN 'Shipped'
WHEN 3 THEN 'Completed'
ELSE 'Cancelled'
END AS Status
, 0 AS Subtotal
, 0 AS Tax
, 500 AS ShippingFee
, 0 AS Discount
FROM
(
SELECT
TOP(10) UserID
FROM
TEST_DB_2.dbo.Users
ORDER BY
UserID
) u;
INSERT
INTO TEST_DB_2.dbo.OrderDetails(
OrderID
, LineNumber
, ProductID
, Quantity
, UnitPrice
, UnitDiscount
)
SELECT
o.OrderID
, d.LineNumber
, p.ProductID
, d.Quantity
, p.Price
, d.UnitDiscount
FROM
TEST_DB_2.dbo.Orders o
CROSS APPLY(VALUES (1, 1, 0.00), (2, 2, 50.00)) AS d(LineNumber, Quantity, UnitDiscount)
JOIN (
SELECT
TOP(10) ProductID
, Price
FROM
TEST_DB_2.dbo.Products
ORDER BY
) p
ON p.ProductID = ((o.OrderID - 1) % 10) + 1
ORDER BY
o.OrderID
, d.LineNumber;
最後にPriceをProductsテーブルから取得して、OrderDetails注文明細を更新しています。
UPDATE od
SET
od.UnitPrice = p.Price
, od.UpdatedAt = SYSUTCDATETIME()
FROM
TEST_DB_2.dbo.OrderDetails od
JOIN TEST_DB_2.dbo.Products p
ON p.ProductID = od.ProductID;
データを抽出する
データ抽出を行います。
テーブル間のリレーションに沿って、結合を行って、データを抽出表示してください。
SELECT文の生成はもちろんのこと、出力はJSON形式で受け取っているようです。
抽出結果をもとに説明も添えてくれます。
以下はSELECT文の実行結果です。
実際に実行されたSQL
SELECT
TOP(20) o.OrderNumber
, CONVERT(date, o.OrderDate) AS OrderDate
, o.Status
, u.Email
, p.SKU
, p.Name AS ProductName
, od.LineNumber
, od.Quantity
, od.UnitPrice
, od.UnitDiscount
, od.LineTotal FROM TEST_DB_2.dbo.OrderDetails od JOIN TEST_DB_2.dbo.Orders o
ON o.OrderID = od.OrderID JOIN TEST_DB_2.dbo.Users u
ON u.UserID = o.UserID JOIN TEST_DB_2.dbo.Products p
ON p.ProductID = od.ProductID ORDER BY
o.OrderID
, od.LineNumber;
SELECT
o.OrderNumber
, u.Email
, COUNT(*) AS Lines
, SUM(od.LineTotal) AS LinesTotal
, o.ShippingFee
, SUM(od.LineTotal) + o.ShippingFee - o.Discount AS OrderComputedTotal FROM TEST_DB_2.dbo.Orders
o JOIN TEST_DB_2.dbo.Users u
ON u.UserID = o.UserID JOIN TEST_DB_2.dbo.OrderDetails od
ON od.OrderID = o.OrderID GROUP BY
o.OrderID
, o.OrderNumber
, u.Email
, o.ShippingFee
, o.Discount ORDER BY
o.OrderID;
データを操作する
データ操作を行ってみます。
OrderDetailsテーブルのUnitPriceが500以上のデータの数量(Quantity)を2倍にしてください。
読み取りを行ってからUPDATEのSQLの生成と実行を行ってますね。丁寧ですね。(当たり前といえば当たり前ですが。。)
無事、該当データのQuantityが2倍に更新されました。
実際に実行されたSQL
以下は実際に実行されたSQLです。
UpdatedAtもちゃんと更新していることに感動です。
UPDATE TEST_DB_2.dbo.OrderDetails
SET
Quantity = Quantity * 2
, UpdatedAt = SYSUTCDATETIME()
WHERE
UnitPrice >= 500;
ER図を出力してもらう
ER図を出力してもらいます。
このデータベースのER図を出力してください。mermaid記法で出力してください。
以下は実際に出力されたER図です。
データベースについて説明してもらう
最後にこのデータベースの仕様について説明してもらいます。
このデータベースはどのようなデータベースといえるでしょうか?リレーションや仕様、データの流れを踏まえて説明してください。
以下は実際の回答です。
ご要望に沿って、このDBの性質・リレーション・仕様・データフローを簡潔に整理します。
- チェックリスト
- 種別・目的の定義を説明
- ER と主なリレーションを列挙
- 主な仕様(キー/制約/計算列/デフォルト)を整理
- データの流れ(業務プロセス)を説明
- 留意点と拡張ポイントを提案
どのようなデータベースか
- EC(ショッピング)サイト向けのトランザクション処理用(OLTP)コアスキーマ
- 正規化(概ね第3正規形)を基本に、注文・ユーザー・商品・明細に分割
- 集計はジョインで計算する前提(分析用DWH/スター型ではなく、アプリの取引処理最適化が目的)
ER とリレーション
- Users 1 — n Orders
- Orders.UserID → Users.UserID(FK)
- Orders 1 — n OrderDetails
- OrderDetails.OrderID → Orders.OrderID(FK、ON DELETE CASCADE)
- Products 1 — n OrderDetails
- OrderDetails.ProductID → Products.ProductID(FK)
補足
- 注文削除時に明細は自動削除(CASCADE)
- 注文内の行番号は(OrderID, LineNumber)で一意
主な仕様(キー/制約/計算列/デフォルト)
- 主キー
- Users(UserID, INT IDENTITY)
- Products(ProductID, INT IDENTITY)
- Orders(OrderID, BIGINT IDENTITY)
- OrderDetails(OrderDetailID, BIGINT IDENTITY)
- 一意制約
- Users.Email(UQ)
- Products.SKU(UQ)
- Orders.OrderNumber(UQ)
- OrderDetails(OrderID, LineNumber)(UQ)
- 外部キー
- Orders.UserID → Users
- OrderDetails.OrderID → Orders(CASCADE)
- OrderDetails.ProductID → Products
- チェック制約(整合性)
- 価格・在庫・数量は0以上、割引は単価以下
- 注文ステータスは定義済み集合(Pending/Paid/Shipped/Completed/Cancelled/Refunded)
- 計算列
- OrderDetails.LineTotal = Quantity × (UnitPrice − UnitDiscount)(PERSISTED)
- Orders.Total = Subtotal + Tax + ShippingFee − Discount(PERSISTED)
- デフォルト
- 通貨は 'JPY'
- CreatedAt/UpdatedAt は SYSUTCDATETIME()
- Users/Products の IsActive 既定 = 1
- セキュリティ
- Users.PasswordHash は VARBINARY(ハッシュ格納)※アルゴリズム/ソルト運用はアプリ側で担保
データの流れ(業務プロセス)
- カタログ管理
- 管理者が Products を登録(SKU一意、価格・在庫・アクティブ状態を管理)
- 会員管理
- ユーザー登録(Users)し、Email は一意
- 注文作成
- ユーザーがカート→注文(Orders)を生成
- 初期値として送料・割引などを設定、OrderNumber は一意
- 注文明細追加
- 各商品を OrderDetails として行追加
- LineTotal は数量・単価・割引から自動計算
- 会計・合計更新
- 小計/税/合計の更新は運用方針次第
- 現状スキーマでは Orders.Subtotal/Tax/Discount をアプリやバッチで更新し、Total が確定
- または明細からの再計算ジョブで一貫性維持(推奨)
- ステータス遷移・出荷
- Pending→Paid→Shipped→Completed などに遷移
- Cancelled/Refunded の取り扱いルールは運用で定義
- 参照・レポート
- 明細単位や注文単位の集計は、4テーブルのジョインで抽出
- 代表的なレポート例はすでに取得済(明細一覧/注文サマリ)
留意点と拡張ポイント
- パフォーマンス(推奨インデックス)
- Orders(UserID), Orders(OrderDate, Status)
- OrderDetails(OrderID), OrderDetails(ProductID)
- Users(Email) はUQで検索効率良
- データ整合性の自動化
- UpdatedAt 自動更新や Subtotal/Tax 自動算出はトリガー/アプリ/ジョブで補完可能
- 正規化の強化
- 住所を別テーブル化(Address、OrderAddress)し履歴性・再利用性向上
- ステータス履歴テーブル、支払い・配送テーブル、クーポン/プロモ組み込み
- 在庫連携
- 受注確定時に Products.StockQuantity を引き当て・減算する業務ロジック
- 多通貨・税制
- 通貨換算レートテーブル、地域税率テーブルを導入すると越境ECや複数税率に対応
総括
本DBはECの基本エンティティ(ユーザー/商品/注文/明細)を正規化して整備したOLTP向けスキーマで、参照はジョイン、整合性はキー/制約/計算列で担保します。合計や税の確定は運用設計(アプリ/ジョブ/トリガー)で補うと実運用に耐える設計になります。
何と言いますか、、拡張ポイントまで説明いただいて、正直びっくりしました。全米が泣いた。
まとめ
ということで、mcp-database-serverを使用してSQL Serverを自然言語で簡単に操作してみました。
かなり手軽に自然言語でデータベース操作ができるので、いままでSQLに悩まされてきた自分にとってはうれしい限りです。
今回はSQL Server でしたが、他にも以下はサポートもされているので、こちらも余力があれば試していきたいです。
- SQLite
- PosgreSQL
- MySQL
本記事が少しでもお役に立てれば幸いです。
参考
- GitHub mcp-database-server
- VS CodeをSQL Serverに接続するMCPサーバー
- Zenn VSCodeでMCPサーバーを使いこなす
Discussion