@wellgrow/mcp 0.1.0 → 0.3.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/README.md +4 -6
- package/dist/index.js +82 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,6 +7,7 @@ WellGrow MCP Server — AI エージェントからユーザーのパーソナ
|
|
|
7
7
|
- **search_user_context** — 質問・回答をセマンティック検索
|
|
8
8
|
- **list_questions** — 質問一覧を取得(タグ・ステータスでフィルタ可)
|
|
9
9
|
- **answer_question** — 質問に対して回答を書き込む
|
|
10
|
+
- **save_feedback** — WellGrow 開発チームへフィードバックを送信
|
|
10
11
|
- **active-questions** リソース — アクティブな質問一覧(`@wellgrow` で参照)
|
|
11
12
|
|
|
12
13
|
## セットアップ
|
|
@@ -23,8 +24,6 @@ npm install -g @wellgrow/mcp
|
|
|
23
24
|
|------|------|------|
|
|
24
25
|
| `WELLGROW_EMAIL` | WellGrow のログインメール | Yes |
|
|
25
26
|
| `WELLGROW_PASSWORD` | WellGrow のログインパスワード | Yes |
|
|
26
|
-
| `WELLGROW_SUPABASE_URL` | Supabase プロジェクト URL | Yes |
|
|
27
|
-
| `WELLGROW_SUPABASE_ANON_KEY` | Supabase anon key | Yes |
|
|
28
27
|
| `OPENAI_API_KEY` | OpenAI API キー(検索の embedding 生成用) | Yes |
|
|
29
28
|
|
|
30
29
|
### 3. MCP サーバーの登録
|
|
@@ -35,8 +34,6 @@ npm install -g @wellgrow/mcp
|
|
|
35
34
|
claude mcp add --transport stdio \
|
|
36
35
|
--env WELLGROW_EMAIL=user@example.com \
|
|
37
36
|
--env WELLGROW_PASSWORD=mypassword \
|
|
38
|
-
--env WELLGROW_SUPABASE_URL=https://xxx.supabase.co \
|
|
39
|
-
--env WELLGROW_SUPABASE_ANON_KEY=eyJ... \
|
|
40
37
|
--env OPENAI_API_KEY=sk-... \
|
|
41
38
|
--scope user \
|
|
42
39
|
wellgrow -- wellgrow-mcp
|
|
@@ -54,8 +51,6 @@ claude mcp add --transport stdio \
|
|
|
54
51
|
"env": {
|
|
55
52
|
"WELLGROW_EMAIL": "user@example.com",
|
|
56
53
|
"WELLGROW_PASSWORD": "mypassword",
|
|
57
|
-
"WELLGROW_SUPABASE_URL": "https://xxx.supabase.co",
|
|
58
|
-
"WELLGROW_SUPABASE_ANON_KEY": "eyJ...",
|
|
59
54
|
"OPENAI_API_KEY": "sk-..."
|
|
60
55
|
}
|
|
61
56
|
}
|
|
@@ -86,6 +81,9 @@ AI: → search_user_context → 検索結果を表示
|
|
|
86
81
|
|
|
87
82
|
ユーザー: 「この質問に『毎朝5分の瞑想から始める』と回答して」
|
|
88
83
|
AI: → answer_question → 回答を保存
|
|
84
|
+
|
|
85
|
+
ユーザー: 「WellGrowの検索、もっとタグでフィルタできるといいな」
|
|
86
|
+
AI: → save_feedback(improvement) → フィードバックを開発チームに送信
|
|
89
87
|
```
|
|
90
88
|
|
|
91
89
|
## 開発
|
package/dist/index.js
CHANGED
|
@@ -6,16 +6,14 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
6
6
|
|
|
7
7
|
// src/auth.ts
|
|
8
8
|
import { createClient } from "@supabase/supabase-js";
|
|
9
|
+
var DEFAULT_SUPABASE_URL = "https://rpywqbtporjdhwtmvwkf.supabase.co";
|
|
10
|
+
var DEFAULT_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJweXdxYnRwb3JqZGh3dG12d2tmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njc4NjA4MDIsImV4cCI6MjA4MzQzNjgwMn0.1nn9F2y1JZBoSgB33CnP-k-6OM5HcEMdUs50RLJ89i4";
|
|
9
11
|
var supabase = null;
|
|
10
12
|
function getSupabaseUrl() {
|
|
11
|
-
|
|
12
|
-
if (!url) throw new Error("WELLGROW_SUPABASE_URL is required");
|
|
13
|
-
return url;
|
|
13
|
+
return process.env.WELLGROW_SUPABASE_URL ?? DEFAULT_SUPABASE_URL;
|
|
14
14
|
}
|
|
15
15
|
function getSupabaseAnonKey() {
|
|
16
|
-
|
|
17
|
-
if (!key) throw new Error("WELLGROW_SUPABASE_ANON_KEY is required");
|
|
18
|
-
return key;
|
|
16
|
+
return process.env.WELLGROW_SUPABASE_ANON_KEY ?? DEFAULT_SUPABASE_ANON_KEY;
|
|
19
17
|
}
|
|
20
18
|
async function getSupabase() {
|
|
21
19
|
if (supabase) {
|
|
@@ -235,23 +233,25 @@ function registerAnswerQuestionTool(server2) {
|
|
|
235
233
|
async ({ question_id, answer, description }) => {
|
|
236
234
|
const supabase2 = await getSupabase();
|
|
237
235
|
const userId = await getUserId();
|
|
236
|
+
const { data: questionData, error: qError } = await supabase2.from("questions").select("question").eq("id", question_id).eq("user_id", userId).single();
|
|
237
|
+
if (qError || !questionData)
|
|
238
|
+
throw new Error(`\u8CEA\u554F\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${question_id}`);
|
|
238
239
|
const { error: insertError } = await supabase2.from("answers").insert({
|
|
239
240
|
question_id,
|
|
240
241
|
user_id: userId,
|
|
242
|
+
question: questionData.question,
|
|
241
243
|
answer,
|
|
242
244
|
description: description ?? null,
|
|
243
245
|
source: "mcp"
|
|
244
246
|
});
|
|
245
247
|
if (insertError)
|
|
246
248
|
throw new Error(`\u56DE\u7B54\u306E\u4FDD\u5B58\u306B\u5931\u6557: ${insertError.message}`);
|
|
247
|
-
const { data: questionData } = await supabase2.from("questions").select("question").eq("id", question_id).single();
|
|
248
|
-
const questionText = questionData?.question ?? question_id;
|
|
249
249
|
return {
|
|
250
250
|
content: [
|
|
251
251
|
{
|
|
252
252
|
type: "text",
|
|
253
253
|
text: `\u56DE\u7B54\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F:
|
|
254
|
-
\u8CEA\u554F: ${
|
|
254
|
+
\u8CEA\u554F: ${questionData.question}
|
|
255
255
|
\u56DE\u7B54: ${answer}`
|
|
256
256
|
}
|
|
257
257
|
]
|
|
@@ -306,6 +306,76 @@ answer_question \u3067\u56DE\u7B54\u3092\u66F8\u304D\u8FBC\u3080\u524D\u306B\u30
|
|
|
306
306
|
);
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
// src/tools/save-feedback.ts
|
|
310
|
+
import { z as z4 } from "zod";
|
|
311
|
+
var feedbackCategories = [
|
|
312
|
+
"bug",
|
|
313
|
+
"improvement",
|
|
314
|
+
"praise",
|
|
315
|
+
"question",
|
|
316
|
+
"other"
|
|
317
|
+
];
|
|
318
|
+
function registerSaveFeedbackTool(server2) {
|
|
319
|
+
server2.registerTool(
|
|
320
|
+
"save_feedback",
|
|
321
|
+
{
|
|
322
|
+
title: "\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u9001\u4FE1",
|
|
323
|
+
description: `WellGrow\u958B\u767A\u30C1\u30FC\u30E0\u3078\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002
|
|
324
|
+
|
|
325
|
+
\u4F7F\u7528\u3059\u308B\u5834\u9762:
|
|
326
|
+
- \u30E6\u30FC\u30B6\u30FC\u304CWellGrow\u3078\u306E\u6539\u5584\u63D0\u6848\u30FB\u30D0\u30B0\u5831\u544A\u30FB\u611F\u60F3\u3092\u4F1D\u3048\u305F\u3044\u3068\u304D
|
|
327
|
+
- WellGrow\u306E\u30C4\u30FC\u30EB\uFF08search_user_context\u7B49\uFF09\u3067\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u305F\u3068\u304D
|
|
328
|
+
- \u30E6\u30FC\u30B6\u30FC\u304CWellGrow\u306E\u4F53\u9A13\u306B\u3064\u3044\u3066\u8A00\u53CA\u3057\u305F\u3068\u304D
|
|
329
|
+
|
|
330
|
+
\u91CD\u8981: \u30E6\u30FC\u30B6\u30FC\u304C\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u306E\u9001\u4FE1\u3092\u610F\u56F3\u3057\u3066\u3044\u308B\u3053\u3068\u3092\u78BA\u8A8D\u3057\u3066\u304B\u3089\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002
|
|
331
|
+
\u30C4\u30FC\u30EB\u30A8\u30E9\u30FC\u306E\u5831\u544A\u3092\u9664\u304D\u3001\u30E6\u30FC\u30B6\u30FC\u306E\u627F\u8A8D\u306A\u304F\u9001\u4FE1\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
|
|
332
|
+
|
|
333
|
+
\u30AB\u30C6\u30B4\u30EA\u306E\u9078\u3073\u65B9:
|
|
334
|
+
- bug: \u30A8\u30E9\u30FC\u3084\u30D0\u30B0\u306B\u95A2\u3059\u308B\u3082\u306E
|
|
335
|
+
- improvement: \u6A5F\u80FD\u6539\u5584\u306E\u63D0\u6848\u3084\u30A2\u30A4\u30C7\u30A2
|
|
336
|
+
- praise: \u826F\u304B\u3063\u305F\u70B9\u3001\u6E80\u8DB3\u3057\u305F\u4F53\u9A13
|
|
337
|
+
- question: WellGrow\u306B\u95A2\u3059\u308B\u672A\u89E3\u6C7A\u306E\u8CEA\u554F
|
|
338
|
+
- other: \u4E0A\u8A18\u306B\u5F53\u3066\u306F\u307E\u3089\u306A\u3044\u3082\u306E`,
|
|
339
|
+
inputSchema: z4.object({
|
|
340
|
+
category: z4.enum(feedbackCategories).describe("\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u306E\u30AB\u30C6\u30B4\u30EA"),
|
|
341
|
+
message: z4.string().min(1).max(2e3).describe(
|
|
342
|
+
"\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u306E\u5185\u5BB9\u3002\u958B\u767A\u8005\u304C\u72B6\u6CC1\u3092\u7406\u89E3\u3067\u304D\u308B\u3088\u3046\u306B\u8981\u7D04"
|
|
343
|
+
),
|
|
344
|
+
user_message: z4.string().max(500).optional().describe("\u304D\u3063\u304B\u3051\u3068\u306A\u3063\u305F\u30E6\u30FC\u30B6\u30FC\u306E\u767A\u8A00\uFF08\u539F\u6587\u3092\u77ED\u304F\u5F15\u7528\uFF09")
|
|
345
|
+
}),
|
|
346
|
+
annotations: {
|
|
347
|
+
readOnlyHint: false,
|
|
348
|
+
destructiveHint: false,
|
|
349
|
+
idempotentHint: false
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
async ({ category, message, user_message }) => {
|
|
353
|
+
const supabase2 = await getSupabase();
|
|
354
|
+
const userId = await getUserId();
|
|
355
|
+
const context = {};
|
|
356
|
+
if (user_message) context.user_message = user_message;
|
|
357
|
+
const { error } = await supabase2.from("feedbacks").insert({
|
|
358
|
+
category,
|
|
359
|
+
message,
|
|
360
|
+
source: "mcp",
|
|
361
|
+
user_id: userId,
|
|
362
|
+
page_path: "mcp",
|
|
363
|
+
context: Object.keys(context).length > 0 ? context : null
|
|
364
|
+
});
|
|
365
|
+
if (error)
|
|
366
|
+
throw new Error(`\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u306E\u4FDD\u5B58\u306B\u5931\u6557: ${error.message}`);
|
|
367
|
+
return {
|
|
368
|
+
content: [
|
|
369
|
+
{
|
|
370
|
+
type: "text",
|
|
371
|
+
text: `\u30D5\u30A3\u30FC\u30C9\u30D0\u30C3\u30AF\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F\uFF08${category}\uFF09`
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
309
379
|
// src/resources/questions.ts
|
|
310
380
|
function registerQuestionsResource(server2) {
|
|
311
381
|
server2.registerResource(
|
|
@@ -332,13 +402,7 @@ function registerQuestionsResource(server2) {
|
|
|
332
402
|
}
|
|
333
403
|
|
|
334
404
|
// src/index.ts
|
|
335
|
-
var required = [
|
|
336
|
-
"WELLGROW_EMAIL",
|
|
337
|
-
"WELLGROW_PASSWORD",
|
|
338
|
-
"WELLGROW_SUPABASE_URL",
|
|
339
|
-
"WELLGROW_SUPABASE_ANON_KEY",
|
|
340
|
-
"OPENAI_API_KEY"
|
|
341
|
-
];
|
|
405
|
+
var required = ["WELLGROW_EMAIL", "WELLGROW_PASSWORD", "OPENAI_API_KEY"];
|
|
342
406
|
for (const key of required) {
|
|
343
407
|
if (!process.env[key]) {
|
|
344
408
|
console.error(`Error: ${key} is required`);
|
|
@@ -356,7 +420,7 @@ try {
|
|
|
356
420
|
process.exit(1);
|
|
357
421
|
}
|
|
358
422
|
var server = new McpServer(
|
|
359
|
-
{ name: "wellgrow", version: "0.
|
|
423
|
+
{ name: "wellgrow", version: "0.3.0" },
|
|
360
424
|
{
|
|
361
425
|
instructions: `WellGrow \u306E\u30E6\u30FC\u30B6\u30FC\u30CA\u30EC\u30C3\u30B8\u30D9\u30FC\u30B9\u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u30B5\u30FC\u30D0\u30FC\u3067\u3059\u3002
|
|
362
426
|
\u30E6\u30FC\u30B6\u30FC\u306E\u8CEA\u554F\u30FB\u56DE\u7B54\u30C7\u30FC\u30BF\u306E\u691C\u7D22\u30FB\u95B2\u89A7\u30FB\u66F8\u304D\u8FBC\u307F\u304C\u3067\u304D\u307E\u3059\u3002
|
|
@@ -366,6 +430,7 @@ var server = new McpServer(
|
|
|
366
430
|
registerSearchContextTool(server);
|
|
367
431
|
registerAnswerQuestionTool(server);
|
|
368
432
|
registerListQuestionsTool(server);
|
|
433
|
+
registerSaveFeedbackTool(server);
|
|
369
434
|
registerQuestionsResource(server);
|
|
370
435
|
var transport = new StdioServerTransport();
|
|
371
436
|
await server.connect(transport);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/auth.ts","../src/tools/search-context.ts","../src/embedding.ts","../src/format.ts","../src/tools/answer-question.ts","../src/tools/list-questions.ts","../src/resources/questions.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { getSupabase } from \"./auth.js\";\nimport { registerSearchContextTool } from \"./tools/search-context.js\";\nimport { registerAnswerQuestionTool } from \"./tools/answer-question.js\";\nimport { registerListQuestionsTool } from \"./tools/list-questions.js\";\nimport { registerQuestionsResource } from \"./resources/questions.js\";\n\nconst required = [\n \"WELLGROW_EMAIL\",\n \"WELLGROW_PASSWORD\",\n \"WELLGROW_SUPABASE_URL\",\n \"WELLGROW_SUPABASE_ANON_KEY\",\n \"OPENAI_API_KEY\",\n];\n\nfor (const key of required) {\n if (!process.env[key]) {\n console.error(`Error: ${key} is required`);\n process.exit(1);\n }\n}\n\ntry {\n await getSupabase();\n console.error(\"Authenticated successfully\");\n} catch (error) {\n console.error(\n \"Authentication failed:\",\n error instanceof Error ? error.message : error\n );\n process.exit(1);\n}\n\nconst server = new McpServer(\n { name: \"wellgrow\", version: \"0.1.0\" },\n {\n instructions: `WellGrow のユーザーナレッジベースにアクセスするサーバーです。\nユーザーの質問・回答データの検索・閲覧・書き込みができます。\nユーザーの考えや価値観を理解したい場面で活用してください。`,\n }\n);\n\nregisterSearchContextTool(server);\nregisterAnswerQuestionTool(server);\nregisterListQuestionsTool(server);\nregisterQuestionsResource(server);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\nconsole.error(\"WellGrow MCP server running on stdio\");\n","import { createClient, type SupabaseClient } from \"@supabase/supabase-js\";\n\nlet supabase: SupabaseClient | null = null;\n\nexport function getSupabaseUrl(): string {\n const url = process.env.WELLGROW_SUPABASE_URL;\n if (!url) throw new Error(\"WELLGROW_SUPABASE_URL is required\");\n return url;\n}\n\nexport function getSupabaseAnonKey(): string {\n const key = process.env.WELLGROW_SUPABASE_ANON_KEY;\n if (!key) throw new Error(\"WELLGROW_SUPABASE_ANON_KEY is required\");\n return key;\n}\n\nexport async function getSupabase(): Promise<SupabaseClient> {\n if (supabase) {\n const {\n data: { session },\n } = await supabase.auth.getSession();\n if (session) return supabase;\n }\n\n supabase = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {\n auth: {\n autoRefreshToken: true,\n persistSession: false,\n },\n });\n\n const { error } = await supabase.auth.signInWithPassword({\n email: process.env.WELLGROW_EMAIL!,\n password: process.env.WELLGROW_PASSWORD!,\n });\n\n if (error) {\n throw new Error(`Authentication failed: ${error.message}`);\n }\n\n return supabase;\n}\n\nexport async function getUserId(): Promise<string> {\n const sb = await getSupabase();\n const {\n data: { user },\n } = await sb.auth.getUser();\n if (!user) throw new Error(\"Not authenticated\");\n return user.id;\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase, getUserId } from \"../auth.js\";\nimport { generateEmbedding } from \"../embedding.js\";\nimport {\n formatSearchResult,\n type QuestionHit,\n type AnswerHit,\n} from \"../format.js\";\n\nexport function registerSearchContextTool(server: McpServer): void {\n server.registerTool(\n \"search_user_context\",\n {\n title: \"ユーザーコンテキスト検索\",\n description: `ユーザーの質問と回答のデータベースを検索します。\nユーザーの考え・価値観・経験・知識を理解するために使います。\n\n使用場面:\n- アドバイスや提案をする前に、ユーザーの価値観・原則を確認したいとき\n- 意思決定の場面で、過去の判断基準や経験を参照したいとき\n- 「私のスタイルで」「私らしく」など、ユーザーの好みを把握したいとき\n- ユーザーの背景(専門分野、関心、目標)を理解したいとき\n\n検索戦略(組み合わせ可能):\n- query のみ: セマンティック検索(意味的に近い内容を幅広く取得)\n- keywords を追加: ハイブリッド検索(意味的類似 + キーワード一致で精度向上)\n- tags/statuses/pinned: フィルタで結果を絞り込み\n\ntarget の使い分け:\n- \"questions\": 質問の一覧を見たいとき(最新回答も付属)\n- \"answers\": 回答の内容を重点的に調べたいとき\n- \"all\": 幅広く情報を集めたいとき(デフォルト)`,\n inputSchema: z.object({\n query: z.string().describe(\"検索クエリ(セマンティック検索に使用)\"),\n keywords: z\n .array(z.string())\n .optional()\n .describe(\"キーワード部分一致\"),\n target: z\n .enum([\"questions\", \"answers\", \"all\"])\n .default(\"all\")\n .describe(\"検索対象\"),\n tags: z.array(z.string()).optional().describe(\"タグでフィルタ\"),\n statuses: z\n .array(z.string())\n .optional()\n .describe(\"ステータスでフィルタ(省略時: active, paused)\"),\n pinned: z.boolean().optional().describe(\"ピン留めされた質問のみ\"),\n limit: z\n .number()\n .min(1)\n .max(50)\n .default(10)\n .describe(\"取得件数上限\"),\n }),\n annotations: {\n readOnlyHint: true,\n openWorldHint: true,\n },\n },\n async ({ query, keywords, target, tags, statuses, pinned, limit }) => {\n const supabase = await getSupabase();\n const userId = await getUserId();\n const embeddingStr = await generateEmbedding(query);\n\n const questions: QuestionHit[] = [];\n const answers: AnswerHit[] = [];\n const promises: PromiseLike<void>[] = [];\n\n if (target !== \"answers\") {\n promises.push(\n supabase\n .rpc(\"search_questions\", {\n p_user_id: userId,\n p_keywords: keywords ?? null,\n p_embedding: embeddingStr,\n p_vector_threshold: 0.3,\n p_statuses: statuses ?? [\"active\", \"paused\"],\n p_tags: tags ?? null,\n p_date_from: null,\n p_date_to: null,\n p_pinned: pinned ?? null,\n p_limit: limit ?? 10,\n })\n .then(({ data }) => {\n if (data) questions.push(...data);\n })\n );\n }\n\n if (target !== \"questions\") {\n promises.push(\n supabase\n .rpc(\"search_answers\", {\n p_user_id: userId,\n p_keywords: keywords ?? null,\n p_embedding: embeddingStr,\n p_vector_threshold: 0.3,\n p_sources: null,\n p_date_from: null,\n p_date_to: null,\n p_exclude_question_ids: null,\n p_limit: limit ?? 10,\n })\n .then(({ data }) => {\n if (data) answers.push(...data);\n })\n );\n }\n\n await Promise.all(promises);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: formatSearchResult({ questions, answers }),\n },\n ],\n };\n }\n );\n}\n","import { embed } from \"ai\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\n\nconst openai = createOpenAI();\nconst embeddingModel = openai.embedding(\"text-embedding-3-small\");\n\nexport async function generateEmbedding(text: string): Promise<string> {\n const { embedding } = await embed({\n model: embeddingModel,\n value: text,\n });\n return JSON.stringify(embedding);\n}\n","export interface QuestionHit {\n id: string;\n question: string;\n tags: string[];\n importance: number | null;\n similarity: number | null;\n latest_answer: string | null;\n latest_answer_at: string | null;\n updated_at: string | null;\n}\n\nexport interface AnswerHit {\n answer_id: string;\n answer: string;\n answer_description: string | null;\n answer_source: string | null;\n similarity: number | null;\n answered_at: string;\n question_id: string;\n question: string;\n}\n\nexport interface QuestionListItem {\n id: string;\n question: string;\n tags: string[];\n status: string;\n importance: number | null;\n pinned: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport function formatSearchResult(result: {\n questions: QuestionHit[];\n answers: AnswerHit[];\n}): string {\n const parts: string[] = [];\n\n if (result.questions.length > 0) {\n parts.push(`## 質問 (${result.questions.length}件)`);\n for (const q of result.questions) {\n const tags = q.tags.length > 0 ? ` [${q.tags.join(\", \")}]` : \"\";\n const answer = q.latest_answer\n ? `\\n 最新回答: ${q.latest_answer}`\n : \"\";\n parts.push(`- **${q.question}**${tags}${answer}\\n ID: ${q.id}`);\n }\n }\n\n if (result.answers.length > 0) {\n parts.push(`## 回答 (${result.answers.length}件)`);\n for (const a of result.answers) {\n const desc = a.answer_description\n ? `\\n 説明: ${a.answer_description}`\n : \"\";\n parts.push(\n `- **${a.question}**\\n 回答: ${a.answer}${desc}\\n 回答日: ${a.answered_at}`\n );\n }\n }\n\n if (parts.length === 0) {\n return \"検索結果はありません。\";\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nexport function formatQuestionList(questions: QuestionListItem[]): string {\n if (questions.length === 0) {\n return \"質問はありません。\";\n }\n\n const lines: string[] = [`## 質問一覧 (${questions.length}件)`];\n\n for (const q of questions) {\n const tags = q.tags.length > 0 ? ` [${q.tags.join(\", \")}]` : \"\";\n const pinned = q.pinned ? \" 📌\" : \"\";\n const status = q.status !== \"active\" ? ` (${q.status})` : \"\";\n lines.push(\n `- **${q.question}**${tags}${pinned}${status}\\n ID: ${q.id} | 更新: ${q.updated_at}`\n );\n }\n\n return lines.join(\"\\n\\n\");\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase, getUserId } from \"../auth.js\";\n\nexport function registerAnswerQuestionTool(server: McpServer): void {\n server.registerTool(\n \"answer_question\",\n {\n title: \"質問への回答書き込み\",\n description: `ユーザーの質問に対して回答を書き込みます。\nユーザーとの会話で重要な気づきや洞察が生まれた時に使います。\n\n使用前に必ずユーザーの承認を得てください。\n\n【回答のルール】\n- answer は140文字以内で、端的に核心を突く回答にする\n- ユーザー自身の言葉を活かした回答にする\n- description には回答の背景・根拠・詳細な説明を書く\n- question_id は search_user_context や list_questions で取得した ID を使う`,\n inputSchema: z.object({\n question_id: z.string().describe(\"対象の質問 ID\"),\n answer: z.string().max(140).describe(\"回答(140文字以内)\"),\n description: z\n .string()\n .max(300)\n .optional()\n .describe(\"回答の詳細説明(300文字以内)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n },\n async ({ question_id, answer, description }) => {\n const supabase = await getSupabase();\n const userId = await getUserId();\n\n const { error: insertError } = await supabase.from(\"answers\").insert({\n question_id,\n user_id: userId,\n answer,\n description: description ?? null,\n source: \"mcp\",\n });\n\n if (insertError)\n throw new Error(`回答の保存に失敗: ${insertError.message}`);\n\n const { data: questionData } = await supabase\n .from(\"questions\")\n .select(\"question\")\n .eq(\"id\", question_id)\n .single();\n\n const questionText = questionData?.question ?? question_id;\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: `回答を保存しました:\\n質問: ${questionText}\\n回答: ${answer}`,\n },\n ],\n };\n }\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase } from \"../auth.js\";\nimport { formatQuestionList } from \"../format.js\";\n\nexport function registerListQuestionsTool(server: McpServer): void {\n server.registerTool(\n \"list_questions\",\n {\n title: \"質問一覧取得\",\n description: `ユーザーの質問一覧を取得します。ステータスやタグでフィルタ可能。\n質問の ID を確認したいときや、ユーザーがどんな質問を持っているか把握したいときに使います。\nanswer_question で回答を書き込む前に、対象の question_id を確認する用途にも使えます。`,\n inputSchema: z.object({\n status: z\n .array(z.string())\n .optional()\n .default([\"active\", \"paused\"])\n .describe(\"ステータスでフィルタ\"),\n tags: z.array(z.string()).optional().describe(\"タグでフィルタ\"),\n pinned: z.boolean().optional().describe(\"ピン留めされた質問のみ\"),\n limit: z\n .number()\n .min(1)\n .max(50)\n .default(20)\n .describe(\"取得件数上限\"),\n }),\n annotations: {\n readOnlyHint: true,\n openWorldHint: true,\n },\n },\n async ({ status, tags, pinned, limit }) => {\n const supabase = await getSupabase();\n\n let query = supabase\n .from(\"questions\")\n .select(\n \"id, question, tags, status, importance, pinned, created_at, updated_at\"\n )\n .in(\"status\", status ?? [\"active\", \"paused\"])\n .order(\"updated_at\", { ascending: false })\n .limit(limit ?? 20);\n\n if (tags?.length) {\n query = query.overlaps(\"tags\", tags);\n }\n if (pinned !== undefined) {\n query = query.eq(\"pinned\", pinned);\n }\n\n const { data, error } = await query;\n if (error) throw new Error(`質問取得に失敗: ${error.message}`);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: formatQuestionList(data ?? []),\n },\n ],\n };\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase } from \"../auth.js\";\n\nexport function registerQuestionsResource(server: McpServer): void {\n server.registerResource(\n \"active-questions\",\n \"wellgrow://questions/active\",\n {\n title: \"アクティブな質問一覧\",\n description: \"ステータスが active の質問一覧。\",\n mimeType: \"application/json\",\n },\n async (uri) => {\n const supabase = await getSupabase();\n const { data } = await supabase\n .from(\"questions\")\n .select(\"id, question, tags, importance, pinned, updated_at\")\n .eq(\"status\", \"active\")\n .order(\"updated_at\", { ascending: false })\n .limit(50);\n\n return {\n contents: [\n {\n uri: uri.href,\n text: JSON.stringify(data ?? [], null, 2),\n },\n ],\n };\n }\n );\n}\n"],"mappings":"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","names":["server","supabase","z","server","z","supabase","z","server","z","supabase","server","supabase"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/auth.ts","../src/tools/search-context.ts","../src/embedding.ts","../src/format.ts","../src/tools/answer-question.ts","../src/tools/list-questions.ts","../src/tools/save-feedback.ts","../src/resources/questions.ts"],"sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { getSupabase } from \"./auth.js\";\nimport { registerSearchContextTool } from \"./tools/search-context.js\";\nimport { registerAnswerQuestionTool } from \"./tools/answer-question.js\";\nimport { registerListQuestionsTool } from \"./tools/list-questions.js\";\nimport { registerSaveFeedbackTool } from \"./tools/save-feedback.js\";\nimport { registerQuestionsResource } from \"./resources/questions.js\";\n\nconst required = [\"WELLGROW_EMAIL\", \"WELLGROW_PASSWORD\", \"OPENAI_API_KEY\"];\n\nfor (const key of required) {\n if (!process.env[key]) {\n console.error(`Error: ${key} is required`);\n process.exit(1);\n }\n}\n\ntry {\n await getSupabase();\n console.error(\"Authenticated successfully\");\n} catch (error) {\n console.error(\n \"Authentication failed:\",\n error instanceof Error ? error.message : error\n );\n process.exit(1);\n}\n\nconst server = new McpServer(\n { name: \"wellgrow\", version: \"0.3.0\" },\n {\n instructions: `WellGrow のユーザーナレッジベースにアクセスするサーバーです。\nユーザーの質問・回答データの検索・閲覧・書き込みができます。\nユーザーの考えや価値観を理解したい場面で活用してください。`,\n }\n);\n\nregisterSearchContextTool(server);\nregisterAnswerQuestionTool(server);\nregisterListQuestionsTool(server);\nregisterSaveFeedbackTool(server);\nregisterQuestionsResource(server);\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\nconsole.error(\"WellGrow MCP server running on stdio\");\n","import { createClient, type SupabaseClient } from \"@supabase/supabase-js\";\n\nconst DEFAULT_SUPABASE_URL = \"https://rpywqbtporjdhwtmvwkf.supabase.co\";\nconst DEFAULT_SUPABASE_ANON_KEY =\n \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJweXdxYnRwb3JqZGh3dG12d2tmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njc4NjA4MDIsImV4cCI6MjA4MzQzNjgwMn0.1nn9F2y1JZBoSgB33CnP-k-6OM5HcEMdUs50RLJ89i4\";\n\nlet supabase: SupabaseClient | null = null;\n\nexport function getSupabaseUrl(): string {\n return process.env.WELLGROW_SUPABASE_URL ?? DEFAULT_SUPABASE_URL;\n}\n\nexport function getSupabaseAnonKey(): string {\n return process.env.WELLGROW_SUPABASE_ANON_KEY ?? DEFAULT_SUPABASE_ANON_KEY;\n}\n\nexport async function getSupabase(): Promise<SupabaseClient> {\n if (supabase) {\n const {\n data: { session },\n } = await supabase.auth.getSession();\n if (session) return supabase;\n }\n\n supabase = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {\n auth: {\n autoRefreshToken: true,\n persistSession: false,\n },\n });\n\n const { error } = await supabase.auth.signInWithPassword({\n email: process.env.WELLGROW_EMAIL!,\n password: process.env.WELLGROW_PASSWORD!,\n });\n\n if (error) {\n throw new Error(`Authentication failed: ${error.message}`);\n }\n\n return supabase;\n}\n\nexport async function getUserId(): Promise<string> {\n const sb = await getSupabase();\n const {\n data: { user },\n } = await sb.auth.getUser();\n if (!user) throw new Error(\"Not authenticated\");\n return user.id;\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase, getUserId } from \"../auth.js\";\nimport { generateEmbedding } from \"../embedding.js\";\nimport {\n formatSearchResult,\n type QuestionHit,\n type AnswerHit,\n} from \"../format.js\";\n\nexport function registerSearchContextTool(server: McpServer): void {\n server.registerTool(\n \"search_user_context\",\n {\n title: \"ユーザーコンテキスト検索\",\n description: `ユーザーの質問と回答のデータベースを検索します。\nユーザーの考え・価値観・経験・知識を理解するために使います。\n\n使用場面:\n- アドバイスや提案をする前に、ユーザーの価値観・原則を確認したいとき\n- 意思決定の場面で、過去の判断基準や経験を参照したいとき\n- 「私のスタイルで」「私らしく」など、ユーザーの好みを把握したいとき\n- ユーザーの背景(専門分野、関心、目標)を理解したいとき\n\n検索戦略(組み合わせ可能):\n- query のみ: セマンティック検索(意味的に近い内容を幅広く取得)\n- keywords を追加: ハイブリッド検索(意味的類似 + キーワード一致で精度向上)\n- tags/statuses/pinned: フィルタで結果を絞り込み\n\ntarget の使い分け:\n- \"questions\": 質問の一覧を見たいとき(最新回答も付属)\n- \"answers\": 回答の内容を重点的に調べたいとき\n- \"all\": 幅広く情報を集めたいとき(デフォルト)`,\n inputSchema: z.object({\n query: z.string().describe(\"検索クエリ(セマンティック検索に使用)\"),\n keywords: z\n .array(z.string())\n .optional()\n .describe(\"キーワード部分一致\"),\n target: z\n .enum([\"questions\", \"answers\", \"all\"])\n .default(\"all\")\n .describe(\"検索対象\"),\n tags: z.array(z.string()).optional().describe(\"タグでフィルタ\"),\n statuses: z\n .array(z.string())\n .optional()\n .describe(\"ステータスでフィルタ(省略時: active, paused)\"),\n pinned: z.boolean().optional().describe(\"ピン留めされた質問のみ\"),\n limit: z\n .number()\n .min(1)\n .max(50)\n .default(10)\n .describe(\"取得件数上限\"),\n }),\n annotations: {\n readOnlyHint: true,\n openWorldHint: true,\n },\n },\n async ({ query, keywords, target, tags, statuses, pinned, limit }) => {\n const supabase = await getSupabase();\n const userId = await getUserId();\n const embeddingStr = await generateEmbedding(query);\n\n const questions: QuestionHit[] = [];\n const answers: AnswerHit[] = [];\n const promises: PromiseLike<void>[] = [];\n\n if (target !== \"answers\") {\n promises.push(\n supabase\n .rpc(\"search_questions\", {\n p_user_id: userId,\n p_keywords: keywords ?? null,\n p_embedding: embeddingStr,\n p_vector_threshold: 0.3,\n p_statuses: statuses ?? [\"active\", \"paused\"],\n p_tags: tags ?? null,\n p_date_from: null,\n p_date_to: null,\n p_pinned: pinned ?? null,\n p_limit: limit ?? 10,\n })\n .then(({ data }) => {\n if (data) questions.push(...data);\n })\n );\n }\n\n if (target !== \"questions\") {\n promises.push(\n supabase\n .rpc(\"search_answers\", {\n p_user_id: userId,\n p_keywords: keywords ?? null,\n p_embedding: embeddingStr,\n p_vector_threshold: 0.3,\n p_sources: null,\n p_date_from: null,\n p_date_to: null,\n p_exclude_question_ids: null,\n p_limit: limit ?? 10,\n })\n .then(({ data }) => {\n if (data) answers.push(...data);\n })\n );\n }\n\n await Promise.all(promises);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: formatSearchResult({ questions, answers }),\n },\n ],\n };\n }\n );\n}\n","import { embed } from \"ai\";\nimport { createOpenAI } from \"@ai-sdk/openai\";\n\nconst openai = createOpenAI();\nconst embeddingModel = openai.embedding(\"text-embedding-3-small\");\n\nexport async function generateEmbedding(text: string): Promise<string> {\n const { embedding } = await embed({\n model: embeddingModel,\n value: text,\n });\n return JSON.stringify(embedding);\n}\n","export interface QuestionHit {\n id: string;\n question: string;\n tags: string[];\n importance: number | null;\n similarity: number | null;\n latest_answer: string | null;\n latest_answer_at: string | null;\n updated_at: string | null;\n}\n\nexport interface AnswerHit {\n answer_id: string;\n answer: string;\n answer_description: string | null;\n answer_source: string | null;\n similarity: number | null;\n answered_at: string;\n question_id: string;\n question: string;\n}\n\nexport interface QuestionListItem {\n id: string;\n question: string;\n tags: string[];\n status: string;\n importance: number | null;\n pinned: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport function formatSearchResult(result: {\n questions: QuestionHit[];\n answers: AnswerHit[];\n}): string {\n const parts: string[] = [];\n\n if (result.questions.length > 0) {\n parts.push(`## 質問 (${result.questions.length}件)`);\n for (const q of result.questions) {\n const tags = q.tags.length > 0 ? ` [${q.tags.join(\", \")}]` : \"\";\n const answer = q.latest_answer\n ? `\\n 最新回答: ${q.latest_answer}`\n : \"\";\n parts.push(`- **${q.question}**${tags}${answer}\\n ID: ${q.id}`);\n }\n }\n\n if (result.answers.length > 0) {\n parts.push(`## 回答 (${result.answers.length}件)`);\n for (const a of result.answers) {\n const desc = a.answer_description\n ? `\\n 説明: ${a.answer_description}`\n : \"\";\n parts.push(\n `- **${a.question}**\\n 回答: ${a.answer}${desc}\\n 回答日: ${a.answered_at}`\n );\n }\n }\n\n if (parts.length === 0) {\n return \"検索結果はありません。\";\n }\n\n return parts.join(\"\\n\\n\");\n}\n\nexport function formatQuestionList(questions: QuestionListItem[]): string {\n if (questions.length === 0) {\n return \"質問はありません。\";\n }\n\n const lines: string[] = [`## 質問一覧 (${questions.length}件)`];\n\n for (const q of questions) {\n const tags = q.tags.length > 0 ? ` [${q.tags.join(\", \")}]` : \"\";\n const pinned = q.pinned ? \" 📌\" : \"\";\n const status = q.status !== \"active\" ? ` (${q.status})` : \"\";\n lines.push(\n `- **${q.question}**${tags}${pinned}${status}\\n ID: ${q.id} | 更新: ${q.updated_at}`\n );\n }\n\n return lines.join(\"\\n\\n\");\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase, getUserId } from \"../auth.js\";\n\nexport function registerAnswerQuestionTool(server: McpServer): void {\n server.registerTool(\n \"answer_question\",\n {\n title: \"質問への回答書き込み\",\n description: `ユーザーの質問に対して回答を書き込みます。\nユーザーとの会話で重要な気づきや洞察が生まれた時に使います。\n\n使用前に必ずユーザーの承認を得てください。\n\n【回答のルール】\n- answer は140文字以内で、端的に核心を突く回答にする\n- ユーザー自身の言葉を活かした回答にする\n- description には回答の背景・根拠・詳細な説明を書く\n- question_id は search_user_context や list_questions で取得した ID を使う`,\n inputSchema: z.object({\n question_id: z.string().describe(\"対象の質問 ID\"),\n answer: z.string().max(140).describe(\"回答(140文字以内)\"),\n description: z\n .string()\n .max(300)\n .optional()\n .describe(\"回答の詳細説明(300文字以内)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n },\n async ({ question_id, answer, description }) => {\n const supabase = await getSupabase();\n const userId = await getUserId();\n\n const { data: questionData, error: qError } = await supabase\n .from(\"questions\")\n .select(\"question\")\n .eq(\"id\", question_id)\n .eq(\"user_id\", userId)\n .single();\n\n if (qError || !questionData)\n throw new Error(`質問が見つかりません: ${question_id}`);\n\n const { error: insertError } = await supabase.from(\"answers\").insert({\n question_id,\n user_id: userId,\n question: questionData.question,\n answer,\n description: description ?? null,\n source: \"mcp\",\n });\n\n if (insertError)\n throw new Error(`回答の保存に失敗: ${insertError.message}`);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: `回答を保存しました:\\n質問: ${questionData.question}\\n回答: ${answer}`,\n },\n ],\n };\n }\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase } from \"../auth.js\";\nimport { formatQuestionList } from \"../format.js\";\n\nexport function registerListQuestionsTool(server: McpServer): void {\n server.registerTool(\n \"list_questions\",\n {\n title: \"質問一覧取得\",\n description: `ユーザーの質問一覧を取得します。ステータスやタグでフィルタ可能。\n質問の ID を確認したいときや、ユーザーがどんな質問を持っているか把握したいときに使います。\nanswer_question で回答を書き込む前に、対象の question_id を確認する用途にも使えます。`,\n inputSchema: z.object({\n status: z\n .array(z.string())\n .optional()\n .default([\"active\", \"paused\"])\n .describe(\"ステータスでフィルタ\"),\n tags: z.array(z.string()).optional().describe(\"タグでフィルタ\"),\n pinned: z.boolean().optional().describe(\"ピン留めされた質問のみ\"),\n limit: z\n .number()\n .min(1)\n .max(50)\n .default(20)\n .describe(\"取得件数上限\"),\n }),\n annotations: {\n readOnlyHint: true,\n openWorldHint: true,\n },\n },\n async ({ status, tags, pinned, limit }) => {\n const supabase = await getSupabase();\n\n let query = supabase\n .from(\"questions\")\n .select(\n \"id, question, tags, status, importance, pinned, created_at, updated_at\"\n )\n .in(\"status\", status ?? [\"active\", \"paused\"])\n .order(\"updated_at\", { ascending: false })\n .limit(limit ?? 20);\n\n if (tags?.length) {\n query = query.overlaps(\"tags\", tags);\n }\n if (pinned !== undefined) {\n query = query.eq(\"pinned\", pinned);\n }\n\n const { data, error } = await query;\n if (error) throw new Error(`質問取得に失敗: ${error.message}`);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: formatQuestionList(data ?? []),\n },\n ],\n };\n }\n );\n}\n","import { z } from \"zod\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase, getUserId } from \"../auth.js\";\n\nconst feedbackCategories = [\n \"bug\",\n \"improvement\",\n \"praise\",\n \"question\",\n \"other\",\n] as const;\n\nexport function registerSaveFeedbackTool(server: McpServer): void {\n server.registerTool(\n \"save_feedback\",\n {\n title: \"フィードバック送信\",\n description: `WellGrow開発チームへフィードバックを送信します。\n\n使用する場面:\n- ユーザーがWellGrowへの改善提案・バグ報告・感想を伝えたいとき\n- WellGrowのツール(search_user_context等)でエラーが発生したとき\n- ユーザーがWellGrowの体験について言及したとき\n\n重要: ユーザーがフィードバックの送信を意図していることを確認してから使用してください。\nツールエラーの報告を除き、ユーザーの承認なく送信しないでください。\n\nカテゴリの選び方:\n- bug: エラーやバグに関するもの\n- improvement: 機能改善の提案やアイデア\n- praise: 良かった点、満足した体験\n- question: WellGrowに関する未解決の質問\n- other: 上記に当てはまらないもの`,\n inputSchema: z.object({\n category: z\n .enum(feedbackCategories)\n .describe(\"フィードバックのカテゴリ\"),\n message: z\n .string()\n .min(1)\n .max(2000)\n .describe(\n \"フィードバックの内容。開発者が状況を理解できるように要約\"\n ),\n user_message: z\n .string()\n .max(500)\n .optional()\n .describe(\"きっかけとなったユーザーの発言(原文を短く引用)\"),\n }),\n annotations: {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n },\n },\n async ({ category, message, user_message }) => {\n const supabase = await getSupabase();\n const userId = await getUserId();\n\n const context: Record<string, unknown> = {};\n if (user_message) context.user_message = user_message;\n\n const { error } = await supabase.from(\"feedbacks\").insert({\n category,\n message,\n source: \"mcp\",\n user_id: userId,\n page_path: \"mcp\",\n context: Object.keys(context).length > 0 ? context : null,\n });\n\n if (error)\n throw new Error(`フィードバックの保存に失敗: ${error.message}`);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: `フィードバックを送信しました(${category})`,\n },\n ],\n };\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { getSupabase } from \"../auth.js\";\n\nexport function registerQuestionsResource(server: McpServer): void {\n server.registerResource(\n \"active-questions\",\n \"wellgrow://questions/active\",\n {\n title: \"アクティブな質問一覧\",\n description: \"ステータスが active の質問一覧。\",\n mimeType: \"application/json\",\n },\n async (uri) => {\n const supabase = await getSupabase();\n const { data } = await supabase\n .from(\"questions\")\n .select(\"id, question, tags, importance, pinned, updated_at\")\n .eq(\"status\", \"active\")\n .order(\"updated_at\", { ascending: false })\n .limit(50);\n\n return {\n contents: [\n {\n uri: uri.href,\n text: JSON.stringify(data ?? [], null, 2),\n },\n ],\n };\n }\n );\n}\n"],"mappings":"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","names":["server","supabase","z","server","z","supabase","z","server","z","supabase","z","server","z","supabase","server","supabase"]}
|