@wellgrow/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @wellgrow/mcp
2
+
3
+ WellGrow MCP Server — AI エージェントからユーザーのパーソナルナレッジベースにアクセスする。
4
+
5
+ ## 機能
6
+
7
+ - **search_user_context** — 質問・回答をセマンティック検索
8
+ - **list_questions** — 質問一覧を取得(タグ・ステータスでフィルタ可)
9
+ - **answer_question** — 質問に対して回答を書き込む
10
+ - **active-questions** リソース — アクティブな質問一覧(`@wellgrow` で参照)
11
+
12
+ ## セットアップ
13
+
14
+ ### 1. インストール
15
+
16
+ ```bash
17
+ npm install -g @wellgrow/mcp
18
+ ```
19
+
20
+ ### 2. 環境変数
21
+
22
+ | 変数 | 説明 | 必須 |
23
+ |------|------|------|
24
+ | `WELLGROW_EMAIL` | WellGrow のログインメール | Yes |
25
+ | `WELLGROW_PASSWORD` | WellGrow のログインパスワード | Yes |
26
+ | `WELLGROW_SUPABASE_URL` | Supabase プロジェクト URL | Yes |
27
+ | `WELLGROW_SUPABASE_ANON_KEY` | Supabase anon key | Yes |
28
+ | `OPENAI_API_KEY` | OpenAI API キー(検索の embedding 生成用) | Yes |
29
+
30
+ ### 3. MCP サーバーの登録
31
+
32
+ #### Claude Code
33
+
34
+ ```bash
35
+ claude mcp add --transport stdio \
36
+ --env WELLGROW_EMAIL=user@example.com \
37
+ --env WELLGROW_PASSWORD=mypassword \
38
+ --env WELLGROW_SUPABASE_URL=https://xxx.supabase.co \
39
+ --env WELLGROW_SUPABASE_ANON_KEY=eyJ... \
40
+ --env OPENAI_API_KEY=sk-... \
41
+ --scope user \
42
+ wellgrow -- wellgrow-mcp
43
+ ```
44
+
45
+ #### Cursor
46
+
47
+ `~/.cursor/mcp.json` に追加:
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "wellgrow": {
53
+ "command": "wellgrow-mcp",
54
+ "env": {
55
+ "WELLGROW_EMAIL": "user@example.com",
56
+ "WELLGROW_PASSWORD": "mypassword",
57
+ "WELLGROW_SUPABASE_URL": "https://xxx.supabase.co",
58
+ "WELLGROW_SUPABASE_ANON_KEY": "eyJ...",
59
+ "OPENAI_API_KEY": "sk-..."
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ ### 4. 動作確認
67
+
68
+ ```bash
69
+ claude mcp list
70
+ ```
71
+
72
+ ### 5. アップデート
73
+
74
+ ```bash
75
+ npm update -g @wellgrow/mcp
76
+ ```
77
+
78
+ ## 使い方
79
+
80
+ ```
81
+ ユーザー: 「私の最近の質問を見せて」
82
+ AI: → list_questions → 質問一覧を表示
83
+
84
+ ユーザー: 「健康に関する過去の回答を調べて」
85
+ AI: → search_user_context → 検索結果を表示
86
+
87
+ ユーザー: 「この質問に『毎朝5分の瞑想から始める』と回答して」
88
+ AI: → answer_question → 回答を保存
89
+ ```
90
+
91
+ ## 開発
92
+
93
+ ```bash
94
+ npm install
95
+ npm run build
96
+ npm run typecheck
97
+ ```
package/dist/index.js ADDED
@@ -0,0 +1,373 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+
7
+ // src/auth.ts
8
+ import { createClient } from "@supabase/supabase-js";
9
+ var supabase = null;
10
+ function getSupabaseUrl() {
11
+ const url = process.env.WELLGROW_SUPABASE_URL;
12
+ if (!url) throw new Error("WELLGROW_SUPABASE_URL is required");
13
+ return url;
14
+ }
15
+ function getSupabaseAnonKey() {
16
+ const key = process.env.WELLGROW_SUPABASE_ANON_KEY;
17
+ if (!key) throw new Error("WELLGROW_SUPABASE_ANON_KEY is required");
18
+ return key;
19
+ }
20
+ async function getSupabase() {
21
+ if (supabase) {
22
+ const {
23
+ data: { session }
24
+ } = await supabase.auth.getSession();
25
+ if (session) return supabase;
26
+ }
27
+ supabase = createClient(getSupabaseUrl(), getSupabaseAnonKey(), {
28
+ auth: {
29
+ autoRefreshToken: true,
30
+ persistSession: false
31
+ }
32
+ });
33
+ const { error } = await supabase.auth.signInWithPassword({
34
+ email: process.env.WELLGROW_EMAIL,
35
+ password: process.env.WELLGROW_PASSWORD
36
+ });
37
+ if (error) {
38
+ throw new Error(`Authentication failed: ${error.message}`);
39
+ }
40
+ return supabase;
41
+ }
42
+ async function getUserId() {
43
+ const sb = await getSupabase();
44
+ const {
45
+ data: { user }
46
+ } = await sb.auth.getUser();
47
+ if (!user) throw new Error("Not authenticated");
48
+ return user.id;
49
+ }
50
+
51
+ // src/tools/search-context.ts
52
+ import { z } from "zod";
53
+
54
+ // src/embedding.ts
55
+ import { embed } from "ai";
56
+ import { createOpenAI } from "@ai-sdk/openai";
57
+ var openai = createOpenAI();
58
+ var embeddingModel = openai.embedding("text-embedding-3-small");
59
+ async function generateEmbedding(text) {
60
+ const { embedding } = await embed({
61
+ model: embeddingModel,
62
+ value: text
63
+ });
64
+ return JSON.stringify(embedding);
65
+ }
66
+
67
+ // src/format.ts
68
+ function formatSearchResult(result) {
69
+ const parts = [];
70
+ if (result.questions.length > 0) {
71
+ parts.push(`## \u8CEA\u554F (${result.questions.length}\u4EF6)`);
72
+ for (const q of result.questions) {
73
+ const tags = q.tags.length > 0 ? ` [${q.tags.join(", ")}]` : "";
74
+ const answer = q.latest_answer ? `
75
+ \u6700\u65B0\u56DE\u7B54: ${q.latest_answer}` : "";
76
+ parts.push(`- **${q.question}**${tags}${answer}
77
+ ID: ${q.id}`);
78
+ }
79
+ }
80
+ if (result.answers.length > 0) {
81
+ parts.push(`## \u56DE\u7B54 (${result.answers.length}\u4EF6)`);
82
+ for (const a of result.answers) {
83
+ const desc = a.answer_description ? `
84
+ \u8AAC\u660E: ${a.answer_description}` : "";
85
+ parts.push(
86
+ `- **${a.question}**
87
+ \u56DE\u7B54: ${a.answer}${desc}
88
+ \u56DE\u7B54\u65E5: ${a.answered_at}`
89
+ );
90
+ }
91
+ }
92
+ if (parts.length === 0) {
93
+ return "\u691C\u7D22\u7D50\u679C\u306F\u3042\u308A\u307E\u305B\u3093\u3002";
94
+ }
95
+ return parts.join("\n\n");
96
+ }
97
+ function formatQuestionList(questions) {
98
+ if (questions.length === 0) {
99
+ return "\u8CEA\u554F\u306F\u3042\u308A\u307E\u305B\u3093\u3002";
100
+ }
101
+ const lines = [`## \u8CEA\u554F\u4E00\u89A7 (${questions.length}\u4EF6)`];
102
+ for (const q of questions) {
103
+ const tags = q.tags.length > 0 ? ` [${q.tags.join(", ")}]` : "";
104
+ const pinned = q.pinned ? " \u{1F4CC}" : "";
105
+ const status = q.status !== "active" ? ` (${q.status})` : "";
106
+ lines.push(
107
+ `- **${q.question}**${tags}${pinned}${status}
108
+ ID: ${q.id} | \u66F4\u65B0: ${q.updated_at}`
109
+ );
110
+ }
111
+ return lines.join("\n\n");
112
+ }
113
+
114
+ // src/tools/search-context.ts
115
+ function registerSearchContextTool(server2) {
116
+ server2.registerTool(
117
+ "search_user_context",
118
+ {
119
+ title: "\u30E6\u30FC\u30B6\u30FC\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u691C\u7D22",
120
+ description: `\u30E6\u30FC\u30B6\u30FC\u306E\u8CEA\u554F\u3068\u56DE\u7B54\u306E\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u3092\u691C\u7D22\u3057\u307E\u3059\u3002
121
+ \u30E6\u30FC\u30B6\u30FC\u306E\u8003\u3048\u30FB\u4FA1\u5024\u89B3\u30FB\u7D4C\u9A13\u30FB\u77E5\u8B58\u3092\u7406\u89E3\u3059\u308B\u305F\u3081\u306B\u4F7F\u3044\u307E\u3059\u3002
122
+
123
+ \u4F7F\u7528\u5834\u9762:
124
+ - \u30A2\u30C9\u30D0\u30A4\u30B9\u3084\u63D0\u6848\u3092\u3059\u308B\u524D\u306B\u3001\u30E6\u30FC\u30B6\u30FC\u306E\u4FA1\u5024\u89B3\u30FB\u539F\u5247\u3092\u78BA\u8A8D\u3057\u305F\u3044\u3068\u304D
125
+ - \u610F\u601D\u6C7A\u5B9A\u306E\u5834\u9762\u3067\u3001\u904E\u53BB\u306E\u5224\u65AD\u57FA\u6E96\u3084\u7D4C\u9A13\u3092\u53C2\u7167\u3057\u305F\u3044\u3068\u304D
126
+ - \u300C\u79C1\u306E\u30B9\u30BF\u30A4\u30EB\u3067\u300D\u300C\u79C1\u3089\u3057\u304F\u300D\u306A\u3069\u3001\u30E6\u30FC\u30B6\u30FC\u306E\u597D\u307F\u3092\u628A\u63E1\u3057\u305F\u3044\u3068\u304D
127
+ - \u30E6\u30FC\u30B6\u30FC\u306E\u80CC\u666F\uFF08\u5C02\u9580\u5206\u91CE\u3001\u95A2\u5FC3\u3001\u76EE\u6A19\uFF09\u3092\u7406\u89E3\u3057\u305F\u3044\u3068\u304D
128
+
129
+ \u691C\u7D22\u6226\u7565\uFF08\u7D44\u307F\u5408\u308F\u305B\u53EF\u80FD\uFF09:
130
+ - query \u306E\u307F: \u30BB\u30DE\u30F3\u30C6\u30A3\u30C3\u30AF\u691C\u7D22\uFF08\u610F\u5473\u7684\u306B\u8FD1\u3044\u5185\u5BB9\u3092\u5E45\u5E83\u304F\u53D6\u5F97\uFF09
131
+ - keywords \u3092\u8FFD\u52A0: \u30CF\u30A4\u30D6\u30EA\u30C3\u30C9\u691C\u7D22\uFF08\u610F\u5473\u7684\u985E\u4F3C + \u30AD\u30FC\u30EF\u30FC\u30C9\u4E00\u81F4\u3067\u7CBE\u5EA6\u5411\u4E0A\uFF09
132
+ - tags/statuses/pinned: \u30D5\u30A3\u30EB\u30BF\u3067\u7D50\u679C\u3092\u7D5E\u308A\u8FBC\u307F
133
+
134
+ target \u306E\u4F7F\u3044\u5206\u3051:
135
+ - "questions": \u8CEA\u554F\u306E\u4E00\u89A7\u3092\u898B\u305F\u3044\u3068\u304D\uFF08\u6700\u65B0\u56DE\u7B54\u3082\u4ED8\u5C5E\uFF09
136
+ - "answers": \u56DE\u7B54\u306E\u5185\u5BB9\u3092\u91CD\u70B9\u7684\u306B\u8ABF\u3079\u305F\u3044\u3068\u304D
137
+ - "all": \u5E45\u5E83\u304F\u60C5\u5831\u3092\u96C6\u3081\u305F\u3044\u3068\u304D\uFF08\u30C7\u30D5\u30A9\u30EB\u30C8\uFF09`,
138
+ inputSchema: z.object({
139
+ query: z.string().describe("\u691C\u7D22\u30AF\u30A8\u30EA\uFF08\u30BB\u30DE\u30F3\u30C6\u30A3\u30C3\u30AF\u691C\u7D22\u306B\u4F7F\u7528\uFF09"),
140
+ keywords: z.array(z.string()).optional().describe("\u30AD\u30FC\u30EF\u30FC\u30C9\u90E8\u5206\u4E00\u81F4"),
141
+ target: z.enum(["questions", "answers", "all"]).default("all").describe("\u691C\u7D22\u5BFE\u8C61"),
142
+ tags: z.array(z.string()).optional().describe("\u30BF\u30B0\u3067\u30D5\u30A3\u30EB\u30BF"),
143
+ statuses: z.array(z.string()).optional().describe("\u30B9\u30C6\u30FC\u30BF\u30B9\u3067\u30D5\u30A3\u30EB\u30BF\uFF08\u7701\u7565\u6642: active, paused\uFF09"),
144
+ pinned: z.boolean().optional().describe("\u30D4\u30F3\u7559\u3081\u3055\u308C\u305F\u8CEA\u554F\u306E\u307F"),
145
+ limit: z.number().min(1).max(50).default(10).describe("\u53D6\u5F97\u4EF6\u6570\u4E0A\u9650")
146
+ }),
147
+ annotations: {
148
+ readOnlyHint: true,
149
+ openWorldHint: true
150
+ }
151
+ },
152
+ async ({ query, keywords, target, tags, statuses, pinned, limit }) => {
153
+ const supabase2 = await getSupabase();
154
+ const userId = await getUserId();
155
+ const embeddingStr = await generateEmbedding(query);
156
+ const questions = [];
157
+ const answers = [];
158
+ const promises = [];
159
+ if (target !== "answers") {
160
+ promises.push(
161
+ supabase2.rpc("search_questions", {
162
+ p_user_id: userId,
163
+ p_keywords: keywords ?? null,
164
+ p_embedding: embeddingStr,
165
+ p_vector_threshold: 0.3,
166
+ p_statuses: statuses ?? ["active", "paused"],
167
+ p_tags: tags ?? null,
168
+ p_date_from: null,
169
+ p_date_to: null,
170
+ p_pinned: pinned ?? null,
171
+ p_limit: limit ?? 10
172
+ }).then(({ data }) => {
173
+ if (data) questions.push(...data);
174
+ })
175
+ );
176
+ }
177
+ if (target !== "questions") {
178
+ promises.push(
179
+ supabase2.rpc("search_answers", {
180
+ p_user_id: userId,
181
+ p_keywords: keywords ?? null,
182
+ p_embedding: embeddingStr,
183
+ p_vector_threshold: 0.3,
184
+ p_sources: null,
185
+ p_date_from: null,
186
+ p_date_to: null,
187
+ p_exclude_question_ids: null,
188
+ p_limit: limit ?? 10
189
+ }).then(({ data }) => {
190
+ if (data) answers.push(...data);
191
+ })
192
+ );
193
+ }
194
+ await Promise.all(promises);
195
+ return {
196
+ content: [
197
+ {
198
+ type: "text",
199
+ text: formatSearchResult({ questions, answers })
200
+ }
201
+ ]
202
+ };
203
+ }
204
+ );
205
+ }
206
+
207
+ // src/tools/answer-question.ts
208
+ import { z as z2 } from "zod";
209
+ function registerAnswerQuestionTool(server2) {
210
+ server2.registerTool(
211
+ "answer_question",
212
+ {
213
+ title: "\u8CEA\u554F\u3078\u306E\u56DE\u7B54\u66F8\u304D\u8FBC\u307F",
214
+ description: `\u30E6\u30FC\u30B6\u30FC\u306E\u8CEA\u554F\u306B\u5BFE\u3057\u3066\u56DE\u7B54\u3092\u66F8\u304D\u8FBC\u307F\u307E\u3059\u3002
215
+ \u30E6\u30FC\u30B6\u30FC\u3068\u306E\u4F1A\u8A71\u3067\u91CD\u8981\u306A\u6C17\u3065\u304D\u3084\u6D1E\u5BDF\u304C\u751F\u307E\u308C\u305F\u6642\u306B\u4F7F\u3044\u307E\u3059\u3002
216
+
217
+ \u4F7F\u7528\u524D\u306B\u5FC5\u305A\u30E6\u30FC\u30B6\u30FC\u306E\u627F\u8A8D\u3092\u5F97\u3066\u304F\u3060\u3055\u3044\u3002
218
+
219
+ \u3010\u56DE\u7B54\u306E\u30EB\u30FC\u30EB\u3011
220
+ - answer \u306F140\u6587\u5B57\u4EE5\u5185\u3067\u3001\u7AEF\u7684\u306B\u6838\u5FC3\u3092\u7A81\u304F\u56DE\u7B54\u306B\u3059\u308B
221
+ - \u30E6\u30FC\u30B6\u30FC\u81EA\u8EAB\u306E\u8A00\u8449\u3092\u6D3B\u304B\u3057\u305F\u56DE\u7B54\u306B\u3059\u308B
222
+ - description \u306B\u306F\u56DE\u7B54\u306E\u80CC\u666F\u30FB\u6839\u62E0\u30FB\u8A73\u7D30\u306A\u8AAC\u660E\u3092\u66F8\u304F
223
+ - question_id \u306F search_user_context \u3084 list_questions \u3067\u53D6\u5F97\u3057\u305F ID \u3092\u4F7F\u3046`,
224
+ inputSchema: z2.object({
225
+ question_id: z2.string().describe("\u5BFE\u8C61\u306E\u8CEA\u554F ID"),
226
+ answer: z2.string().max(140).describe("\u56DE\u7B54\uFF08140\u6587\u5B57\u4EE5\u5185\uFF09"),
227
+ description: z2.string().max(300).optional().describe("\u56DE\u7B54\u306E\u8A73\u7D30\u8AAC\u660E\uFF08300\u6587\u5B57\u4EE5\u5185\uFF09")
228
+ }),
229
+ annotations: {
230
+ readOnlyHint: false,
231
+ destructiveHint: false,
232
+ idempotentHint: false
233
+ }
234
+ },
235
+ async ({ question_id, answer, description }) => {
236
+ const supabase2 = await getSupabase();
237
+ const userId = await getUserId();
238
+ const { error: insertError } = await supabase2.from("answers").insert({
239
+ question_id,
240
+ user_id: userId,
241
+ answer,
242
+ description: description ?? null,
243
+ source: "mcp"
244
+ });
245
+ if (insertError)
246
+ 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
+ return {
250
+ content: [
251
+ {
252
+ type: "text",
253
+ text: `\u56DE\u7B54\u3092\u4FDD\u5B58\u3057\u307E\u3057\u305F:
254
+ \u8CEA\u554F: ${questionText}
255
+ \u56DE\u7B54: ${answer}`
256
+ }
257
+ ]
258
+ };
259
+ }
260
+ );
261
+ }
262
+
263
+ // src/tools/list-questions.ts
264
+ import { z as z3 } from "zod";
265
+ function registerListQuestionsTool(server2) {
266
+ server2.registerTool(
267
+ "list_questions",
268
+ {
269
+ title: "\u8CEA\u554F\u4E00\u89A7\u53D6\u5F97",
270
+ description: `\u30E6\u30FC\u30B6\u30FC\u306E\u8CEA\u554F\u4E00\u89A7\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\u30B9\u30C6\u30FC\u30BF\u30B9\u3084\u30BF\u30B0\u3067\u30D5\u30A3\u30EB\u30BF\u53EF\u80FD\u3002
271
+ \u8CEA\u554F\u306E ID \u3092\u78BA\u8A8D\u3057\u305F\u3044\u3068\u304D\u3084\u3001\u30E6\u30FC\u30B6\u30FC\u304C\u3069\u3093\u306A\u8CEA\u554F\u3092\u6301\u3063\u3066\u3044\u308B\u304B\u628A\u63E1\u3057\u305F\u3044\u3068\u304D\u306B\u4F7F\u3044\u307E\u3059\u3002
272
+ answer_question \u3067\u56DE\u7B54\u3092\u66F8\u304D\u8FBC\u3080\u524D\u306B\u3001\u5BFE\u8C61\u306E question_id \u3092\u78BA\u8A8D\u3059\u308B\u7528\u9014\u306B\u3082\u4F7F\u3048\u307E\u3059\u3002`,
273
+ inputSchema: z3.object({
274
+ status: z3.array(z3.string()).optional().default(["active", "paused"]).describe("\u30B9\u30C6\u30FC\u30BF\u30B9\u3067\u30D5\u30A3\u30EB\u30BF"),
275
+ tags: z3.array(z3.string()).optional().describe("\u30BF\u30B0\u3067\u30D5\u30A3\u30EB\u30BF"),
276
+ pinned: z3.boolean().optional().describe("\u30D4\u30F3\u7559\u3081\u3055\u308C\u305F\u8CEA\u554F\u306E\u307F"),
277
+ limit: z3.number().min(1).max(50).default(20).describe("\u53D6\u5F97\u4EF6\u6570\u4E0A\u9650")
278
+ }),
279
+ annotations: {
280
+ readOnlyHint: true,
281
+ openWorldHint: true
282
+ }
283
+ },
284
+ async ({ status, tags, pinned, limit }) => {
285
+ const supabase2 = await getSupabase();
286
+ let query = supabase2.from("questions").select(
287
+ "id, question, tags, status, importance, pinned, created_at, updated_at"
288
+ ).in("status", status ?? ["active", "paused"]).order("updated_at", { ascending: false }).limit(limit ?? 20);
289
+ if (tags?.length) {
290
+ query = query.overlaps("tags", tags);
291
+ }
292
+ if (pinned !== void 0) {
293
+ query = query.eq("pinned", pinned);
294
+ }
295
+ const { data, error } = await query;
296
+ if (error) throw new Error(`\u8CEA\u554F\u53D6\u5F97\u306B\u5931\u6557: ${error.message}`);
297
+ return {
298
+ content: [
299
+ {
300
+ type: "text",
301
+ text: formatQuestionList(data ?? [])
302
+ }
303
+ ]
304
+ };
305
+ }
306
+ );
307
+ }
308
+
309
+ // src/resources/questions.ts
310
+ function registerQuestionsResource(server2) {
311
+ server2.registerResource(
312
+ "active-questions",
313
+ "wellgrow://questions/active",
314
+ {
315
+ title: "\u30A2\u30AF\u30C6\u30A3\u30D6\u306A\u8CEA\u554F\u4E00\u89A7",
316
+ description: "\u30B9\u30C6\u30FC\u30BF\u30B9\u304C active \u306E\u8CEA\u554F\u4E00\u89A7\u3002",
317
+ mimeType: "application/json"
318
+ },
319
+ async (uri) => {
320
+ const supabase2 = await getSupabase();
321
+ const { data } = await supabase2.from("questions").select("id, question, tags, importance, pinned, updated_at").eq("status", "active").order("updated_at", { ascending: false }).limit(50);
322
+ return {
323
+ contents: [
324
+ {
325
+ uri: uri.href,
326
+ text: JSON.stringify(data ?? [], null, 2)
327
+ }
328
+ ]
329
+ };
330
+ }
331
+ );
332
+ }
333
+
334
+ // 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
+ ];
342
+ for (const key of required) {
343
+ if (!process.env[key]) {
344
+ console.error(`Error: ${key} is required`);
345
+ process.exit(1);
346
+ }
347
+ }
348
+ try {
349
+ await getSupabase();
350
+ console.error("Authenticated successfully");
351
+ } catch (error) {
352
+ console.error(
353
+ "Authentication failed:",
354
+ error instanceof Error ? error.message : error
355
+ );
356
+ process.exit(1);
357
+ }
358
+ var server = new McpServer(
359
+ { name: "wellgrow", version: "0.1.0" },
360
+ {
361
+ 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
+ \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
363
+ \u30E6\u30FC\u30B6\u30FC\u306E\u8003\u3048\u3084\u4FA1\u5024\u89B3\u3092\u7406\u89E3\u3057\u305F\u3044\u5834\u9762\u3067\u6D3B\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002`
364
+ }
365
+ );
366
+ registerSearchContextTool(server);
367
+ registerAnswerQuestionTool(server);
368
+ registerListQuestionsTool(server);
369
+ registerQuestionsResource(server);
370
+ var transport = new StdioServerTransport();
371
+ await server.connect(transport);
372
+ console.error("WellGrow MCP server running on stdio");
373
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@wellgrow/mcp",
3
+ "version": "0.1.0",
4
+ "description": "WellGrow MCP Server — Access your personal knowledge base from AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "wellgrow-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup",
14
+ "dev": "tsup --watch",
15
+ "start": "node dist/index.js",
16
+ "typecheck": "tsc --noEmit",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "@ai-sdk/openai": "^1.0.0",
21
+ "@modelcontextprotocol/sdk": "^1.26.0",
22
+ "@supabase/supabase-js": "^2.49.0",
23
+ "ai": "^4.0.0",
24
+ "zod": "^3.24.0"
25
+ },
26
+ "devDependencies": {
27
+ "tsup": "^8.0.0",
28
+ "typescript": "^5.0.0"
29
+ },
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "license": "UNLICENSED",
34
+ "private": false
35
+ }