Claude Code カスタムコマンド + MCPサーバーでDBスキーマからOpenAPI定義を自動生成してみた
はじめに
APIを開発する際にOpenAPIで定義するのは開発現場でよくある話かと思うのですが、意外と定義を書くのって面倒だったりしますよね、、、
必要だった項目を見落としていたり、requiredかどうか間違えて書いてしまったり、インデント絶妙に間違えたり、、、と人為的なものによるミスもよくある話なのではないかと思います。そんな地味に面倒くさい作業を自動化できたらいいなと思い、今回はClaude Codeのカスタムコマンドを活用して自動生成できるようにしてみました!本記事は実施の行程と感想を載せていけたらと思っています!
前提
対象読者
- Claude Codeのカスタムコマンドを使って開発フローを楽にしたいと思っている方
- カスタムコマンドについて知りたいと思っている方
環境
- go version go1.23.9 linux/amd64
- Claude Code: v1.0.55
- redocly/cli: OpenAPIのコンパイル
- Ogen: OpenAPI定義を参照してGoでコード生成する
MCPで使用したツール
こちら を使わせていただきました!
MCPを通じて環境変数で指定した環境にSQLを投げて取得してくれる。read onlyにもできるし、read onlyを外せば更新等もできます。
ワークフロー
1. Claude CodeにMCPサーバーを設定
Goのコードをコンパイルしてプロジェクト内に設置し、.mcp.jsonに設定
※環境に合わせてargsは設定してください。
{
"mcpServers": {
"mysql": {
"command": "./mcp/mysql-server/go-mcp-mysql",
"args": [
"-read-only",
"-host", "HOST",
"-port", "PORT",
"-user", "USER",
"-pass", "PASS",
"-db", "DATABASE"
]
}
}
}
2. Claudeのカスタムコマンドを設定する
プロジェクト内でカスタムコマンド設定のファイルを設置
テーブル構造を確認してOpenAPI定義を記載し、redocly/cliでコンパイル→Ogenでコード生成→仮handler実装まで指示
create-openapi.md
<!-- allowed-toolsは読み書きできるファイル形式の許可やMCPサーバーのツールの許可ができる -->
<!-- mysql:desc_tableはMCPのツールでテーブルを参照する -->
---
allowed-tools: Read(*), Write(*.yaml), Write(*.go), List(*), mysql:desc_table
description: "テーブル構造を調べて、指定されたHTTPメソッドのOpenAPI定義を作成 例: /create-openapi 'users' 'web' '/users' 'get'"
---
# 概要
あなたはアプリケーションエンジニアで、アーキテクチャ設計のプロフェッショナルです。
現在は、APIをGoで作成する仕事を任されています。
本タスクではAPI仕様書の定義をOpenAPIで行い、Ogenによる自動生成、仮実装までを行います。
あなたのやることを下記に列挙します。
実装手順:
- [ ] CLAUDE.mdやserenaのドキュメントを確認して、コーディングルールや決まり事について理解してください
- [ ] mysql:desc_tableで、第1引数のテーブルの構造を把握してください
...
3. カスタムコマンドを実行して動作確認
カスタムコマンド実行して生成されたOpenAPI例
user.yaml
login:
post:
operationId: postLogin
tags:
- authentication
summary: ユーザーログイン
description: |
メールアドレスとパスワードを使用してユーザーログインを行います。
## 使用例
- ログイン: `POST /login` with `{"email": "user@example.com", "password": "password123"}`
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
description: メールアドレス
example: "user@example.com"
password:
type: string
format: password
description: パスワード
example: "password123"
responses:
"200":
description: ログイン成功
content:
application/json:
schema:
type: object
required:
- user
properties:
user:
$ref: "../../components/user.yaml#/user"
"401":
description: 認証に失敗しました
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: "Unauthorized"
required:
- message
"429":
description: ログイン試行回数が上限に達しました
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: "ログイン試行回数が上限に達しました。10秒後に再試行してください"
required:
- message
使ってみた感想
良かったポイント
- テーブル構造を確認しなくても定義できるので確認が容易になったこと
- コード生成まで一気通貫で実装してくれるので、実装の内容に集中できること
- descriptionやexampleも自動で入れてくれていること
- APIの種類によってエラーの種類をよしなに入れてくれていること
- テーブルの構造を見て、型やrequired等を自動で設定してくれていること
- チーム全員が同じカスタムコマンドで作成することで一貫した定義作成ができること
難しかったポイントや課題
- テーブルをそのまま参照しない場合や、ビジネスロジックに依存するAPIだと思ったような定義とは異なったものが生成される場合がある
- 今回POSTの場合にリクエストで投げるパラメータも引数で定義しているのですが、どれがrequiredでどれがoptionalかまでの判断は難しい
総じて、ビジネスロジックに依存しないAPIであれば、ほとんど手をかけずに定義できるので開発効率が上がり、副次的に定義の書き方も大きく統一できるようになりました。また、MCPサーバーをプロジェクトにそのまま置いたことで、MCPを登録した人だけでなく、チームメンバー全員が同じことができるようになるのは大きかったと思います。
今後の展望
APIの実装も同様に、ビジネスロジックが大きく絡まない単純なAPIであればやることが決まってきているので、実装までカスタムコマンドに任せられるとより開発効率が上がると考えています。他にもテーブルを参照できることで、仕様書等の書き起こしにも使えそうです。
まとめ
カスタムコマンドを使うと、チームメンバーがそれぞれAIを活用する際にもプロンプトによる差が生じづらく、全員が同じような動作を期待できるため、統一化を図りたいと考えている比較的フローがはっきりしているものに関しては、カスタムコマンドの活用は有用的だと感じました!
もちろん最終的には人間による確認をして、必要に応じて整えるという作業は必要ですが、単純な作業に時間を割かれるのではなく、より重要なところに集中して行えると思うと結果として効率は上がると思います。
今回の記事で少しでも参考になっていましたら幸いです!
ここまで読んでいただきありがとうございました!
Discussion