bluelamp 4.3.3 → 4.3.4
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 +78 -0
- package/bin/bluelamp-vscode-base +357 -1
- package/bin/bluelamp1 +0 -0
- package/bin/bluelamp10 +0 -0
- package/bin/bluelamp100 +0 -0
- package/bin/bluelamp101 +0 -0
- package/bin/bluelamp102 +0 -0
- package/bin/bluelamp103 +0 -0
- package/bin/bluelamp104 +0 -0
- package/bin/bluelamp105 +0 -0
- package/bin/bluelamp106 +0 -0
- package/bin/bluelamp107 +0 -0
- package/bin/bluelamp108 +0 -0
- package/bin/bluelamp109 +0 -0
- package/bin/bluelamp11 +0 -0
- package/bin/bluelamp110 +0 -0
- package/bin/bluelamp111 +0 -0
- package/bin/bluelamp112 +0 -0
- package/bin/bluelamp113 +0 -0
- package/bin/bluelamp114 +0 -0
- package/bin/bluelamp115 +0 -0
- package/bin/bluelamp116 +0 -0
- package/bin/bluelamp117 +0 -0
- package/bin/bluelamp118 +0 -0
- package/bin/bluelamp119 +0 -0
- package/bin/bluelamp12 +0 -0
- package/bin/bluelamp120 +0 -0
- package/bin/bluelamp121 +0 -0
- package/bin/bluelamp122 +0 -0
- package/bin/bluelamp123 +0 -0
- package/bin/bluelamp124 +0 -0
- package/bin/bluelamp125 +0 -0
- package/bin/bluelamp126 +0 -0
- package/bin/bluelamp127 +0 -0
- package/bin/bluelamp128 +0 -0
- package/bin/bluelamp129 +0 -0
- package/bin/bluelamp13 +0 -0
- package/bin/bluelamp130 +0 -0
- package/bin/bluelamp131 +0 -0
- package/bin/bluelamp132 +0 -0
- package/bin/bluelamp133 +0 -0
- package/bin/bluelamp134 +0 -0
- package/bin/bluelamp135 +0 -0
- package/bin/bluelamp136 +0 -0
- package/bin/bluelamp137 +0 -0
- package/bin/bluelamp138 +0 -0
- package/bin/bluelamp139 +0 -0
- package/bin/bluelamp14 +0 -0
- package/bin/bluelamp140 +0 -0
- package/bin/bluelamp141 +0 -0
- package/bin/bluelamp142 +0 -0
- package/bin/bluelamp143 +0 -0
- package/bin/bluelamp144 +0 -0
- package/bin/bluelamp145 +0 -0
- package/bin/bluelamp146 +0 -0
- package/bin/bluelamp147 +0 -0
- package/bin/bluelamp148 +0 -0
- package/bin/bluelamp149 +0 -0
- package/bin/bluelamp15 +0 -0
- package/bin/bluelamp150 +0 -0
- package/bin/bluelamp151 +0 -0
- package/bin/bluelamp152 +0 -0
- package/bin/bluelamp153 +0 -0
- package/bin/bluelamp154 +0 -0
- package/bin/bluelamp155 +0 -0
- package/bin/bluelamp156 +0 -0
- package/bin/bluelamp157 +0 -0
- package/bin/bluelamp158 +0 -0
- package/bin/bluelamp159 +0 -0
- package/bin/bluelamp16 +0 -0
- package/bin/bluelamp160 +0 -0
- package/bin/bluelamp161 +0 -0
- package/bin/bluelamp162 +0 -0
- package/bin/bluelamp163 +0 -0
- package/bin/bluelamp164 +0 -0
- package/bin/bluelamp165 +0 -0
- package/bin/bluelamp166 +0 -0
- package/bin/bluelamp167 +0 -0
- package/bin/bluelamp168 +0 -0
- package/bin/bluelamp169 +0 -0
- package/bin/bluelamp17 +0 -0
- package/bin/bluelamp170 +0 -0
- package/bin/bluelamp171 +0 -0
- package/bin/bluelamp172 +0 -0
- package/bin/bluelamp173 +0 -0
- package/bin/bluelamp174 +0 -0
- package/bin/bluelamp175 +0 -0
- package/bin/bluelamp176 +0 -0
- package/bin/bluelamp177 +0 -0
- package/bin/bluelamp178 +0 -0
- package/bin/bluelamp179 +0 -0
- package/bin/bluelamp18 +0 -0
- package/bin/bluelamp180 +0 -0
- package/bin/bluelamp181 +0 -0
- package/bin/bluelamp182 +0 -0
- package/bin/bluelamp183 +0 -0
- package/bin/bluelamp184 +0 -0
- package/bin/bluelamp185 +0 -0
- package/bin/bluelamp186 +0 -0
- package/bin/bluelamp187 +0 -0
- package/bin/bluelamp188 +0 -0
- package/bin/bluelamp189 +0 -0
- package/bin/bluelamp19 +0 -0
- package/bin/bluelamp190 +0 -0
- package/bin/bluelamp191 +0 -0
- package/bin/bluelamp192 +0 -0
- package/bin/bluelamp193 +0 -0
- package/bin/bluelamp194 +0 -0
- package/bin/bluelamp195 +0 -0
- package/bin/bluelamp196 +0 -0
- package/bin/bluelamp197 +0 -0
- package/bin/bluelamp198 +0 -0
- package/bin/bluelamp199 +0 -0
- package/bin/bluelamp2 +0 -0
- package/bin/bluelamp20 +0 -0
- package/bin/bluelamp200 +0 -0
- package/bin/bluelamp21 +0 -0
- package/bin/bluelamp22 +0 -0
- package/bin/bluelamp23 +0 -0
- package/bin/bluelamp24 +0 -0
- package/bin/bluelamp25 +0 -0
- package/bin/bluelamp26 +0 -0
- package/bin/bluelamp27 +0 -0
- package/bin/bluelamp28 +0 -0
- package/bin/bluelamp29 +0 -0
- package/bin/bluelamp3 +0 -0
- package/bin/bluelamp30 +0 -0
- package/bin/bluelamp31 +0 -0
- package/bin/bluelamp32 +0 -0
- package/bin/bluelamp33 +0 -0
- package/bin/bluelamp34 +0 -0
- package/bin/bluelamp35 +0 -0
- package/bin/bluelamp36 +0 -0
- package/bin/bluelamp37 +0 -0
- package/bin/bluelamp38 +0 -0
- package/bin/bluelamp39 +0 -0
- package/bin/bluelamp4 +0 -0
- package/bin/bluelamp40 +0 -0
- package/bin/bluelamp41 +0 -0
- package/bin/bluelamp42 +0 -0
- package/bin/bluelamp43 +0 -0
- package/bin/bluelamp44 +0 -0
- package/bin/bluelamp45 +0 -0
- package/bin/bluelamp46 +0 -0
- package/bin/bluelamp47 +0 -0
- package/bin/bluelamp48 +0 -0
- package/bin/bluelamp49 +0 -0
- package/bin/bluelamp5 +0 -0
- package/bin/bluelamp50 +0 -0
- package/bin/bluelamp51 +0 -0
- package/bin/bluelamp52 +0 -0
- package/bin/bluelamp53 +0 -0
- package/bin/bluelamp54 +0 -0
- package/bin/bluelamp55 +0 -0
- package/bin/bluelamp56 +0 -0
- package/bin/bluelamp57 +0 -0
- package/bin/bluelamp58 +0 -0
- package/bin/bluelamp59 +0 -0
- package/bin/bluelamp6 +0 -0
- package/bin/bluelamp60 +0 -0
- package/bin/bluelamp61 +0 -0
- package/bin/bluelamp62 +0 -0
- package/bin/bluelamp63 +0 -0
- package/bin/bluelamp64 +0 -0
- package/bin/bluelamp65 +0 -0
- package/bin/bluelamp66 +0 -0
- package/bin/bluelamp67 +0 -0
- package/bin/bluelamp68 +0 -0
- package/bin/bluelamp69 +0 -0
- package/bin/bluelamp7 +0 -0
- package/bin/bluelamp70 +0 -0
- package/bin/bluelamp71 +0 -0
- package/bin/bluelamp72 +0 -0
- package/bin/bluelamp73 +0 -0
- package/bin/bluelamp74 +0 -0
- package/bin/bluelamp75 +0 -0
- package/bin/bluelamp76 +0 -0
- package/bin/bluelamp77 +0 -0
- package/bin/bluelamp78 +0 -0
- package/bin/bluelamp79 +0 -0
- package/bin/bluelamp8 +0 -0
- package/bin/bluelamp80 +0 -0
- package/bin/bluelamp81 +0 -0
- package/bin/bluelamp82 +0 -0
- package/bin/bluelamp83 +0 -0
- package/bin/bluelamp84 +0 -0
- package/bin/bluelamp85 +0 -0
- package/bin/bluelamp86 +0 -0
- package/bin/bluelamp87 +0 -0
- package/bin/bluelamp88 +0 -0
- package/bin/bluelamp89 +0 -0
- package/bin/bluelamp9 +0 -0
- package/bin/bluelamp90 +0 -0
- package/bin/bluelamp91 +0 -0
- package/bin/bluelamp92 +0 -0
- package/bin/bluelamp93 +0 -0
- package/bin/bluelamp94 +0 -0
- package/bin/bluelamp95 +0 -0
- package/bin/bluelamp96 +0 -0
- package/bin/bluelamp97 +0 -0
- package/bin/bluelamp98 +0 -0
- package/bin/bluelamp99 +0 -0
- package/lib/auth/InteractiveLogin.js +253 -1
- package/lib/auth/PortalAuthClient.js +184 -1
- package/lib/auth/TokenManager.js +260 -1
- package/lib/i18n/en.json +2 -2
- package/lib/i18n/index.js +75 -1
- package/lib/i18n/ja.json +2 -2
- package/lib/mcp-server/index.cjs +452 -1
- package/lib/mcp-server/portal-api-client.cjs +634 -1
- package/lib/utils/logger.js +83 -1
- package/package.json +17 -7
- package/scripts/build.js +350 -0
- package/scripts/generate-commands.js +44 -1
- package/scripts/playwright-launch.js +221 -1
- package/scripts/setup-mcps.js +124 -1
- package/scripts/setup-playwright.js +61 -1
- package/lib/mcp-gmail/credentials.json +0 -1
package/lib/mcp-server/index.cjs
CHANGED
|
@@ -1,2 +1,453 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BlueLamp VSCode MCP Server
|
|
5
|
+
* VSCode拡張機能専用のMCPサーバー実装
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
9
|
+
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
10
|
+
const {
|
|
11
|
+
CallToolRequestSchema,
|
|
12
|
+
ListToolsRequestSchema,
|
|
13
|
+
} = require('@modelcontextprotocol/sdk/types.js');
|
|
14
|
+
const { getPromptFromPortal, verifyTokenAndGetUser, listAvailableMcps, getMcpInfo } = require('./portal-api-client.cjs');
|
|
15
|
+
const { execSync } = require('child_process');
|
|
16
|
+
const { logger } = require('../utils/logger');
|
|
17
|
+
const { t, setLanguage } = require('../i18n');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const os = require('os');
|
|
21
|
+
|
|
22
|
+
// .envファイルを読み込み(.env.localを優先)
|
|
23
|
+
const dotenvLocalPath = path.join(__dirname, '../../.env.local');
|
|
24
|
+
const dotenvPath = path.join(__dirname, '../../.env');
|
|
25
|
+
|
|
26
|
+
if (fs.existsSync(dotenvLocalPath)) {
|
|
27
|
+
require('dotenv').config({ path: dotenvLocalPath });
|
|
28
|
+
logger.debug('[MCP Server] Loaded .env.local');
|
|
29
|
+
} else if (fs.existsSync(dotenvPath)) {
|
|
30
|
+
require('dotenv').config({ path: dotenvPath });
|
|
31
|
+
logger.debug('[MCP Server] Loaded .env');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 環境変数から取得
|
|
35
|
+
const KEYWORD = process.env.BLUELAMP_KEYWORD || 'BL-要件定義';
|
|
36
|
+
const TOKEN = process.env.BLUELAMP_TOKEN;
|
|
37
|
+
const PORTAL_URL = process.env.PORTAL_URL || 'https://bluelamp-6clpzmy5pa-an.a.run.app';
|
|
38
|
+
const LANGUAGE = process.env.BLUELAMP_LANGUAGE || 'ja';
|
|
39
|
+
|
|
40
|
+
// 言語設定を適用
|
|
41
|
+
setLanguage(LANGUAGE);
|
|
42
|
+
|
|
43
|
+
// ログファイル設定(ユーザーホームディレクトリに保存)
|
|
44
|
+
const LOG_DIR = path.join(os.homedir(), '.bluelamp-vscode', 'logs');
|
|
45
|
+
const LOG_FILE = path.join(LOG_DIR, 'mcp.log');
|
|
46
|
+
|
|
47
|
+
// ログディレクトリが存在しない場合は作成
|
|
48
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
49
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* ファイルとコンソールにログを出力
|
|
54
|
+
* @param {string} message - ログメッセージ
|
|
55
|
+
*/
|
|
56
|
+
function log(message) {
|
|
57
|
+
const timestamp = new Date().toISOString();
|
|
58
|
+
const logMessage = `[${timestamp}] ${message}\n`;
|
|
59
|
+
fs.appendFileSync(LOG_FILE, logMessage);
|
|
60
|
+
logger.info(`[MCP Server] ${message}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 皆伝以上のランク一覧
|
|
64
|
+
const KAIDEN_RANKS = ['皆伝プラン', '編集者', '管理者'];
|
|
65
|
+
|
|
66
|
+
log(`MCP Server started - Log file: ${LOG_FILE}`);
|
|
67
|
+
log(`Environment variables:`);
|
|
68
|
+
log(` KEYWORD: ${KEYWORD}`);
|
|
69
|
+
log(` TOKEN: ${TOKEN ? TOKEN.substring(0, 20) + '...' : 'NOT SET'}`);
|
|
70
|
+
log(` PORTAL_URL: ${PORTAL_URL}`);
|
|
71
|
+
log(` LANGUAGE: ${LANGUAGE}`);
|
|
72
|
+
log(` .env file exists: ${fs.existsSync(dotenvPath)}`);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* BlueLamp VSCode MCPサーバークラス
|
|
76
|
+
* @class BlueLampVSCodeServer
|
|
77
|
+
*/
|
|
78
|
+
class BlueLampVSCodeServer {
|
|
79
|
+
constructor() {
|
|
80
|
+
this.server = new Server(
|
|
81
|
+
{
|
|
82
|
+
name: 'bluelamp',
|
|
83
|
+
version: '1.0.0',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
capabilities: {
|
|
87
|
+
tools: {},
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
this.setupHandlers();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
setupHandlers() {
|
|
96
|
+
// ツール一覧を返す
|
|
97
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
98
|
+
log('[MCP Server] ListTools request received');
|
|
99
|
+
const toolSchema = {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
keyword: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
description: t('mcp.keywordDescription'),
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
required: ['keyword'],
|
|
108
|
+
};
|
|
109
|
+
const toolAnnotations = {
|
|
110
|
+
readOnlyHint: true,
|
|
111
|
+
idempotentHint: true,
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
tools: [
|
|
115
|
+
{
|
|
116
|
+
name: 'load_knowledge',
|
|
117
|
+
description: t('mcp.toolDescriptionLoadKnowledge'),
|
|
118
|
+
annotations: toolAnnotations,
|
|
119
|
+
inputSchema: toolSchema,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'list_mcps',
|
|
123
|
+
description: 'インストール可能なMCPサーバーの一覧を表示します(皆伝プラン以上)',
|
|
124
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {},
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'install_mcp',
|
|
132
|
+
description: 'MCPサーバーをサーバーからダウンロードしてローカルにインストールし、Claude Codeの設定に自動追加します',
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: 'object',
|
|
135
|
+
properties: {
|
|
136
|
+
mcp_id: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
description: 'インストールするMCPのID(list_mcpsで確認可能)',
|
|
139
|
+
},
|
|
140
|
+
env_vars: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
description: '環境変数(MCPが必要とする環境変数をキー・バリューで指定)',
|
|
143
|
+
additionalProperties: { type: 'string' },
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
required: ['mcp_id'],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
],
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// ツール実行
|
|
154
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
155
|
+
const { name } = request.params;
|
|
156
|
+
if (name === 'load_knowledge') {
|
|
157
|
+
const { keyword } = request.params.arguments;
|
|
158
|
+
|
|
159
|
+
log(`[MCP Server] load_knowledge called with keyword: ${keyword}`);
|
|
160
|
+
log(`[MCP Server] TOKEN: ${TOKEN ? TOKEN.substring(0, 20) + '...' : 'missing'}`);
|
|
161
|
+
log(`[MCP Server] PORTAL_URL: ${PORTAL_URL}`);
|
|
162
|
+
log(`[MCP Server] LANGUAGE: ${LANGUAGE}`);
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
// Portal APIから認証付きで知識を取得(言語パラメータ付き)
|
|
166
|
+
const result = await getPromptFromPortal(keyword, TOKEN, LANGUAGE);
|
|
167
|
+
|
|
168
|
+
if (!result || !result.success) {
|
|
169
|
+
const errorMessage = result?.error || t('mcp.knowledgeNotFound', { keyword });
|
|
170
|
+
log(`[MCP Server] Knowledge loading failed: ${errorMessage}`);
|
|
171
|
+
return {
|
|
172
|
+
content: [
|
|
173
|
+
{
|
|
174
|
+
type: 'text',
|
|
175
|
+
text: `❌ ${t('mcp.portalApiFailed', { error: errorMessage })}`,
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
isError: true,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// 言語指示(英語ユーザーの場合、周囲の日本語コンテキストに流されないよう明示)
|
|
183
|
+
const langInstruction = LANGUAGE !== 'ja'
|
|
184
|
+
? `\n\n[Note] The user's preferred language is English.`
|
|
185
|
+
: '';
|
|
186
|
+
|
|
187
|
+
// 専門コンテキスト読み込み完了メッセージを返す
|
|
188
|
+
return {
|
|
189
|
+
content: [
|
|
190
|
+
{
|
|
191
|
+
type: 'text',
|
|
192
|
+
text: `✅ ${t('mcp.knowledgeLoadSuccess')}
|
|
193
|
+
|
|
194
|
+
${result.knowledge}${langInstruction}
|
|
195
|
+
|
|
196
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
197
|
+
${t('mcp.knowledgeApplied')}`,
|
|
198
|
+
},
|
|
199
|
+
],
|
|
200
|
+
};
|
|
201
|
+
} catch (error) {
|
|
202
|
+
log(`[MCP Server] Exception in load_knowledge: ${error.message}`);
|
|
203
|
+
return {
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
type: 'text',
|
|
207
|
+
text: `❌ ${t('mcp.knowledgeLoadError', { error: error.message })}`,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
isError: true,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// list_mcps ツール
|
|
216
|
+
if (name === 'list_mcps') {
|
|
217
|
+
log('[MCP Server] list_mcps called');
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
// ポータルAPIからカタログ取得(ランクチェック込み)
|
|
221
|
+
const catalogResult = await listAvailableMcps({}, TOKEN, LANGUAGE);
|
|
222
|
+
if (!catalogResult.success) {
|
|
223
|
+
return {
|
|
224
|
+
content: [{ type: 'text', text: `❌ カタログ取得エラー: ${catalogResult.error}\nブルーランプにログインしてください。` }],
|
|
225
|
+
isError: true,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const rawData = catalogResult.data || {};
|
|
230
|
+
const mcps = rawData.mcps || rawData || [];
|
|
231
|
+
const mcpList = Array.isArray(mcps) ? mcps : [];
|
|
232
|
+
// アクセス可能なMCPのみ表示
|
|
233
|
+
const downloadable = mcpList.filter(m => m.hasAccess);
|
|
234
|
+
|
|
235
|
+
if (downloadable.length === 0) {
|
|
236
|
+
return {
|
|
237
|
+
content: [{ type: 'text', text: '現在インストール可能なMCPはありません。\nプランのアップグレードが必要な場合があります。' }],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const mcpDisplay = downloadable.map(m => {
|
|
242
|
+
const toolInfo = m.toolCount ? `ツール数: ${m.toolCount}` : '';
|
|
243
|
+
return `📦 ${m.name} (ID: ${m.mcpId})\n ${m.description}\n ${toolInfo}`;
|
|
244
|
+
}).join('\n\n');
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
content: [{
|
|
248
|
+
type: 'text',
|
|
249
|
+
text: `✅ インストール可能なMCPサーバー一覧\n\n${mcpDisplay}\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nインストールするには install_mcp ツールを使用してください。\n必要な環境変数は各MCPの詳細で確認できます。`,
|
|
250
|
+
}],
|
|
251
|
+
};
|
|
252
|
+
} catch (error) {
|
|
253
|
+
log(`[MCP Server] list_mcps error: ${error.message}`);
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: 'text', text: `❌ エラー: ${error.message}` }],
|
|
256
|
+
isError: true,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// install_mcp ツール
|
|
262
|
+
if (name === 'install_mcp') {
|
|
263
|
+
const { mcp_id, env_vars = {} } = request.params.arguments;
|
|
264
|
+
log(`[MCP Server] install_mcp called: mcp_id=${mcp_id}`);
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
// ポータルAPIからパッケージをダウンロード(ランクチェック込み)
|
|
268
|
+
const fetch = (...args) => import('node-fetch').then(({default: f}) => f(...args));
|
|
269
|
+
const downloadUrl = `${PORTAL_URL}/api/mcp/${encodeURIComponent(mcp_id)}/download`;
|
|
270
|
+
log(`[MCP Server] Downloading from: ${downloadUrl}`);
|
|
271
|
+
|
|
272
|
+
const response = await fetch(downloadUrl, {
|
|
273
|
+
method: 'GET',
|
|
274
|
+
headers: {
|
|
275
|
+
'X-CLI-Token': TOKEN,
|
|
276
|
+
'Content-Type': 'application/json',
|
|
277
|
+
'User-Agent': 'BlueLamp-MCP/1.0'
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
if (!response.ok) {
|
|
282
|
+
const errorText = await response.text();
|
|
283
|
+
let errorMessage = `HTTP ${response.status}`;
|
|
284
|
+
try {
|
|
285
|
+
const errorData = JSON.parse(errorText);
|
|
286
|
+
errorMessage = errorData.error || errorMessage;
|
|
287
|
+
} catch (e) { /* ignore */ }
|
|
288
|
+
return {
|
|
289
|
+
content: [{ type: 'text', text: `❌ ダウンロードエラー: ${errorMessage}` }],
|
|
290
|
+
isError: true,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const downloadData = await response.json();
|
|
295
|
+
if (!downloadData.success || !downloadData.data) {
|
|
296
|
+
return {
|
|
297
|
+
content: [{ type: 'text', text: `❌ ダウンロードデータが不正です` }],
|
|
298
|
+
isError: true,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const { files, packageSource, name: mcpName } = downloadData.data;
|
|
303
|
+
|
|
304
|
+
// manifest.json を探して設定情報を取得
|
|
305
|
+
const manifestFile = files.find(f => f.path === 'manifest.json');
|
|
306
|
+
let manifest = {};
|
|
307
|
+
if (manifestFile) {
|
|
308
|
+
manifest = JSON.parse(manifestFile.content);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// 必須環境変数の確認(ブロックせず、未設定分はプレースホルダーで進める)
|
|
312
|
+
const requiredEnvVars = packageSource.requiredEnvVars || manifest.requiredEnvVars || [];
|
|
313
|
+
const missingVars = requiredEnvVars.filter(v => !env_vars[v]);
|
|
314
|
+
// 未指定の環境変数にはプレースホルダーをセット
|
|
315
|
+
for (const v of missingVars) {
|
|
316
|
+
env_vars[v] = `YOUR_${v}_HERE`;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// インストール先ディレクトリ
|
|
320
|
+
const destDir = path.join(os.homedir(), '.claude', 'mcp-servers', mcp_id);
|
|
321
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
322
|
+
|
|
323
|
+
// ファイルを書き込み(manifest.json以外)
|
|
324
|
+
for (const file of files) {
|
|
325
|
+
if (file.path === 'manifest.json') continue;
|
|
326
|
+
const filePath = path.join(destDir, file.path);
|
|
327
|
+
const fileDir = path.dirname(filePath);
|
|
328
|
+
fs.mkdirSync(fileDir, { recursive: true });
|
|
329
|
+
fs.writeFileSync(filePath, file.content);
|
|
330
|
+
}
|
|
331
|
+
log(`[MCP Server] Files written to ${destDir}`);
|
|
332
|
+
|
|
333
|
+
// npm install(必要な場合)
|
|
334
|
+
const needsNpm = packageSource.needsNpmInstall || manifest.needsNpmInstall;
|
|
335
|
+
if (needsNpm && fs.existsSync(path.join(destDir, 'package.json'))) {
|
|
336
|
+
log('[MCP Server] Running npm install...');
|
|
337
|
+
try {
|
|
338
|
+
execSync('npm install --production', {
|
|
339
|
+
cwd: destDir,
|
|
340
|
+
stdio: 'pipe',
|
|
341
|
+
timeout: 120000,
|
|
342
|
+
});
|
|
343
|
+
log('[MCP Server] npm install completed');
|
|
344
|
+
} catch (npmError) {
|
|
345
|
+
return {
|
|
346
|
+
content: [{ type: 'text', text: `❌ npm install に失敗しました: ${npmError.message}\n\n手動でインストールしてください:\ncd ${destDir} && npm install` }],
|
|
347
|
+
isError: true,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// 設定ファイルにMCPを登録
|
|
353
|
+
const entryPoint = packageSource.entryPoint || manifest.entryPoint || 'index.js';
|
|
354
|
+
const configTarget = packageSource.configTarget || manifest.configTarget || 'home-mcp';
|
|
355
|
+
const entryPath = path.join(destDir, entryPoint);
|
|
356
|
+
|
|
357
|
+
// 環境変数オブジェクトを構築
|
|
358
|
+
const envConfig = {};
|
|
359
|
+
for (const key of requiredEnvVars) {
|
|
360
|
+
if (env_vars[key]) envConfig[key] = env_vars[key];
|
|
361
|
+
}
|
|
362
|
+
const optionalEnvVars = packageSource.optionalEnvVars || manifest.optionalEnvVars || [];
|
|
363
|
+
for (const key of optionalEnvVars) {
|
|
364
|
+
if (env_vars[key]) envConfig[key] = env_vars[key];
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const mcpConfig = {
|
|
368
|
+
type: 'stdio',
|
|
369
|
+
command: 'node',
|
|
370
|
+
args: [entryPath],
|
|
371
|
+
...(Object.keys(envConfig).length > 0 ? { env: envConfig } : {}),
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
let configFilePath;
|
|
375
|
+
if (configTarget === 'claude-json') {
|
|
376
|
+
configFilePath = path.join(os.homedir(), '.claude.json');
|
|
377
|
+
} else {
|
|
378
|
+
configFilePath = path.join(os.homedir(), '.mcp.json');
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
let config = {};
|
|
382
|
+
if (fs.existsSync(configFilePath)) {
|
|
383
|
+
config = JSON.parse(fs.readFileSync(configFilePath, 'utf8'));
|
|
384
|
+
}
|
|
385
|
+
config.mcpServers = config.mcpServers || {};
|
|
386
|
+
config.mcpServers[mcp_id] = mcpConfig;
|
|
387
|
+
fs.writeFileSync(configFilePath, JSON.stringify(config, null, 2));
|
|
388
|
+
|
|
389
|
+
log(`[MCP Server] ${mcp_id} installed and configured in ${configFilePath}`);
|
|
390
|
+
|
|
391
|
+
const installNotes = packageSource.installNotes || manifest.installNotes || '';
|
|
392
|
+
const envSummary = Object.keys(envConfig).length > 0
|
|
393
|
+
? '\n🔧 環境変数:\n' + Object.keys(envConfig).map(k => ` - ${k}: ${envConfig[k].substring(0, 30)}...`).join('\n')
|
|
394
|
+
: '';
|
|
395
|
+
const missingNote = missingVars.length > 0
|
|
396
|
+
? `\n\n⚠️ 以下の環境変数を設定ファイル (${configFilePath}) で実際の値に書き換えてください:\n${missingVars.map(v => ` - ${v}`).join('\n')}`
|
|
397
|
+
: '';
|
|
398
|
+
|
|
399
|
+
return {
|
|
400
|
+
content: [{
|
|
401
|
+
type: 'text',
|
|
402
|
+
text: `✅ ${mcpName || mcp_id} をインストールしました!
|
|
403
|
+
|
|
404
|
+
📁 インストール先: ${destDir}
|
|
405
|
+
📁 設定ファイル: ${configFilePath}${envSummary}
|
|
406
|
+
|
|
407
|
+
⚡ Claude Codeを再起動すると使用可能になります。${missingNote}
|
|
408
|
+
${installNotes ? '\n📝 ' + installNotes : ''}`,
|
|
409
|
+
}],
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
} catch (error) {
|
|
413
|
+
log(`[MCP Server] install_mcp error: ${error.message}`);
|
|
414
|
+
return {
|
|
415
|
+
content: [{ type: 'text', text: `❌ インストールエラー: ${error.message}` }],
|
|
416
|
+
isError: true,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return {
|
|
422
|
+
content: [
|
|
423
|
+
{
|
|
424
|
+
type: 'text',
|
|
425
|
+
text: `Unknown tool: ${request.params.name}`,
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
isError: true,
|
|
429
|
+
};
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async run() {
|
|
434
|
+
const transport = new StdioServerTransport();
|
|
435
|
+
await this.server.connect(transport);
|
|
436
|
+
logger.info('BlueLamp VSCode MCP server started');
|
|
437
|
+
|
|
438
|
+
// 起動時に自動的に知識を読み込み(環境変数で指定されたキーワード)
|
|
439
|
+
if (KEYWORD && TOKEN) {
|
|
440
|
+
log(`[MCP Server] Auto-loading knowledge for keyword: ${KEYWORD} (lang: ${LANGUAGE})`);
|
|
441
|
+
const result = await getPromptFromPortal(KEYWORD, TOKEN, LANGUAGE);
|
|
442
|
+
if (result && result.success) {
|
|
443
|
+
log(`[MCP Server] Auto-load successful: ${result.title}`);
|
|
444
|
+
} else {
|
|
445
|
+
log(`[MCP Server] Auto-load failed for keyword: ${KEYWORD}`);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// サーバー起動
|
|
452
|
+
const server = new BlueLampVSCodeServer();
|
|
453
|
+
server.run().catch((err) => logger.error(err.message));
|