bizgate-mcp-server 0.3.0 → 0.3.3
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/README.md +71 -76
- package/dist/bizgate-client.d.ts +4 -4
- package/dist/bizgate-client.js +64 -69
- package/dist/index.js +43 -58
- package/dist/install-skill.d.ts +2 -0
- package/dist/install-skill.js +107 -0
- package/dist/usage-tracker.d.ts +4 -0
- package/dist/usage-tracker.js +13 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ Claude に話しかけるだけで、企業の担当者名・電話番号・住
|
|
|
33
33
|
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
## セットアップ(所要時間:約
|
|
36
|
+
## セットアップ(所要時間:約3分)
|
|
37
37
|
|
|
38
38
|
### 事前に必要なもの
|
|
39
39
|
|
|
@@ -54,90 +54,43 @@ Mac の場合:
|
|
|
54
54
|
|
|
55
55
|
---
|
|
56
56
|
|
|
57
|
-
### ステップ 2
|
|
57
|
+
### ステップ 2:インストールスクリプトを実行する
|
|
58
58
|
|
|
59
59
|
ターミナルに以下を **そのままコピーして貼り付け** → Enter を押してください。
|
|
60
60
|
|
|
61
|
-
```
|
|
62
|
-
claude mcp add --scope user
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
ファイルの中から `"bizgate"` というセクションを探してください。
|
|
83
|
-
以下のように **書き換え** ます。
|
|
84
|
-
|
|
85
|
-
#### 書き換え前
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
"bizgate": {
|
|
89
|
-
"type": "stdio",
|
|
90
|
-
"command": "npx",
|
|
91
|
-
"args": ["bizgate-mcp-server"],
|
|
92
|
-
"env": {}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
#### 書き換え後
|
|
97
|
-
|
|
98
|
-
```json
|
|
99
|
-
"bizgate": {
|
|
100
|
-
"type": "stdio",
|
|
101
|
-
"command": "npx",
|
|
102
|
-
"args": ["bizgate-mcp-server"],
|
|
103
|
-
"env": {
|
|
104
|
-
"BIZGATE_USERNAME": "ここにユーザー名を入力",
|
|
105
|
-
"BIZGATE_PASSWORD": "ここにパスワードを入力",
|
|
106
|
-
"BIZGATE_AUTH_MODE": "basic",
|
|
107
|
-
"BIZGATE_DAILY_LIMIT": "200",
|
|
108
|
-
"BIZGATE_SKEY_COMPANY": "ここに企業APIキーを入力",
|
|
109
|
-
"BIZGATE_SKEY_DEPARTMENT": "ここに部署APIキーを入力",
|
|
110
|
-
"BIZGATE_SKEY_MARKETING": "ここにマーケAPIキーを入力",
|
|
111
|
-
"BIZGATE_SKEY_KEYMAN": "ここにキーマン(人名なし)APIキーを入力",
|
|
112
|
-
"BIZGATE_SKEY_KEYMAN_NAME": "ここにキーマン(人名あり)APIキーを入力"
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
> **注意(よくあるミス)**
|
|
118
|
-
> - `ここに〇〇を入力` の部分を、管理者から受け取った **実際の値** に置き換えてください
|
|
119
|
-
> - ダブルクォーテーション `"` は **消さないで** ください
|
|
120
|
-
> - カンマ `,` の位置を **変えないで** ください
|
|
121
|
-
> - 最後の行(`"BIZGATE_SKEY_KEYMAN_NAME"` の行)の末尾には **カンマをつけないで** ください
|
|
122
|
-
> - 編集後、`Command + S` で保存 → ファイルを閉じる
|
|
61
|
+
```smalltalk
|
|
62
|
+
claude mcp add bizgate --scope user \
|
|
63
|
+
-e "BIZGATE_USERNAME=digi-man_bizg1" \
|
|
64
|
+
-e "BIZGATE_PASSWORD=digi-man_bizg1" \
|
|
65
|
+
-e "BIZGATE_AUTH_MODE=basic" \
|
|
66
|
+
-e "BIZGATE_DAILY_LIMIT=200" \
|
|
67
|
+
-e "BIZGATE_SKEY_COMPANY=/EhMJ9YMCJtJgo73.DjLuew8rnnTlb.F6/MuiESFXmZwlCKvG8bMm" \
|
|
68
|
+
-e "BIZGATE_SKEY_DEPARTMENT=i08d/E8OwOtb2L0cdzbh1.Y5LvlTwpvZ49o3rBFVOnzRL7lDvR4Om" \
|
|
69
|
+
-e "BIZGATE_SKEY_MARKETING=X96mHxuTt4RExyo94/eGIOJwsFKr6aVlYQ80UozjTZaUVf9t/1CDu" \
|
|
70
|
+
-e "BIZGATE_SKEY_KEYMAN=3Rc3.RMt53yzVJ5zv28bjOIZVx8KjfIfo2PiCryGtF81feOv3hPZ." \
|
|
71
|
+
-e "BIZGATE_SKEY_KEYMAN_NAME=qT42YqynPg0uhPoGvquwbOUAYCotYSzxHhwiCHG5gZbTFMk75waAG" \
|
|
72
|
+
-- npx bizgate-mcp-server
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
- サービスキーを誤って入力した場合
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
claude mcp remove bizgate -s user
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
その後、再度入力してください。
|
|
123
82
|
|
|
124
83
|
---
|
|
125
84
|
|
|
126
|
-
### ステップ
|
|
127
|
-
|
|
128
|
-
もし Claude Code が開いている場合は、一度閉じてください。
|
|
85
|
+
### ステップ 3:Claude Code で接続を確認する
|
|
129
86
|
|
|
130
|
-
|
|
87
|
+
Claude Code を起動(またはすでに開いていれば再起動)してください。
|
|
131
88
|
|
|
132
89
|
```
|
|
133
90
|
claude
|
|
134
91
|
```
|
|
135
92
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
### ステップ 5:接続を確認する
|
|
139
|
-
|
|
140
|
-
Claude Code が起動したら、以下を入力してください。
|
|
93
|
+
起動したら、以下を入力してください。
|
|
141
94
|
|
|
142
95
|
```
|
|
143
96
|
/mcp
|
|
@@ -165,6 +118,33 @@ Claude Code が起動したら、以下を入力してください。
|
|
|
165
118
|
| 採用活動をしている会社か確認 | 「○○のマーケティングタグを教えて」 |
|
|
166
119
|
| 全情報をまとめて見たい | 「○○の全情報を調べて」 |
|
|
167
120
|
| Excelに入力したい | 「○○の情報を調べてExcelに入れて」 |
|
|
121
|
+
| DigiManのサービスに合う部署を探したい | 「○○にDigiManのサービスが売れそうな部署を探して」 |
|
|
122
|
+
|
|
123
|
+
### prospect-match スキル(部署マッチング)
|
|
124
|
+
|
|
125
|
+
企業の部署一覧から、DigiManの各サービス(営業代行・Solution・AI)に適した営業ターゲット部署を自動で提案するスキルです。
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
/prospect-match 兼松株式会社
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
または自然言語でもOK:
|
|
132
|
+
```
|
|
133
|
+
「兼松株式会社にDigiManのサービスが売れそうな部署を探して」
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**出力内容:**
|
|
137
|
+
- サービスごとの推薦部署(最大5件ずつ)+ 電話番号
|
|
138
|
+
- マッチ理由
|
|
139
|
+
- 最優先アプローチ先
|
|
140
|
+
|
|
141
|
+
**すでにBizGate MCPをインストール済みの方** は、以下でスキルだけ追加できます:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
bash install-skill.sh
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
新規インストールの場合は `install.sh` にスキルも含まれています。
|
|
168
148
|
|
|
169
149
|
### 注意点
|
|
170
150
|
|
|
@@ -176,6 +156,21 @@ Claude Code が起動したら、以下を入力してください。
|
|
|
176
156
|
|
|
177
157
|
---
|
|
178
158
|
|
|
159
|
+
## パフォーマンス最適化
|
|
160
|
+
|
|
161
|
+
本サーバーには以下の最適化が組み込まれています。
|
|
162
|
+
|
|
163
|
+
### APIコール節約
|
|
164
|
+
- **5分キャッシュ**: 同じ会社を5分以内に再検索した場合、APIを消費しません
|
|
165
|
+
- **キーマン詳細の並列取得**: 5件ずつ並列リクエストで高速化
|
|
166
|
+
|
|
167
|
+
### LLMトークン節約
|
|
168
|
+
- **部署検索**: デフォルト30件のみ表示(`limit`で変更可能)。残りは絞り込みで取得
|
|
169
|
+
- **一括取得**: 部署は上位15件、人事は役職一覧のみ(人名が必要な場合は個別ツールで)
|
|
170
|
+
- 超過分は「残りN件あります」と案内し、必要に応じて追加取得
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
179
174
|
## 提供ツール(参考情報)
|
|
180
175
|
|
|
181
176
|
通常はツール名を意識する必要はありません。Claude が自動で適切なツールを選びます。
|
|
@@ -183,10 +178,10 @@ Claude Code が起動したら、以下を入力してください。
|
|
|
183
178
|
| ツール名 | 説明 | API消費 |
|
|
184
179
|
|---------|------|--------|
|
|
185
180
|
| `bizgate__company_search` | 企業の基本情報(住所・電話・代表者・業種・資本金 等) | 1回(結果なしでも課金) |
|
|
186
|
-
| `bizgate__department_search` |
|
|
181
|
+
| `bizgate__department_search` | 部署情報(部署名・住所・電話番号)デフォルト30件表示 | 1回(データなしは課金なし) |
|
|
187
182
|
| `bizgate__marketing_tags` | マーケティングタグ(SNS・MA・採用・活動) | 1回(データなしは課金なし) |
|
|
188
|
-
| `bizgate__keyman_search` |
|
|
189
|
-
| `bizgate__company_full` |
|
|
183
|
+
| `bizgate__keyman_search` | 担当者情報(実名・役職・電話番号・住所)デフォルト10名 | 1回 + 詳細N回 |
|
|
184
|
+
| `bizgate__company_full` | 企業+部署(15件)+キーマン(要約)を一括取得 | 3回 |
|
|
190
185
|
| `bizgate__usage_status` | 本日の残りAPI回数を確認 | 0回 |
|
|
191
186
|
|
|
192
187
|
---
|
package/dist/bizgate-client.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export declare class BizGateClient {
|
|
|
32
32
|
private cacheKey;
|
|
33
33
|
/**
|
|
34
34
|
* Company lookup (企業).
|
|
35
|
-
* Cached for
|
|
35
|
+
* Cached for 5 minutes. Billed even on no-result.
|
|
36
36
|
*/
|
|
37
37
|
searchCompany(params: {
|
|
38
38
|
shogo?: string;
|
|
@@ -43,7 +43,7 @@ export declare class BizGateClient {
|
|
|
43
43
|
}): Promise<CompanyResult>;
|
|
44
44
|
/**
|
|
45
45
|
* Department lookup (部署).
|
|
46
|
-
* Cached for
|
|
46
|
+
* Cached for 5 minutes. Not billed on failure.
|
|
47
47
|
*/
|
|
48
48
|
searchDepartments(params: {
|
|
49
49
|
shogo?: string;
|
|
@@ -55,7 +55,7 @@ export declare class BizGateClient {
|
|
|
55
55
|
}): Promise<DepartmentResult>;
|
|
56
56
|
/**
|
|
57
57
|
* Marketing tags lookup (マーケティングタグ).
|
|
58
|
-
* Cached for
|
|
58
|
+
* Cached for 5 minutes. Not billed on failure.
|
|
59
59
|
*/
|
|
60
60
|
searchMarketingTags(params: {
|
|
61
61
|
shogo?: string;
|
|
@@ -63,7 +63,7 @@ export declare class BizGateClient {
|
|
|
63
63
|
}): Promise<MarketingResult>;
|
|
64
64
|
/**
|
|
65
65
|
* Keyman lookup (キーマン・人名なし).
|
|
66
|
-
* Cached for
|
|
66
|
+
* Cached for 5 minutes. Not billed on failure.
|
|
67
67
|
*/
|
|
68
68
|
searchKeyman(params: {
|
|
69
69
|
shogo?: string;
|
package/dist/bizgate-client.js
CHANGED
|
@@ -6,8 +6,14 @@ export function first(field) {
|
|
|
6
6
|
return field[0] ?? "";
|
|
7
7
|
return field ?? "";
|
|
8
8
|
}
|
|
9
|
-
// Cache TTL:
|
|
10
|
-
const CACHE_TTL =
|
|
9
|
+
// Cache TTL: 5 minutes — same company searched within 5min won't hit the API again
|
|
10
|
+
const CACHE_TTL = 300_000;
|
|
11
|
+
/** BizGate error codes that do NOT consume a billable request. */
|
|
12
|
+
const NON_BILLABLE_ERRORS = new Set(["404", "504", "604"]);
|
|
13
|
+
/** Pick only defined (non-null, non-undefined) string values from an object. */
|
|
14
|
+
function pickDefined(obj) {
|
|
15
|
+
return Object.fromEntries(Object.entries(obj).filter((entry) => entry[1] != null));
|
|
16
|
+
}
|
|
11
17
|
export class BizGateClient {
|
|
12
18
|
config;
|
|
13
19
|
usageTracker;
|
|
@@ -62,7 +68,7 @@ export class BizGateClient {
|
|
|
62
68
|
}
|
|
63
69
|
/**
|
|
64
70
|
* Company lookup (企業).
|
|
65
|
-
* Cached for
|
|
71
|
+
* Cached for 5 minutes. Billed even on no-result.
|
|
66
72
|
*/
|
|
67
73
|
async searchCompany(params) {
|
|
68
74
|
const key = this.cacheKey(params);
|
|
@@ -70,17 +76,7 @@ export class BizGateClient {
|
|
|
70
76
|
if (cached)
|
|
71
77
|
return cached;
|
|
72
78
|
this.usageTracker.increment();
|
|
73
|
-
const queryParams =
|
|
74
|
-
if (params.shogo)
|
|
75
|
-
queryParams.shogo = params.shogo;
|
|
76
|
-
if (params.compno)
|
|
77
|
-
queryParams.compno = params.compno;
|
|
78
|
-
if (params.hpurl)
|
|
79
|
-
queryParams.hpurl = params.hpurl;
|
|
80
|
-
if (params.email)
|
|
81
|
-
queryParams.email = params.email;
|
|
82
|
-
if (params.tel)
|
|
83
|
-
queryParams.tel = params.tel;
|
|
79
|
+
const queryParams = pickDefined(params);
|
|
84
80
|
const result = await this.request(this.config.skeyCompany, queryParams);
|
|
85
81
|
const data = {
|
|
86
82
|
matchPattern: result.responseHeader.matchpatern ?? "",
|
|
@@ -91,7 +87,7 @@ export class BizGateClient {
|
|
|
91
87
|
}
|
|
92
88
|
/**
|
|
93
89
|
* Department lookup (部署).
|
|
94
|
-
* Cached for
|
|
90
|
+
* Cached for 5 minutes. Not billed on failure.
|
|
95
91
|
*/
|
|
96
92
|
async searchDepartments(params) {
|
|
97
93
|
const key = this.cacheKey(params);
|
|
@@ -99,30 +95,26 @@ export class BizGateClient {
|
|
|
99
95
|
if (cached)
|
|
100
96
|
return cached;
|
|
101
97
|
this.usageTracker.increment();
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
numFound: result.response?.numFound ?? 0,
|
|
119
|
-
};
|
|
120
|
-
this.departmentCache.set(key, data);
|
|
121
|
-
return data;
|
|
98
|
+
try {
|
|
99
|
+
const queryParams = pickDefined(params);
|
|
100
|
+
const result = await this.request(this.config.skeyDepartment, queryParams);
|
|
101
|
+
const data = {
|
|
102
|
+
docs: result.response?.docs ?? [],
|
|
103
|
+
numFound: result.response?.numFound ?? 0,
|
|
104
|
+
};
|
|
105
|
+
this.departmentCache.set(key, data);
|
|
106
|
+
return data;
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
if (e instanceof BizGateApiError && NON_BILLABLE_ERRORS.has(e.code)) {
|
|
110
|
+
this.usageTracker.decrement();
|
|
111
|
+
}
|
|
112
|
+
throw e;
|
|
113
|
+
}
|
|
122
114
|
}
|
|
123
115
|
/**
|
|
124
116
|
* Marketing tags lookup (マーケティングタグ).
|
|
125
|
-
* Cached for
|
|
117
|
+
* Cached for 5 minutes. Not billed on failure.
|
|
126
118
|
*/
|
|
127
119
|
async searchMarketingTags(params) {
|
|
128
120
|
const key = this.cacheKey(params);
|
|
@@ -130,21 +122,25 @@ export class BizGateClient {
|
|
|
130
122
|
if (cached)
|
|
131
123
|
return cached;
|
|
132
124
|
this.usageTracker.increment();
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
|
|
125
|
+
try {
|
|
126
|
+
const queryParams = pickDefined(params);
|
|
127
|
+
const result = await this.request(this.config.skeyMarketing, queryParams);
|
|
128
|
+
const data = {
|
|
129
|
+
docs: result.response?.docs ?? [],
|
|
130
|
+
};
|
|
131
|
+
this.marketingCache.set(key, data);
|
|
132
|
+
return data;
|
|
133
|
+
}
|
|
134
|
+
catch (e) {
|
|
135
|
+
if (e instanceof BizGateApiError && NON_BILLABLE_ERRORS.has(e.code)) {
|
|
136
|
+
this.usageTracker.decrement();
|
|
137
|
+
}
|
|
138
|
+
throw e;
|
|
139
|
+
}
|
|
144
140
|
}
|
|
145
141
|
/**
|
|
146
142
|
* Keyman lookup (キーマン・人名なし).
|
|
147
|
-
* Cached for
|
|
143
|
+
* Cached for 5 minutes. Not billed on failure.
|
|
148
144
|
*/
|
|
149
145
|
async searchKeyman(params) {
|
|
150
146
|
const key = this.cacheKey(params);
|
|
@@ -152,26 +148,22 @@ export class BizGateClient {
|
|
|
152
148
|
if (cached)
|
|
153
149
|
return cached;
|
|
154
150
|
this.usageTracker.increment();
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
numFound: result.response?.numFound ?? 0,
|
|
172
|
-
};
|
|
173
|
-
this.keymanCache.set(key, data);
|
|
174
|
-
return data;
|
|
151
|
+
try {
|
|
152
|
+
const queryParams = pickDefined(params);
|
|
153
|
+
const result = await this.request(this.config.skeyKeyman, queryParams);
|
|
154
|
+
const data = {
|
|
155
|
+
docs: result.response?.docs ?? [],
|
|
156
|
+
numFound: result.response?.numFound ?? 0,
|
|
157
|
+
};
|
|
158
|
+
this.keymanCache.set(key, data);
|
|
159
|
+
return data;
|
|
160
|
+
}
|
|
161
|
+
catch (e) {
|
|
162
|
+
if (e instanceof BizGateApiError && NON_BILLABLE_ERRORS.has(e.code)) {
|
|
163
|
+
this.usageTracker.decrement();
|
|
164
|
+
}
|
|
165
|
+
throw e;
|
|
166
|
+
}
|
|
175
167
|
}
|
|
176
168
|
/**
|
|
177
169
|
* Keyman with name lookup (キーマン・人名あり).
|
|
@@ -186,7 +178,10 @@ export class BizGateClient {
|
|
|
186
178
|
});
|
|
187
179
|
return result.response?.docs?.[0] ?? null;
|
|
188
180
|
}
|
|
189
|
-
catch {
|
|
181
|
+
catch (e) {
|
|
182
|
+
if (e instanceof BizGateApiError && NON_BILLABLE_ERRORS.has(e.code)) {
|
|
183
|
+
this.usageTracker.decrement();
|
|
184
|
+
}
|
|
190
185
|
return null;
|
|
191
186
|
}
|
|
192
187
|
};
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,9 @@ import { BizGateClient, first as f } from "./bizgate-client.js";
|
|
|
6
6
|
import { BizGateApiError, DEPARTMENT_CATEGORIES } from "./types.js";
|
|
7
7
|
import { UsageTracker } from "./usage-tracker.js";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
|
-
import { join } from "node:path";
|
|
9
|
+
import { join, dirname } from "node:path";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
10
12
|
// ---------- 環境変数読み込み ----------
|
|
11
13
|
const skeyCompany = process.env.BIZGATE_SKEY_COMPANY;
|
|
12
14
|
const skeyDepartment = process.env.BIZGATE_SKEY_DEPARTMENT;
|
|
@@ -50,9 +52,11 @@ const config = {
|
|
|
50
52
|
const usageTracker = new UsageTracker(usageFile, dailyLimit);
|
|
51
53
|
const client = new BizGateClient(config, usageTracker);
|
|
52
54
|
// ---------- MCPサーバー ----------
|
|
55
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
56
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
53
57
|
const server = new McpServer({
|
|
54
58
|
name: "bizgate-mcp-server",
|
|
55
|
-
version:
|
|
59
|
+
version: pkg.version,
|
|
56
60
|
});
|
|
57
61
|
// ---------- ヘルパー ----------
|
|
58
62
|
function usageFooter() {
|
|
@@ -345,73 +349,54 @@ server.tool("bizgate__company_full", "会社名または法人番号で企業情
|
|
|
345
349
|
const err = validateInput(shogo, compno);
|
|
346
350
|
if (err)
|
|
347
351
|
return { content: [{ type: "text", text: err }] };
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const { matchPattern, docs } = await client.searchCompany({
|
|
352
|
-
shogo, compno, hpurl, email,
|
|
353
|
-
});
|
|
352
|
+
// Parallel fetch: company + department + keyman simultaneously
|
|
353
|
+
const companyPromise = client.searchCompany({ shogo, compno, hpurl, email })
|
|
354
|
+
.then(({ matchPattern, docs }) => {
|
|
354
355
|
if (docs.length > 0) {
|
|
355
|
-
|
|
356
|
-
sections.push(`マッチパターン: ${matchPattern}`);
|
|
356
|
+
return docs.map(formatCompanyDoc).join("\n\n") + `\nマッチパターン: ${matchPattern}`;
|
|
357
357
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
sections.push(`企業情報: ${e instanceof Error ? e.message : "取得失敗"}`);
|
|
364
|
-
}
|
|
365
|
-
// 2. Department info (top 15 for token efficiency)
|
|
366
|
-
try {
|
|
367
|
-
const { docs, numFound } = await client.searchDepartments({
|
|
368
|
-
shogo, compno, bKwd, cList,
|
|
369
|
-
});
|
|
358
|
+
return `企業情報: 該当なし(マッチパターン: ${matchPattern})`;
|
|
359
|
+
})
|
|
360
|
+
.catch((e) => `企業情報: ${e instanceof Error ? e.message : "取得失敗"}`);
|
|
361
|
+
const deptPromise = client.searchDepartments({ shogo, compno, bKwd, cList })
|
|
362
|
+
.then(({ docs, numFound }) => {
|
|
370
363
|
if (docs.length > 0) {
|
|
371
364
|
const displayed = docs.slice(0, 15);
|
|
372
365
|
const companyName = f(docs[0].shogo);
|
|
373
|
-
|
|
374
|
-
|
|
366
|
+
let text = `\n## 部署情報${companyName ? `: ${companyName}` : ""}(全${numFound}件中${displayed.length}件表示)\n`;
|
|
367
|
+
text += displayed.map((d, i) => formatDepartmentDoc(d, i + 1)).join("\n\n");
|
|
375
368
|
if (numFound > 15) {
|
|
376
|
-
|
|
369
|
+
text += `\n\n> 残り${numFound - 15}件はbizgate__department_searchで個別に取得できます。`;
|
|
377
370
|
}
|
|
371
|
+
return text;
|
|
378
372
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
// 3. Keyman info
|
|
392
|
-
if (skeyKeyman) {
|
|
393
|
-
try {
|
|
394
|
-
const { docs, numFound } = await client.searchKeyman({
|
|
395
|
-
shogo, compno, bKwd, cList,
|
|
396
|
-
});
|
|
373
|
+
return "\n## 部署情報\n該当なし";
|
|
374
|
+
})
|
|
375
|
+
.catch((e) => {
|
|
376
|
+
if (e instanceof BizGateApiError && e.code === "504")
|
|
377
|
+
return "\n## 部署情報\nデータなし";
|
|
378
|
+
return `\n## 部署情報\n${e instanceof Error ? e.message : "取得失敗"}`;
|
|
379
|
+
});
|
|
380
|
+
const keymanPromise = skeyKeyman
|
|
381
|
+
? client.searchKeyman({ shogo, compno, bKwd, cList })
|
|
382
|
+
.then(({ docs, numFound }) => {
|
|
397
383
|
if (docs.length > 0) {
|
|
398
384
|
const companyName = f(docs[0].shogo);
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
}
|
|
402
|
-
else {
|
|
403
|
-
sections.push("\n## 人事情報\n該当なし");
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
catch (e) {
|
|
407
|
-
if (e instanceof BizGateApiError && e.code === "604") {
|
|
408
|
-
sections.push("\n## 人事情報\nデータなし");
|
|
409
|
-
}
|
|
410
|
-
else {
|
|
411
|
-
sections.push(`\n## 人事情報\n${e instanceof Error ? e.message : "取得失敗"}`);
|
|
385
|
+
return `\n## 人事情報${companyName ? `: ${companyName}` : ""}(全${numFound}件)\n` +
|
|
386
|
+
docs.map((d, i) => formatKeymanDoc(d, i + 1)).join("\n\n");
|
|
412
387
|
}
|
|
413
|
-
|
|
414
|
-
|
|
388
|
+
return "\n## 人事情報\n該当なし";
|
|
389
|
+
})
|
|
390
|
+
.catch((e) => {
|
|
391
|
+
if (e instanceof BizGateApiError && e.code === "604")
|
|
392
|
+
return "\n## 人事情報\nデータなし";
|
|
393
|
+
return `\n## 人事情報\n${e instanceof Error ? e.message : "取得失敗"}`;
|
|
394
|
+
})
|
|
395
|
+
: Promise.resolve("");
|
|
396
|
+
const [companyText, deptText, keymanText] = await Promise.all([
|
|
397
|
+
companyPromise, deptPromise, keymanPromise,
|
|
398
|
+
]);
|
|
399
|
+
const sections = [companyText, deptText, keymanText].filter(Boolean);
|
|
415
400
|
return {
|
|
416
401
|
content: [{ type: "text", text: sections.join("\n") + usageFooter() }],
|
|
417
402
|
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdirSync, writeFileSync, existsSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
const SKILL_DIR = join(homedir(), ".claude", "skills", "prospect-match");
|
|
6
|
+
const SKILL_MD = `---
|
|
7
|
+
name: prospect-match
|
|
8
|
+
description: |
|
|
9
|
+
企業の部署リストとDigiManサービスをマッチングし、営業ターゲット部署を提案する。
|
|
10
|
+
"売れそうな部署", "部署マッチング", "prospect", "ターゲット部署", "영업 타겟",
|
|
11
|
+
"DigiManのサービスが売れそうな", "サービスが売れそう", "営業代行", "Solution", "AI",
|
|
12
|
+
"どの部署に売れる", "ターゲット探して", "部署を探して"
|
|
13
|
+
user-invocable: true
|
|
14
|
+
argument-hint: "[会社名] [サービス種別(営業代行/Solution/AI/全部)]"
|
|
15
|
+
allowed-tools: mcp__bizgate__bizgate__department_search, mcp__bizgate__bizgate__keyman_search, mcp__bizgate__bizgate__company_search, Read, Grep, Glob, AskUserQuestion
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Prospect Match: 企業部署 × DigiManサービス マッチング
|
|
19
|
+
|
|
20
|
+
企業名を受け取り、BizGate APIで部署情報を取得し、DigiManのサービスに適した営業ターゲット部署を提案するスキルです。
|
|
21
|
+
|
|
22
|
+
## DigiManサービス定義
|
|
23
|
+
|
|
24
|
+
### 1. 営業代行
|
|
25
|
+
- **内容**: 営業チームのKPIダッシュボード、架電/アポ進捗管理、担当者別パフォーマンス分析
|
|
26
|
+
- **ターゲット部署の特徴**: 営業組織を持つ部署、営業企画、営業管理、営業推進
|
|
27
|
+
- **マッチキーワード**: 営業, 販売, 販促, 商品, 事業開発, マーケティング, 顧客
|
|
28
|
+
|
|
29
|
+
### 2. Solution
|
|
30
|
+
- **内容**: 内部管理システム(DB・データ分析・ダッシュボード構築)
|
|
31
|
+
- **ターゲット部署の特徴**: DX推進、経営企画、総務、システム、業務改善担当
|
|
32
|
+
- **マッチキーワード**: ICT, システム, DX, 情報, 企画, 経営企画, 総務, 管理, イノベーション, デジタル
|
|
33
|
+
|
|
34
|
+
### 3. AI
|
|
35
|
+
- **内容**: Claude × BizGate連携MCP。自然言語で企業情報を検索・取得
|
|
36
|
+
- **ターゲット部署の特徴**: 新規事業、事業創造、戦略推進、営業企画
|
|
37
|
+
- **マッチキーワード**: 戦略, 成長, 事業創造, イノベーション, 企画, 開発, 推進, DX, AI, ICT
|
|
38
|
+
|
|
39
|
+
## プロセス
|
|
40
|
+
|
|
41
|
+
### Step 1: 入力を解析
|
|
42
|
+
- ユーザーの入力から **会社名** と **対象サービス** を特定する
|
|
43
|
+
- サービスが指定されていない場合は「全部」として3サービスすべてをマッチングする
|
|
44
|
+
- 会社名が不明な場合は \`AskUserQuestion\` で確認する
|
|
45
|
+
|
|
46
|
+
### Step 2: 部署情報を取得
|
|
47
|
+
- \`bizgate__department_search\` で部署一覧を取得する(limit: 200)
|
|
48
|
+
- 電話番号がある部署は電話番号も含める
|
|
49
|
+
|
|
50
|
+
### Step 3: サービスとマッチング
|
|
51
|
+
各サービスについて、以下の基準で部署をマッチングする:
|
|
52
|
+
|
|
53
|
+
1. **部署名にマッチキーワードが含まれるか** を確認
|
|
54
|
+
2. **部署のカテゴリ(ctg_01〜15)** も参考にする:
|
|
55
|
+
- 営業代行 → ctg_02(営業企画), ctg_13(営業)
|
|
56
|
+
- Solution → ctg_01(経営企画), ctg_05(総務), ctg_10(システム)
|
|
57
|
+
- AI → ctg_01(経営企画), ctg_02(営業企画), ctg_10(システム)
|
|
58
|
+
3. キーワードマッチだけでなく、**部署の役割から判断** して適切な部署を選ぶ
|
|
59
|
+
|
|
60
|
+
### Step 4: 結果を出力
|
|
61
|
+
以下のフォーマットで出力する:
|
|
62
|
+
|
|
63
|
+
## [会社名] × DigiMan サービスマッチング
|
|
64
|
+
|
|
65
|
+
### 1. 営業代行
|
|
66
|
+
| 部署名 | 電話番号 | マッチ理由 |
|
|
67
|
+
|--------|---------|----------|
|
|
68
|
+
|
|
69
|
+
### 2. Solution
|
|
70
|
+
| 部署名 | 電話番号 | マッチ理由 |
|
|
71
|
+
|--------|---------|----------|
|
|
72
|
+
|
|
73
|
+
### 3. AI
|
|
74
|
+
| 部署名 | 電話番号 | マッチ理由 |
|
|
75
|
+
|--------|---------|----------|
|
|
76
|
+
|
|
77
|
+
### 最優先アプローチ先
|
|
78
|
+
[3サービスに共通して関連性が高い部署をピックアップ]
|
|
79
|
+
|
|
80
|
+
## 注意事項
|
|
81
|
+
- 電話番号がない部署は「-」と表示する
|
|
82
|
+
- 各サービスにつき最大5部署まで提案する(多すぎると選べない)
|
|
83
|
+
- 明らかに関連のない部署(畜産、食品など事業部門)はスキップする
|
|
84
|
+
- マッチ理由は1行で簡潔に書く
|
|
85
|
+
- ユーザーの言語(日本語 or 韓国語)に合わせて出力する
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
$ARGUMENTS
|
|
90
|
+
`;
|
|
91
|
+
function main() {
|
|
92
|
+
const existed = existsSync(join(SKILL_DIR, "SKILL.md"));
|
|
93
|
+
mkdirSync(SKILL_DIR, { recursive: true });
|
|
94
|
+
writeFileSync(join(SKILL_DIR, "SKILL.md"), SKILL_MD, "utf-8");
|
|
95
|
+
if (existed) {
|
|
96
|
+
console.log("✔ prospect-match スキルを更新しました");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log("✔ prospect-match スキルをインストールしました");
|
|
100
|
+
}
|
|
101
|
+
console.log(` 場所: ${SKILL_DIR}/SKILL.md`);
|
|
102
|
+
console.log("");
|
|
103
|
+
console.log("使い方:");
|
|
104
|
+
console.log(" /prospect-match 会社名");
|
|
105
|
+
console.log(' または「○○にDigiManのサービスが売れそうな部署を探して」');
|
|
106
|
+
}
|
|
107
|
+
main();
|
package/dist/usage-tracker.d.ts
CHANGED
|
@@ -8,6 +8,10 @@ export declare class UsageTracker {
|
|
|
8
8
|
private writeState;
|
|
9
9
|
/** Increment counter before making an API call. Throws if limit exceeded. */
|
|
10
10
|
increment(cost?: number): number;
|
|
11
|
+
/** Check if limit allows the call, but don't increment yet. Throws if limit exceeded. */
|
|
12
|
+
checkLimit(cost?: number): void;
|
|
13
|
+
/** Decrement counter (rollback on API failure). */
|
|
14
|
+
decrement(cost?: number): void;
|
|
11
15
|
/** Remaining requests for today. */
|
|
12
16
|
remaining(): number;
|
|
13
17
|
/** Current usage count for today. */
|
package/dist/usage-tracker.js
CHANGED
|
@@ -36,6 +36,19 @@ export class UsageTracker {
|
|
|
36
36
|
this.writeState(state);
|
|
37
37
|
return state.count;
|
|
38
38
|
}
|
|
39
|
+
/** Check if limit allows the call, but don't increment yet. Throws if limit exceeded. */
|
|
40
|
+
checkLimit(cost = 1) {
|
|
41
|
+
const state = this.readState();
|
|
42
|
+
if (state.count + cost > this.limit) {
|
|
43
|
+
throw new Error(`本日のAPI利用上限(${this.limit}回)に達しました。明日以降に再度お試しください。`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Decrement counter (rollback on API failure). */
|
|
47
|
+
decrement(cost = 1) {
|
|
48
|
+
const state = this.readState();
|
|
49
|
+
state.count = Math.max(0, state.count - cost);
|
|
50
|
+
this.writeState(state);
|
|
51
|
+
}
|
|
39
52
|
/** Remaining requests for today. */
|
|
40
53
|
remaining() {
|
|
41
54
|
const state = this.readState();
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bizgate-mcp-server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "BizGate APIとClaudeを連携するMCPサーバー",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"bizgate-mcp-server": "dist/index.js"
|
|
8
|
+
"bizgate-mcp-server": "dist/index.js",
|
|
9
|
+
"bizgate-install-skill": "dist/install-skill.js"
|
|
9
10
|
},
|
|
10
11
|
"files": [
|
|
11
12
|
"dist"
|