@rex0220/kintone-sql-tools
v3.85.0
Published
kintone SQL plugin, CLI, and MCP tools (ksql)
Downloads
2,375
Readme
kintone-sql-tools
kintone アプリを SQL 風の構文で操作するツールセットです。
- kintone プラグイン(UI)
- CLI(
ksql) - MCP サーバー(AI クライアントから kintone を SQL 操作。Claude Desktop 用 MCPB 同梱)
- read-only エンジン・ライブラリ(ESM / CJS / UMD)
他の kintone プラグインやカスタマイズへ read-only kSQL エンジンを組み込む場合は、 エンジン・ライブラリ利用ガイドを参照してください。
engine ライブラリでは、runQuery() が単文の SELECT / WITH / UNION /
SHOW APPS / DESCRIBE / 既存レコード VALIDATE を、runBatch() がそれらに加えて
CREATE / DROP TEMP TABLE、SET / DECLARE、ASSERT、EXPLAIN を実行します。
書き込み DML、DML VALIDATE ONLY、IMPORT、APPLY は対象外です。
生成 AI が MCP で作った SQL を library で実行する場合は、この API 別の境界を確認してください。
機能概要
SELECT(JOIN/GROUP BY/HAVING/CTE/UNION)INSERT/UPDATE/UPDATE ... FROM/UPSERT/DELETE/REORDER(--allow-dml必須)EXPLAIN- 型付きcanonical
ORDER BYとkintone固有順を選ぶKORDER BY(v3.0.0) - 最大30桁のNUMBERをraw字句のまま比較する厳密10進primitive(v3.3.0)
- バッチ実行(
;区切りの複文)と一時テーブルCREATE TEMP TABLE #t AS SELECT ...- CLI / MCP: read-only バッチ + DML バッチ(一時テーブル経由の
INSERT ... SELECTを含む) - プラグイン: read-only バッチのみ(最終結果を表示)
- CLI / MCP: read-only バッチ + DML バッチ(一時テーブル経由の
ASSERT(実行時ゲート。DML 前の件数ガード / CLI ヘルスチェック)- サブテーブル仮想テーブル(
APP100$明細) - CLI 拡張
APP@profile- 同一 SQL 内で同一 APP の profile 混在を許可
INSERT/UPDATE/UPSERT対応、DELETEは未対応
- CLI / MCP の論理アプリ参照
LAPP_<NAME>- profile ごとの
logicalAppsで、同じ SQL を異なる物理アプリ ID へ安全に解決 APP100は常に物理 ID 100 のまま(暗黙変換なし)allowPhysicalAppRefs: falseで、その profile の物理APPxxx直接参照を禁止可能
- profile ごとの
FROM省略 SELECT(例:SELECT 'xxx' AS a)
インストール
npm(グローバル)
npm install -g @rex0220/kintone-sql-tools
ksql --helpローカル開発
npm install
npm run build:cli
node dist-cli/ksql.js --helpプラグインをビルドする場合:
npm run build:pluginテストを実行するときは KSQL_* を外す
CLI は環境変数を設定ファイルより優先します(CLI 引数 → 環境変数 → 設定ファイル)。
シェルに KSQL_USERNAME / KSQL_PASSWORD / KSQL_CONFIG / KSQL_PROFILE などが
残っていると、テストが別の認証・別の設定で走り、リポジトリを変えていないのに
落ちたり通ったりします。
env -u KSQL_USERNAME -u KSQL_PASSWORD npm test日常の CLI 利用のために KSQL_* を設定している場合は、上のように外して実行してください。
テストが落ちたら、まず env | grep KSQL_ を確認すると早いことがあります
(実装が読む KSQL_* は 32 個あります)。
使い分け(CLI / Plugin)
CLI を使うケース:
- DML を含むバッチ実行・SQL ファイル実行(
-f) - CI/CD 連携
APP@profileを使った環境切替LAPP_<NAME>を使った配置非依存 SQL--dry-run/EXPLAINによる安全確認
- DML を含むバッチ実行・SQL ファイル実行(
Plugin を使うケース:
- kintone 画面内での対話操作(read-only バッチ + 一時テーブルも利用可)
- 非エンジニア向けの運用
- UI で結果確認したい場合
MCP を使うケース:
- Claude 等の AI クライアントから kintone を照会・更新
- 一時テーブルで中間結果をサーバー内に保持し、AI のコンテキスト消費を抑えたい場合
- validation / EXPLAIN で論理名から最終的な物理アプリ ID への解決を確認したい場合
言語リファレンス・レシピは MCP resources(ksql://language-reference / ksql://recipes)に加えて、read-only ツール ksql_docs でも読めます。中継環境(リモート接続のプロキシ等)が resources を通さないクライアントでは、ksql_docs を引数なしで呼ぶと全章キーの索引が返るので、必要な章だけ {"section":"language-reference/05-string-number-functions"} の形で取得してください。
今つながっている MCP が何版かは、ksql_docs を引数なしで呼ぶと索引の先頭行で分かります(v3.56.3〜)。MCP は常駐プロセスなので、npm install してもクライアントを再読み込みするまで差し替わりません。ksql.js --version は別プロセス(CLI)の版なので、常駐 MCP の版とは食い違うことがあります。測定結果が期待と違うときは、まず索引の先頭行で版を確かめてください。
注意:
APP@profileとLAPP_<NAME>[@profile]は Node.js runtime(CLI / MCP)の拡張です。plugin 側では非対応です。
最短実行例(CLI)
node dist-cli/ksql.js --base-url https://example.cybozu.com --token xxx -e "SELECT * FROM APP100 LIMIT 5"FROM 省略 SELECT:
node dist-cli/ksql.js -e "SELECT 'xxx' AS a"DML(確認付き):
node dist-cli/ksql.js \
--base-url https://example.cybozu.com \
--token xxx \
--allow-dml \
-e "UPDATE APP100 SET 状態 = '完了' WHERE ステータス = '未着手'"コンソール:
node dist-cli/ksql.js --console --base-url https://example.cybozu.com --token xxx設定ファイル
- 既定:
./ksql.config.json - profile 切替:
--profile <name>
例:
node dist-cli/ksql.js --config ./ksql.config.json --profile dev -e "SELECT * FROM APP100"論理アプリ参照を使う場合、profile ごとに論理名と物理 ID を定義します。
{
"defaultProfile": "dev",
"profiles": {
"dev": {
"baseUrl": "https://dev.example.cybozu.com",
"logicalApps": { "ORDERS": 100 },
"tokenMap": { "APP100": "env:DEV_ORDERS_TOKEN" }
},
"prod": {
"baseUrl": "https://prod.example.cybozu.com",
"allowPhysicalAppRefs": false,
"logicalApps": { "ORDERS": 1200 },
"tokenMap": { "APP1200": "env:PROD_ORDERS_TOKEN" }
}
}
}node dist-cli/ksql.js --config ./ksql.config.json --profile dev -e "SELECT * FROM LAPP_ORDERS"
node dist-cli/ksql.js --config ./ksql.config.json --profile prod -e "SELECT * FROM LAPP_ORDERS"どちらも同じ SQL ですが、前者は APP100、後者は APP1200 に解決されます。logicalApps のキーは LAPP_ を付けない ASCII 論理名です。APP100、100、LAPP_ORDERS は設定キーとして拒否されます。
CLI オプション
ksql - Execute SQL against kintone apps
Usage:
ksql [options]
ksql -e "<SQL>"
ksql -f <file.sql>
Options:
-e, --execute <sql> Execute SQL string
-f, --file <path> Execute SQL file
--console Start interactive console mode
--dry-run Parse and show execution plan only
--var <name=value> Override a DECLARE variable (repeatable; not for secrets)
--import-csv <name=path> Supply named CSV and enable IMPORT (repeatable)
--import-json <name=path> Supply named JSON and enable IMPORT (repeatable)
--export-csv <name=path> Export temp table #<name> as RFC 4180 CSV after the batch succeeds (repeatable)
--export-csv <path> Export the result of a single SELECT as CSV (no name; path must not contain '=')
--export-encoding <type> CSV export encoding: utf8 | sjis (default: utf8; unrepresentable characters fail)
--export-timezone <zone> IANA timezone for DATETIME cells in CSV export (default: keep UTC)
--format <type> Output format: table | json | jsonl | csv | markdown | md
(batch + json: prints one JSON envelope for the whole batch)
--max-records <n> Max records to fetch (default: 500)
--fetch-parallel <n> Parallel page fetches per query: 1-10 (default: 3)
--on-limit <mode> On record limit: error | truncate (local ORDER BY needs complete input)
--temp-table-max-rows <n> Max rows per temp table (default: 10000, always errors on overflow)
--timeout <ms> Request timeout in milliseconds (default: 30000)
--max-concurrent <n> Max concurrent kintone requests: 1-50 (default: 10)
(process-wide; fixed at first resolution; KSQL_MAX_CONCURRENT wins)
--cursor-max-active <n> Max active cursors per host: 1-5 (default: 2; KSQL_CURSOR_MAX_ACTIVE wins)
--retry <n> GET retry count: 0-10, 0 disables (default: 3; KSQL_RETRY wins)
--retry-base-delay <ms> GET retry backoff base delay (default: 500)
--retry-max-delay <ms> GET retry backoff max delay (default: 8000)
--config <path> Config file path (default: ./ksql.config.json)
--profile <name> Profile name in config
--base-url <url> kintone base URL
--guest-space-id <id> Guest space ID (uses /k/guest/<id>/v1 APIs)
--auth <type> Auth type: token | userpass | auto
--username <name> Login username (for userpass auth)
--password <pass> Login password (for userpass auth)
--token <token> Single-app token
--token-map <mapping> App token map (APP100=...,APP101=...)
--token-file <path> JSON file for app token map
--app <id> Default app id context
--diag-record-id <id> Diagnostic: GET record.json by app+id
--no-header Hide table header
--pretty Pretty-print JSON output
--user-format <mode> User field format: full | name | code
--array-format <mode> Array field format: full | join
--table-format <mode> Subtable format: full | count
--date-format <mode> Date format: full | local
--attachment-format <mode> Attachment format: full | name | fileKey
--output <path> Write output to file
--no-color Disable ANSI colors
--quiet Suppress non-result logs
--debug Show request/response debug logs
--debug-url Show only HTTP request URL debug logs
--debug-headers Show request headers in debug logs (masked)
--exit-on-empty Return exit code 1 when rowCount is 0
--allow-dml Enable UPDATE/DELETE/INSERT/UPSERT/REORDER execution
--yes Skip DML confirmation prompt
--allow-without-where Allow UPDATE/DELETE without WHERE
--dml-max-rows <n> Max affected parent rows for DML/APPLY guard (default: 100)
--dml-max-subtable-rows <n> Max changed subtable rows for APPLY guard; multi-value fields excluded (default: 500)
--continue-on-error Batch: keep executing after a statement error (read-only batch only)
-h, --help Show help
-v, --version Show version--export-csv の引数規則: 最初の = で name と path に分割し、= を含む引数は必ず名前付き(左辺が temp table
識別子でなければ ArgumentError。C:\... の : は区切りではない)。名前なし <path> は単文 SELECT のときだけ・1 件だけで、
= を含む path には使えない。同じ名前・同じ path の重複、--output と同じ path、--dry-run との併用は実行前に拒否。
SQL 全文が成功した後にだけ全 sink を serialize し、同一 directory の一時 file → fsync → close → rename で書く
(失敗時は旧 file 維持・一時 file 削除)。既存 file を他プロセスが開いている Windows では EPERM で失敗し旧 file が残る。
最低限のトラブルシュート
ArgumentError: no APPxxx found...
FROMありクエリではAPPxxx指定が必要です。SELECT 'xxx' AS aのような式 SELECT は実行可能です。
AuthError: token is missing...
--token-map/--token-file/ config のtokenMapを確認してください。
ArgumentError: unknown field code(s)...
- フィールドコード名を確認してください(ラベル名ではなくコード)。
DML is disabled
--allow-dmlを付けて再実行してください。
@profileを使った DELETE が失敗する
- 現在
DELETEの@profileは未対応です。
- Windows で
ksql --help実行時にエディタが開いてしまう
.js関連付けの影響の可能性があります。ksql.cmd --helpまたはnode dist-cli/ksql.js --helpで確認してください。
公式 API(プログラムから使う)
npm パッケージは 2 つのサブパスを semver 対象の公開 API として提供します。 ここに載る export のシグネチャ・挙動の互換性は semver(破壊的変更=メジャー、追加=マイナー)で管理します。
| サブパス | 用途 | 主な export |
|---|---|---|
| @rex0220/kintone-sql-tools/engine | read-only のクエリ実行(ダッシュボード等)。書込 API は構造的に遮断 | runQuery / runBatch / explainQuery / createReadonlyKintoneClient / KsqlEngineError / version |
| @rex0220/kintone-sql-tools/flow | Flow dialect 1(→ 言語リファレンス §27)のスクリプト解析・検証・文単位実行(バッチランナー向け・書込可能) | parseScript / validateScript / explainScript(asOf/timezone 注入可) / createExecutionContext(onChunkWritten 書込チャンク通知・onImportSourceMaterialized IMPORT receipt) / executeStatement / previewStatement(dry-run 差分プレビュー・書込 0 回) / disposeExecutionContext / createImportSourceResolver / FlowImportProviderError / createKintoneClient / isDmlResult(FlowDmlResult 型ガード) / version |
バッチ実行ランナー kSQL Flow(/flow API を使った公式ランナー・別リポジトリ): https://github.com/rex0220/ksql-flow
/flow の典型的な使い方(1 文ずつ実行して結果で継続判断する):
import { parseScript, createExecutionContext, executeStatement, disposeExecutionContext, createKintoneClient } from "@rex0220/kintone-sql-tools/flow";
const client = createKintoneClient({ baseUrl, auth: { type: "apiToken", apiToken } });
const { statements, meta, diagnostics } = parseScript(source, { apps: { 受注: 100 } });
const ctx = createExecutionContext({ client, script: source, apps: { 受注: 100, 顧客マスタ: 200 }, asOf: new Date("2026-08-01T00:00:00+09:00"), timezone: "Asia/Tokyo" });
try {
for (const stmt of statements) {
const result = await executeStatement(stmt, ctx);
// result で ASSERT 違反 / EXIT 成立 / skipped を判別して継続を判断する
}
} finally {
await disposeExecutionContext(ctx);
}/flow から named IMPORT source を使う場合は、全APIへ enableImport: true を明示し、
pathではなくlazy loaderが返す Uint8Array を登録します。省略または false は従来どおり
KSQL1202 で拒否し、resolverを渡すだけでは有効になりません。
import {
createImportSourceResolver,
parseScript,
createExecutionContext,
} from "@rex0220/kintone-sql-tools/flow";
const capability = { enableImport: true } as const;
const importSource = createImportSourceResolver([{
name: "orders",
loader: { async load() { return { bytes, encoding: "sjis" }; } },
}]);
const parsed = parseScript(sql, capability);
const ctx = createExecutionContext({
...capability, client, statements: parsed.statements, meta: parsed.meta, importSource,
onImportSourceMaterialized(info) {
// { statementIndex, name, kind, rows, encoding }
inputFiles.push(info);
},
});source名は完全一致・case-sensitiveです。loaderは対象文の実行到達時だけ呼ばれます。
CSVの文字コードは SQL ENCODING > loader metadata > UTF-8、payload上限は10 MiBです。
path解決、通常ファイル・symlink・allowlist・hash検査、open/readは呼出側の責務であり、
engineはpathを受け取りません。providerは FlowImportProviderError でread不能または通常ファイル外を
分類でき、その他のsource境界エラーも StatementResult.error.code の安定codeで返ります。
onImportSourceMaterialized はdecode・raw materialize成功直後、projection・validation・
ON ERROR SKIP の選別・mutationより前に1回awaitされます。CSVの rows はheaderを除く
RFC 4180 data record数(subtable CSVは継続行を含む)、JSONはtop-level record数です。
CSVの encoding は上記優先順位の解決後、JSONは "utf8" です。callbackがthrow/rejectすると
当該文はerrorになり、その文のmutation APIは0回です。通知objectのkeyは
statementIndex / name / kind / rows / encoding の5つだけです。
CSV export(B179)は temp table を名前付きシンクとして事前宣言し、全文実行後に serialize します。 engine は path を持たず bytes と receipt を返すだけで、file 書込みと sha256 は呼出側の責務です:
import {
createExecutionContext, executeStatement, exportSinkStatus, serializeExportSink,
serializeSelectResultAsCsv, disposeExecutionContext,
} from "@rex0220/kintone-sql-tools/flow";
const ctx = createExecutionContext({
client, script: "CREATE TEMP TABLE #export AS SELECT code, amount FROM APP1; UPDATE APP1 SET 状態 = '済' WHERE ...",
exportSinks: [{ name: "export" }], // #export の CREATE TEMP TABLE がちょうど 1 文なければ同期 throw
});
for (const statement of statements) await executeStatement(statement, ctx); // EXIT 後の skipped も回収
if (exportSinkStatus(ctx, "export") === "materialized") { // not-created = EXIT で未生成(file を作らない)
const csv = serializeExportSink(ctx, "export", { encoding: "utf8", timezone: "Asia/Tokyo" });
// csv.data (Uint8Array) を書く/sha256 を取る。csv.receipt = { rows, columns, bytes, encoding }
}
await disposeExecutionContext(ctx);
// 単文 SELECT: serializeSelectResultAsCsv(await executeStatement(stmt, ctx))CSV は RFC 4180(CRLF・header あり・BOM なし)。複数値は LF 連結、user 系は code、SUBTABLE / FILE 列は
ExportSinkUnsupportedColumnError、計算列の指数表記は 10 進展開、DATETIME は timezone 指定時だけ offset 付き。
Shift_JIS は encoding: "sjis" と encoder: { encoding: "sjis", encode(text) } の注入で、encoder は表現不能文字で
throw する義務を負います(encoding-japanese / iconv-lite は黙って ? 置換するため、encode → decode → 完全一致検査を
wrapper で行ってください)。
読取上限は既定 10,000 件(maxRecords)です。一時テーブルの実体化には独立の tempTableMaxRows(既定 10,000 行・超過は常にエラー)が適用されるため、大きなバッチでは両方を併せて指定してください:
const ctx = createExecutionContext({ client, script: source, maxRecords: 25000, tempTableMaxRows: 25000 });
await explainScript(source, { client, maxRecords: 25000 }); // EXPLAIN 面にも同じ上限を渡せるexecuteStatement / previewStatement は実行コンテキストの maxRecords を共有します(3 面同値)。詳細は言語リファレンス §27.9。
エンジンバージョン × dialect 対応表
| エンジン | dialect 0(既定・宣言なし) | dialect 1(-- @ksql dialect: 1) | ksql-flow |
|---|---|---|---|
| 〜 v3.67.0 | ✅ | —(未実装) | — |
| v3.68.0 | ✅ | 解析のみ(エンジン内部 API。実行できる出荷面なし・実験的) | — |
| v3.69.0 〜 v3.70.0 | ✅ | ✅ CLI / MCP / プラグイン / /flow で実行可 | — |
| v3.71.0 〜 | ✅ | ✅ 同上 + previewStatement | 0.1.0(要求: ^3.71.0) |
dialect は後方互換で管理します: dialect 0 のスクリプトはどのエンジン版でも挙動不変・破壊的変更は dialect 番号の繰り上げでのみ導入します。変更履歴は CHANGELOG.md を参照してください。
機密情報の取り扱い
- token / password は直書きせず、環境変数または
env:参照を推奨します。 ksql.config.jsonはローカル運用ファイルとして.gitignore済みです。private.ppk/pluginId.txtは.gitignore済みです。
ドキュメント
- Docs Index
- 言語リファレンス
- CLI / Console 仕様
- バッチ実行・一時テーブル仕様
- MCP サーバー仕様 / Claude Desktop への導入(MCPB)
- APP@profile 仕様
- 公開前チェックリスト
ライセンス
MIT License. See LICENSE.
