yamatovision 1.0.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.
Potentially problematic release.
This version of yamatovision might be problematic. Click here for more details.
- package/README.md +14 -0
- package/bin/bluelamp-vscode-base +325 -0
- package/bin/bluelamp1 +2 -0
- package/bin/bluelamp10 +2 -0
- package/bin/bluelamp100 +2 -0
- package/bin/bluelamp11 +2 -0
- package/bin/bluelamp12 +2 -0
- package/bin/bluelamp13 +2 -0
- package/bin/bluelamp14 +2 -0
- package/bin/bluelamp15 +2 -0
- package/bin/bluelamp16 +2 -0
- package/bin/bluelamp17 +2 -0
- package/bin/bluelamp18 +2 -0
- package/bin/bluelamp19 +2 -0
- package/bin/bluelamp2 +2 -0
- package/bin/bluelamp20 +2 -0
- package/bin/bluelamp21 +2 -0
- package/bin/bluelamp22 +2 -0
- package/bin/bluelamp23 +2 -0
- package/bin/bluelamp24 +2 -0
- package/bin/bluelamp25 +2 -0
- package/bin/bluelamp26 +2 -0
- package/bin/bluelamp27 +2 -0
- package/bin/bluelamp28 +2 -0
- package/bin/bluelamp29 +2 -0
- package/bin/bluelamp3 +2 -0
- package/bin/bluelamp30 +2 -0
- package/bin/bluelamp31 +2 -0
- package/bin/bluelamp32 +2 -0
- package/bin/bluelamp33 +2 -0
- package/bin/bluelamp34 +2 -0
- package/bin/bluelamp35 +2 -0
- package/bin/bluelamp36 +2 -0
- package/bin/bluelamp37 +2 -0
- package/bin/bluelamp38 +2 -0
- package/bin/bluelamp39 +2 -0
- package/bin/bluelamp4 +2 -0
- package/bin/bluelamp40 +2 -0
- package/bin/bluelamp41 +2 -0
- package/bin/bluelamp42 +2 -0
- package/bin/bluelamp43 +2 -0
- package/bin/bluelamp44 +2 -0
- package/bin/bluelamp45 +2 -0
- package/bin/bluelamp46 +2 -0
- package/bin/bluelamp47 +2 -0
- package/bin/bluelamp48 +2 -0
- package/bin/bluelamp49 +2 -0
- package/bin/bluelamp5 +2 -0
- package/bin/bluelamp50 +2 -0
- package/bin/bluelamp51 +2 -0
- package/bin/bluelamp52 +2 -0
- package/bin/bluelamp53 +2 -0
- package/bin/bluelamp54 +2 -0
- package/bin/bluelamp55 +2 -0
- package/bin/bluelamp56 +2 -0
- package/bin/bluelamp57 +2 -0
- package/bin/bluelamp58 +2 -0
- package/bin/bluelamp59 +2 -0
- package/bin/bluelamp6 +2 -0
- package/bin/bluelamp60 +2 -0
- package/bin/bluelamp61 +2 -0
- package/bin/bluelamp62 +2 -0
- package/bin/bluelamp63 +2 -0
- package/bin/bluelamp64 +2 -0
- package/bin/bluelamp65 +2 -0
- package/bin/bluelamp66 +2 -0
- package/bin/bluelamp67 +2 -0
- package/bin/bluelamp68 +2 -0
- package/bin/bluelamp69 +2 -0
- package/bin/bluelamp7 +2 -0
- package/bin/bluelamp70 +2 -0
- package/bin/bluelamp71 +2 -0
- package/bin/bluelamp72 +2 -0
- package/bin/bluelamp73 +2 -0
- package/bin/bluelamp74 +2 -0
- package/bin/bluelamp75 +2 -0
- package/bin/bluelamp76 +2 -0
- package/bin/bluelamp77 +2 -0
- package/bin/bluelamp78 +2 -0
- package/bin/bluelamp79 +2 -0
- package/bin/bluelamp8 +2 -0
- package/bin/bluelamp80 +2 -0
- package/bin/bluelamp81 +2 -0
- package/bin/bluelamp82 +2 -0
- package/bin/bluelamp83 +2 -0
- package/bin/bluelamp84 +2 -0
- package/bin/bluelamp85 +2 -0
- package/bin/bluelamp86 +2 -0
- package/bin/bluelamp87 +2 -0
- package/bin/bluelamp88 +2 -0
- package/bin/bluelamp89 +2 -0
- package/bin/bluelamp9 +2 -0
- package/bin/bluelamp90 +2 -0
- package/bin/bluelamp91 +2 -0
- package/bin/bluelamp92 +2 -0
- package/bin/bluelamp93 +2 -0
- package/bin/bluelamp94 +2 -0
- package/bin/bluelamp95 +2 -0
- package/bin/bluelamp96 +2 -0
- package/bin/bluelamp97 +2 -0
- package/bin/bluelamp98 +2 -0
- package/bin/bluelamp99 +2 -0
- package/bin/musuhi1 +2 -0
- package/bin/musuhi10 +2 -0
- package/bin/musuhi100 +2 -0
- package/bin/musuhi11 +2 -0
- package/bin/musuhi12 +2 -0
- package/bin/musuhi13 +2 -0
- package/bin/musuhi14 +2 -0
- package/bin/musuhi15 +2 -0
- package/bin/musuhi16 +2 -0
- package/bin/musuhi17 +2 -0
- package/bin/musuhi18 +2 -0
- package/bin/musuhi19 +2 -0
- package/bin/musuhi2 +2 -0
- package/bin/musuhi20 +2 -0
- package/bin/musuhi21 +2 -0
- package/bin/musuhi22 +2 -0
- package/bin/musuhi23 +2 -0
- package/bin/musuhi24 +2 -0
- package/bin/musuhi25 +2 -0
- package/bin/musuhi26 +2 -0
- package/bin/musuhi27 +2 -0
- package/bin/musuhi28 +2 -0
- package/bin/musuhi29 +2 -0
- package/bin/musuhi3 +2 -0
- package/bin/musuhi30 +2 -0
- package/bin/musuhi31 +2 -0
- package/bin/musuhi32 +2 -0
- package/bin/musuhi33 +2 -0
- package/bin/musuhi34 +2 -0
- package/bin/musuhi35 +2 -0
- package/bin/musuhi36 +2 -0
- package/bin/musuhi37 +2 -0
- package/bin/musuhi38 +2 -0
- package/bin/musuhi39 +2 -0
- package/bin/musuhi4 +2 -0
- package/bin/musuhi40 +2 -0
- package/bin/musuhi41 +2 -0
- package/bin/musuhi42 +2 -0
- package/bin/musuhi43 +2 -0
- package/bin/musuhi44 +2 -0
- package/bin/musuhi45 +2 -0
- package/bin/musuhi46 +2 -0
- package/bin/musuhi47 +2 -0
- package/bin/musuhi48 +2 -0
- package/bin/musuhi49 +2 -0
- package/bin/musuhi5 +2 -0
- package/bin/musuhi50 +2 -0
- package/bin/musuhi51 +2 -0
- package/bin/musuhi52 +2 -0
- package/bin/musuhi53 +2 -0
- package/bin/musuhi54 +2 -0
- package/bin/musuhi55 +2 -0
- package/bin/musuhi56 +2 -0
- package/bin/musuhi57 +2 -0
- package/bin/musuhi58 +2 -0
- package/bin/musuhi59 +2 -0
- package/bin/musuhi6 +2 -0
- package/bin/musuhi60 +2 -0
- package/bin/musuhi61 +2 -0
- package/bin/musuhi62 +2 -0
- package/bin/musuhi63 +2 -0
- package/bin/musuhi64 +2 -0
- package/bin/musuhi65 +2 -0
- package/bin/musuhi66 +2 -0
- package/bin/musuhi67 +2 -0
- package/bin/musuhi68 +2 -0
- package/bin/musuhi69 +2 -0
- package/bin/musuhi7 +2 -0
- package/bin/musuhi70 +2 -0
- package/bin/musuhi71 +2 -0
- package/bin/musuhi72 +2 -0
- package/bin/musuhi73 +2 -0
- package/bin/musuhi74 +2 -0
- package/bin/musuhi75 +2 -0
- package/bin/musuhi76 +2 -0
- package/bin/musuhi77 +2 -0
- package/bin/musuhi78 +2 -0
- package/bin/musuhi79 +2 -0
- package/bin/musuhi8 +2 -0
- package/bin/musuhi80 +2 -0
- package/bin/musuhi81 +2 -0
- package/bin/musuhi82 +2 -0
- package/bin/musuhi83 +2 -0
- package/bin/musuhi84 +2 -0
- package/bin/musuhi85 +2 -0
- package/bin/musuhi86 +2 -0
- package/bin/musuhi87 +2 -0
- package/bin/musuhi88 +2 -0
- package/bin/musuhi89 +2 -0
- package/bin/musuhi9 +2 -0
- package/bin/musuhi90 +2 -0
- package/bin/musuhi91 +2 -0
- package/bin/musuhi92 +2 -0
- package/bin/musuhi93 +2 -0
- package/bin/musuhi94 +2 -0
- package/bin/musuhi95 +2 -0
- package/bin/musuhi96 +2 -0
- package/bin/musuhi97 +2 -0
- package/bin/musuhi98 +2 -0
- package/bin/musuhi99 +2 -0
- package/lib/agents//343/203/226/343/203/253/343/203/274/343/203/251/343/203/263/343/203/227.md +106 -0
- package/lib/auth/InteractiveLogin.js +253 -0
- package/lib/auth/PortalAuthClient.js +184 -0
- package/lib/auth/TokenManager.js +260 -0
- package/lib/i18n/en.json +136 -0
- package/lib/i18n/index.js +75 -0
- package/lib/i18n/ja.json +136 -0
- package/lib/mcp-server/index.cjs +536 -0
- package/lib/mcp-server/portal-api-client.cjs +586 -0
- package/lib/utils/logger.js +83 -0
- package/package.json +155 -0
- package/scripts/build.js +348 -0
- package/scripts/generate-commands.js +45 -0
- package/scripts/playwright-launch.js +141 -0
- package/scripts/setup-playwright.js +62 -0
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
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, reportViolation, listAvailableMcps, getMcpInfo, callMcpTool, deployUserMcp, listUserCreatedMcps, deleteUserMcp } = require('./portal-api-client.cjs');
|
|
15
|
+
const { logger } = require('../utils/logger');
|
|
16
|
+
const { t, setLanguage } = require('../i18n');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const os = require('os');
|
|
20
|
+
|
|
21
|
+
// .envファイルを読み込み(.env.localを優先)
|
|
22
|
+
const dotenvLocalPath = path.join(__dirname, '../../.env.local');
|
|
23
|
+
const dotenvPath = path.join(__dirname, '../../.env');
|
|
24
|
+
|
|
25
|
+
if (fs.existsSync(dotenvLocalPath)) {
|
|
26
|
+
require('dotenv').config({ path: dotenvLocalPath });
|
|
27
|
+
logger.debug('[MCP Server] Loaded .env.local');
|
|
28
|
+
} else if (fs.existsSync(dotenvPath)) {
|
|
29
|
+
require('dotenv').config({ path: dotenvPath });
|
|
30
|
+
logger.debug('[MCP Server] Loaded .env');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 環境変数から取得
|
|
34
|
+
const KEYWORD = process.env.BLUELAMP_KEYWORD || 'BL-要件定義';
|
|
35
|
+
const TOKEN = process.env.BLUELAMP_TOKEN;
|
|
36
|
+
const PORTAL_URL = process.env.PORTAL_URL || 'https://musuhi-portal-235426778039.asia-northeast1.run.app';
|
|
37
|
+
const LANGUAGE = process.env.BLUELAMP_LANGUAGE || 'ja';
|
|
38
|
+
|
|
39
|
+
// 言語設定を適用
|
|
40
|
+
setLanguage(LANGUAGE);
|
|
41
|
+
|
|
42
|
+
// ログファイル設定(ユーザーホームディレクトリに保存)
|
|
43
|
+
const LOG_DIR = path.join(os.homedir(), '.bluelamp-vscode', 'logs');
|
|
44
|
+
const LOG_FILE = path.join(LOG_DIR, 'mcp.log');
|
|
45
|
+
|
|
46
|
+
// ログディレクトリが存在しない場合は作成
|
|
47
|
+
if (!fs.existsSync(LOG_DIR)) {
|
|
48
|
+
fs.mkdirSync(LOG_DIR, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* ファイルとコンソールにログを出力
|
|
53
|
+
* @param {string} message - ログメッセージ
|
|
54
|
+
*/
|
|
55
|
+
function log(message) {
|
|
56
|
+
const timestamp = new Date().toISOString();
|
|
57
|
+
const logMessage = `[${timestamp}] ${message}\n`;
|
|
58
|
+
fs.appendFileSync(LOG_FILE, logMessage);
|
|
59
|
+
logger.info(`[MCP Server] ${message}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
log(`MCP Server started - Log file: ${LOG_FILE}`);
|
|
63
|
+
log(`Environment variables:`);
|
|
64
|
+
log(` KEYWORD: ${KEYWORD}`);
|
|
65
|
+
log(` TOKEN: ${TOKEN ? TOKEN.substring(0, 20) + '...' : 'NOT SET'}`);
|
|
66
|
+
log(` PORTAL_URL: ${PORTAL_URL}`);
|
|
67
|
+
log(` LANGUAGE: ${LANGUAGE}`);
|
|
68
|
+
log(` .env file exists: ${fs.existsSync(dotenvPath)}`);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* BlueLamp VSCode MCPサーバークラス
|
|
72
|
+
* @class BlueLampVSCodeServer
|
|
73
|
+
*/
|
|
74
|
+
class BlueLampVSCodeServer {
|
|
75
|
+
constructor() {
|
|
76
|
+
this.server = new Server(
|
|
77
|
+
{
|
|
78
|
+
name: 'bluelamp',
|
|
79
|
+
version: '1.0.0',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
capabilities: {
|
|
83
|
+
tools: {},
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
this.setupHandlers();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
setupHandlers() {
|
|
92
|
+
// ツール一覧を返す
|
|
93
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
94
|
+
log('[MCP Server] ListTools request received');
|
|
95
|
+
const toolSchema = {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
keyword: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
description: t('mcp.keywordDescription'),
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
required: ['keyword'],
|
|
104
|
+
};
|
|
105
|
+
const toolAnnotations = {
|
|
106
|
+
readOnlyHint: true,
|
|
107
|
+
idempotentHint: true,
|
|
108
|
+
};
|
|
109
|
+
return {
|
|
110
|
+
tools: [
|
|
111
|
+
{
|
|
112
|
+
name: 'load_knowledge',
|
|
113
|
+
description: t('mcp.toolDescriptionLoadKnowledge'),
|
|
114
|
+
annotations: toolAnnotations,
|
|
115
|
+
inputSchema: toolSchema,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: 'inject_knowledge',
|
|
119
|
+
description: t('mcp.toolDescriptionInjectKnowledge'),
|
|
120
|
+
annotations: toolAnnotations,
|
|
121
|
+
inputSchema: toolSchema,
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
name: 'report_violation',
|
|
125
|
+
description: t('mcp.toolDescriptionReportViolation'),
|
|
126
|
+
annotations: {
|
|
127
|
+
readOnlyHint: false,
|
|
128
|
+
idempotentHint: false,
|
|
129
|
+
},
|
|
130
|
+
inputSchema: {
|
|
131
|
+
type: 'object',
|
|
132
|
+
properties: {
|
|
133
|
+
reason: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
description: t('mcp.violationReasonDescription'),
|
|
136
|
+
},
|
|
137
|
+
severity: {
|
|
138
|
+
type: 'string',
|
|
139
|
+
enum: ['warning', 'serious', 'critical'],
|
|
140
|
+
description: t('mcp.violationSeverityDescription'),
|
|
141
|
+
},
|
|
142
|
+
userMessage: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
description: t('mcp.violationUserMessageDescription'),
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
required: ['reason', 'severity'],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: 'list_available_mcps',
|
|
152
|
+
description: t('mcp.toolDescriptionListMcps'),
|
|
153
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
154
|
+
inputSchema: {
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: {
|
|
157
|
+
category: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
enum: ['productivity', 'development', 'communication', 'data', 'media', 'custom'],
|
|
160
|
+
description: t('mcp.listMcpsCategoryDescription'),
|
|
161
|
+
},
|
|
162
|
+
search: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
description: t('mcp.listMcpsSearchDescription'),
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
required: [],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'get_mcp_info',
|
|
172
|
+
description: t('mcp.toolDescriptionGetMcpInfo'),
|
|
173
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
174
|
+
inputSchema: {
|
|
175
|
+
type: 'object',
|
|
176
|
+
properties: {
|
|
177
|
+
mcp_id: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
description: t('mcp.getMcpInfoIdDescription'),
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
required: ['mcp_id'],
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: 'call_tool',
|
|
187
|
+
description: t('mcp.toolDescriptionCallTool'),
|
|
188
|
+
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: 'object',
|
|
191
|
+
properties: {
|
|
192
|
+
mcp_id: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
description: t('mcp.callToolMcpIdDescription'),
|
|
195
|
+
},
|
|
196
|
+
tool_name: {
|
|
197
|
+
type: 'string',
|
|
198
|
+
description: t('mcp.callToolNameDescription'),
|
|
199
|
+
},
|
|
200
|
+
arguments: {
|
|
201
|
+
type: 'object',
|
|
202
|
+
description: t('mcp.callToolArgsDescription'),
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
required: ['mcp_id', 'tool_name'],
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'create_user_mcp',
|
|
210
|
+
description: t('mcp.toolDescriptionCreateUserMcp'),
|
|
211
|
+
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
212
|
+
inputSchema: {
|
|
213
|
+
type: 'object',
|
|
214
|
+
properties: {
|
|
215
|
+
name: { type: 'string', description: t('mcp.createMcpNameDescription') },
|
|
216
|
+
description: { type: 'string', description: t('mcp.createMcpDescDescription') },
|
|
217
|
+
tools: { type: 'string', description: t('mcp.createMcpToolsDescription') },
|
|
218
|
+
code: { type: 'string', description: t('mcp.createMcpCodeDescription') },
|
|
219
|
+
category: { type: 'string', enum: ['productivity', 'development', 'communication', 'data', 'media', 'custom'], description: t('mcp.createMcpCategoryDescription') },
|
|
220
|
+
envVars: { type: 'string', description: t('mcp.createMcpEnvVarsDescription') },
|
|
221
|
+
},
|
|
222
|
+
required: ['name', 'description', 'code'],
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: 'list_user_mcps',
|
|
227
|
+
description: t('mcp.toolDescriptionListUserMcps'),
|
|
228
|
+
annotations: { readOnlyHint: true, idempotentHint: true },
|
|
229
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
name: 'delete_user_mcp',
|
|
233
|
+
description: t('mcp.toolDescriptionDeleteUserMcp'),
|
|
234
|
+
annotations: { readOnlyHint: false, idempotentHint: false },
|
|
235
|
+
inputSchema: {
|
|
236
|
+
type: 'object',
|
|
237
|
+
properties: {
|
|
238
|
+
mcp_id: { type: 'string', description: t('mcp.deleteUserMcpIdDescription') },
|
|
239
|
+
},
|
|
240
|
+
required: ['mcp_id'],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// ツール実行
|
|
248
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
249
|
+
const { name } = request.params;
|
|
250
|
+
if (name === 'load_knowledge' || name === 'inject_knowledge') {
|
|
251
|
+
const { keyword } = request.params.arguments;
|
|
252
|
+
|
|
253
|
+
log(`[MCP Server] load_knowledge called with keyword: ${keyword}`);
|
|
254
|
+
log(`[MCP Server] TOKEN: ${TOKEN ? TOKEN.substring(0, 20) + '...' : 'missing'}`);
|
|
255
|
+
log(`[MCP Server] PORTAL_URL: ${PORTAL_URL}`);
|
|
256
|
+
log(`[MCP Server] LANGUAGE: ${LANGUAGE}`);
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
// Portal APIから認証付きで知識を取得(言語パラメータ付き)
|
|
260
|
+
const result = await getPromptFromPortal(keyword, TOKEN, LANGUAGE);
|
|
261
|
+
|
|
262
|
+
if (!result || !result.success) {
|
|
263
|
+
const errorMessage = result?.error || t('mcp.knowledgeNotFound', { keyword });
|
|
264
|
+
log(`[MCP Server] Knowledge loading failed: ${errorMessage}`);
|
|
265
|
+
return {
|
|
266
|
+
content: [
|
|
267
|
+
{
|
|
268
|
+
type: 'text',
|
|
269
|
+
text: `❌ ${t('mcp.portalApiFailed', { error: errorMessage })}`,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
isError: true,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// 言語指示(英語ユーザーの場合、周囲の日本語コンテキストに流されないよう明示)
|
|
277
|
+
const langInstruction = LANGUAGE !== 'ja'
|
|
278
|
+
? `\n\n[Language Instruction] Communicate with the user in English. Respond in English regardless of surrounding context language.`
|
|
279
|
+
: '';
|
|
280
|
+
|
|
281
|
+
// 専門コンテキスト読み込み完了メッセージを返す
|
|
282
|
+
return {
|
|
283
|
+
content: [
|
|
284
|
+
{
|
|
285
|
+
type: 'text',
|
|
286
|
+
text: `✅ ${t('mcp.knowledgeLoadSuccess')}
|
|
287
|
+
|
|
288
|
+
${result.knowledge}${langInstruction}
|
|
289
|
+
|
|
290
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
291
|
+
${t('mcp.knowledgeApplied')}`,
|
|
292
|
+
},
|
|
293
|
+
],
|
|
294
|
+
};
|
|
295
|
+
} catch (error) {
|
|
296
|
+
log(`[MCP Server] Exception in load_knowledge: ${error.message}`);
|
|
297
|
+
return {
|
|
298
|
+
content: [
|
|
299
|
+
{
|
|
300
|
+
type: 'text',
|
|
301
|
+
text: `❌ ${t('mcp.knowledgeLoadError', { error: error.message })}`,
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
isError: true,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (name === 'report_violation') {
|
|
310
|
+
const { reason, severity, userMessage } = request.params.arguments;
|
|
311
|
+
|
|
312
|
+
log(`[MCP Server] report_violation called: severity=${severity}, reason=${reason}`);
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
const result = await reportViolation(reason, severity, TOKEN, userMessage);
|
|
316
|
+
|
|
317
|
+
if (!result || !result.success) {
|
|
318
|
+
return {
|
|
319
|
+
content: [{ type: 'text', text: `❌ ${t('mcp.violationReportFailed', { error: result?.error || 'Unknown' })}` }],
|
|
320
|
+
isError: true,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
content: [{ type: 'text', text: `🔒 ${result.message}` }],
|
|
326
|
+
};
|
|
327
|
+
} catch (error) {
|
|
328
|
+
log(`[MCP Server] report_violation error: ${error.message}`);
|
|
329
|
+
return {
|
|
330
|
+
content: [{ type: 'text', text: `❌ ${t('mcp.violationReportError', { error: error.message })}` }],
|
|
331
|
+
isError: true,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (name === 'list_available_mcps') {
|
|
337
|
+
const { category, search } = request.params.arguments || {};
|
|
338
|
+
log(`[MCP Server] list_available_mcps called: category=${category}, search=${search}`);
|
|
339
|
+
try {
|
|
340
|
+
const result = await listAvailableMcps({ category, search }, TOKEN, LANGUAGE);
|
|
341
|
+
if (!result || !result.success) {
|
|
342
|
+
return { content: [{ type: 'text', text: `❌ ${t('mcp.listMcpsFailed', { error: result?.error || 'Unknown' })}` }], isError: true };
|
|
343
|
+
}
|
|
344
|
+
const mcps = result.data || [];
|
|
345
|
+
let text = `📋 ${t('mcp.listMcpsTitle')}\n\n`;
|
|
346
|
+
if (mcps.length === 0) {
|
|
347
|
+
text += t('mcp.listMcpsEmpty');
|
|
348
|
+
} else {
|
|
349
|
+
mcps.forEach(mcp => {
|
|
350
|
+
const toolCount = mcp.tools?.length || 0;
|
|
351
|
+
text += `**${mcp.name}** (${mcp.mcpId})\n`;
|
|
352
|
+
text += ` ${mcp.description}\n`;
|
|
353
|
+
text += ` カテゴリ: ${mcp.category} | ツール数: ${toolCount} | アクセス: ${mcp.hasAccess ? '✅' : '❌'}\n\n`;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
return { content: [{ type: 'text', text }] };
|
|
357
|
+
} catch (error) {
|
|
358
|
+
log(`[MCP Server] list_available_mcps error: ${error.message}`);
|
|
359
|
+
return { content: [{ type: 'text', text: `❌ ${error.message}` }], isError: true };
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (name === 'get_mcp_info') {
|
|
364
|
+
const { mcp_id } = request.params.arguments;
|
|
365
|
+
log(`[MCP Server] get_mcp_info called: mcpId=${mcp_id}`);
|
|
366
|
+
try {
|
|
367
|
+
const result = await getMcpInfo(mcp_id, TOKEN, LANGUAGE);
|
|
368
|
+
if (!result || !result.success) {
|
|
369
|
+
return { content: [{ type: 'text', text: `❌ ${t('mcp.getMcpInfoFailed', { error: result?.error || 'Unknown' })}` }], isError: true };
|
|
370
|
+
}
|
|
371
|
+
const mcp = result.data;
|
|
372
|
+
let text = `🔧 **${mcp.name}** (${mcp.mcpId})\n\n`;
|
|
373
|
+
text += `${mcp.description}\n\n`;
|
|
374
|
+
text += `カテゴリ: ${mcp.category}\n`;
|
|
375
|
+
text += `アクセス: ${mcp.hasAccess ? '利用可能' : '利用不可'}\n`;
|
|
376
|
+
text += `ステータス: ${mcp.status}\n\n`;
|
|
377
|
+
if (mcp.tools && mcp.tools.length > 0) {
|
|
378
|
+
text += `### ツール一覧 (${mcp.tools.length})\n\n`;
|
|
379
|
+
mcp.tools.forEach(tool => {
|
|
380
|
+
text += `- **${tool.name}**: ${tool.description}\n`;
|
|
381
|
+
if (tool.inputSchema?.properties) {
|
|
382
|
+
const params = Object.entries(tool.inputSchema.properties);
|
|
383
|
+
params.forEach(([key, val]) => {
|
|
384
|
+
text += ` - \`${key}\` (${val.type || 'any'}): ${val.description || ''}\n`;
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
if (mcp.requiredCredentials && mcp.requiredCredentials.length > 0) {
|
|
390
|
+
text += `\n### 必要な認証情報\n`;
|
|
391
|
+
mcp.requiredCredentials.forEach(cred => {
|
|
392
|
+
text += `- **${cred.displayName}** (${cred.key}): ${cred.required ? '必須' : '任意'}\n`;
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return { content: [{ type: 'text', text }] };
|
|
396
|
+
} catch (error) {
|
|
397
|
+
log(`[MCP Server] get_mcp_info error: ${error.message}`);
|
|
398
|
+
return { content: [{ type: 'text', text: `❌ ${error.message}` }], isError: true };
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if (name === 'call_tool') {
|
|
403
|
+
const { mcp_id, tool_name, arguments: toolArgs } = request.params.arguments;
|
|
404
|
+
log(`[MCP Server] call_tool called: mcpId=${mcp_id}, tool=${tool_name}`);
|
|
405
|
+
try {
|
|
406
|
+
const result = await callMcpTool(mcp_id, tool_name, toolArgs || {}, TOKEN);
|
|
407
|
+
if (!result || !result.success) {
|
|
408
|
+
return { content: [{ type: 'text', text: `❌ ${t('mcp.callToolFailed', { error: result?.error || 'Unknown' })}` }], isError: true };
|
|
409
|
+
}
|
|
410
|
+
const data = result.data;
|
|
411
|
+
if (typeof data === 'string') {
|
|
412
|
+
return { content: [{ type: 'text', text: data }] };
|
|
413
|
+
}
|
|
414
|
+
return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };
|
|
415
|
+
} catch (error) {
|
|
416
|
+
log(`[MCP Server] call_tool error: ${error.message}`);
|
|
417
|
+
return { content: [{ type: 'text', text: `❌ ${error.message}` }], isError: true };
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (name === 'create_user_mcp') {
|
|
422
|
+
const args = request.params.arguments;
|
|
423
|
+
log(`[MCP Server] create_user_mcp called: name=${args.name}`);
|
|
424
|
+
try {
|
|
425
|
+
// tools/envVars がJSON文字列の場合パース
|
|
426
|
+
let tools = args.tools;
|
|
427
|
+
if (typeof tools === 'string') {
|
|
428
|
+
try { tools = JSON.parse(tools); } catch (e) { tools = []; }
|
|
429
|
+
}
|
|
430
|
+
let envVars = args.envVars;
|
|
431
|
+
if (typeof envVars === 'string') {
|
|
432
|
+
try { envVars = JSON.parse(envVars); } catch (e) { envVars = undefined; }
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const deployData = {
|
|
436
|
+
code: args.code,
|
|
437
|
+
name: args.name,
|
|
438
|
+
description: args.description || '',
|
|
439
|
+
tools: tools || [],
|
|
440
|
+
category: args.category || 'custom',
|
|
441
|
+
envVars
|
|
442
|
+
};
|
|
443
|
+
|
|
444
|
+
const result = await deployUserMcp(deployData, TOKEN);
|
|
445
|
+
if (!result || !result.success) {
|
|
446
|
+
const errorMsg = result?.details
|
|
447
|
+
? `${t('mcp.createMcpScanFailed')}\n${JSON.stringify(result.details, null, 2)}`
|
|
448
|
+
: t('mcp.createMcpFailed', { error: result?.error || 'Unknown' });
|
|
449
|
+
return { content: [{ type: 'text', text: `❌ ${errorMsg}` }], isError: true };
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const data = result.data;
|
|
453
|
+
return {
|
|
454
|
+
content: [{ type: 'text', text: `✅ ${t('mcp.createMcpSuccess')}\n\n**MCP ID**: ${data.mcpId}\n**Endpoint**: ${data.endpoint}\n**有効化**: ${data.enabled ? '自動有効化済み' : '未有効化'}` }]
|
|
455
|
+
};
|
|
456
|
+
} catch (error) {
|
|
457
|
+
log(`[MCP Server] create_user_mcp error: ${error.message}`);
|
|
458
|
+
return { content: [{ type: 'text', text: `❌ ${error.message}` }], isError: true };
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
if (name === 'list_user_mcps') {
|
|
463
|
+
log(`[MCP Server] list_user_mcps called`);
|
|
464
|
+
try {
|
|
465
|
+
const result = await listUserCreatedMcps(TOKEN);
|
|
466
|
+
if (!result || !result.success) {
|
|
467
|
+
return { content: [{ type: 'text', text: `❌ ${result?.error || 'Unknown'}` }], isError: true };
|
|
468
|
+
}
|
|
469
|
+
const mcps = result.data?.mcps || [];
|
|
470
|
+
let text = `📋 ${t('mcp.listUserMcpsTitle')}\n\n`;
|
|
471
|
+
if (mcps.length === 0) {
|
|
472
|
+
text += t('mcp.listUserMcpsEmpty');
|
|
473
|
+
} else {
|
|
474
|
+
mcps.forEach(mcp => {
|
|
475
|
+
text += `**${mcp.name}** (${mcp.mcpId})\n`;
|
|
476
|
+
text += ` ${mcp.description || ''}\n`;
|
|
477
|
+
text += ` カテゴリ: ${mcp.category} | ツール数: ${mcp.toolCount || 0} | ステータス: ${mcp.status}\n`;
|
|
478
|
+
if (mcp.endpoint) text += ` エンドポイント: ${mcp.endpoint}\n`;
|
|
479
|
+
text += '\n';
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
return { content: [{ type: 'text', text }] };
|
|
483
|
+
} catch (error) {
|
|
484
|
+
log(`[MCP Server] list_user_mcps error: ${error.message}`);
|
|
485
|
+
return { content: [{ type: 'text', text: `❌ ${error.message}` }], isError: true };
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (name === 'delete_user_mcp') {
|
|
490
|
+
const { mcp_id } = request.params.arguments;
|
|
491
|
+
log(`[MCP Server] delete_user_mcp called: mcpId=${mcp_id}`);
|
|
492
|
+
try {
|
|
493
|
+
const result = await deleteUserMcp(mcp_id, TOKEN);
|
|
494
|
+
if (!result || !result.success) {
|
|
495
|
+
return { content: [{ type: 'text', text: `❌ ${t('mcp.deleteUserMcpFailed', { error: result?.error || 'Unknown' })}` }], isError: true };
|
|
496
|
+
}
|
|
497
|
+
return { content: [{ type: 'text', text: `✅ ${t('mcp.deleteUserMcpSuccess', { mcpId: mcp_id })}` }] };
|
|
498
|
+
} catch (error) {
|
|
499
|
+
log(`[MCP Server] delete_user_mcp error: ${error.message}`);
|
|
500
|
+
return { content: [{ type: 'text', text: `❌ ${error.message}` }], isError: true };
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return {
|
|
505
|
+
content: [
|
|
506
|
+
{
|
|
507
|
+
type: 'text',
|
|
508
|
+
text: `Unknown tool: ${request.params.name}`,
|
|
509
|
+
},
|
|
510
|
+
],
|
|
511
|
+
isError: true,
|
|
512
|
+
};
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
async run() {
|
|
517
|
+
const transport = new StdioServerTransport();
|
|
518
|
+
await this.server.connect(transport);
|
|
519
|
+
logger.info('BlueLamp VSCode MCP server started');
|
|
520
|
+
|
|
521
|
+
// 起動時に自動的に知識を読み込み(環境変数で指定されたキーワード)
|
|
522
|
+
if (KEYWORD && TOKEN) {
|
|
523
|
+
log(`[MCP Server] Auto-loading knowledge for keyword: ${KEYWORD} (lang: ${LANGUAGE})`);
|
|
524
|
+
const result = await getPromptFromPortal(KEYWORD, TOKEN, LANGUAGE);
|
|
525
|
+
if (result && result.success) {
|
|
526
|
+
log(`[MCP Server] Auto-load successful: ${result.title}`);
|
|
527
|
+
} else {
|
|
528
|
+
log(`[MCP Server] Auto-load failed for keyword: ${KEYWORD}`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// サーバー起動
|
|
535
|
+
const server = new BlueLampVSCodeServer();
|
|
536
|
+
server.run().catch((err) => logger.error(err.message));
|