@kintone/mcp-server 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +25 -13
- package/dist/{client.js → client/index.js} +4 -9
- package/dist/client/types/client.js +1 -0
- package/dist/config/command-line.js +2 -1
- package/dist/config/index.js +30 -62
- package/dist/config/parser.js +72 -0
- package/dist/config/schema.js +4 -0
- package/dist/config/types/config.js +1 -0
- package/dist/index.js +16 -6
- package/dist/lib/filesystem.js +47 -0
- package/dist/schema/app/form-layout.js +101 -0
- package/dist/schema/app/index.js +1 -0
- package/dist/schema/record/index.js +2 -0
- package/dist/schema/record/records.js +1 -1
- package/dist/server/index.js +17 -0
- package/dist/server/tool-filters.js +14 -0
- package/dist/server/types/server.js +1 -0
- package/dist/tools/factory.js +10 -0
- package/dist/tools/index.js +9 -0
- package/dist/tools/kintone/app/get-app-deploy-status.js +42 -0
- package/dist/tools/kintone/app/get-app.js +7 -8
- package/dist/tools/kintone/app/get-apps.js +7 -8
- package/dist/tools/kintone/app/get-form-fields.js +12 -8
- package/dist/tools/kintone/app/get-form-layout.js +43 -0
- package/dist/tools/kintone/app/get-general-settings.js +119 -0
- package/dist/tools/kintone/app/get-process-management.js +12 -8
- package/dist/tools/kintone/file/download-file.js +49 -0
- package/dist/tools/kintone/record/add-records.js +8 -9
- package/dist/tools/kintone/record/delete-records.js +7 -8
- package/dist/tools/kintone/record/get-records.js +8 -9
- package/dist/tools/kintone/record/update-records.js +8 -9
- package/dist/tools/kintone/record/update-statuses.js +7 -8
- package/dist/tools/types/tool.js +1 -0
- package/dist/version.js +1 -1
- package/package.json +6 -5
- package/dist/server.js +0 -20
- package/dist/tool-filters.js +0 -14
- package/dist/tools/utils.js +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.0](https://github.com/kintone/mcp-server/compare/1.0.0...1.1.0) (2025-09-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add the tool for downloading file ([#80](https://github.com/kintone/mcp-server/issues/80)) ([6cead9e](https://github.com/kintone/mcp-server/commit/6cead9ed1891a4ce0aa26978a52dd7df27e195ff))
|
|
9
|
+
* add tools for get app settings ([#114](https://github.com/kintone/mcp-server/issues/114)) ([470e755](https://github.com/kintone/mcp-server/commit/470e75555cfeef9fbf582aab504e24528c3f94cd))
|
|
10
|
+
* supports preview ([#112](https://github.com/kintone/mcp-server/issues/112)) ([3bb032e](https://github.com/kintone/mcp-server/commit/3bb032e00bd0532cac832dbdd9fc6aec1e7255d8))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **deps:** update dependency @modelcontextprotocol/sdk to ^1.17.5 ([#100](https://github.com/kintone/mcp-server/issues/100)) ([ad8ce6e](https://github.com/kintone/mcp-server/commit/ad8ce6e2557c4ccbf10f2d0895ceaebbde3d5083))
|
|
16
|
+
|
|
3
17
|
## [1.0.0](https://github.com/kintone/mcp-server/compare/0.1.0...1.0.0) (2025-08-27)
|
|
4
18
|
|
|
5
19
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
[ci-badge]: https://github.com/kintone/mcp-server/actions/workflows/ci.yaml/badge.svg
|
|
9
9
|
[ci-url]: https://github.com/kintone/mcp-server/actions/workflows/ci.yaml
|
|
10
|
-
[npm-badge]: https://badge.fury.io/js/@kintone%2Fmcp-server.svg
|
|
10
|
+
[npm-badge]: https://badge.fury.io/js/@kintone%2Fmcp-server.svg?icon=si%3Anpm
|
|
11
11
|
[npm-url]: https://badge.fury.io/js/@kintone%2Fmcp-server
|
|
12
12
|
[license-badge]: https://img.shields.io/badge/License-Apache_2.0-blue.svg
|
|
13
13
|
[license-url]: LICENSE
|
|
@@ -160,6 +160,7 @@ DXTファイルをインストールした場合、追加の手順は必要あ
|
|
|
160
160
|
| `--pfx-file-path` | `KINTONE_PFX_FILE_PATH` | PFXファイルのパス(クライアント証明書認証用) | - |
|
|
161
161
|
| `--pfx-file-password` | `KINTONE_PFX_FILE_PASSWORD` | PFXファイルのパスワード | - |
|
|
162
162
|
| `--proxy` | `HTTPS_PROXY` | HTTPSプロキシのURL(例: `http://proxy.example.com:8080`) | - |
|
|
163
|
+
| `--attachments-dir` | `KINTONE_ATTACHMENTS_DIR` | ダウンロードしたファイルの保存先 | - |
|
|
163
164
|
|
|
164
165
|
※1: `KINTONE_USERNAME` & `KINTONE_PASSWORD` または `KINTONE_API_TOKEN` のいずれかが必須
|
|
165
166
|
|
|
@@ -183,22 +184,34 @@ export HTTPS_PROXY="http://username:password@proxy.example.com:8080"
|
|
|
183
184
|
|
|
184
185
|
## ツール一覧
|
|
185
186
|
|
|
186
|
-
| ツール名 | 説明
|
|
187
|
-
| -------------------------------- |
|
|
188
|
-
| `kintone-get-apps` | 複数のアプリ情報を取得
|
|
189
|
-
| `kintone-get-app` | 単一アプリの詳細情報を取得
|
|
190
|
-
| `kintone-get-form-fields` | アプリのフィールド設定を取得
|
|
191
|
-
| `kintone-get-
|
|
192
|
-
| `kintone-get-
|
|
193
|
-
| `kintone-
|
|
194
|
-
| `kintone-
|
|
195
|
-
| `kintone-
|
|
196
|
-
| `kintone-
|
|
187
|
+
| ツール名 | 説明 |
|
|
188
|
+
| -------------------------------- | -------------------------------------- |
|
|
189
|
+
| `kintone-get-apps` | 複数のアプリ情報を取得 |
|
|
190
|
+
| `kintone-get-app` | 単一アプリの詳細情報を取得 |
|
|
191
|
+
| `kintone-get-form-fields` | アプリのフィールド設定を取得 |
|
|
192
|
+
| `kintone-get-form-layout` | アプリのフォームレイアウトを取得 |
|
|
193
|
+
| `kintone-get-process-management` | プロセス管理設定を取得 |
|
|
194
|
+
| `kintone-get-app-deploy-status` | アプリ設定の運用環境への反映状況確認 |
|
|
195
|
+
| `kintone-get-general-settings` | アプリの一般設定を取得 |
|
|
196
|
+
| `kintone-get-records` | 複数のレコードを取得 |
|
|
197
|
+
| `kintone-add-records` | 複数のレコードを追加 |
|
|
198
|
+
| `kintone-update-records` | 複数のレコードを更新 |
|
|
199
|
+
| `kintone-delete-records` | 複数のレコードを削除 |
|
|
200
|
+
| `kintone-update-statuses` | 複数のレコードのステータスを更新 |
|
|
201
|
+
| `kintone-download-file` | 添付ファイルフィールドのファイルを保存 |
|
|
197
202
|
|
|
198
203
|
## ドキュメント
|
|
199
204
|
|
|
200
205
|
- [認証設定ガイド](./docs/ja/authentication.md) - 認証方法の詳細と設定例
|
|
201
206
|
|
|
207
|
+
## 使用上の注意
|
|
208
|
+
|
|
209
|
+
### `kintone-download-file`ツールの注意点
|
|
210
|
+
|
|
211
|
+
- ダウンロードしたファイルは、`--attachments-dir`または`KINTONE_ATTACHMENTS_DIR`で指定したディレクトリに保存されます。
|
|
212
|
+
- `--attachments-dir`または`KINTONE_ATTACHMENTS_DIR`を指定しない場合はツール実行時にエラーになります。
|
|
213
|
+
- `--attachments-dir`または`KINTONE_ATTACHMENTS_DIR`に存在しないディレクトリを指定した場合は、ディレクトリを新規作成してからそこに保存されます。
|
|
214
|
+
|
|
202
215
|
## 制限事項
|
|
203
216
|
|
|
204
217
|
### レコード操作の制限
|
|
@@ -209,7 +222,6 @@ export HTTPS_PROXY="http://username:password@proxy.example.com:8080"
|
|
|
209
222
|
### その他の制限
|
|
210
223
|
|
|
211
224
|
- **ゲストスペースに非対応**: ゲストスペース内のアプリにはアクセスできません
|
|
212
|
-
- **動作テスト環境に非対応**: アプリの動作テスト環境(アプリ設定を本番環境に反映する前に検証できる環境)は利用できません
|
|
213
225
|
|
|
214
226
|
## サポート方針
|
|
215
227
|
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { KintoneRestAPIClient } from "@kintone/rest-api-client";
|
|
2
|
-
import { PACKAGE_NAME, } from "./config/index.js";
|
|
3
2
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
4
3
|
import { Agent } from "https";
|
|
5
4
|
import { readFileSync } from "fs";
|
|
6
|
-
import { version } from "./version.js";
|
|
7
5
|
let client = null;
|
|
8
6
|
export const getKintoneClient = (config) => {
|
|
9
7
|
if (client) {
|
|
10
8
|
return client;
|
|
11
9
|
}
|
|
12
|
-
const { KINTONE_BASE_URL, KINTONE_USERNAME, KINTONE_PASSWORD, KINTONE_API_TOKEN, KINTONE_BASIC_AUTH_USERNAME, KINTONE_BASIC_AUTH_PASSWORD, HTTPS_PROXY, KINTONE_PFX_FILE_PATH, KINTONE_PFX_FILE_PASSWORD, } = config
|
|
10
|
+
const { KINTONE_BASE_URL, KINTONE_USERNAME, KINTONE_PASSWORD, KINTONE_API_TOKEN, KINTONE_BASIC_AUTH_USERNAME, KINTONE_BASIC_AUTH_PASSWORD, HTTPS_PROXY, KINTONE_PFX_FILE_PATH, KINTONE_PFX_FILE_PASSWORD, USER_AGENT, } = config;
|
|
13
11
|
const authParams = buildAuthParams({
|
|
14
12
|
username: KINTONE_USERNAME,
|
|
15
13
|
password: KINTONE_PASSWORD,
|
|
16
14
|
apiToken: KINTONE_API_TOKEN,
|
|
17
|
-
isApiTokenAuth: config.isApiTokenAuth,
|
|
18
15
|
});
|
|
19
16
|
client = new KintoneRestAPIClient({
|
|
20
17
|
baseUrl: KINTONE_BASE_URL,
|
|
@@ -23,7 +20,7 @@ export const getKintoneClient = (config) => {
|
|
|
23
20
|
basicAuthUsername: KINTONE_BASIC_AUTH_USERNAME,
|
|
24
21
|
basicAuthPassword: KINTONE_BASIC_AUTH_PASSWORD,
|
|
25
22
|
}),
|
|
26
|
-
userAgent:
|
|
23
|
+
userAgent: USER_AGENT,
|
|
27
24
|
httpsAgent: buildHttpsAgent({
|
|
28
25
|
proxy: HTTPS_PROXY,
|
|
29
26
|
pfxFilePath: KINTONE_PFX_FILE_PATH,
|
|
@@ -32,11 +29,9 @@ export const getKintoneClient = (config) => {
|
|
|
32
29
|
});
|
|
33
30
|
return client;
|
|
34
31
|
};
|
|
35
|
-
export const resetKintoneClient = () => {
|
|
36
|
-
client = null;
|
|
37
|
-
};
|
|
38
32
|
const buildAuthParams = (option) => {
|
|
39
|
-
|
|
33
|
+
const isApiTokenAuth = !(option.username && option.password) && !!option.apiToken;
|
|
34
|
+
return isApiTokenAuth
|
|
40
35
|
? { auth: { apiToken: option.apiToken } }
|
|
41
36
|
: { auth: { username: option.username, password: option.password } };
|
|
42
37
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -5,7 +5,7 @@ import { parseArgs } from "node:util";
|
|
|
5
5
|
* (process.argv[0]はnode、[1]はスクリプトパスなので除外されます)
|
|
6
6
|
* @param args process.argv で取得した値
|
|
7
7
|
*/
|
|
8
|
-
export const
|
|
8
|
+
export const parse = (args) => {
|
|
9
9
|
const { values } = parseArgs({
|
|
10
10
|
args: args.slice(2), // process.argv[0]はnode、[1]はスクリプトパスなので除外
|
|
11
11
|
allowPositionals: true,
|
|
@@ -19,6 +19,7 @@ export const parseCommandLineOptions = (args) => {
|
|
|
19
19
|
"pfx-file-path": { type: "string" },
|
|
20
20
|
"pfx-file-password": { type: "string" },
|
|
21
21
|
proxy: { type: "string" },
|
|
22
|
+
"attachments-dir": { type: "string" },
|
|
22
23
|
},
|
|
23
24
|
});
|
|
24
25
|
return values;
|
package/dist/config/index.js
CHANGED
|
@@ -1,66 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export const
|
|
6
|
-
// 同等の変数の指定があればコマンドライン引数を優先
|
|
1
|
+
import { version } from "../version.js";
|
|
2
|
+
import { parseKintoneMcpServerConfig } from "./parser.js";
|
|
3
|
+
import { PACKAGE_NAME } from "./schema.js";
|
|
4
|
+
const config = parseKintoneMcpServerConfig();
|
|
5
|
+
export const getMcpServerConfig = () => {
|
|
7
6
|
return {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
KINTONE_PASSWORD: args.password ?? env.KINTONE_PASSWORD,
|
|
11
|
-
KINTONE_API_TOKEN: args["api-token"] ?? env.KINTONE_API_TOKEN,
|
|
12
|
-
KINTONE_BASIC_AUTH_USERNAME: args["basic-auth-username"] ?? env.KINTONE_BASIC_AUTH_USERNAME,
|
|
13
|
-
KINTONE_BASIC_AUTH_PASSWORD: args["basic-auth-password"] ?? env.KINTONE_BASIC_AUTH_PASSWORD,
|
|
14
|
-
KINTONE_PFX_FILE_PATH: args["pfx-file-path"] ?? env.KINTONE_PFX_FILE_PATH,
|
|
15
|
-
KINTONE_PFX_FILE_PASSWORD: args["pfx-file-password"] ?? env.KINTONE_PFX_FILE_PASSWORD,
|
|
16
|
-
HTTPS_PROXY: args.proxy ?? env.HTTPS_PROXY ?? env.https_proxy,
|
|
7
|
+
name: PACKAGE_NAME,
|
|
8
|
+
version: version,
|
|
17
9
|
};
|
|
18
10
|
};
|
|
19
|
-
export const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
if (errors.KINTONE_API_TOKEN?._errors.length) {
|
|
44
|
-
errorMessages.push(`KINTONE_API_TOKEN: ${errors.KINTONE_API_TOKEN._errors.join(", ")}`);
|
|
45
|
-
}
|
|
46
|
-
if (errors.HTTPS_PROXY?._errors.length) {
|
|
47
|
-
errorMessages.push(`HTTPS_PROXY: ${errors.HTTPS_PROXY._errors.join(", ")}`);
|
|
48
|
-
}
|
|
49
|
-
if (errors.KINTONE_PFX_FILE_PATH?._errors.length) {
|
|
50
|
-
errorMessages.push(`KINTONE_PFX_FILE_PATH: ${errors.KINTONE_PFX_FILE_PATH._errors.join(", ")}`);
|
|
51
|
-
}
|
|
52
|
-
if (errors.KINTONE_PFX_FILE_PASSWORD?._errors.length) {
|
|
53
|
-
errorMessages.push(`KINTONE_PFX_FILE_PASSWORD: ${errors.KINTONE_PFX_FILE_PASSWORD._errors.join(", ")}`);
|
|
54
|
-
}
|
|
55
|
-
if (errors.KINTONE_BASIC_AUTH_USERNAME?._errors.length) {
|
|
56
|
-
errorMessages.push(`KINTONE_BASIC_AUTH_USERNAME: ${errors.KINTONE_BASIC_AUTH_USERNAME._errors.join(", ")}`);
|
|
57
|
-
}
|
|
58
|
-
if (errors.KINTONE_BASIC_AUTH_PASSWORD?._errors.length) {
|
|
59
|
-
errorMessages.push(`KINTONE_BASIC_AUTH_PASSWORD: ${errors.KINTONE_BASIC_AUTH_PASSWORD._errors.join(", ")}`);
|
|
60
|
-
}
|
|
61
|
-
// Handle cross-field validation errors
|
|
62
|
-
if (errors._errors?.length) {
|
|
63
|
-
errorMessages.push(...errors._errors);
|
|
64
|
-
}
|
|
65
|
-
throw new Error(`Environment variables are missing or invalid:\n${errorMessages.join("\n")}`);
|
|
11
|
+
export const getKintoneClientConfig = () => {
|
|
12
|
+
return {
|
|
13
|
+
KINTONE_BASE_URL: config.config.KINTONE_BASE_URL,
|
|
14
|
+
KINTONE_USERNAME: config.config.KINTONE_USERNAME,
|
|
15
|
+
KINTONE_PASSWORD: config.config.KINTONE_PASSWORD,
|
|
16
|
+
KINTONE_API_TOKEN: config.config.KINTONE_API_TOKEN,
|
|
17
|
+
KINTONE_BASIC_AUTH_USERNAME: config.config.KINTONE_BASIC_AUTH_USERNAME,
|
|
18
|
+
KINTONE_BASIC_AUTH_PASSWORD: config.config.KINTONE_BASIC_AUTH_PASSWORD,
|
|
19
|
+
HTTPS_PROXY: config.config.HTTPS_PROXY,
|
|
20
|
+
KINTONE_PFX_FILE_PATH: config.config.KINTONE_PFX_FILE_PATH,
|
|
21
|
+
KINTONE_PFX_FILE_PASSWORD: config.config.KINTONE_PFX_FILE_PASSWORD,
|
|
22
|
+
USER_AGENT: config.userAgent,
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export const getToolConditionConfig = () => {
|
|
26
|
+
return {
|
|
27
|
+
isApiTokenAuth: config.isApiTokenAuth,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export const getFileConfig = () => {
|
|
31
|
+
return {
|
|
32
|
+
attachmentsDir: config.config.KINTONE_ATTACHMENTS_DIR,
|
|
33
|
+
};
|
|
66
34
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { parse } from "./command-line.js";
|
|
2
|
+
import { PACKAGE_NAME, configSchema } from "./schema.js";
|
|
3
|
+
import { version } from "../version.js";
|
|
4
|
+
export const parseKintoneMcpServerConfig = () => {
|
|
5
|
+
const cmdArgs = parse(process.argv);
|
|
6
|
+
const mergedConfig = merge(process.env, cmdArgs);
|
|
7
|
+
const result = configSchema.safeParse(mergedConfig);
|
|
8
|
+
if (result.success) {
|
|
9
|
+
const data = result.data;
|
|
10
|
+
const isApiTokenAuth = !(data.KINTONE_USERNAME && data.KINTONE_PASSWORD) &&
|
|
11
|
+
!!data.KINTONE_API_TOKEN;
|
|
12
|
+
return {
|
|
13
|
+
config: data,
|
|
14
|
+
userAgent: `${PACKAGE_NAME}@${version}`,
|
|
15
|
+
isApiTokenAuth,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const errorMessages = createErrorMessage(result.error.format());
|
|
19
|
+
throw new Error(`Environment variables are missing or invalid:\n${errorMessages.join("\n")}`);
|
|
20
|
+
};
|
|
21
|
+
export const merge = (env, args) => {
|
|
22
|
+
return {
|
|
23
|
+
KINTONE_BASE_URL: args["base-url"] ?? env.KINTONE_BASE_URL,
|
|
24
|
+
KINTONE_USERNAME: args.username ?? env.KINTONE_USERNAME,
|
|
25
|
+
KINTONE_PASSWORD: args.password ?? env.KINTONE_PASSWORD,
|
|
26
|
+
KINTONE_API_TOKEN: args["api-token"] ?? env.KINTONE_API_TOKEN,
|
|
27
|
+
KINTONE_BASIC_AUTH_USERNAME: args["basic-auth-username"] ?? env.KINTONE_BASIC_AUTH_USERNAME,
|
|
28
|
+
KINTONE_BASIC_AUTH_PASSWORD: args["basic-auth-password"] ?? env.KINTONE_BASIC_AUTH_PASSWORD,
|
|
29
|
+
KINTONE_PFX_FILE_PATH: args["pfx-file-path"] ?? env.KINTONE_PFX_FILE_PATH,
|
|
30
|
+
KINTONE_PFX_FILE_PASSWORD: args["pfx-file-password"] ?? env.KINTONE_PFX_FILE_PASSWORD,
|
|
31
|
+
HTTPS_PROXY: args.proxy ?? env.HTTPS_PROXY ?? env.https_proxy,
|
|
32
|
+
KINTONE_ATTACHMENTS_DIR: args["attachments-dir"] ?? env.KINTONE_ATTACHMENTS_DIR,
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const createErrorMessage = (errors) => {
|
|
36
|
+
const errorMessages = [];
|
|
37
|
+
if (errors.KINTONE_BASE_URL?._errors.length) {
|
|
38
|
+
errorMessages.push(`KINTONE_BASE_URL: ${errors.KINTONE_BASE_URL._errors.join(", ")}`);
|
|
39
|
+
}
|
|
40
|
+
if (errors.KINTONE_USERNAME?._errors.length) {
|
|
41
|
+
errorMessages.push(`KINTONE_USERNAME: ${errors.KINTONE_USERNAME._errors.join(", ")}`);
|
|
42
|
+
}
|
|
43
|
+
if (errors.KINTONE_PASSWORD?._errors.length) {
|
|
44
|
+
errorMessages.push(`KINTONE_PASSWORD: ${errors.KINTONE_PASSWORD._errors.join(", ")}`);
|
|
45
|
+
}
|
|
46
|
+
if (errors.KINTONE_API_TOKEN?._errors.length) {
|
|
47
|
+
errorMessages.push(`KINTONE_API_TOKEN: ${errors.KINTONE_API_TOKEN._errors.join(", ")}`);
|
|
48
|
+
}
|
|
49
|
+
if (errors.HTTPS_PROXY?._errors.length) {
|
|
50
|
+
errorMessages.push(`HTTPS_PROXY: ${errors.HTTPS_PROXY._errors.join(", ")}`);
|
|
51
|
+
}
|
|
52
|
+
if (errors.KINTONE_PFX_FILE_PATH?._errors.length) {
|
|
53
|
+
errorMessages.push(`KINTONE_PFX_FILE_PATH: ${errors.KINTONE_PFX_FILE_PATH._errors.join(", ")}`);
|
|
54
|
+
}
|
|
55
|
+
if (errors.KINTONE_PFX_FILE_PASSWORD?._errors.length) {
|
|
56
|
+
errorMessages.push(`KINTONE_PFX_FILE_PASSWORD: ${errors.KINTONE_PFX_FILE_PASSWORD._errors.join(", ")}`);
|
|
57
|
+
}
|
|
58
|
+
if (errors.KINTONE_BASIC_AUTH_USERNAME?._errors.length) {
|
|
59
|
+
errorMessages.push(`KINTONE_BASIC_AUTH_USERNAME: ${errors.KINTONE_BASIC_AUTH_USERNAME._errors.join(", ")}`);
|
|
60
|
+
}
|
|
61
|
+
if (errors.KINTONE_BASIC_AUTH_PASSWORD?._errors.length) {
|
|
62
|
+
errorMessages.push(`KINTONE_BASIC_AUTH_PASSWORD: ${errors.KINTONE_BASIC_AUTH_PASSWORD._errors.join(", ")}`);
|
|
63
|
+
}
|
|
64
|
+
if (errors.KINTONE_ATTACHMENTS_DIR?._errors.length) {
|
|
65
|
+
errorMessages.push(`KINTONE_ATTACHMENTS_DIR: ${errors.KINTONE_ATTACHMENTS_DIR._errors.join(", ")}`);
|
|
66
|
+
}
|
|
67
|
+
// Handle cross-field validation errors
|
|
68
|
+
if (errors._errors?.length) {
|
|
69
|
+
errorMessages.push(...errors._errors.map(String));
|
|
70
|
+
}
|
|
71
|
+
return errorMessages;
|
|
72
|
+
};
|
package/dist/config/schema.js
CHANGED
|
@@ -50,6 +50,10 @@ export const configSchema = z
|
|
|
50
50
|
.string()
|
|
51
51
|
.optional()
|
|
52
52
|
.describe("Password for PFX client certificate file"),
|
|
53
|
+
KINTONE_ATTACHMENTS_DIR: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe("Directory path for downloading files from kintone"),
|
|
53
57
|
})
|
|
54
58
|
.refine((data) => {
|
|
55
59
|
// Either username/password or API token must be provided
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
-
import { createServer } from "./server.js";
|
|
4
|
-
import {
|
|
5
|
-
import { getKintoneClient } from "./client.js";
|
|
3
|
+
import { createServer } from "./server/index.js";
|
|
4
|
+
import { getFileConfig, getKintoneClientConfig, getMcpServerConfig, getToolConditionConfig, } from "./config/index.js";
|
|
6
5
|
const main = async () => {
|
|
7
6
|
const transport = new StdioServerTransport();
|
|
8
7
|
console.error("Starting server...");
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const
|
|
8
|
+
const mcpServerConfig = getMcpServerConfig();
|
|
9
|
+
const clientConfig = getKintoneClientConfig();
|
|
10
|
+
const fileConfig = getFileConfig();
|
|
11
|
+
const toolConditionConfig = getToolConditionConfig();
|
|
12
|
+
const serverConfig = {
|
|
13
|
+
name: mcpServerConfig.name,
|
|
14
|
+
version: mcpServerConfig.version,
|
|
15
|
+
config: {
|
|
16
|
+
clientConfig,
|
|
17
|
+
fileConfig,
|
|
18
|
+
toolConditionConfig,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const server = createServer(serverConfig);
|
|
12
22
|
await server.connect(transport);
|
|
13
23
|
};
|
|
14
24
|
main().catch(console.error);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { fileTypeFromBuffer } from "file-type";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
export const generateFileName = (fileName, ext) => {
|
|
5
|
+
const extWithDot = ext ? `.${ext}` : "";
|
|
6
|
+
return `${replaceSpecialCharacters(fileName)}${extWithDot}`;
|
|
7
|
+
};
|
|
8
|
+
export const generateFilePath = (downloadDir, filename) => {
|
|
9
|
+
const filePath = path.join(downloadDir, filename);
|
|
10
|
+
return filePath;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Replace special characters in filename for Windows compatibility
|
|
14
|
+
*/
|
|
15
|
+
const replaceSpecialCharacters = (filename) => {
|
|
16
|
+
// Windows forbidden characters: < > : " | ? * \ /
|
|
17
|
+
return filename.replace(/[<>:"|?*\\/]/g, "_");
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Ensure directory exists, create if it doesn't
|
|
21
|
+
*/
|
|
22
|
+
export const ensureDirectoryExists = (dirPath) => {
|
|
23
|
+
if (!fs.existsSync(dirPath)) {
|
|
24
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export const writeFileSyncWithoutOverwrite = (filePath, arrayBuffer) => {
|
|
28
|
+
const buffer = Buffer.from(arrayBuffer);
|
|
29
|
+
const uniqueFilePath = generateUniqueLocalFilePath(filePath);
|
|
30
|
+
fs.writeFileSync(uniqueFilePath, buffer);
|
|
31
|
+
};
|
|
32
|
+
export const getFileTypeFromArrayBuffer = async (arrayBuffer) => {
|
|
33
|
+
return fileTypeFromBuffer(arrayBuffer);
|
|
34
|
+
};
|
|
35
|
+
const generateUniqueLocalFilePath = (filePath) => {
|
|
36
|
+
const internal = (index) => {
|
|
37
|
+
const newFileName = index === 0
|
|
38
|
+
? path.basename(filePath)
|
|
39
|
+
: `${path.basename(filePath, path.extname(filePath))} (${index})${path.extname(filePath)}`;
|
|
40
|
+
const newFilePath = path.join(path.dirname(filePath), newFileName);
|
|
41
|
+
if (fs.existsSync(newFilePath)) {
|
|
42
|
+
return internal(index + 1);
|
|
43
|
+
}
|
|
44
|
+
return newFilePath;
|
|
45
|
+
};
|
|
46
|
+
return internal(0);
|
|
47
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// All field types that have a 'code' property
|
|
3
|
+
const fieldTypesWithCode = z.union([
|
|
4
|
+
z.literal("SINGLE_LINE_TEXT").describe("文字列(1行)"),
|
|
5
|
+
z.literal("MULTI_LINE_TEXT").describe("文字列(複数行)"),
|
|
6
|
+
z.literal("NUMBER").describe("数値"),
|
|
7
|
+
z.literal("CALC").describe("計算"),
|
|
8
|
+
z.literal("CHECK_BOX").describe("チェックボックス"),
|
|
9
|
+
z.literal("RADIO_BUTTON").describe("ラジオボタン"),
|
|
10
|
+
z.literal("DROP_DOWN").describe("ドロップダウン"),
|
|
11
|
+
z.literal("MULTI_SELECT").describe("複数選択"),
|
|
12
|
+
z.literal("LINK").describe("リンク"),
|
|
13
|
+
z.literal("DATE").describe("日付"),
|
|
14
|
+
z.literal("TIME").describe("時刻"),
|
|
15
|
+
z.literal("DATETIME").describe("日時"),
|
|
16
|
+
z.literal("FILE").describe("添付ファイル"),
|
|
17
|
+
z.literal("USER_SELECT").describe("ユーザー選択"),
|
|
18
|
+
z.literal("ORGANIZATION_SELECT").describe("組織選択"),
|
|
19
|
+
z.literal("GROUP_SELECT").describe("グループ選択"),
|
|
20
|
+
z.literal("RICH_TEXT").describe("リッチエディター"),
|
|
21
|
+
z.literal("RECORD_NUMBER").describe("レコード番号"),
|
|
22
|
+
z.literal("CREATOR").describe("作成者"),
|
|
23
|
+
z.literal("CREATED_TIME").describe("作成日時"),
|
|
24
|
+
z.literal("MODIFIER").describe("更新者"),
|
|
25
|
+
z.literal("UPDATED_TIME").describe("更新日時"),
|
|
26
|
+
z.literal("REFERENCE_TABLE").describe("関連レコード一覧"),
|
|
27
|
+
]);
|
|
28
|
+
// Standard field with code
|
|
29
|
+
const standardFieldSchema = z.object({
|
|
30
|
+
type: fieldTypesWithCode.describe("The field type"),
|
|
31
|
+
code: z.string().describe("The field code"),
|
|
32
|
+
size: z
|
|
33
|
+
.object({
|
|
34
|
+
width: z.string().describe("Field width"),
|
|
35
|
+
height: z.string().optional().describe("Field height"),
|
|
36
|
+
innerHeight: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Inner height for multi-line text"),
|
|
40
|
+
})
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Field size configuration"),
|
|
43
|
+
});
|
|
44
|
+
// LABEL field with label property instead of code
|
|
45
|
+
const labelFieldSchema = z.object({
|
|
46
|
+
type: z.literal("LABEL").describe("Label field type"),
|
|
47
|
+
label: z.string().describe("The label text"),
|
|
48
|
+
size: z
|
|
49
|
+
.object({
|
|
50
|
+
width: z.string().describe("Field width"),
|
|
51
|
+
})
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Field size configuration"),
|
|
54
|
+
});
|
|
55
|
+
// SPACER field with elementId instead of code
|
|
56
|
+
const spacerFieldSchema = z.object({
|
|
57
|
+
type: z.literal("SPACER").describe("Spacer field type"),
|
|
58
|
+
elementId: z.string().describe("The element ID"),
|
|
59
|
+
size: z
|
|
60
|
+
.object({
|
|
61
|
+
width: z.string().describe("Field width"),
|
|
62
|
+
height: z.string().optional().describe("Field height"),
|
|
63
|
+
})
|
|
64
|
+
.optional()
|
|
65
|
+
.describe("Field size configuration"),
|
|
66
|
+
});
|
|
67
|
+
// HR field without code
|
|
68
|
+
const hrFieldSchema = z.object({
|
|
69
|
+
type: z.literal("HR").describe("Horizontal rule field type"),
|
|
70
|
+
size: z
|
|
71
|
+
.object({
|
|
72
|
+
width: z.string().describe("Field width"),
|
|
73
|
+
})
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Field size configuration"),
|
|
76
|
+
});
|
|
77
|
+
const layoutFieldSchema = z.union([
|
|
78
|
+
standardFieldSchema,
|
|
79
|
+
labelFieldSchema,
|
|
80
|
+
spacerFieldSchema,
|
|
81
|
+
hrFieldSchema,
|
|
82
|
+
]);
|
|
83
|
+
const layoutRowSchema = z.object({
|
|
84
|
+
type: z.literal("ROW").describe("Row type identifier"),
|
|
85
|
+
fields: z.array(layoutFieldSchema).describe("Array of fields in this row"),
|
|
86
|
+
});
|
|
87
|
+
const layoutSubtableSchema = z.object({
|
|
88
|
+
type: z.literal("SUBTABLE").describe("Subtable type identifier"),
|
|
89
|
+
code: z.string().describe("Subtable field code"),
|
|
90
|
+
fields: z
|
|
91
|
+
.array(layoutFieldSchema)
|
|
92
|
+
.describe("Array of fields in this subtable"),
|
|
93
|
+
});
|
|
94
|
+
export const layoutElementSchema = z.lazy(() => z.union([layoutRowSchema, layoutSubtableSchema, layoutGroupSchema]));
|
|
95
|
+
const layoutGroupSchema = z.object({
|
|
96
|
+
type: z.literal("GROUP").describe("Group type identifier"),
|
|
97
|
+
code: z.string().describe("Group field code"),
|
|
98
|
+
layout: z
|
|
99
|
+
.array(layoutElementSchema)
|
|
100
|
+
.describe("Nested layout elements within this group"),
|
|
101
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { layoutElementSchema } from "./form-layout.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { shouldEnableTool } from "./tool-filters.js";
|
|
3
|
+
import { getKintoneClient } from "../client/index.js";
|
|
4
|
+
import { createToolCallback, tools } from "../tools/index.js";
|
|
5
|
+
export const createServer = (options) => {
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: options.name,
|
|
8
|
+
version: options.version,
|
|
9
|
+
});
|
|
10
|
+
const client = getKintoneClient(options.config.clientConfig);
|
|
11
|
+
const toolCondition = options.config.toolConditionConfig;
|
|
12
|
+
const attachmentsDir = options.config.fileConfig.attachmentsDir;
|
|
13
|
+
tools
|
|
14
|
+
.filter((tool) => shouldEnableTool(tool.name, toolCondition))
|
|
15
|
+
.forEach((tool) => server.registerTool(tool.name, tool.config, createToolCallback(tool.callback, { client, attachmentsDir })));
|
|
16
|
+
return server;
|
|
17
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const filterRules = [
|
|
2
|
+
{
|
|
3
|
+
condition: (condition) => condition.isApiTokenAuth,
|
|
4
|
+
excludeTools: ["kintone-get-apps"],
|
|
5
|
+
},
|
|
6
|
+
];
|
|
7
|
+
export function shouldEnableTool(toolName, condition) {
|
|
8
|
+
for (const rule of filterRules) {
|
|
9
|
+
if (rule.condition(condition) && rule.excludeTools.includes(toolName)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tools/index.js
CHANGED
|
@@ -5,16 +5,25 @@ import { updateRecords } from "./kintone/record/update-records.js";
|
|
|
5
5
|
import { getApp } from "./kintone/app/get-app.js";
|
|
6
6
|
import { getApps } from "./kintone/app/get-apps.js";
|
|
7
7
|
import { getFormFields } from "./kintone/app/get-form-fields.js";
|
|
8
|
+
import { getFormLayout } from "./kintone/app/get-form-layout.js";
|
|
8
9
|
import { getProcessManagement } from "./kintone/app/get-process-management.js";
|
|
10
|
+
import { getAppDeployStatus } from "./kintone/app/get-app-deploy-status.js";
|
|
11
|
+
import { getGeneralSettings } from "./kintone/app/get-general-settings.js";
|
|
9
12
|
import { updateStatuses } from "./kintone/record/update-statuses.js";
|
|
13
|
+
import { downloadFile } from "./kintone/file/download-file.js";
|
|
14
|
+
export { createToolCallback } from "./factory.js";
|
|
10
15
|
export const tools = [
|
|
11
16
|
getApp,
|
|
12
17
|
getApps,
|
|
13
18
|
getFormFields,
|
|
19
|
+
getFormLayout,
|
|
14
20
|
getProcessManagement,
|
|
21
|
+
getAppDeployStatus,
|
|
22
|
+
getGeneralSettings,
|
|
15
23
|
updateStatuses,
|
|
16
24
|
addRecords,
|
|
17
25
|
deleteRecords,
|
|
18
26
|
getRecords,
|
|
19
27
|
updateRecords,
|
|
28
|
+
downloadFile,
|
|
20
29
|
];
|