kintoneの標準の通知は、kintoneのユーザーにしか届きません。顧客リストをkintoneで管理していても、そこに載っている社外の担当者へメールを送るには、別の仕組みが必要になります。
サイボウズが公開しているkintoneの公式MCPサーバーと、blastengineのMCPサーバーを1つのエージェントにつなぐと、「kintoneから配信対象の顧客を取り出し、blastengineで1件ずつ案内メールを送り、配信結果をkintoneのレコードに書き戻す」までを会話で回せます。本記事ではこの構成をClaude Codeで組み、実際に送信して書き戻すところまで確認します。
書き戻しで一番大事なのは、何をもって「送れた」と判断するかです。送信APIが受け付けた時点では、まだ届いたとは限りません。実際に動かしてみると、配信情報のステータスがSENTなのに1通も届いていない、というケースがありました。この判定の部分に紙幅を割きます。
※記事中の送信者名と送信元メールアドレスは、掲載用に置き換えています。
blastengine MCPの導入手順は導入記事、各ツールの入出力は全15ツールの検証記事を参照してください。
全体構成
┌──────────────────────────────┐
│ Claude Code │
└───────┬──────────────┬───────┘
stdio │ │ stdio
(Docker) │ │
┌────────────────▼───┐ ┌───▼──────────────────┐
│ kintone MCP │ │ blastengine MCP │
│ (公式Docker) │ │ │
└────────┬───────────┘ └───────────┬──────────┘
│ REST API │
┌────────▼───────────┐ ┌───────────▼──────────┐
│ kintone │ │ blastengine │
└────────────────────┘ └──────────────────────┘
どちらも手元で動くstdioサーバーです。kintone側は公式のDockerイメージ(ghcr.io/kintone/mcp-server)を使います。npmパッケージ(@kintone/mcp-server)やClaude Desktop用のMCPBファイルも配布されています。
準備1:kintoneの環境と認証方式を決める
検証用のkintone環境は、kintone開発者ライセンスで無料で用意できます。ユーザー5人・ディスク25GBの固定で、開発やテストの目的に限って使える環境です。本番運用には使えません。
kintone MCPサーバーの認証は、パスワード認証かAPIトークン認証のどちらかを選びます。
| 方式 | 環境変数 | 向いている使い方 |
|---|---|---|
| パスワード認証 |
KINTONE_USERNAME / KINTONE_PASSWORD
|
アプリの作成など、アプリの設定まで触る場合(アプリを作成するAPIはAPIトークンに対応していない) |
| APIトークン認証 |
KINTONE_API_TOKEN(カンマ区切りで最大9個) |
既存アプリのレコードを読み書きするだけの場合 |
両方を指定すると、パスワード認証が優先されます。
パスワード認証では、そのユーザーが触れるものはすべてエージェントからも触れます。本記事では手順1でアプリ自体をClaudeに作らせるのでパスワード認証を使いますが、運用に載せる段階では、対象アプリだけに権限を付けたAPIトークンへ切り替えるのが安全です。APIトークンはアプリごとに発行し、「レコード閲覧」「レコード編集」のように操作単位で権限を付けられます。
準備2:Claude Codeに2つのMCPを登録する
プロジェクト直下の.mcp.jsonに2つのサーバーを書きます。認証情報は直接書かず、${VAR}で環境変数から展開させます。
{
"mcpServers": {
"kintone": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "KINTONE_BASE_URL", "-e", "KINTONE_USERNAME", "-e", "KINTONE_PASSWORD",
"ghcr.io/kintone/mcp-server:latest"],
"env": {
"KINTONE_BASE_URL": "${KINTONE_BASE_URL}",
"KINTONE_USERNAME": "${KINTONE_USERNAME}",
"KINTONE_PASSWORD": "${KINTONE_PASSWORD}"
}
},
"blastengine": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/blastengine-mcp/dist/index.js"],
"env": {
"BLASTENGINE_LOGIN_ID": "${BLASTENGINE_LOGIN_ID}",
"BLASTENGINE_API_KEY": "${BLASTENGINE_API_KEY}",
"BLASTENGINE_ENABLE_SEND": "true",
"BLASTENGINE_ENABLE_BULK": "false",
"BLASTENGINE_ENABLE_CSV_IMPORT": "false"
}
}
}
}
KINTONE_BASE_URLはhttps://(サブドメイン).cybozu.comの形です。kintone側はdocker runの-e KINTONE_BASE_URLのように値を書かずに変数名だけを渡し、envで設定した値をコンテナに引き継がせています。
blastengine側は、今回トランザクション配信しか使わないので、BLASTENGINE_ENABLE_SENDだけを有効にしています。一斉配信とCSVインポートは切っておきます。
Claude Codeを起動して/mcpを開き、両方が接続済みになっていれば準備は完了です。
kintone側のツールを把握する
手元のkintone MCPサーバー1.11.2では、28個のツールが提供されていました。今回使うのは次のものです。
| 用途 | ツール |
|---|---|
| アプリを作る |
kintone-add-app / kintone-add-form-fields / kintone-deploy-app / kintone-get-app-deploy-status
|
| フィールドを調べる | kintone-get-form-fields |
| レコードを読み書きする |
kintone-get-records / kintone-add-records / kintone-update-records
|
このほかに、レコードやフィールド、スペースを削除するツール(kintone-delete-records / kintone-delete-form-fields / kintone-delete-space)もあります。今回の作業では削除は不要なので、後述の「エージェントに渡すツールを絞る」で使えないようにします。
手順1:配信先のアプリをClaudeに作らせる
kintone MCPサーバーはアプリの設定まで扱えるので、配信先を管理するアプリそのものを会話から作れます。
kintoneに「配信先顧客」というアプリを新規作成してください。フィールドは次のとおり。
会社名(文字列1行, 必須, フィールドコード company)、担当者名(文字列1行, contact_name)、
メールアドレス(文字列1行, 必須, email)、配信対象(チェックボックス、選択肢「対象」1つ, target)、
配信ステータス(ドロップダウン 選択肢: 未送信/送信済み/エラー, 初期値 未送信, status)、
配信ID(数値, delivery_id)、送信日時(日時, sent_at)、配信結果メモ(文字列複数行, result_note)。
作成後、運用環境へ反映し、反映完了を確認してアプリIDを報告してください。
エージェントは次の順でツールを呼びました。
-
kintone-add-appでアプリを作る(返り値は{"app":"1","revision":"2"}) -
kintone-add-form-fieldsで8つのフィールドをまとめて追加する -
kintone-deploy-appで運用環境へ反映する -
kintone-get-app-deploy-statusで反映状況を確認する。1回目はPROCESSING、2回目でSUCCESS
kintone-add-appで作ったアプリは、まだ動作テスト環境にあるだけです。ツールの説明にも、運用環境に反映するにはkintone-deploy-appを実行するよう書かれています。指示に「反映完了を確認して」と入れておくと、エージェントがSUCCESSになるまで状況を確認してくれます。
フィールドコードは指示で明示しておくのがおすすめです。後の手順の指示や書き戻しの引数にそのまま出てくるので、短い英数字に決めておくと読みやすく、取り違えも起きにくくなります。
ここまでで6ターン、約0.32ドル(Sonnet)でした。
動作確認用に、ダミーの顧客を5件登録しておきます。配信対象にチェックしたレコードが4件、チェックしていないレコードが1件です。登録はkintone-add-recordsの1回で済みました。
手順2:配信対象のレコードを取り出す
「配信対象にチェックが入っていて、まだ送っていない」レコードを取り出します。
kintoneのアプリID 1(配信先顧客)から、配信対象に「対象」がチェックされていて
配信ステータスが「未送信」のレコードを取得してください。
エージェントはまずkintone-get-form-fieldsでフィールドの型を確認し、そのうえでkintone-get-recordsを次の引数で呼びました。
{
"app": "1",
"filters": {
"inValues": [
{ "field": "target", "values": ["対象"] },
{ "field": "status", "values": ["未送信"] }
]
}
}
kintoneのREST APIを直接使ったことがある人は、target in ("対象") and status in ("未送信")のようなクエリ文字列を思い浮かべるはずです。kintone MCPサーバーのkintone-get-recordsは、クエリ文字列ではなく、構造化されたfiltersで条件を受け取ります。
| 条件の種類 | 対応する演算子 | 主な対象フィールド |
|---|---|---|
textContains |
like |
文字列(1行・複数行)、リッチエディター、リンク |
equals |
= |
レコード番号、文字列1行、数値、日付・日時、ステータス |
dateRange |
>= / <=
|
日付・時刻・日時、作成日時・更新日時 |
numberRange |
>= / <=
|
レコード番号、数値、計算 |
inValues / notInValues
|
in / not in
|
チェックボックス、ドロップダウン、ラジオボタン、ユーザー選択など |
条件はすべてAND結合で、OR条件は書けません。ツールの説明にも「OR conditions are not supported」と明記されています。「配信対象」か「VIP」のどちらかにチェックがある、のような条件ならinValuesのvaluesに並べれば済みます。一方、異なるフィールドにまたがるOR条件は、2回に分けて取得してまとめる必要があります。
クエリ記法の細かい書き方をエージェントに覚えさせなくていいので、条件の組み立てで失敗しにくいのは利点です。チェックボックスのフィールドにはinValuesを使う、という型の対応も、kintone-get-form-fieldsの結果を見てエージェントが自分で選んでいました。
1回に取得できるのは最大500件(limitは1〜500)で、それ以上はoffsetで続きを取ります。
手順3:blastengineで1件ずつ送る
取り出したレコードに、トランザクション配信で1件ずつ送ります。
取得した各レコードに、blastengineのトランザクション配信で1件ずつ案内メールを送ってください。
- 送信元: info@example.com(送信者名: 株式会社example)
- 件名: 【ご案内】11月のサービス説明会のお知らせ
- 本文(テキスト): 「{会社名}\n{担当者名} 様\n\nいつもお世話になっております。株式会社exampleです。\n11月のサービス説明会のご案内をお送りします。\n」({}はレコードの値で置き換える)
エージェントはblastengine_send_transactionをレコードの数だけ呼びます。会社名と担当者名は、エージェントが本文に埋め込んで送っていました。
{
"from_email": "info@example.com",
"from_name": "株式会社example",
"to": "yamada@example.jp",
"subject": "【ご案内】11月のサービス説明会のお知らせ",
"text_part": "株式会社サンプル商事\n山田 太郎 様\n\nいつもお世話になっております。株式会社exampleです。\n11月のサービス説明会のご案内をお送りします。\n"
}
送信が受け付けられると{"delivery_id":5}のように配信IDが返ります。
BLASTENGINE_ENABLE_BULKを切ってあるので、件数が多くてもエージェントが一斉配信に切り替えることはありません。宛先ごとにトランザクション配信が1件ずつ作られ、配信IDも1件ずつ付きます。レコードと配信IDを1対1で対応させたい今回の用途には、このほうが都合がいいです。
手順4:配信結果を確かめてから書き戻す
ここがこの構成の要です。
配信IDが返っても、届いたとは限らない
最初、指示を「送信が受け付けられたらstatusを『送信済み』にする」と書いて実行しました。このときは、宛先をblastengineの配信可能アドレスに登録し忘れていました。結果は、4件とも配信IDが返ったにもかかわらず、1通も届いていませんでした。
このときエージェントは、受け付けた後に自分で配信情報を確認し、指示どおり「送信済み」にせず「エラー」で書き戻しました。報告にはこうありました。
ご指示では、API が受け付けたら「送信済み」にするとなっていました。
ただ、配信されていないレコードを「送信済み」にすると、再送の対象から外れてしまうため、
「エラー」にしました。
今回はエージェントが気を利かせてくれました。ただ、毎回こう判断してくれる保証はありません。何をもって送信済みとするかは、指示の中で決めておくべきです。
配信情報のSENTは「配信処理が終わった」という意味
判定に使うツールの選び方にも注意が要ります。blastengine_delivery_getで配信情報を引くと、届かなかった配信でも次のように返ってきました。
{
"delivery_id": 1,
"delivery_type": "TRANSACTION",
"status": "SENT",
"total_count": 1,
"sent_count": 0,
"drop_count": 1,
"hard_error_count": 0,
"soft_error_count": 0
}
statusはSENTですが、sent_countは0で、drop_countが1です。配信情報のstatusは配信処理の段階を表す値なので、宛先に届いたかどうかの判定には使えません。
宛先ごとの結果は、blastengine_mail_results_listで配信IDを指定して引きます。
{
"delivery_id": 1,
"email": "yamada@example.jp",
"status": "DROP",
"last_response_code": "554(rejection)",
"last_response_message": "宛先が配信可能なアドレスではありません。配信可能アドレスの登録状況をご確認ください。..."
}
届いた場合はstatusがSENT、last_response_codeが250、last_response_messageが「配信に成功しました」になります。判定はこちらのstatusとlast_response_codeで行います。
配信ログに載るまで数秒かかることがある
宛先を配信可能アドレスに登録し、もう一度送り直しました。3件とも届きましたが、このとき配信ID 6だけ、送った直後にblastengine_mail_results_listを引くと{"data":[]}が返りました。同じ時点のblastengine_delivery_getはstatus: SENTで、sent_countもdrop_countも0です。
何度か引き直すと、配信ログにSENT / 250が現れました。ログの作成時刻が11:51:09、配信時刻が11:51:15、更新時刻が11:51:18で、送信から結果が確定するまで10秒ほどかかっています。
送った直後に1回だけ確認して、ログが空なら「エラー」、という判定にすると、届いているメールを失敗扱いにしてしまいます。空のときは少し待って引き直し、それでも出なければ「未確定」として残す、という扱いが必要です。
書き戻しまでを含めた指示
以上を踏まえて、指示を次のように書き直しました。
送信APIが受け付けたら、すぐに「送信済み」にはせず、配信ログで実際の配信結果を確認してください。
- 配信に成功していたら: delivery_id に配信ID、sent_at に送信日時を入れ、status を「送信済み」
- DROPやエラーだったら: delivery_id と sent_at を入れたうえで status を「エラー」、result_note に結果コードとエラー内容
- 送信API自体がエラーを返したら: status を「エラー」、result_note にエラー内容
最後に、更新後のレコード一覧(レコード番号・会社名・status・delivery_id・sent_at・result_note)を報告してください。
エージェントは3件を送り、配信ログが空だった配信ID 6について引き直しを繰り返し、全件のSENT / 250を確認してからkintone-update-recordsを1回呼びました。
{
"app": "1",
"records": [
{ "id": "1", "record": { "status": { "value": "送信済み" }, "delivery_id": { "value": "5" }, "sent_at": { "value": "2026-10-29T02:51:08Z" } } },
{ "id": "2", "record": { "status": { "value": "送信済み" }, "delivery_id": { "value": "6" }, "sent_at": { "value": "2026-10-29T02:51:15Z" } } },
{ "id": "3", "record": { "status": { "value": "送信済み" }, "delivery_id": { "value": "7" }, "sent_at": { "value": "2026-10-29T02:51:10Z" } } }
]
}
sent_atには、配信ログのdelivery_time(日本時間)をUTCに直した値が入っています。kintoneの日時フィールドはYYYY-MM-DDTHH:mm:ssZのUTCで受け取り、画面ではユーザーのタイムゾーンで表示されます。
書き戻した後に読み直すと、sent_atは2026-10-29T02:51:00Zのように、秒が切り捨てられて分単位になっていました。kintoneの日時フィールドは秒を保持しないためです。秒まで残したい場合は、配信ログのdelivery_timeを文字列フィールドに入れるか、result_noteに書いておきます。
ここまでで19ターン、約0.16ドルでした。引き直しの分だけターン数は増えますが、取り違えて書き戻すよりは安く済みます。
書き戻した後のレコードは次のとおりです。
| レコード | 配信対象 | status | delivery_id | 備考 |
|---|---|---|---|---|
| 1 | 対象 | 送信済み | 5 | |
| 2 | 対象 | 送信済み | 6 | 配信ログの反映待ちあり |
| 3 | 対象 | 送信済み | 7 | |
| 4 | 対象 | エラー | 4 | 1回目の送信でDROP。result_noteに554の内容 |
| 5 | なし | 未送信 | 配信対象外のため送っていない |
同じ指示をもう一度実行しても二重に送らない
取り出す条件を「statusが『未送信』」にしているので、送信済みとエラーのレコードは次回の対象から外れます。同じ指示を何度実行しても、同じ相手に二重には送りません。エラーになったレコードは、宛先を直してからstatusを「未送信」に戻せば、次回の実行で送り直されます。
この形にしておくと、手順2〜4をまとめた指示をclaude -pで定期実行に載せることもできます。非対話での実行方法は週次レポートの記事を参照してください。
エージェントに渡すツールを絞る
kintone MCPサーバーには、アプリの設定変更や削除のツールも含まれています。配信と書き戻しだけを行う運用であれば、使うツールを明示的に許可し、それ以外は使わせない形にします。
claude -p "(手順2〜4をまとめた指示)" \
--mcp-config .mcp.json --strict-mcp-config --tools "" \
--allowedTools "mcp__kintone__kintone-get-form-fields,mcp__kintone__kintone-get-records,mcp__kintone__kintone-update-records,mcp__blastengine__blastengine_send_transaction,mcp__blastengine__blastengine_delivery_get,mcp__blastengine__blastengine_mail_results_list"
対話で使う場合は、.claude/settings.jsonのpermissions.denyに削除系のツールを入れておくと安心です。
{
"permissions": {
"deny": [
"mcp__kintone__kintone-delete-records",
"mcp__kintone__kintone-delete-form-fields",
"mcp__kintone__kintone-delete-space"
]
}
}
送信の直前に承認を挟む方法は、誤送信を防ぐ記事で詳しく扱っています。
kintoneの通知とblastengineの使い分け
| 観点 | kintoneの通知 | blastengine経由 |
|---|---|---|
| 宛先 | kintoneのユーザー | 社外を含む任意のメールアドレス |
| 送信元 | kintoneの通知用アドレス | SPF・DKIM・DMARCを設定した自社ドメイン |
| 文面 | 通知の定型 | 件名・本文を自由に組める |
| 届いたかどうか | 宛先ごとの配信結果は残らない | 宛先ごとの配信ログ(SENT / DROP / HARDERRORなど)を取れる |
| レコードとの紐付け | レコードに直接紐づく | 配信IDを自分で書き戻す |
社内のメンバーに「レコードが更新された」と知らせるだけならkintoneの通知で足ります。顧客や取引先にメールを届けたいとき、そして届いたかどうかをkintone側で管理したいときに、blastengineを挟む意味があります。
つまずきやすいポイント
| 症状 | 原因と対処 |
|---|---|
| アプリを作ったのにレコードを登録できない |
kintone-add-appは動作テスト環境に作るだけ。kintone-deploy-appで反映し、kintone-get-app-deploy-statusがSUCCESSになるのを待つ |
| クエリ文字列で条件を書かせると失敗する |
kintone-get-recordsはクエリ文字列ではなく構造化されたfiltersを受け取る。条件はAND結合のみでOR不可 |
| 500件を超えると取りこぼす |
limitは1〜500。offsetで続きを取る |
| MCP Inspectorから直接呼ぶと引数エラーになる | アプリIDやレコードIDは文字列で渡す。数値で渡すとInput validation error: expected string, received number at app
|
| 配信IDが返ったのに届いていない | 受け付けと配信は別。blastengine_mail_results_listで宛先ごとのstatusとlast_response_codeを確認する |
配信情報がSENTなのに届いていない |
blastengine_delivery_getのstatusは配信処理の段階。sent_countとdrop_count、または配信ログで判定する |
| 送った直後に配信ログが空 | 反映まで10秒ほどかかることがある。少し待って引き直す |
554(rejection)でDROPになる |
宛先が配信可能アドレスに登録されていない。トライアルでは登録した宛先にしか送れない |
| 送信日時の秒が消える | kintoneの日時フィールドは分単位。秒が必要なら文字列フィールドに残す |
| アプリの作成がAPIトークンでできない | アプリを作成するAPIはAPIトークン認証に対応していない。アプリ自体を作るならパスワード認証を使う |
| MCP Inspectorで認証が通らない | InspectorのCLIモードは親シェルの環境変数をサーバーに渡さない。-e KEY=valueをサーバーのコマンドより前に書き、--で区切る |
| blastengine MCPが起動しない | Node.js 22.15以上が必要(package.jsonのengines) |
まとめ
kintoneとblastengineを1つのエージェントにつなぐ構成のポイントは3つです。
- kintoneの公式MCPサーバーは、Dockerイメージを
.mcp.jsonに書くだけで使える。アプリの作成から反映まで会話で済むが、運用ではレコード操作だけに絞ったAPIトークンに切り替える - レコードの抽出は、クエリ文字列ではなく構造化された
filtersで行う。条件はAND結合のみで、statusが「未送信」のものだけを取り出せば、何度実行しても二重には送らない - 書き戻しの判定は、配信IDが返ったかどうかでも、配信情報の
statusでもなく、blastengine_mail_results_listで引いた宛先ごとの配信結果で行う。ログが空なら少し待って引き直す
「送れた」の基準をはっきりさせておけば、kintoneのレコードを見るだけで、誰に送って誰に届かなかったかが分かる状態にできます。
blastengine MCPサーバーへの要望や感想は、以下のアンケートフォームから送ると開発チームに届くみたいです。
https://docs.google.com/forms/d/e/1FAIpQLSdNZ9TswUT3JEv3pMHkJGqOvgmsXuKP1smkJiNEsqbTVDwRyg/viewform
※本記事の手順は、kintone開発者ライセンスの環境に、kintone MCPサーバー1.11.2(Dockerイメージ)とblastengine MCPサーバー v0.2.2を接続し、Claude Code(Sonnet)からアプリの作成、レコードの抽出、実送信、配信結果の確認、書き戻しまで通しで確認しました。提供ツールや引数はバージョンによって変わるため、手元のtools/listを確認してください。