claude-session-continuity-mcp 1.13.0 → 1.13.1

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 CHANGED
@@ -1,4 +1,4 @@
1
- # claude-session-continuity-mcp (v1.12.1)
1
+ # claude-session-continuity-mcp (v1.13.0)
2
2
 
3
3
  > **Zero Re-explanation Session Continuity for Claude Code** — Automatic context capture + semantic search + auto error→solution pipeline
4
4
 
@@ -6,6 +6,7 @@
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
  [![Tests](https://img.shields.io/badge/tests-111%20passed-brightgreen.svg)]()
8
8
  [![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)]()
9
+ [![claude-session-continuity-mcp MCP server](https://glama.ai/mcp/servers/leesgit/claude-session-continuity-mcp/badges/card.svg)](https://glama.ai/mcp/servers/leesgit/claude-session-continuity-mcp)
9
10
 
10
11
  ## The Problem
11
12
 
@@ -7,6 +7,47 @@
7
7
  import * as fs from 'fs';
8
8
  import * as path from 'path';
9
9
  import Database from 'better-sqlite3';
10
+ // ===== Playwright 캐시 정리 (20MB 컨텍스트 초과 방지) =====
11
+ function cleanPlaywrightCache(cwd) {
12
+ const MAX_TOTAL = 3 * 1024 * 1024; // 3MB 초과 시 정리
13
+ const MAX_FILES = 20; // 최대 파일 수
14
+ // .playwright-mcp/ 정리
15
+ const playwrightDir = path.join(cwd, '.playwright-mcp');
16
+ if (fs.existsSync(playwrightDir)) {
17
+ try {
18
+ const files = fs.readdirSync(playwrightDir)
19
+ .map(f => ({ name: f, path: path.join(playwrightDir, f), stat: fs.statSync(path.join(playwrightDir, f)) }))
20
+ .sort((a, b) => a.stat.mtimeMs - b.stat.mtimeMs);
21
+ let totalSize = files.reduce((sum, f) => sum + f.stat.size, 0);
22
+ // 오래된 파일부터 삭제 (최근 5개만 유지)
23
+ while (files.length > 5 || totalSize > MAX_TOTAL) {
24
+ const oldest = files.shift();
25
+ if (!oldest)
26
+ break;
27
+ try {
28
+ fs.unlinkSync(oldest.path);
29
+ totalSize -= oldest.stat.size;
30
+ }
31
+ catch { /* ignore */ }
32
+ }
33
+ }
34
+ catch { /* ignore */ }
35
+ }
36
+ // 루트의 스크린샷 파일 정리 (최근 3개만 유지)
37
+ try {
38
+ const screenshots = fs.readdirSync(cwd)
39
+ .filter(f => /\.(png|jpeg|jpg)$/i.test(f))
40
+ .map(f => ({ name: f, path: path.join(cwd, f), stat: fs.statSync(path.join(cwd, f)) }))
41
+ .sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs); // 최신순
42
+ for (let i = 3; i < screenshots.length; i++) {
43
+ try {
44
+ fs.unlinkSync(screenshots[i].path);
45
+ }
46
+ catch { /* ignore */ }
47
+ }
48
+ }
49
+ catch { /* ignore */ }
50
+ }
10
51
  // ===== 에러 감지 → 솔루션 자동 주입 =====
11
52
  const ERROR_PATTERNS = [
12
53
  /(?:error|Error|ERROR)\s*[:\[]/,
@@ -190,6 +231,12 @@ async function main() {
190
231
  }
191
232
  process.exit(0);
192
233
  }
234
+ // Playwright 도구 사용 후 캐시 정리 (20MB 컨텍스트 초과 방지)
235
+ if (toolName.startsWith('mcp__playwright__')) {
236
+ const cwd = input.cwd || process.cwd();
237
+ cleanPlaywrightCache(cwd);
238
+ process.exit(0);
239
+ }
193
240
  const TRACKED_TOOLS = ['Edit', 'Write', 'Read', 'Glob', 'Grep'];
194
241
  const IGNORED_PATTERNS = ['node_modules', '.git/', 'dist/', 'build/', '.next/', 'coverage/', '.DS_Store'];
195
242
  if (!TRACKED_TOOLS.includes(toolName)) {
@@ -143,6 +143,55 @@ function buildHandoverContext(transcript) {
143
143
  context.recentErrors = context.recentErrors.slice(0, 3);
144
144
  return context;
145
145
  }
146
+ /**
147
+ * Playwright 캐시 정리 - 오래된 스냅샷/로그 제거 (20MB 컨텍스트 초과 방지)
148
+ */
149
+ function cleanPlaywrightCache(cwd) {
150
+ const playwrightDir = path.join(cwd, '.playwright-mcp');
151
+ if (!fs.existsSync(playwrightDir))
152
+ return;
153
+ const now = Date.now();
154
+ const MAX_AGE = 30 * 60 * 1000; // 30분 이상 된 파일 정리
155
+ const MAX_DIR_SIZE = 5 * 1024 * 1024; // 5MB 초과 시 정리
156
+ try {
157
+ const files = fs.readdirSync(playwrightDir);
158
+ let totalSize = 0;
159
+ const fileInfos = [];
160
+ for (const file of files) {
161
+ const filePath = path.join(playwrightDir, file);
162
+ const stat = fs.statSync(filePath);
163
+ totalSize += stat.size;
164
+ fileInfos.push({ name: file, mtime: stat.mtimeMs, size: stat.size });
165
+ }
166
+ if (totalSize < MAX_DIR_SIZE)
167
+ return; // 5MB 미만이면 정리 불필요
168
+ // 오래된 파일부터 삭제
169
+ fileInfos.sort((a, b) => a.mtime - b.mtime);
170
+ for (const fi of fileInfos) {
171
+ if (now - fi.mtime > MAX_AGE) {
172
+ fs.unlinkSync(path.join(playwrightDir, fi.name));
173
+ totalSize -= fi.size;
174
+ }
175
+ if (totalSize < MAX_DIR_SIZE)
176
+ break;
177
+ }
178
+ }
179
+ catch { /* ignore */ }
180
+ // 루트의 오래된 스크린샷 PNG/JPEG도 정리
181
+ try {
182
+ const rootFiles = fs.readdirSync(cwd);
183
+ for (const file of rootFiles) {
184
+ if (!/\.(png|jpeg|jpg)$/i.test(file))
185
+ continue;
186
+ const filePath = path.join(cwd, file);
187
+ const stat = fs.statSync(filePath);
188
+ if (now - stat.mtimeMs > MAX_AGE) {
189
+ fs.unlinkSync(filePath);
190
+ }
191
+ }
192
+ }
193
+ catch { /* ignore */ }
194
+ }
146
195
  async function main() {
147
196
  try {
148
197
  let inputData = '';
@@ -151,6 +200,8 @@ async function main() {
151
200
  }
152
201
  const input = inputData ? JSON.parse(inputData) : {};
153
202
  const cwd = input.cwd || process.cwd();
203
+ // Playwright 캐시 정리 (20MB 컨텍스트 초과 방지)
204
+ cleanPlaywrightCache(cwd);
154
205
  const project = detectProject(cwd);
155
206
  const dbPath = getDbPath(cwd);
156
207
  if (!fs.existsSync(dbPath)) {
package/dist/index.js CHANGED
@@ -22,11 +22,23 @@ import { mkdirSync, existsSync } from 'fs';
22
22
  import * as path from 'path';
23
23
  import { execSync } from 'child_process';
24
24
  import Database from 'better-sqlite3';
25
- // @ts-ignore - transformers.js
26
- import { pipeline, env } from '@xenova/transformers';
27
- // 모델 캐시 설정
28
- env.cacheDir = path.join(process.env.HOME || '/tmp', '.cache', 'transformers');
29
- env.allowLocalModels = true;
25
+ // @xenova/transformers - 동적 import (sharp 의존성 문제 방지)
26
+ let transformersModule = null;
27
+ async function loadTransformers() {
28
+ if (transformersModule)
29
+ return transformersModule;
30
+ try {
31
+ // @ts-ignore - transformers.js
32
+ const mod = await import('@xenova/transformers');
33
+ mod.env.cacheDir = path.join(process.env.HOME || '/tmp', '.cache', 'transformers');
34
+ mod.env.allowLocalModels = true;
35
+ transformersModule = mod;
36
+ return mod;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
30
42
  // 기본 경로 설정 (자동 감지)
31
43
  function detectWorkspaceRoot() {
32
44
  // 1. 환경변수가 설정되어 있으면 사용
@@ -234,7 +246,10 @@ async function initEmbedding() {
234
246
  if (embeddingPipeline)
235
247
  return;
236
248
  try {
237
- embeddingPipeline = await pipeline('feature-extraction', 'Xenova/multilingual-e5-small');
249
+ const mod = await loadTransformers();
250
+ if (!mod)
251
+ return;
252
+ embeddingPipeline = await mod.pipeline('feature-extraction', 'Xenova/multilingual-e5-small');
238
253
  }
239
254
  catch (error) {
240
255
  console.error('Failed to load embedding model:', error);
@@ -396,54 +411,54 @@ const tools = [
396
411
  // ===== 1. 세션/컨텍스트 (4개) =====
397
412
  {
398
413
  name: 'session_start',
399
- description: '세션 시작 프로젝트 컨텍스트를 로드합니다. Hook에서 자동 호출되지만 수동 호출도 가능합니다.',
414
+ description: 'Load project context at the beginning of a session. Typically auto-invoked by the SessionStart hook, but can be called manually. Returns the project\'s tech stack, recent activity, pending tasks, and active blockers as a compressed context payload (~650 tokens). Read-only — does not modify any state. Use this instead of project_status when you need the full session bootstrap context.',
400
415
  inputSchema: {
401
416
  type: 'object',
402
417
  properties: {
403
- project: { type: 'string', description: '프로젝트 이름' },
404
- compact: { type: 'boolean', description: '간결한 포맷 (기본: true)' }
418
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
419
+ compact: { type: 'boolean', description: 'Return compressed format (default: true). Set false for verbose output.' }
405
420
  },
406
421
  required: ['project']
407
422
  }
408
423
  },
409
424
  {
410
425
  name: 'session_end',
411
- description: '세션 종료 현재 상태를 저장합니다. 다음 세션에서 자동 복구됩니다.',
426
+ description: 'Save the current session state before ending a conversation. Persists a summary, completed work, next steps, modified files, and blockers to SQLite. The saved state is automatically restored by session_start in the next session. Side effects: writes to the sessions table and updates the active_context record for the project. Idempotent — calling multiple times overwrites the previous session record.',
412
427
  inputSchema: {
413
428
  type: 'object',
414
429
  properties: {
415
- project: { type: 'string', description: '프로젝트 이름' },
416
- summary: { type: 'string', description: '이번 세션 요약 (1-2줄)' },
417
- workDone: { type: 'string', description: '완료한 작업' },
418
- nextSteps: { type: 'array', items: { type: 'string' }, description: '다음 ' },
419
- modifiedFiles: { type: 'array', items: { type: 'string' }, description: '수정한 파일' },
420
- blockers: { type: 'string', description: '막힌 것/이슈' }
430
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
431
+ summary: { type: 'string', description: 'One-line summary of this session' },
432
+ workDone: { type: 'string', description: 'Description of completed work' },
433
+ nextSteps: { type: 'array', items: { type: 'string' }, description: 'Ordered list of next tasks to pick up' },
434
+ modifiedFiles: { type: 'array', items: { type: 'string' }, description: 'Files modified during this session' },
435
+ blockers: { type: 'string', description: 'Current blockers or issues (null if none)' }
421
436
  },
422
437
  required: ['project', 'summary']
423
438
  }
424
439
  },
425
440
  {
426
441
  name: 'session_history',
427
- description: '프로젝트의 세션 이력을 조회합니다.',
442
+ description: 'Retrieve past session records for a project. Returns an array of session objects ordered by most recent first, each containing summary, work done, modified files, and verification results. Read-only. Use search_sessions instead when you need semantic/keyword matching rather than a chronological list.',
428
443
  inputSchema: {
429
444
  type: 'object',
430
445
  properties: {
431
- project: { type: 'string', description: '프로젝트 이름' },
432
- limit: { type: 'number', description: '조회 개수 (기본: 5)' },
433
- days: { type: 'number', description: '최근 N (기본: 7)' }
446
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
447
+ limit: { type: 'number', description: 'Max records to return (default: 5)' },
448
+ days: { type: 'number', description: 'Only return sessions from the last N days (default: 7)' }
434
449
  },
435
450
  required: ['project']
436
451
  }
437
452
  },
438
453
  {
439
454
  name: 'search_sessions',
440
- description: '세션 이력을 시맨틱 검색합니다. "저번에 인증 작업했을 " 같은 검색에 유용합니다.',
455
+ description: 'Semantic search across session history using multilingual embeddings (94+ languages). Finds past sessions by meaning, not just keywords — e.g. "when I worked on authentication" matches sessions about login, OAuth, JWT. Falls back to FTS5 keyword search when embeddings are unavailable. Read-only. Use session_history instead when you just need the N most recent sessions.',
441
456
  inputSchema: {
442
457
  type: 'object',
443
458
  properties: {
444
- query: { type: 'string', description: '검색어' },
445
- project: { type: 'string', description: '프로젝트 (선택)' },
446
- limit: { type: 'number', description: '결과 개수 (기본: 5)' }
459
+ query: { type: 'string', description: 'Natural language search query' },
460
+ project: { type: 'string', description: 'Filter by project (optional)' },
461
+ limit: { type: 'number', description: 'Max results to return (default: 5)' }
447
462
  },
448
463
  required: ['query']
449
464
  }
@@ -451,42 +466,42 @@ const tools = [
451
466
  // ===== 2. 프로젝트 관리 (4개) =====
452
467
  {
453
468
  name: 'project_status',
454
- description: '프로젝트 진행 현황을 조회합니다. 완성도, 태스크, 최근 변경 등.',
469
+ description: 'Get a project\'s current status including completion percentage, task breakdown (pending/in-progress/done/blocked), recent session activity, and active blockers. Read-only. Returns a structured JSON object. Use session_start instead when bootstrapping a new conversation; use this for mid-session status checks.',
455
470
  inputSchema: {
456
471
  type: 'object',
457
472
  properties: {
458
- project: { type: 'string', description: '프로젝트 이름' }
473
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' }
459
474
  },
460
475
  required: ['project']
461
476
  }
462
477
  },
463
478
  {
464
479
  name: 'project_init',
465
- description: ' 프로젝트를 초기화합니다. 컨텍스트 테이블에 기본 정보를 저장합니다.',
480
+ description: 'Initialize a new project in the continuity system. Creates records in the project_context and active_context tables. Auto-detects tech stack from package.json/pubspec.yaml/build.gradle if present. Side effects: writes to SQLite. Idempotent — safe to call on an already-initialized project (updates existing record). Call this once when adding a new project, then use session_start for subsequent sessions.',
466
481
  inputSchema: {
467
482
  type: 'object',
468
483
  properties: {
469
- project: { type: 'string', description: '프로젝트 이름' },
470
- techStack: { type: 'object', description: '기술 스택 (자동 감지 가능)' },
471
- description: { type: 'string', description: '프로젝트 설명' }
484
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
485
+ techStack: { type: 'object', description: 'Tech stack override {framework, language, database, ...}. Omit for auto-detection.' },
486
+ description: { type: 'string', description: 'Human-readable project description' }
472
487
  },
473
488
  required: ['project']
474
489
  }
475
490
  },
476
491
  {
477
492
  name: 'project_analyze',
478
- description: '프로젝트를 분석하여 기술 스택, 구조 등을 자동 감지합니다.',
493
+ description: 'Auto-detect a project\'s tech stack, framework, platform (Web/Android/Flutter/Server), directory structure, and dependency count by scanning its files. Read-only — does not persist results. Returns a structured analysis object. Use project_init to persist the detected configuration.',
479
494
  inputSchema: {
480
495
  type: 'object',
481
496
  properties: {
482
- project: { type: 'string', description: '프로젝트 이름' }
497
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' }
483
498
  },
484
499
  required: ['project']
485
500
  }
486
501
  },
487
502
  {
488
503
  name: 'list_projects',
489
- description: 'apps/ 디렉토리의 모든 프로젝트 목록을 반환합니다.',
504
+ description: 'List all projects under the apps/ directory with their platform type (Web/Android/Flutter), initialization status, and whether session context exists. Read-only. Returns an array of project summary objects. No parameters required.',
490
505
  inputSchema: {
491
506
  type: 'object',
492
507
  properties: {}
@@ -495,52 +510,52 @@ const tools = [
495
510
  // ===== 3. 태스크/백로그 (4개) =====
496
511
  {
497
512
  name: 'task_add',
498
- description: ' 태스크를 추가합니다.',
513
+ description: 'Add a new task to a project\'s backlog. Tasks are persisted in SQLite with priority ranking and optional file associations. Side effects: inserts into the tasks table. Returns the created task ID. Use task_list to view existing tasks before adding duplicates. Use task_suggest to auto-generate tasks from code comments (TODO/FIXME).',
499
514
  inputSchema: {
500
515
  type: 'object',
501
516
  properties: {
502
- project: { type: 'string', description: '프로젝트 이름' },
503
- title: { type: 'string', description: '태스크 제목' },
504
- description: { type: 'string', description: '상세 설명' },
505
- priority: { type: 'number', description: '우선순위 1-10 (기본: 5)' },
506
- relatedFiles: { type: 'array', items: { type: 'string' }, description: '관련 파일' }
517
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
518
+ title: { type: 'string', description: 'Task title (concise, actionable)' },
519
+ description: { type: 'string', description: 'Detailed description (optional)' },
520
+ priority: { type: 'number', description: 'Priority 1-10 where 10 is highest (default: 5)' },
521
+ relatedFiles: { type: 'array', items: { type: 'string' }, description: 'Associated file paths (optional)' }
507
522
  },
508
523
  required: ['project', 'title']
509
524
  }
510
525
  },
511
526
  {
512
527
  name: 'task_update',
513
- description: '태스크 상태를 변경합니다.',
528
+ description: 'Update a task\'s status. Valid transitions: pending → in_progress → done, or any state → blocked. Setting status to "done" automatically records a completion timestamp. Side effects: updates the tasks table. Idempotent. Returns success/failure and whether the row was actually modified.',
514
529
  inputSchema: {
515
530
  type: 'object',
516
531
  properties: {
517
- taskId: { type: 'number', description: '태스크 ID' },
518
- status: { type: 'string', enum: ['pending', 'in_progress', 'done', 'blocked'], description: ' 상태' },
519
- note: { type: 'string', description: '메모 (완료 결과 )' }
532
+ taskId: { type: 'number', description: 'Task ID (from task_add or task_list)' },
533
+ status: { type: 'string', enum: ['pending', 'in_progress', 'done', 'blocked'], description: 'New status' },
534
+ note: { type: 'string', description: 'Optional note (e.g. completion summary or block reason)' }
520
535
  },
521
536
  required: ['taskId', 'status']
522
537
  }
523
538
  },
524
539
  {
525
540
  name: 'task_list',
526
- description: '프로젝트의 태스크 목록을 조회합니다.',
541
+ description: 'List tasks for a project, filtered by status. Returns an array of task objects with id, title, description, status, priority, related files, and timestamps, plus a summary count by status. Read-only. Default filter is "pending" — pass status="all" to see everything.',
527
542
  inputSchema: {
528
543
  type: 'object',
529
544
  properties: {
530
- project: { type: 'string', description: '프로젝트 이름' },
531
- status: { type: 'string', enum: ['all', 'pending', 'in_progress', 'done', 'blocked'], description: '필터 (기본: pending)' }
545
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
546
+ status: { type: 'string', enum: ['all', 'pending', 'in_progress', 'done', 'blocked'], description: 'Status filter (default: "pending")' }
532
547
  },
533
548
  required: ['project']
534
549
  }
535
550
  },
536
551
  {
537
552
  name: 'task_suggest',
538
- description: '코드 분석 기반으로 TODO, FIXME 등에서 태스크를 추출하여 제안합니다.',
553
+ description: 'Scan project source files for TODO, FIXME, HACK, and XXX comments and return them as suggested tasks. Read-only — does not create tasks automatically. Review the suggestions and use task_add to persist the ones you want. Optionally scope the scan to a specific subdirectory.',
539
554
  inputSchema: {
540
555
  type: 'object',
541
556
  properties: {
542
- project: { type: 'string', description: '프로젝트 이름' },
543
- path: { type: 'string', description: '특정 경로만 분석 (선택)' }
557
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
558
+ path: { type: 'string', description: 'Subdirectory path to limit the scan (optional, e.g. "src/components")' }
544
559
  },
545
560
  required: ['project']
546
561
  }
@@ -548,41 +563,41 @@ const tools = [
548
563
  // ===== 4. 솔루션 아카이브 (3개) =====
549
564
  {
550
565
  name: 'solution_record',
551
- description: '에러 해결 방법을 기록합니다. 나중에 같은 에러 발생 자동 검색됩니다.',
566
+ description: 'Record an error-solution pair in the solution archive. Associates an error signature (the searchable key), optional full error message, the fix, and related files. Automatically extracts keywords for FTS5 indexing. Side effects: inserts into the solutions table. Use solution_find to check for existing solutions before recording a duplicate.',
552
567
  inputSchema: {
553
568
  type: 'object',
554
569
  properties: {
555
- project: { type: 'string', description: '프로젝트 이름' },
556
- errorSignature: { type: 'string', description: '에러 패턴/시그니처 (검색 )' },
557
- errorMessage: { type: 'string', description: '전체 에러 메시지' },
558
- solution: { type: 'string', description: '해결 방법' },
559
- relatedFiles: { type: 'array', items: { type: 'string' }, description: '관련 파일' }
570
+ project: { type: 'string', description: 'Project name (optional — omit for cross-project solutions)' },
571
+ errorSignature: { type: 'string', description: 'Error pattern/signature used as the search key (e.g. "ENOENT: no such file", "WorkManager not initialized")' },
572
+ errorMessage: { type: 'string', description: 'Full error message or stack trace (optional)' },
573
+ solution: { type: 'string', description: 'Step-by-step fix description' },
574
+ relatedFiles: { type: 'array', items: { type: 'string' }, description: 'Files that were modified to fix the error' }
560
575
  },
561
576
  required: ['errorSignature', 'solution']
562
577
  }
563
578
  },
564
579
  {
565
580
  name: 'solution_find',
566
- description: '유사한 에러의 해결 방법을 검색합니다. semantic=true 시맨틱 검색 가능.',
581
+ description: 'Search the solution archive for previously resolved errors. Matches against error signatures, messages, and keywords using FTS5. Set semantic=true to enable embedding-based similarity search for better recall across different error phrasings. Read-only. Returns matched solutions with their fix descriptions and related files. Use solution_suggest instead if you want AI-powered fix recommendations.',
567
582
  inputSchema: {
568
583
  type: 'object',
569
584
  properties: {
570
- query: { type: 'string', description: '에러 메시지 또는 키워드' },
571
- project: { type: 'string', description: '프로젝트 (선택)' },
572
- limit: { type: 'number', description: '결과 개수 (기본: 3)' },
573
- semantic: { type: 'boolean', description: '시맨틱 검색 사용 (기본: false, 임베딩 기반)' }
585
+ query: { type: 'string', description: 'Error message, signature, or natural language description of the problem' },
586
+ project: { type: 'string', description: 'Filter by project (optional — also includes cross-project solutions)' },
587
+ limit: { type: 'number', description: 'Max results to return (default: 3)' },
588
+ semantic: { type: 'boolean', description: 'Enable semantic/embedding search for fuzzy matching (default: false)' }
574
589
  },
575
590
  required: ['query']
576
591
  }
577
592
  },
578
593
  {
579
594
  name: 'solution_suggest',
580
- description: '과거 솔루션 기반으로 현재 에러에 대한 해결책을 AI 제안합니다.',
595
+ description: 'Get AI-powered fix suggestions for a current error based on the solution archive. Retrieves the most relevant past solutions and generates a contextual recommendation. Read-only. Use solution_find for direct archive lookup without AI synthesis; use solution_record after fixing an error to grow the archive.',
581
596
  inputSchema: {
582
597
  type: 'object',
583
598
  properties: {
584
- errorMessage: { type: 'string', description: '현재 에러 메시지' },
585
- project: { type: 'string', description: '프로젝트' }
599
+ errorMessage: { type: 'string', description: 'The current error message or stack trace' },
600
+ project: { type: 'string', description: 'Project name for context (optional)' }
586
601
  },
587
602
  required: ['errorMessage']
588
603
  }
@@ -590,35 +605,35 @@ const tools = [
590
605
  // ===== 5. 검증/품질 (3개) =====
591
606
  {
592
607
  name: 'verify_build',
593
- description: '프로젝트 빌드를 실행합니다.',
608
+ description: 'Run the project\'s build command (auto-detected per platform: "pnpm build" for Web, "flutter build" for Flutter, "./gradlew assembleDebug" for Android). Side effects: executes a shell command in the project directory with a 5-minute timeout. Returns {success, output} with the last 1000 chars of stdout/stderr. Use verify_all to run build + test + lint together.',
594
609
  inputSchema: {
595
610
  type: 'object',
596
611
  properties: {
597
- project: { type: 'string', description: '프로젝트 이름' }
612
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' }
598
613
  },
599
614
  required: ['project']
600
615
  }
601
616
  },
602
617
  {
603
618
  name: 'verify_test',
604
- description: '프로젝트 테스트를 실행합니다.',
619
+ description: 'Run the project\'s test suite (auto-detected per platform: "pnpm test:run" for Web, "flutter test" for Flutter, "./gradlew test" for Android). Optionally scope to a specific test file or directory. Side effects: executes a shell command with a 5-minute timeout. Returns {success, output}. Use verify_all to run build + test + lint together.',
605
620
  inputSchema: {
606
621
  type: 'object',
607
622
  properties: {
608
- project: { type: 'string', description: '프로젝트 이름' },
609
- testPath: { type: 'string', description: '특정 테스트 파일/폴더 (선택)' }
623
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
624
+ testPath: { type: 'string', description: 'Specific test file or directory to run (optional — runs all tests if omitted)' }
610
625
  },
611
626
  required: ['project']
612
627
  }
613
628
  },
614
629
  {
615
630
  name: 'verify_all',
616
- description: '빌드 + 테스트 + 린트를 번에 실행합니다.',
631
+ description: 'Run build, test, and lint sequentially for a project. Auto-detects platform-specific commands. Side effects: executes up to 3 shell commands with 5-minute timeouts each. Returns per-gate results and an overall pass/fail status. Use this as a quality gate before committing or ending a session. Use verify_build or verify_test individually when you only need one check.',
617
632
  inputSchema: {
618
633
  type: 'object',
619
634
  properties: {
620
- project: { type: 'string', description: '프로젝트 이름' },
621
- stopOnFail: { type: 'boolean', description: '실패 중단 (기본: false)' }
635
+ project: { type: 'string', description: 'Project name (must match a directory under apps/)' },
636
+ stopOnFail: { type: 'boolean', description: 'Abort remaining gates on first failure (default: false — runs all gates)' }
622
637
  },
623
638
  required: ['project']
624
639
  }
@@ -626,117 +641,117 @@ const tools = [
626
641
  // ===== 6. 메모리 시스템 (4개) - v4 신규 =====
627
642
  {
628
643
  name: 'memory_store',
629
- description: '메모리를 저장합니다. 타입별로 분류되어 나중에 체계적으로 검색 가능합니다.',
644
+ description: 'Store a piece of knowledge in the memory system. Memories are typed (observation, decision, learning, error, pattern), tagged, and automatically embedded for semantic retrieval. Side effects: inserts into the memories table and asynchronously generates a vector embedding. If relatedTo is provided, also creates a knowledge graph edge. Returns the new memory ID. Use memory_search to verify no duplicate exists before storing.',
630
645
  inputSchema: {
631
646
  type: 'object',
632
647
  properties: {
633
- content: { type: 'string', description: '저장할 내용' },
648
+ content: { type: 'string', description: 'The knowledge content to store' },
634
649
  type: {
635
650
  type: 'string',
636
651
  enum: ['observation', 'decision', 'learning', 'error', 'pattern'],
637
- description: '메모리 타입: observation(발견), decision(결정), learning(학습), error(에러), pattern(패턴)'
652
+ description: 'Memory type: observation (discovery/finding), decision (architecture/tech choice), learning (new knowledge), error (error encountered), pattern (code convention)'
638
653
  },
639
- project: { type: 'string', description: '관련 프로젝트 (선택)' },
640
- tags: { type: 'array', items: { type: 'string' }, description: '태그 (검색용)' },
641
- importance: { type: 'number', description: '중요도 1-10 (기본: 5)' },
642
- relatedTo: { type: 'number', description: '연결할 기존 메모리 ID (선택)' }
654
+ project: { type: 'string', description: 'Associated project name (optional — omit for cross-project knowledge)' },
655
+ tags: { type: 'array', items: { type: 'string' }, description: 'Tags for filtering (e.g. ["auth", "performance"])' },
656
+ importance: { type: 'number', description: 'Importance score 1-10 where 10 is critical (default: 5)' },
657
+ relatedTo: { type: 'number', description: 'ID of an existing memory to link via knowledge graph (optional)' }
643
658
  },
644
659
  required: ['content', 'type']
645
660
  }
646
661
  },
647
662
  {
648
663
  name: 'memory_search',
649
- description: '메모리를 검색합니다. 기본은 인덱스만 반환 (토큰 절약). detail=true 전체 내용 확인.',
664
+ description: 'Search stored memories using FTS5 full-text search or semantic/embedding similarity. Default mode returns compact index entries (id, type, truncated content) to save tokens — set detail=true for full content. Supports filtering by type, project, tags, and minimum importance. Read-only. Use memory_get to fetch full content for specific IDs found in search results. Use memory_related to explore graph connections from a known memory.',
650
665
  inputSchema: {
651
666
  type: 'object',
652
667
  properties: {
653
- query: { type: 'string', description: '검색어 (자연어)' },
668
+ query: { type: 'string', description: 'Natural language search query' },
654
669
  type: {
655
670
  type: 'string',
656
671
  enum: ['observation', 'decision', 'learning', 'error', 'pattern', 'all'],
657
- description: '메모리 타입 필터 (기본: all)'
672
+ description: 'Filter by memory type (default: "all")'
658
673
  },
659
- project: { type: 'string', description: '프로젝트 필터 (선택)' },
660
- tags: { type: 'array', items: { type: 'string' }, description: '태그 필터 (선택)' },
661
- semantic: { type: 'boolean', description: '시맨틱 검색 사용 (기본: false, 임베딩 기반)' },
662
- minImportance: { type: 'number', description: '최소 중요도 (기본: 1)' },
663
- limit: { type: 'number', description: '결과 개수 (기본: 10)' },
664
- detail: { type: 'boolean', description: 'true면 전체 content, false 요약 인덱스만 (기본: false)' }
674
+ project: { type: 'string', description: 'Filter by project (optional)' },
675
+ tags: { type: 'array', items: { type: 'string' }, description: 'Filter by tags — matches if any tag is present (optional)' },
676
+ semantic: { type: 'boolean', description: 'Use embedding-based semantic search instead of keyword FTS5 (default: false)' },
677
+ minImportance: { type: 'number', description: 'Minimum importance threshold 1-10 (default: 1)' },
678
+ limit: { type: 'number', description: 'Max results to return (default: 10)' },
679
+ detail: { type: 'boolean', description: 'Return full content per memory (default: false returns compact index only)' }
665
680
  },
666
681
  required: ['query']
667
682
  }
668
683
  },
669
684
  {
670
685
  name: 'memory_get',
671
- description: '메모리 ID 전체 내용을 조회합니다. memory_search 결과에서 상세 내용 확인 사용.',
686
+ description: 'Retrieve full content for one or more memories by ID. Designed as a follow-up to memory_search: first search to find relevant IDs, then use memory_get to load full details. Read-only. Accepts up to 20 IDs per call. Returns an array of complete memory objects including content, type, tags, importance, timestamps, and access count.',
672
687
  inputSchema: {
673
688
  type: 'object',
674
689
  properties: {
675
- ids: { type: 'array', items: { type: 'number' }, description: '조회할 메모리 ID 배열 (최대 20)' }
690
+ ids: { type: 'array', items: { type: 'number' }, description: 'Array of memory IDs to retrieve (max 20)' }
676
691
  },
677
692
  required: ['ids']
678
693
  }
679
694
  },
680
695
  {
681
696
  name: 'memory_related',
682
- description: '특정 메모리와 관련된 메모리들을 찾습니다. 지식 그래프 + 시맨틱 유사도 결합.',
697
+ description: 'Find memories related to a given memory using knowledge graph traversal and/or semantic similarity. Combines two strategies: (1) graph edges created via graph_connect or memory_store\'s relatedTo, and (2) cosine similarity between embeddings. Read-only. Use graph_explore for pure graph traversal with depth control; use memory_search for text-based search.',
683
698
  inputSchema: {
684
699
  type: 'object',
685
700
  properties: {
686
- memoryId: { type: 'number', description: '기준 메모리 ID' },
687
- includeGraph: { type: 'boolean', description: '지식 그래프 관계 포함 (기본: true)' },
688
- includeSemantic: { type: 'boolean', description: '시맨틱 유사 메모리 포함 (기본: true)' },
689
- limit: { type: 'number', description: '결과 개수 (기본: 10)' }
701
+ memoryId: { type: 'number', description: 'The anchor memory ID to find relations for' },
702
+ includeGraph: { type: 'boolean', description: 'Include knowledge graph connections (default: true)' },
703
+ includeSemantic: { type: 'boolean', description: 'Include semantically similar memories via embeddings (default: true)' },
704
+ limit: { type: 'number', description: 'Max results to return (default: 10)' }
690
705
  },
691
706
  required: ['memoryId']
692
707
  }
693
708
  },
694
709
  {
695
710
  name: 'memory_stats',
696
- description: '메모리 시스템 통계를 조회합니다. 타입별, 프로젝트별 분포 등.',
711
+ description: 'Get aggregate statistics about the memory system: total count, breakdown by type (observation/decision/learning/error/pattern), breakdown by project, top 5 most accessed memories, and 5 most recent entries. Read-only. Useful for understanding memory distribution and system health. Optionally scope to a single project.',
697
712
  inputSchema: {
698
713
  type: 'object',
699
714
  properties: {
700
- project: { type: 'string', description: '특정 프로젝트만 (선택)' }
715
+ project: { type: 'string', description: 'Scope statistics to a single project (optional — omit for global stats)' }
701
716
  }
702
717
  }
703
718
  },
704
719
  // ===== 7. 지식 그래프 (2개) - v4 신규 =====
705
720
  {
706
721
  name: 'graph_connect',
707
- description: ' 메모리 사이에 관계를 생성합니다. 지식 그래프 구축용.',
722
+ description: 'Create a directed edge between two memories in the knowledge graph. Supports 7 relation types for structured knowledge organization. Side effects: inserts or replaces a row in memory_relations (upsert on sourceId+targetId+relation). Use memory_related to discover existing connections; use graph_explore to traverse the graph from a starting node.',
708
723
  inputSchema: {
709
724
  type: 'object',
710
725
  properties: {
711
- sourceId: { type: 'number', description: '출발 메모리 ID' },
712
- targetId: { type: 'number', description: '도착 메모리 ID' },
726
+ sourceId: { type: 'number', description: 'Source memory ID (the "from" node)' },
727
+ targetId: { type: 'number', description: 'Target memory ID (the "to" node)' },
713
728
  relation: {
714
729
  type: 'string',
715
730
  enum: ['related_to', 'causes', 'solves', 'depends_on', 'contradicts', 'extends', 'example_of'],
716
- description: '관계 유형: related_to(관련), causes(원인), solves(해결), depends_on(의존), contradicts(상충), extends(확장), example_of(예시)'
731
+ description: 'Edge type: related_to (general association), causes (A causes B), solves (A fixes B), depends_on (A requires B), contradicts (A conflicts with B), extends (A builds on B), example_of (A demonstrates B)'
717
732
  },
718
- strength: { type: 'number', description: '관계 강도 0-1 (기본: 1.0)' }
733
+ strength: { type: 'number', description: 'Connection strength 0.0-1.0 (default: 1.0). Lower values indicate weaker associations.' }
719
734
  },
720
735
  required: ['sourceId', 'targetId', 'relation']
721
736
  }
722
737
  },
723
738
  {
724
739
  name: 'graph_explore',
725
- description: '지식 그래프를 탐색합니다. 특정 메모리부터 연결된 모든 메모리를 깊이 우선 탐색.',
740
+ description: 'Traverse the knowledge graph from a starting memory using depth-first search. Returns all connected memories up to the specified depth, with their relation types, strengths, and directions. Read-only. Supports filtering by relation type and traversal direction. Use memory_related instead for a combined graph+semantic approach; use graph_connect to add new edges.',
726
741
  inputSchema: {
727
742
  type: 'object',
728
743
  properties: {
729
- memoryId: { type: 'number', description: '시작 메모리 ID' },
730
- depth: { type: 'number', description: '탐색 깊이 (기본: 2, 최대: 4)' },
744
+ memoryId: { type: 'number', description: 'Starting memory ID for graph traversal' },
745
+ depth: { type: 'number', description: 'Maximum traversal depth 1-4 (default: 2). Higher values return more results but may be slower.' },
731
746
  relation: {
732
747
  type: 'string',
733
748
  enum: ['related_to', 'causes', 'solves', 'depends_on', 'contradicts', 'extends', 'example_of', 'all'],
734
- description: '관계 유형 필터 (기본: all)'
749
+ description: 'Filter by relation type (default: "all")'
735
750
  },
736
751
  direction: {
737
752
  type: 'string',
738
753
  enum: ['outgoing', 'incoming', 'both'],
739
- description: '탐색 방향 (기본: both)'
754
+ description: 'Traversal direction — outgoing (A→B), incoming (B→A), or both (default: "both")'
740
755
  }
741
756
  },
742
757
  required: ['memoryId']
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-session-continuity-mcp",
3
- "version": "1.13.0",
3
+ "version": "1.13.1",
4
4
  "description": "Session Continuity for Claude Code - Never re-explain your project again",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",