AnchorMindANCHORMIND
SIGN IN

Releases

AnchorMind MCP 서버의 버전별 변경 내역. GitHub 릴리즈와 동일한 내용이다.

v5.6.2

LATEST

[5.6.2] - 2026-08-13

임베딩 차원 마이그레이션 판정 결함(#54)과 운영 와치독 재시작 폭풍을 정비한 패치.

Fixed

  • 임베딩 차원 마이그레이션 스킵 판정을 (타입, 선언 차원) 쌍 비교로 교체한다 (#54). pgvector는 vector(1536)·vector(384)를 모두 udt_name='vector'로 보고하므로 타입 이름 단독 비교가 실제 차원 변경을 스킵했고, transformers 384차원 전환 환경에서 임베딩 쓰기 전량 실패·시맨틱 검색 무력화로 이어졌다. 선언 차원은 pg_attribute.atttypmod에서 읽으며 무차원 선언(-1)도 변환 대상으로 판정한다.
  • 기동 게이트(check-embedding-consistency)가 임베딩 데이터 전량 NULL 상태의 선언 차원 불일치를 통과시키던 공백을 막는다. 행 표본 검사 전에 선언 차원 검사를 수행해, 불일치 상태로 서버가 기동해 NULL을 양산하기 전에 차단한다.
  • 와치독 스크립트에 기동 유예 120초를 도입한다. 유예 없이는 부팅(모델 로드 등)이 헬스체크 주기를 넘는 순간 매분 강제 재시작이 반복되는 재시작 폭풍이 된다.

Added

  • 차원 마이그레이션 스크립트에 --dry-run(변환 대상 미리보기), 테이블별 트랜잭션(중간 실패 시 롤백으로 "임베딩 전량 NULL + 인덱스 없음" 중간 상태 방지), 변환 후 검증 출력(NULL 수·pg_index.indisvalid)을 추가한다. halfvec 목표 시 실행 경로 호환 미검증 경고를 출력한다.
  • (타입, 차원) 판정 로직을 lib/memory/embedding/column-spec.js로 분리해 마이그레이션 스크립트와 기동 게이트가 공유한다.

Changed

  • 마이그레이션의 HNSW 인덱스 재생성 파라미터를 기본 스키마와 동일한 ef_construction=128로 정합한다(기존 64는 재생성 시 검색 품질 회귀 요인).

v5.6.1

[5.6.1] - 2026-08-12

운영 인스턴스 주간 텔레메트리(recall 무관 피드백 27건 중 topic_mismatch 17건)와 열린 이슈 2건(#51, #52)을 반영한 검색 정합 패치.

Fixed

  • recall 명시 topic/type 필터가 L1 유래 후보에서 소실되던 경로 2곳을 차단한다 (#51). topic/type 인덱스가 0건이면 L1이 공집합을 반환하고(0건 집합이 교집합에서 누락되어 keyword 집합 단독이 교집합 행세하던 결함), L1 미스분 ID 보충 조회 결과에 SearchScope(topic/type/caseId/phase/affect)와 timeRange를 정합 적용한다. 오기 topic은 이제 0건과 함께 topic_mismatch 후보 힌트로 응답한다.
  • RRF 병합에서 L1의 ID-only 항목이 이후 도착한 완전 파편 객체로 승격되지 않아 content 부재 필터에서 정당한 L1 hit가 탈락하던 결함을 수정한다.
  • morpheme_dict의 embedding NULL 행이 캐시 히트로 오인되어 재계산 없이 영구 잔존하던 결함을 수정한다 (#52). NULL 행을 miss로 취급해 재계산하고, 등록 쿼리를 NULL 행 한정 조건부 UPDATE로 교체해 접근 시 치유한다. 유효 임베딩은 덮어쓰지 않아 프로바이더·차원 혼합을 방지한다.

Added

  • scripts/backfill-morpheme-dict.js — morpheme_dict NULL 행 일괄 재임베딩. 커서 기반 배치, --dry-run, 실패 형태소 격리(무한 재선택 방지), 배치 전멸 시 중단. 기존 backfill-embeddings.js는 fragments 전용이라 이 테이블을 다루지 않는다.
  • 형태소 임베딩 등록에 프로바이더 오류 분류(인증·한도·서버·네트워크)와 지수 백오프 쿨다운(30초~10분), 동시 중복 요청 방지(inFlight)를 도입한다. 배치 1회 실패가 단건 최대 200회 호출로 증폭되던 경로를 차단한다.

Changed

  • L1 폴백 계약: 명시 조건(keywords/topic/type/text)이 있는 검색은 인덱스 0건 시 최근 접근 파편 폴백을 발동하지 않는다. 폴백은 조건 전무 조회 전용이다.

v5.6.0

운영 인스턴스의 최근 7일 검색 텔레메트리(무결과 mixed 검색 60건 중 51건이 topic 필터 조합)와 열린 이슈 2건(#48, #33)을 반영한다.

Added

  • recall이 topic 지정 검색에서 0건일 때 키 스코프의 유사 토픽 후보를 _meta.hintstopic_mismatch 신호로 반환한다. 후보는 topic별 파편 수 집계를 형태소 벡터 코사인으로 랭킹해 상위 3개까지 제시하며, topic 필터 자체는 정확일치 그대로다. 후보가 없으면 기존 no_results로 떨어진다.
  • task_feedbackoutcome(completed/partial/blocked/abandoned/unknown), evaluator(agent/automatic/human), evidence, unmet_requirements 필드 추가 (#48, migration-039). overall_success만으로는 "완수했으나 도구가 방해했다"를 표현할 수 없어 성공률 지표가 변별하지 못했다. overall_success는 호환을 위해 유지하고, 기존 행은 NULL(미보고)로 남겨 신규 표본과 분리한다.
  • tool_feedbackirrelevance_reason(not_stored/search_miss/scope_leak/topic_mismatch/other) 추가 (#48). 저장된 적 없는 내용을 찾은 호출과 검색이 실패한 호출을 분리 집계한다. ConsolidatorGC 피드백 리포트에 원인 분포·outcome 분포 블록이 추가되고, memory_stats의 evaluation에 completed_rate·irrelevance 키가 늘어난다(기존 키 불변).
  • 쓰기 도구(remember/amend/forget) 성공 응답의 _meta.hints에 확률적 피드백 유도(feedback_sampled) 추가 (#48). 표본이 recall에 편중되는 문제의 완화책으로, 세션당 최대 2건·쿨다운 15분·도구별 확률(remember 0.10, amend/forget 0.25)로 제한하며 MEMENTO_FEEDBACK_SAMPLING=false로 끌 수 있다. 유도된 피드백은 trigger_type='sampled'로 저장되어 자발 표본과 분리 관측된다.
  • 분할 자식 품질 게이트 2종 (#33). 부모 원문의 주어 앵커(고유명사·코드 식별자·라틴+한글 혼합 토큰)가 자식 본문에 하나도 남지 않으면 reject(subject_loss), 부모에 없는 시제·서법 표지(예정/의도/추정/당위 4패밀리)를 자식이 새로 도입하면 reject(modality_drift). 완료 사실이 미래 계획으로 바뀌거나 주어를 잃은 조각이 독립 파편이 되는 경로를 차단한다. MEMENTO_SPLIT_SUBJECT_GATE/MEMENTO_SPLIT_MODALITY_GATE(기본 활성)로 토글하며, 앵커 미추출 시 게이트를 적용하지 않는다. memento_consolidate_split_skipped_total에 두 reason 라벨이 추가된다(자식 단위 집계).

Changed

  • topic 정확일치 필터가 0건을 반환한 검색을 SearchParamAdaptor의 minSimilarity 학습 표본에서 제외한다. topic 오기가 반복되면 원인과 무관한 시맨틱 임계값이 하향 학습되던 경로를 차단한다.
  • remember·recall의 topic 값에 trim을 적용한다. 소문자화는 기존 저장 topic과의 불일치를 만들므로 도입하지 않는다.

배포 주의

  • migration-039를 적용하지 않은 DB에서 tool_feedback 저장이 실패한다. 서비스 재시작 전 마이그레이션을 선행한다.

v5.5.0

운영 인스턴스의 최근 15일 피드백을 분석해 도출한 결함 4건을 수정한다. 모두 격리 DB에서 실제 코드 경로로 재현을 확인한 뒤 조치했다.

Fixed

  • amendresolutionStatus/outcome/phase를 받아도 반영하지 않고 updated: true를 반환하던 문제 수정 (#43). 세 필드가 도구 스키마와 FragmentWriter의 갱신 허용 필드에 모두 없어 조용히 버려졌고, SKILL.mdlib/jsonrpc.js가 안내하는 케이스 종결 절차가 수행되지 않았다. 변경 전 상태는 fragment_versions에 UPDATE와 동일 트랜잭션으로 기록하며(migration-038), resolved 전환 시 case_closed 이벤트를 남긴다.
  • 반영 가능한 필드가 하나도 없는 amend 호출이 성공으로 보고되던 문제 수정 (#43). updated: falseunsupportedFields를 반환한다.
  • 만료(valid_to 설정) 파편 amend가 미존재 id와 동일한 오류를 반환하던 문제 수정 (#43). 만료 파편은 이력이므로 수정 불가 정책을 유지하되 validTo와 함께 구분되는 오류를 반환한다.
  • type/topic 필터가 L1/L2에만 적용되어, timeRange 지정 시 시간창 레이어가 타입 무관 파편을 수집하고 RRF에서 2배 가중을 받아 상위를 점령하던 문제 수정 (#44). SearchScope에 두 필드를 추가하고 searchByTimeRange·searchBySemantic에 전달한다. 격리 DB 실측 기준 type=decision 지정 시 반환 8건(불일치 6건)에서 2건(불일치 0건)으로 변경.
  • 사용자가 keywords를 지정하면 본문 추출이 수행되지 않아 본문에만 등장하는 코드 식별자가 색인되지 않던 문제 수정 (#45). 지정 키워드를 앞에 두고 중복 제거 후 최대 10개까지 추출 결과를 병합한다. 운영 데이터 기준 본문에 식별자가 있는 파편 3,032건 중 1,265건이 대상이었다.
  • morphemeIndexminSimilarity·fallbackThreshold·fallbackLimit이 검색 경로에서 소비되지 않던 문제 수정 (#46). 형태소 프로브가 semanticSearch.minSimilarity(0.4)를 재사용해, 문장 임베딩보다 코사인이 낮은 형태소 평균 벡터가 사실상 전량 탈락했다. 전용 임계값 0.15를 적용하고 기본 결과가 fallbackThreshold 이하일 때만 fallbackLimit까지 채택한다.

Changed

  • FragmentReader.searchBySemantic이 위치 인자 대신 옵션 객체를 받는다 (#44). 필터가 12종을 넘어 순서 오류 위험이 커졌다.
  • scripts/backfill-split-keywords.js, scripts/backfill-body-keywords.js로 기존 파편을 소급 처리할 수 있다. 둘 다 dryRun 기본.

v5.4.1

Security

  • 의존성 취약점 9건 해소. npm audit 기준 잔여 0건.
    • fast-uri 3.1.2 → 3.1.5 (host confusion 2건: GHSA-v2hh-gcrm-f6hx, GHSA-4c8g-83qw-93j6). @modelcontextprotocol/sdkajv 경유 전이 의존성이다.
    • sharp 0.34.5 → 0.35.3 (libvips 상속 취약점 4건: GHSA-f88m-g3jw-g9cj). @huggingface/transformers의 선언 범위(^0.34.1) 밖이라 override로 강제하며, 로컬 임베딩 통합 테스트로 호환을 확인했다.
    • brace-expansion 1.1.14 → 1.1.18 (DoS 2건: GHSA-3jxr-9vmj-r5cp, GHSA-mh99-v99m-4gvg).
    • @hono/node-server 1.19.14 → 2.0.12 (Windows 경로 순회: GHSA-frvp-7c67-39w9).
    • mongoose 9.6.2 → 9.9.1 (프로토타입 오염: GHSA-664h-wqgq-64gw).
    • tar 7.5.20 → 7.5.22 (스택 오버플로 DoS: GHSA-r292-9mhp-454m).
    • body-parser 2.2.2 → 2.3.0 (limit 무력화 DoS: GHSA-v422-hmwv-36x6).

Changed

  • @modelcontextprotocol/sdk ^1.27.1^1.30.0. 1.30.0이 @hono/node-server 2.x를 지원 범위에 포함한다.
  • docs/INSTALL.mdCONSOLIDATE_INTERVAL_MS 기본값 표기를 실제 값(21600000 = 6시간)으로 정정.

v5.4.0

Fixed

  • splitLongFragments가 생성한 자식 파편이 keywords를 빈 배열로 저장해 키워드 배열 교집합(keywords && $1)을 사용하는 검색 경로에서 조회되지 않던 문제 수정 (#32). 자식 본문에서 FragmentFactory.extractKeywords 결과를 추출해 저장한다. 기존 파편은 scripts/backfill-split-keywords.js로 소급 처리한다(dryRun 기본, --execute로 반영).
  • 분할된 원본 파편이 물리 삭제될 수 있던 문제 수정 (#33). deleteExpired의 utility 분기에는 valid_to 조건도 링크 보호도 없는데 분할은 원본을 valid_to 설정과 함께 importance 하향·cold 강등 처리하므로 anchor/permanent 보호가 적용되지 않았다. 자식이 남아 있는 원본을 삭제 후보에서 제외한다.
  • E2E group-key-isolation 스위트가 api_keys에 없는 key_id로 파편을 저장해 외래키 위반으로 실패하던 문제 수정. 시드 키를 선삽입하고 teardown에서 시드 파편을 물리 삭제해 재실행 가능성을 확보했다.
  • lib/memory/memory-schema.sqlcontent_hash 전역 UNIQUE 인덱스를 생성해, migration-031이 도입한 키별 partial unique index(uq_frag_hash_master, uq_frag_hash_per_key)와 상충하던 문제 수정. 스키마 파일을 재적용할 때 키별 유일성이 전역 유일성으로 되돌아갔다.

Added

  • 분할 앵커 커버리지 게이트. 분할은 원문을 자르지 않고 LLM이 다시 쓰므로 명제 하나가 통째로 누락될 수 있는데, 기존에는 자식 수가 minItems만 넘으면 원본을 대체했다. 자식 저장 직전에 원문의 수치 앵커(날짜·금액·비율·측정값)가 자식 합집합에 남아 있는지 대조하고, 빠진 것이 있으면 원본을 유지한 채 중단한다. 날짜 2026-07-152026/07/15로, 범위 75~8575/85로 분해 비교하므로 표기 변형은 통과한다.
  • memento_consolidate_split_skipped_totalanchor_loss reason 라벨 추가.
  • scripts/backfill-split-keywords.js.

Changed

  • Antigravity CLI provider(agy-cli) 추가. LLM_PRIMARY/LLM_FALLBACKS에서 선택 가능하며 --print --mode plan --sandbox로 실행되어 파일 수정과 도구 승인을 하지 않는다.

v5.3.1

Fixed

  • keywords-only recall에서 시맨틱 보조(L3kw) 결과가 정확 키워드 일치 파편을 랭킹에서 밀어내거나 tokenBudget 절단으로 소실시킬 수 있던 문제 수정 (#30). 정확 일치 파편에 절단 이전 랭킹 가산(ranking.exactKeywordBoost, 기본 0.35)을 적용하고, 절단을 슬롯 보장 방식(정확 일치 예산 50% 선점, 시맨틱 보조 25% 몫 보장, 잔여 경쟁)으로 확장했다. text/mixed 쿼리의 절단 동작은 변경 없다.
  • explanations의 semantic_similarity 사유가 L3kw 세그먼트 회수 파편에도 부여된다.

Changed

  • L3kw 보조 질의를 정규화(소문자·중복 제거·정렬, contextText 제외)해 임베딩 캐시 적중률을 높이고, 이 경로의 형태소 보조 검색을 생략한다. 실측 기준 L3kw 발동 지연 p50이 약 2.5초에서 0.5~1.1초로 감소.
  • L3kw 실행 상한 도입: MEMENTO_KEYWORD_FALLBACK_TIMEOUT_MS(기본 1500ms, 100~60000 클램프). 초과 시 보조 없이 즉시 반환하며 searchPath에 L3kw:timeout을 남긴다.

v5.3.0

Added

  • text 없는 keywords-only recall에 L3 시맨틱 보조 경로. keywords(+contextText) 합성 텍스트 임베딩이 L2와 병렬 수행되어 저장 keywords 배열에 없는 용어도 content 기반으로 회수된다. searchPath에 L3kw:N 세그먼트가 남으며 semanticSearch.keywordFallback(env MEMENTO_KEYWORD_SEMANTIC_FALLBACK=false)로 비활성화할 수 있다.
  • reflectworkspace 파라미터 노출. 생성되는 모든 reflect 파편에 적용되며, 미지정 시 API 키의 default_workspace → 전역(NULL) 순으로 폴백한다.

Fixed

  • 서버 재기동 후 Redis에서 복원된 세션이 이전 협상값(negotiatedVersion)을 그대로 되살려 이후 모든 요청이 400으로 거부되던 문제 수정. 협상값과 헤더가 달라도 지원 목록에 있는 값이면 헤더 값으로 재앵커링해 통과시키며(mcp_protocol_version_reanchored_total 카운터로 관측), 미지원 버전에 대한 400 거부는 유지된다. initialize 시 협상값을 Redis에 즉시 영속한다. (#26)

Changed

  • batch_remember의 fragments가 JSON 인코딩 문자열로 전달된 경우 원인을 명시하는 별도 오류 메시지를 반환한다.
  • JSON body 파싱 실패(-32700) 응답 message에 파서 위치 정보를 보존한다. 대량 배열 요청에서 손상 지점을 특정할 수 있다.
  • search_events의 l3_count가 keywords 폴백 보조 세그먼트(L3kw:N)도 집계한다.

v5.2.3

Changed

  • semanticSearch.minSimilarity 기본값 0.5→0.4. 12쿼리 골드셋 실측에서 상위5 유용 결과 수가 최대인 지점으로, 어휘 중첩이 낮은 회상형 질의의 무응답을 줄인다(0.35는 노이즈 유입이 이득을 상쇄해 기각). SearchParamAdaptor 기존 학습 행도 0.4 상한으로 동기화됐다.

v5.2.2

Fixed

  • text/mixed recall의 RRF importance 컷오프가 기준값 미지정 시 모든 후보를 탈락시키던 문제 수정. 기준 미지정 시 no-op으로 동작하며, rrfSearch.candidateMinImportance(기본 0.1)를 정책값으로 명시한다.
  • extractKeywords가 한글 토큰의 조사 접미를 제거하고, 카멜/스네이크 케이스 코드 식별자를 소문자화 없이 원형 보존한다.

Added

  • morpheme_indexed 백필 잡: 5분 주기로 미인덱싱 파편을 배치(기본 500) 처리해 형태소 L3 커버리지를 회복한다. embedding-consistency 경고에 백필 잡 상태가 병기된다.
  • 마이그레이션 스크립트 3종(dryRun 기본): reflect 파편 keywords 재추출(scripts/reextract-reflect-keywords.js), reflect permanent TTL 강등, SearchParamAdaptor min_similarity 리셋.
  • recall 품질 검증 지표 SQL과 스모크 절차 문서(docs/operations/recall-quality-verification.md, scripts/recall-quality-metrics.sql).

Changed

  • reflect decision 파편 importance 0.8→0.7, reflectionPolicy.maxImportance 0.3→0.55 — reflect 파편의 permanent 승격을 차단하고 정리 주기가 실제로 동작하게 한다.

v5.2.1

Fixed

  • recallfields sparse 목록이 응답에 적용되지 않던 문제 수정. 필드 선택이 응답 프로젝션에서 최종 적용되며, 파생 키(confidence, age_days)와 keywords(이 경우 includeKeywords 없이도 포함)·valid_to·affect·ema_activation도 요청 시 반환된다.
  • key_idincludeKeyName 미지정 시에도 recall 응답에 포함되던 문제 수정. key_id·key_name 모두 includeKeyName=true일 때만 포함된다.

v5.2.0

Added

  • recall·contextincludeKeyName 파라미터: true 시 각 파편에 key_id·key_name(액세스 키 라벨)을 포함한다. 같은 키 그룹 스코프의 정보만 노출되며 기본 false. recallfields sparse 목록에도 key_id/key_name을 지정할 수 있다.
  • 임베딩 API 호출에 per-call 절대 타임아웃(EMBEDDING_TIMEOUT_MS, 기본 8000ms)과 프로세스 전역 동시성 세마포어(EMBEDDING_CONCURRENCY/EMBEDDING_SEM_WAIT_MS)를 적용해 임베딩 서비스 지연이 전체 요청 큐로 전파되는 것을 차단. 세마포어 대기 초과는 mcp_embedding_semaphore_wait_exceeded_total로 관측 가능.
  • initialize(무세션) 요청에 인증·DB 조회 이전 IP rate limit 선차단 추가. 차단 시 429 응답과 함께 mcp_initialize_ip_rate_limited_total 카운터가 증가한다.
  • batch_remember에 배열 전체 content 총 문자수 게이트(BATCH_REMEMBER_MAX_TOTAL_CHARS, 기본 200,000자) 추가. 항목별 4000자 상한과 별개로 요청 전체를 사전에 거부한다.
  • QuotaChecker.check()에 캐시 우선 판정 경로 추가: 잔여 할당량이 QUOTA_NEAR_LIMIT_MARGIN(기본 10)보다 크면 FOR UPDATE 트랜잭션 없이 통과하며, 이 경로는 mcp_quota_cache_pass_total로 관측된다. 한도 임박 시에만 기존 정밀 검사로 전환된다.
  • EmbeddingWorker가 remember() 동기 경로에서 이미 생성된 임베딩 벡터를 캐시로 재사용하여 동일 파편에 대한 중복 임베딩 API 호출을 제거.
  • 관리자 REST에 키 스코프 파편 조회·검색·통계·내보내기 엔드포인트 추가(key_id/group_id 스코프 적용).

Changed

  • 외부 reranker 3연속 실패 시 기본 정책을 in-process 전환에서 쿨다운 스킵으로 변경(RERANKER_EXTERNAL_FALLBACK=skip, 기본값). 쿨다운(RERANKER_EXTERNAL_COOLDOWN_MS, 기본 60초) 동안 external 호출을 생략하고 원점수(RRF 순서)를 유지하며, 만료 후 1건 재시도한다. RERANKER_EXTERNAL_FALLBACK=inprocess로 이전 동작(ONNX in-process 전환) 유지 가능.
  • 관리 콘솔 메모리 뷰: 1024px 미만 화면에서 Fragment Detail이 하단 고정 시트로 표시된다. 닫기 버튼과 ESC로 닫을 수 있으며 데스크톱 레이아웃은 동일하다.
  • admin API의 CORS 허용 origin을 화이트리스트 반사 방식으로 처리하고 인증 실패를 로깅한다(ADMIN_ALLOWED_ORIGINS).

Fixed

  • 외부 reranker의 TEI(text-embeddings-inference) 호환: 요청에 texts 필드를 documents와 함께 전송하고, [{ index, score }] 배열 응답을 매핑하며, 빈 바디 /health를 허용한다 (#22, @itismyfield 기여).
  • 외부 rerank 배열 응답 처리: 빈 배열은 실패로 간주해 폴백 경로를 타고, index 범위와 score 타입이 유효한 항목만 반영한다.

v5.0.1

[5.0.1] - 2026-07-15

Added

  • 프로세스 전역 에러 가드(lib/process-guards.js): unhandledRejection은 로깅 후 프로세스를 유지하고, uncaughtException은 로깅 후 graceful shutdown을 exit code 1로 수행한다(onFatal 1회 보장, 35초 강제 종료 타이머). SIGTERM/SIGINT 경로는 기존과 동일하게 exit 0으로 종료한다.

Changed

  • 전이 의존성 lockfile 갱신 (hono 4.12.30, protobufjs 7.6.5, tar 7.5.20).

v5.0.0

Changed

  • 프로젝트명을 AnchorMind로 변경 (패키지명 anchormind-mcp). memento-mcp라는 이름이 다수의 동명·유사 프로젝트와 겹쳐 개명했으며, 도구명·환경 변수(MEMENTO_*)·DB 스키마·API 경로·키 형식(mmcp_) 등 런타임 계약은 모두 그대로다 (Breaking 없음).
  • CLI bin에 anchormind 명령 추가. 기존 memento-mcp 명령은 별칭으로 유지.
  • MCP initialize 응답의 serverInfo.name을 anchormind-server로 변경 (표시 메타데이터).
  • admin 콘솔·로그인 화면 브랜딩과 README 로고를 AnchorMind로 교체.
  • README·SKILL.md·docs 전반의 표기를 현행 코드 기준으로 정비.

v4.8.0

Added

  • content 입력 길이 상한 4000자 도입: remember·batch_remember 항목·amendcontent가 이를 초과하면 JSON-RPC -32602 에러로 거부한다. 파편 유형별 저장 절삭(episode 1000자, 그 외 300자)은 그 이전 단계로 그대로 유지되며, batch_remember는 초과 항목만 실패 처리하고 나머지 배치는 계속 진행한다.

Changed

  • 패턴 기반 캐시 무효화(invalidateCacheByPattern)를 KEYS 대신 Redis SCAN 커서 순회(COUNT 500, 순회 상한)로 전환.
  • 로컬 임베딩(transformers provider) 초기화를 모델별 싱글톤으로 단일화해 동시 중복 로딩을 방지하고, 추론을 FIFO 큐로 직렬화. 배치 임베딩(embedBatch)은 청크 단위 텍스트 배열을 파이프라인에 1회 추론으로 전달한다.
  • 마이그레이션 SQL 파일을 lib/memory/migrations/ 디렉토리로 이동. npm run migrate 동작은 변경 없음.
  • lib/memory/ 하위를 read/·write/·consolidate/·link/·signals/·processors/·embedding/ 서브디렉토리 체계로 재배치.

v4.7.0

[4.7.0] - 2026-06-20

Added

  • batch_remember 비동기 신뢰성 처리: 백그라운드 워커가 ack·재시도(최대 3회)·dead-letter·기동 복구(RPOPLPUSH reliable queue)로 at-least-once 배치 처리를 보장한다.
  • batch_status(jobId) 도구 추가: batch_remember(async: true) 결과 jobId로 처리 상태(queued/processing/completed/dead)를 조회하는 읽기 전용 도구.
  • Deferred tool discovery 클라이언트 가이드: Codex Desktop 등 lazy 로딩 클라이언트를 위한 instructions 초기화 지침·SKILL.md 섹션·README 가이드를 일관되게 정비.
  • 코어 도구에 MCP title + annotations(readOnlyHint/idempotentHint/openWorldHint) 메타데이터 추가. tools/list 응답에서 recallremember 바로 다음에 노출된다.

Changed

  • batch_remember·memory_consolidate가 표준 단일 JSON-RPC 응답으로 반환된다. stream 파라미터는 deprecated(하위 호환 유지, 동작 없음).
  • 총 도구 수 17 → 20(batch_status, session_rotate, check_update/apply_update 반영).

v4.6.0

[4.6.0] - 2026-06-16

Added

  • 벡터 검색 HNSW 인덱스 강제 옵션·토글: ORDER BY embedding <=> v LIMIT 트랜잭션에 enable_seqscan=off·enable_bitmapscan=off·hnsw.iterative_scan 힌트를 적용해 HNSW 인덱스 경로를 강제.
  • batch_remember 비동기(파이어앤포겟) 모드 opt-in: async: true 지정 시 선검증 후 Redis 큐 적재, {async, accepted, rejected, jobId} 즉시 반환. BatchRememberWorker가 본처리. 기본 async: false로 기존 동기 동작 불변. Redis 비활성 환경에서는 동기 폴백.
  • 배치 작업 전용 연결 풀(getBatchPool, application_name='memento-mcp:batch') 및 배치 풀 통계 메트릭 수집.

Changed

  • HNSW 인덱스 정의의 ef_construction 정합화, L3 형태소 보강 검색 병렬 실행, RRF 병합 후보에 importance 하한 컷오프 적용.
  • reflect 항목 자기완결성 게이트 및 한글 하한 강화.
  • 키 스코프 조회를 keyScopeClause 공용 헬퍼로 통일: getById·findCaseIdBySessionTopic·findErrorFragmentsBySessionTopic·GraphLinker 공유. GraphLinker 키 필터를 파라미터 바인딩·text 타입 정합으로 정리.
  • 피드백 importance 보정 계수를 feedbackFactor 순수 함수로 단일화(라이브 계수 0.85/1.1/0.95 유지).
  • tools/call 메트릭 중복 집계 제거.
  • 내부 중복 정리: 요청 컨텍스트 추출·키워드 정규화·도구 감사 래퍼·검색 SELECT 상수·affect 조건·Bearer 추출·환경변수 리스트 파싱·공통 파라미터 스키마 각각 단일 위치로 통합.
  • 대형 메서드 분해: remember·handleMcpPost·buildAdminPaths·dispatchJsonRpc·ContextBuilder.build·검색 RRF·컨솔리데이션/분해/압축.

Fixed

  • getUnreflectedSessions의 Redis SCAN 순회에 상한(최대 20라운드)을 두어 대용량 keyspace에서 context 응답이 지연되던 문제 해결.

v4.5.0

파편 분해 단계(splitLongFragments)에 two-phase gate-then-commit, 분할 자식 품질 게이트(최소 길이·CJK 혼입·대명사 reject), 분할 전용 provider 체인(MEMENTO_SPLIT_LLM_*), 분할 실패 backoff(split_attempt_failed_at, migration-036), FragmentGC split 자식 정리(branch-2)를 추가. 전체 변경은 CHANGELOG [4.5.0] 참조.

v4.4.0

보조 조회 도구(graph_explore·search_traces·reconstruct_history)가 그룹 공유 키 범위의 파편을 조회하도록 키 격리 절을 keyScopeClause 공용 헬퍼로 통합. FragmentReader.getByIds에 groupKeyIds 인자 추가. recall stale 판정에 verified_at 부재 시 created_at 폴백 적용.

전체 변경: CHANGELOG [4.4.0] 참조.

v4.3.0

형태소 토크나이저 로컬 전환

  • L3 형태소 토크나이저를 LLM 서브프로세스에서 로컬 CPU 분석기로 전환: 한글 garu-ko, 영어 PorterStemmer, 중국어 @node-rs/jieba, 일본어 kuromoji
  • 환경변수 MEMENTO_MORPHEME_TOKENIZER(local|llm), MEMENTO_ENABLE_KUROMOJI(true|false)
  • 서버 기동 시 한글·영어 분석기 프리로드
  • Docker 베이스 이미지 node:24-alpine

reflect 최적화

  • episode 저장 경로 충돌 감지 생략 옵션(skipConflictDetection)으로 저장 지연 단축

테스트

  • jest 제거 및 node:test 단일화

v4.2.0

v4.2.0 — 자동 후처리 게이트 정리

변경 요약

ProactiveRecall · autoLinkSessionFragments · MemoryConsolidator 세 층위의 자동 후처리에 schema-fit gate를 결합하고, tool_reflect 응답에 _meta 블록을 신설했다.

Added

  • config/memory.js proactiveRecall 블록: mode (off/auto/legacy), keywordOverlapMin, requireSameWorkspace, caseIdPolicy (both-required/strict-or-adjacent/loose), adjacencyWindowMs, requireSameTopicOrType.
  • config/memory.js consolidate.schemaFit: pendingCaseFragmentsMin 5, recentRelatedLinksMin 20, fragmentsSinceLastRunMin 30, mode (all/any/off).
  • config/memory.js consolidate.enableRiskyStages: splitLongFragments, detectContradictions, compressOldFragments 플래그.
  • lib/symbolic/rules/v1/proactive-gate.js workspace_mismatch·case_policy 차단 사유.
  • lib/scheduler.js evaluateSchemaFitGate 함수 (DB COUNT 3종 기반).
  • 신규 unit 테스트 4종 (36개 시나리오).

Changed

  • lib/memory/SessionLinker.js autoLinkSessionFragments: 카르테시안 곱집합 → 1:1 top-1 schema-fit 매칭. 게이트 미통과 후보는 linkSuggestions[] 반환.
  • lib/memory/RememberPostProcessor.js _proactiveRecall: proactiveRecall.mode 분기 wrap.
  • lib/memory/consolidate/MemoryConsolidator.js: LLM 재작성 stage 3종에 enableRiskyStages 분기.
  • lib/tools/memory.js tool_reflect 응답: _meta 블록 신설 (searchEventId, hints, suggestion, link_suggestions, serverTime).
  • lib/scheduler.js: CONSOLIDATE_INTERVAL_MS 처리를 MEMORY_CONFIG.consolidateIntervalMs 단일 진입점으로 교체.
  • config/memory.js consolidateIntervalMs 기본값 1h → 6h (scheduler 실제 동작값 일치).

호환성: 기존 DB 스키마·외부 API 호환, _meta.link_suggestions[] 추가 필드만 신규 노출.

v4.1.0

recall 최종 정렬에서 cross-encoder reranker 결과를 보존하고, topic/keyword 직접 일치 신호를 제한된 가산항으로 반영. recall/context 응답 _meta에 서버 현재 시각을 일관되게 노출하여 LLM 클라이언트의 학습 시점 시간 고착을 방지. 기존 API·DB 스키마 호환, 응답에 _meta.serverTime 필드만 신규 노출.

Highlights

  • recall 정렬 신호 복원: MemoryRecaller.recall의 통합 정렬을 computeRecallScore 단일 함수로 교체. rerankerScore 보유 시 그것을 base로 보존, 미보유 시 복합 점수에 unrerankedBaseDiscount(0.85) 적용. lexical 일치는 log 정규화 후 파편별 제한 가중치(reranked 0.12 / fallback 0.18, 연결 파편 절반 감쇠)로 가산.
  • _meta.serverTime 신규 필드: recall/context 응답에 { iso, epoch_ms, display_kst, timezone } 4필드 일관 노출. LLM이 매 응답마다 서버 현재 시각 재확인 가능.
  • ranking 설정 키 5종: lexicalWeightReranked, lexicalWeightFallback, lexicalLinkedMultiplier, lexicalSaturation, unrerankedBaseDiscount (config/memory.js).

Design notes

검토 단계에서 lexical 일치를 if (lexical > 0) return 1000 + lexical 형태의 hard override로 부여하는 패치가 제안됐으나, 다중 LLM 토론(Oracle Pro / Claude / Gemini)을 거쳐 다음 5개 결함으로 기각: (a) reranker 결과 폐기 (b) reranker와 lexical의 이중 계산 (c) 직접/연결 파편 미구분 (d) threshold 필터 우회 (e) cursor 페이지네이션 불안정. 채택된 가산항 방식은 rerankerScore 격차를 lexical 보정이 무조건 뒤집지 않도록 lexWeight 상한을 둠.

Compatibility

기존 클라이언트 코드 수정 불필요. _meta에 필드만 추가, 기존 필드(searchEventId, hints, suggestion) 구조·이름 그대로.

자세한 변경 목록은 CHANGELOG.md v4.1.0 섹션.

v4.0.1

v4.0.1은 recall 정확도 보정 patch 릴리즈다. 외부 API·DB 스키마 호환. 외부 호출자 응답 구조 무변경.

Changed

  • lib/memory/read/FragmentSearch.js _executeSearch:
    • Cross-encoder Reranker 호출 시 topic: <topic> keywords: <keywords> text: <text> 형식의 query를 전달하여 정확 매칭 신호가 재정렬 단계까지 보존된다.
    • l1MissIdsl1IsFallback에 따라 빈 배열로 강제. fallback fragment가 _searchL2.getByIds로 추가 조회되어 결과에 섞이는 경로를 차단.
    • RRF의 L1 layer 가중치를 l1IsFallback ? 0.5 : MEMORY_CONFIG.rrfSearch.l1WeightFactor로 분기. fallback 경로의 L1 결과 가중을 강등.
  • config/memory.js semanticSearch.minSimilarity 0.35 → 0.5.
  • lib/memory/embedding/EmbeddingCache._key 캐시 키에 EMBEDDING_MODEL prefix 결합. 모델 변경 시 stale 벡터 hit 방지.
  • lib/memory/assistant-query.js boostAssistantFragments 기본 boost 0.05 → 0.02.

Added

  • MEMENTO_RECALL_MIN_SIM_FLOOR 환경변수. SearchParamAdaptor.getMinSimilarity가 반환하는 적응형 임계값에 옵트인 하한을 강제한다. 미설정 시 기존 동작 그대로.

Tests

  • tests/unit/fragment-search-fallback-guard.test.js 신설. 정적 가드 3건 + 동적 가드 2건.
  • 영향권 단위 테스트 114건 회귀 0.

Docs

  • CHANGELOG.md, SKILL.md, docs/configuration.md/.en.md, docs/features.md 정합.

호환성

  • 외부 호출자 search/recall/remember 응답 구조 무변경.
  • _searchEventId 동기 반환 계약 유지.
  • DB 스키마 무변경. 마이그레이션 불필요.
  • 운영 반영 시 systemd 재시작만 필요.

후속

  • v4.1: SqliteVecStore 본격 구현, 저장 임베딩 텍스트에 keywords·topic prefix 결합(시그니처 확장 + 마이그레이션), expandAssistantQuery 활성 조건 좁히기 + 원본·확장 쿼리 Reranker 점수 앙상블, Reranker recencyBoost / _applyMMR lambda 검토.

상세: https://github.com/JinHo-von-Choi/memento-mcp/blob/main/CHANGELOG.md

v4.0.0

v4.0.0은 v3.2.0 이후의 모든 patch·minor 변경을 단일 메이저 릴리즈로 통합한다. 외부 호출자 인터페이스와 DB 스키마는 호환된다. major 표시는 storage 어댑터 계층 도입과 lib/memory 6서브디렉토리 재편 등 내부 surface가 새로 추가됐기 때문이다.

---

Added

  • lib/storage/ 어댑터 계층. getStorage() 팩토리가 MEMENTO_STORAGE 환경변수에 따라 PgVectorStore(기본) 또는 SqliteVecStore(v4.1 본격 구현 예정 stub)를 반환한다. 인터페이스: query / queryAsAgent / transaction / migrate / close + engine / vectorSupport 프로퍼티.
  • lib/memory/read/SearchScope.js. workspace·caseId·resolutionStatus·phase·affect·keyId를 캡슐화한 값객체. L1/HotCache/L2/L3/Graph 검색 레이어가 처음부터 정합 필터링한다.
  • lib/memory/read/SearchSideEffects.js. commitSearchSideEffects(query, sq, cleanResult, ctx) → searchEventId 함수로 검색 이벤트 영속화·SearchParamAdaptor 학습을 격리.
  • lib/llm/index.jsdispatchChain(chain, prompt, options, deps) export. llmJson은 chain 빌드·redact만 담당하고 dispatcher에 위임.
  • scripts/lint-migrations.js + npm run lint:migrations. 신규 마이그레이션 파일의 body-only 규약과 파일명 형식을 PR 시점에 강제.
  • 신규 환경변수: MEMENTO_REMEMBER_ATOMIC, MEMENTO_CASE_BACKPROP_ENABLED, MEMENTO_STORAGE, MIGRATION_LINT_FROM.
  • 신규 문서: docs/concurrency.md, docs/features.md, docs/migration-conventions.md, docs/operations/agent-worktree.md, docs/operations/upstream-porting.md.

Changed

  • MemoryRememberer.remember의 PolicyRules 게이트 평가를 _runPolicyGate 헬퍼로 통일. dryRun·atomic·non-atomic 분기 모두 동일 시점에 평가하며 hard gate(api_keys.symbolic_hard_gate=true) 위반 시 SymbolicPolicyViolationError를 throw해 트랜잭션 시작을 차단한다. apiKeyStore 조회 실패는 fail-open.
  • MemoryRememberer._finalizeRemember 응답에 validation_warnings 노출. atomic·non-atomic 응답 형식이 정합화됐다.
  • MemoryConsolidator._mergeDuplicates 그룹 키를 (key_id, workspace, content_hash)로 한정. WHERE key_id IS NOT NULL로 master 키 자동 병합 제외. linked_to UPDATE와 store.delete에 key_id 전달. 그룹 동질성 어설션 추가.
  • MemoryConsolidator._runConsolidationCycle을 선언형 stageDefs 배열로 재구성. 21개 stage. TOTAL_STAGES = stageDefs.length. SSE/관리 콘솔 진행률 정합.
  • lib/memory/ 14개 핵심 모듈을 6 서브디렉토리(read/, write/, link/, consolidate/, embedding/, signals/)로 분류 이동. 기존 위치(lib/memory/<File>.js)에 stub re-export 14개 유지로 외부 import 경로 호환. 신규 코드는 직접 서브디렉토리 경로 권장.
  • FragmentSearch의 부작용 처리를 SearchSideEffects 모듈로 외부화. 메서드 추출(v3.8.0) → 모듈 외부화(v3.9.0) 두 단계. _searchEventId 동기 반환 계약 유지.
  • FragmentSearch._executeSearch의 후처리 보정 4블록(workspace/caseId/resolutionStatus/phase/affect) 제거. SearchScope contract 적용으로 검색 레이어가 처음부터 정합 결과를 반환한다.
  • CaseRewardBackprop.backprop이 매 호출 시 process.env.MEMENTO_CASE_BACKPROP_ENABLED를 평가. 기본 off, 호출이 즉시 반환되어 DB·메트릭 영향 0. 런타임 토글 가능.
  • lib/llm/util/parse-json.js에 reasoning 모델(MiniMax-M2.7, DeepSeek-R1, Qwen-QwQ 등) 응답의 <think>...</think> 사전 제거 도입. 닫힘 태그만 남은 비대칭 응답도 처리.
  • package.json test:cinpm test && npm run test:integration으로 변경. 통합·e2e 테스트가 CI 단일 게이트에 포함된다.
  • scripts/migrate.js의 인라인 BEGIN/COMMIT·schema_migrations INSERT 제거 정규식을 삭제하고, 기존 14개 마이그레이션 파일을 body-only 규약으로 일괄 normalize. opclass placeholder 치환은 유지.
  • docs/features.md 실험 플래그 표 정합화. 실험 플래그(SpreadingActivation, CaseRewardBackprop)와 dual-mode/항상 활성(NLIClassifier, AutoReflect, ReconsolidationEngine, storage 어댑터)을 분리.

Tests

  • 신규 회귀 가드 케이스 누적 다수. 핵심:
    • tests/unit/atomic-remember-policy-gate.test.js — atomic+hard gate+dryRun 5 케이스
    • tests/unit/consolidator-merge-tenant-scope.test.js_mergeDuplicates SQL/scope 6 케이스
    • tests/unit/consolidator-stage-declarative.test.js — stageDefs 산출 + progress 정합 4 케이스
    • tests/unit/llm-dispatcher-concurrency.test.js 재작성 — dispatchChain을 실제 검증(인라인 mirror 제거)
    • tests/unit/llm-dispatcher-no-inline-mirror.test.js — 인라인 mirror 재발 방지 정적 가드
    • tests/unit/fragment-search-side-effect-split.test.js — SearchSideEffects 외부화 정적 가드
    • tests/unit/search-scope-contract.test.js — SearchScope contract + 후처리 보정 잔존 0
    • tests/unit/storage-adapter.test.js — 어댑터 인터페이스/팩토리/not-implemented throw
    • tests/unit/case-reward-backprop.test.js — ENV 활성·미설정·false 명시 3축 (7 케이스)
  • 누적 단위 테스트 영향권 회귀 0.

Docs

  • v4.0 기준 단일 sweep으로 17개 문서 정합화. 본문 갱신 대상: README.md, SKILL.md, CONTRIBUTING.md, docs/architecture.md/.en.md, docs/internals.md/.en.md, docs/concurrency.md, docs/features.md, docs/api-reference.md/.en.md, docs/configuration.md/.en.md, docs/INSTALL.md/.en.md, docs/testing.md, docs/admin-console-guide.md.

호환성·이식 안내

  • 외부 호출자 인터페이스(search 응답, _searchEventId, remember 응답, recall 응답) 무변경.
  • DB 스키마 무변경.
  • 기존 import { X } from "lib/memory/<File>.js"는 stub re-export로 동일하게 동작. 신규 코드는 lib/memory/<sub>/<File>.js 직접 경로 권장.
  • lib/storage/ 어댑터 도입. 기존 데이터 액세스 코드는 그대로 동작. 호출 사이트의 어댑터 마이그레이션은 v4.1에서 점진 수행.

v4.x 후속

  • v4.1: SqliteVecStore 본격 구현 (sqlite-vec npm 의존, SQLite 마이그레이션 변환, lite 모드 e2e). 기존 lib/memory/* 호출 사이트의 getStorage() 어댑터 마이그레이션.
  • v4.x: lib/memory/ stub re-export 14개의 점진 제거(외부 호출 사이트가 서브디렉토리 경로로 직접 import 전환 후).

---

상세 커밋 히스토리: 8c4fb81(v4.0.0), 25eb61f, b9f312d, 345d511, 79d741c, 7d49215, ea1e1b3, 1e9ac29, b8275c5, aadee7a, cc6b191 (origin/main).

v3.2.0

[3.2.0] - 2026-04-29

기존 API·DB 스키마 호환. Breaking change 없음.

Added

  • BatchRememberProcessor: multi-row INSERT (24컬럼 × N행 placeholder, RETURNING id, ON CONFLICT 유지, 누적 256KB 또는 500행 chunk).
  • ReflectProcessor: 5카테고리(summary / decisions / errors_resolved / new_procedures / open_questions)를 BatchRememberProcessor.process에 단일 위임. 사전 validate 강화.
  • EmbeddingWorker._embedMany: generateBatchEmbeddings 1회 + multi-row UPDATE 1회. row 단위 dead-letter, 단건 fallback.
  • MorphemeIndex.getOrRegisterEmbeddings: batch 등록 (generateBatchEmbeddings 1회 + multi-row INSERT).
  • RememberPostProcessor: morpheme 등록을 fire-and-forget으로 분리.
  • fragments.morpheme_indexed BOOLEAN 컬럼 (migration-035, default NULL). 인덱스 미완료 파편을 L3 형태소 검색에서 자동 제외.
  • drainMorpheme graceful shutdown 훅.
  • SessionLinker.autoLinkSessionFragments: sortedKey 사전식 정렬 + wouldCreateCycle 캐시.
  • LinkStore.createLinks: advisory lock + multi-row INSERT 단일 트랜잭션. 단건 fallback 유지.
  • FragmentStore.createLinks: N개 링크 생성 통합.
  • db.js getBatchPool(): max = primaryMax × 0.3, application_name = 'memento-mcp:batch'.
  • BATCH_DATABASE_URL 환경변수: 배치 전용 DB 엔드포인트 분리 옵션.
  • GEMINI_TIMEOUT_MS 환경변수: AutoReflect LLM timeout 오버라이드 (기본 30s).
  • batchPool Prometheus Gauge 3개: memento_batchpool_active, memento_batchpool_idle, memento_batchpool_waiting.

Migration

1. npm run migrate — migration-035 자동 적용 (ADD COLUMN, hot deploy 안전). 2. npm install — dependency 변화 없음. 3. 선택: BATCH_DATABASE_URL, GEMINI_TIMEOUT_MS 환경변수. 4. 서비스 재시작.

v3.0.0

v3.0.0 - Umbrella release (v2.8.1 ~ v2.16.0 consolidated)

v2.8.0 태그 이후 누적된 un-tagged 빌드 11종(v2.8.1 ~ v2.16.0)을 umbrella 릴리즈로 통합한다. 개별 minor/patch 라벨은 CHANGELOG 하단 "Pre-3.0.0 incremental builds" 섹션에 상세 보존된다.

Highlights

  • Admin Metrics Dashboard (v2.16.0): Prometheus 8 카드(Active Sessions / Auth Denied / RBAC Denied / Tenant Blocked / RPC p50/p99 / Tool Errors / Symbolic Gate Blocked / OAuth Tokens) + 도구별 호출/에러 분포 테이블 + SVG sparkline 시계열. /v1/internal/model/nothing/metrics-summary 엔드포인트(master/admin 전용, TTL 10초 캐시, ?windowSec=N)
  • CLI/API Enhancement L+M+H (v2.11.0 ~ v2.12.0): 원격 CLI(lib/cli/_mcpClient.js, --remote URL / --key KEY), _meta 래퍼(searchEventId / hints / suggestion), sparse fields 17종 화이트리스트, --help/--format table|json|csv, idempotencyKey(maxLength 128, partial UNIQUE), X-RateLimit 헤더, dryRun 파라미터(remember/link/forget/amend), stdin / progress streaming / export·import, CLI session 관리 및 rotate / rate-limit / CSRF
  • MemoryManager 분해 (v2.10.0): 1252줄 → 259줄 facade. 비즈니스 로직을 lib/memory/processors/ 4개 클래스로 분리(MemoryRememberer / MemoryRecaller / MemoryReflector / MemoryLinker). facade ↔ 프로세서 간 _installSharedSync setter 동기화 패턴
  • Mode preset / Affective tagging / Local Embedding (v2.9.0): recall-only / write-only / onboarding / audit 4개 JSON preset(X-Memento-Mode 헤더 / initialize.params.mode / api_keys.default_mode). fragments.affect 컬럼(6 enum: neutral / frustration / confidence / surprise / doubt / satisfaction). @huggingface/transformers 로컬 임베딩 provider(EMBEDDING_PROVIDER=transformers, Xenova/multilingual-e5-small / bge-m3). Codex CLI / GitHub Copilot CLI LLM provider 추가. RecallSuggestionEngine 비침습적 힌트 필드. 토큰 기반 세션 재사용(sha256 + keyId 네임스페이스)
  • Session 안정화 + OAuth 호환성 (v2.8.1 ~ v2.8.7): claude.ai / ChatGPT / Copilot / Gemini OAuth DCR-less 커넥터 완전 호환. name-based DCR client_id(<name>_<keyIdHex8>) + client_name="apikey:<keyId>" 내부 바인딩, client_secret API 키 바인딩, bound_key_id 경로. 세션 ID 보존 복구 + keyId 교차 검증(403). RFC 8707 resource 파라미터. token_endpoint_auth_methods_supported 확장. MCP 2025-06-18 Protocol-Version 헤더 검증. MCP_REJECT_NONAPIKEY_OAUTH / MCP_ALLOW_AUTO_DCR_REGISTER / MCP_STRICT_ORIGIN 보안 기본값. FragmentReader keyId ANY() 래핑 일괄 수정(v2.8.7)
  • Symbolic Memory Layer hard gate (v2.8.0): 이미 v2.8.0에서 도입(본 릴리즈는 hard gate 이후 후속 수정 및 문서 동기화 포함). fragment_claims + api_keys.symbolic_hard_gate BOOLEAN. 6 Phase(Foundation / Shadow / Explain / Link Integrity / Policy / CBR+Proactive) 전개. 기본값 전면 opt-out
  • Scripts rename (un-tagged 2026-04-19): scripts/migration-007-flexible-embedding-dims.jsscripts/post-migrate-flexible-embedding-dims.js. 자동 마이그레이션 러너와 수동 dimension 재구성 스크립트 구분. 심볼릭 링크로 하위 호환
  • Test cleanup hang 근본 해결 (v2.16.1 scope): node:test runner "Promise resolution pending" 14초 잔여 제거. SSE heartbeat .unref(), cleanup 훅, lifecycle 회귀 가드

Breaking Changes

코드 레벨 breaking 없음. 모든 신규 기능 opt-in. 기존 환경 변수·API 응답·DB 스키마 완전 호환.

Deprecation 예고(v3.1.0에서 제거): recall / context 응답의 top-level _searchEventId / _memento_hint / _suggestion 필드. v3.0.0은 _meta.searchEventId / _meta.hints / _meta.suggestion과 top-level mirror를 동시 제공. 호출부는 _meta.*로 전환 권고.

Migration Guide (v2.8.0 → v3.0.0)

1. npm install@huggingface/transformers 신규 의존성(로컬 임베딩 사용 시에만 실제 로드). 기존 lock 갱신 2. npm run migrate — migration-034(api_keys.default_mode ADD COLUMN) + migration-034-v2.16.0-bundle(fragments.affect / idempotency_key ADD COLUMN + partial unique 인덱스) 자동 적용. 모두 ADD COLUMN이므로 기존 행 변경 없음 3. 환경 변수 확인 — 기본값 유지 시 추가 작업 없음. 선택적 기능 활성화:

  • EMBEDDING_PROVIDER=transformers (로컬 임베딩)
    • LLM_PRIMARY / LLM_FALLBACKS (LLM 폴백 체인)
    • MEMENTO_SYMBOLIC_* (Symbolic 계층 단계적 활성화 — v2.8.0 Migration Guide 참조)
    • MCP_REJECT_NONAPIKEY_OAUTH=false (claude.ai 외 DCR-less 클라이언트에 대한 하위 호환 복원이 필요한 경우만)

4. EMBEDDING_PROVIDER 변경 시에만 npm run backfill:embeddings 수동 실행. 차원 불일치 시 서버 기동 단계에서 scripts/check-embedding-consistency.js가 즉시 중단 5. 기존 스크립트 경로 scripts/migration-007-flexible-embedding-dims.js 참조 시 scripts/post-migrate-flexible-embedding-dims.js로 전환 권고(심볼릭 링크는 v2.13.0 네임스페이스 하위 호환 유지)

Known Limitations

  • v2.8.0 이후 v2.9.0 ~ v2.16.0의 중간 빌드는 git tag가 존재하지 않는다. v3.0.0이 유일한 공식 릴리즈 태그이며, 하위 빌드 히스토리는 본 CHANGELOG로만 추적된다
  • MEMENTO_ACCESS_KEY 미설정 상태에서 MEMENTO_AUTH_DISABLED=true 없이 서버를 기동하면 fail-closed로 거부된다(v2.7.0 정책 유지)

---

Pre-3.0.0 incremental builds (un-tagged)

아래는 v2.8.0 태그 이후 누적된 11개 빌드의 원본 상세 이력이다. 모두 v3.0.0 릴리즈에 포함되며, 개별 git tag는 존재하지 않는다.

v2.16.0 draft — Admin Metrics Dashboard (2026-04-20)

Added

  • Admin Console: 메트릭 메뉴 추가 — Prometheus 8 카드(Active Sessions / Auth Denied / RBAC Denied / Tenant Blocked / RPC p50/p99 / Tool Errors / Symbolic Gate Blocked / OAuth Tokens) + 도구별 호출 통계 테이블 + 에러 타입별 분포 테이블. Admin UI 좌측 사이드바 메뉴 7개 → 8개.
  • /v1/internal/model/nothing/metrics-summary 엔드포인트 (master/admin 전용): prom-client Registry에서 직접 산출, 응답 캐시 TTL 10초, ?windowSec=N 파라미터 지원.

---

v2.12.0 — CLI/API Enhancement Phase 2 (2026-04-20)

Added

  • M1 원격 CLI: lib/cli/_mcpClient.js 신설. --remote URL / --key KEY 전역 플래그 및 MEMENTO_CLI_REMOTE / MEMENTO_CLI_KEY 환경변수 fallback. initialize → tools/call 2단계 세션을 생성하고 재사용한다. local-only 명령(migrate, admin 등)을 원격 모드에서 호출하면 에러를 반환한다.
  • M3 X-RateLimit HTTP 헤더: 모든 API 응답에 X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Resource 헤더 포함. QuotaChecker.getUsage + 모듈 레벨 Map 캐시(TTL 10초, 상한 1000 엔트리). master key 또는 limit=null이면 헤더 생략.
  • M5 dryRun 파라미터: remember / link / forget / amend 4개 MCP 도구에 dryRun: boolean 파라미터 추가. 기본값 false. true 시 simulated: true 응답 반환 + 모든 side-effect 스킵.

v2.11.0 — CLI/API Enhancement Phase 1 (2026-04-20)

Added

  • H1 _meta 래퍼: recall / context 응답에 _meta: { searchEventId, hints, suggestion } 필드 추가. 기존 top-level 필드는 v2.12.x 마지막 릴리즈까지 동일 값으로 mirror 제공된다.
  • H2 sparse fields: recall 파라미터에 fields: string[] 추가. 17개 화이트리스트(id / content / type / topic / keywords / importance / created_at / access_count / confidence / linked / explanations / workspace / context_summary / case_id / valid_to / affect / ema_activation). L1/L2/RRF 단계는 전체 필드 유지 후 응답 직전에 필터링.
  • H3 CLI 서브명령별 --help / -h: 11개 모듈의 usage export 추가.
  • H4 CLI --format table|json|csv: TTY 환경 자동 감지. --json--format json 별칭. lib/cli/_format.js 신설.
  • H5 idempotencyKey: remember / batchRemember 스키마에 idempotencyKey 파라미터 추가(maxLength 128). 같은 key_id 범위 내 partial UNIQUE 보장. FragmentReader.findByIdempotencyKey 신설. migration-034-v2.16.0-bundle(tenant partial index + master partial index 2개).

Deprecated

  • recall / context 응답의 top-level _searchEventId / _memento_hint / _suggestion 필드: v2.12.x 마지막 릴리즈를 끝으로 v2.13.0에서 제거된다. _meta.searchEventId / _meta.hints / _meta.suggestion으로 전환할 것.

v2.10.1 — TDZ 핫픽스 (2026-04-20)

Fixed

  • R12 TDZ 핫픽스: remember() 내부의 atomic 분기(MEMENTO_REMEMBER_ATOMIC=true && keyId != null 경로)가 const fragment 선언 이전에 위치하여 ReferenceError가 발생했다. atomic 분기를 fragment 생성 이후로 이동하고, quotaChecker.check!(atomicRemember && keyId) 가드로 조건부 호출하도록 수정했다. 원격 memento.anchormind.net 서버에서 동일 증상이 발생하던 문제도 함께 해소된다.

Added

  • 회귀 방지 단위 테스트 tests/unit/memory-manager-remember-tdz.test.js: atomic 분기의 TDZ 경로를 직접 재현하는 테스트 추가.

v2.10.0 — MemoryManager 분해 (2026-04-20)

Changed

  • MemoryManager 1252줄 → 259줄 facade로 축소. 비즈니스 로직을 lib/memory/processors/ 4개 클래스로 분리했다: MemoryRememberer(remember/batchRemember), MemoryRecaller(recall/context), MemoryReflector(reflect), MemoryLinker(link/graph_explore).
  • facade ↔ 프로세서 간 공유 프로퍼티 setter를 _installSharedSync 패턴으로 동기화한다. 외부에서 memoryManager.embedder = x처럼 세터를 호출하면 모든 프로세서에 자동 전파된다.

Tests

  • tests/unit/memory-manager-di.test.js: DI 경로를 MemoryManager.prototype.remember.toString()MemoryRememberer.prototype.remember.toString()으로 전환.
  • tests/unit/remember-processor.test.js: MemoryRememberer 직접 DI 경로로 전환.

Pre-2.10.0 — Scripts rename (2026-04-19)

Changed

  • scripts/migration-007-flexible-embedding-dims.js 를 scripts/post-migrate-flexible-embedding-dims.js 로 이름 변경. 자동 마이그레이션 러너(lib/memory/migration-NNN-*.sql)와 수동 dimension 재구성 스크립트를 파일명으로 명확히 구분하기 위함.
  • setup.sh, .env.example 내 구 경로 참조를 신 경로로 일괄 치환.

Deprecation Notice

  • scripts/migration-007-flexible-embedding-dims.js 는 신 경로(post-migrate-flexible-embedding-dims.js)를 가리키는 심볼릭 링크로 v2.13.0까지 유지된다.
  • 외부 스크립트나 CI에서 구 경로를 직접 참조하는 경우 scripts/post-migrate-flexible-embedding-dims.js 로 전환할 것을 권고한다.

v2.9.0 — Mode preset / Affect / Local Embedding / LLM CLI Providers (2026-04-18)

Added

  • Mode preset 시스템: recall-only / write-only / onboarding / audit 4개 JSON preset. X-Memento-Mode 헤더, initialize.params.mode, api_keys.default_mode DB 컬럼 3경로로 활성화. tools/list 응답이 mode별로 필터링된다. (lib/memory/ModeRegistry.js, lib/memory/modes/*.json, migration-034-v2.16.0-bundle.sql)
  • RecallSuggestionEngine 비침습적 힌트 필드: recall 응답에 _suggestion: {code, message, recommendedTool, recommendedArgs} 메타 필드 첨부. 4개 감지 규칙(repeat_query / empty_result_no_context / large_limit_no_budget / no_type_filter_noisy). 클라이언트가 무시해도 기존 동작 불변. (lib/memory/RecallSuggestionEngine.js)
  • Affective tagging: fragments.affect 컬럼(neutral / frustration / confidence / surprise / doubt / satisfaction 6 enum). remember / recall 스키마에 affect 파라미터 노출. CHECK 제약 + partial index. (migration-034-v2.16.0-bundle.sql, FragmentWriter / Reader)
  • Tool 메타 레지스트리: 16개 도구에 meta: {capabilities[], riskLevel, requiresMaster, beta, idempotent} 정적 필드 추가. 도구별 능력 디스커버리를 위한 Node.js 관용 메타데이터 레지스트리. (lib/tool-registry.js)
  • Codex CLI provider: LLM_PRIMARY / LLM_FALLBACKScodex-cli 지정 시 codex exec --skip-git-repo-check --full-auto -o FILE 경로로 JSON 출력을 파싱한다. (lib/codex.js, lib/llm/providers/CodexCliProvider.js)
  • GitHub Copilot CLI provider: copilot-cli 지정 시 copilot -p "prompt" --allow-all-tools --output-format text 호출 + extractJsonBlock으로 통계 꼬리를 제거한다. (lib/copilot.js, lib/llm/providers/CopilotCliProvider.js)
  • 로컬 transformers.js 임베딩 provider: EMBEDDING_PROVIDER=transformers@huggingface/transformers 파이프라인 기반 임베딩. 기본 Xenova/multilingual-e5-small (384d), 옵션 Xenova/bge-m3 (1024d). OpenAI API와 상호 배타 (데이터 혼합 방지). (lib/embeddings/LocalTransformersEmbedder.js, docs/embedding-local.md)
  • Startup embedding consistency check: fragments + morpheme_dict 두 테이블 차원이 config와 일치하는지 server.js 기동 시 검증, 불일치 시 기동 거부. (scripts/check-embedding-consistency.js)
  • 토큰 기반 세션 재사용: claude.ai 커넥터가 Mcp-Session-Id 유실 후 매 initialize마다 새 세션을 생성하던 문제 해결. sha256 해시 + keyId 네임스페이스로 Redis 역인덱스를 구성하여 동일 액세스 토큰에 기존 세션을 재사용한다. (lib/handlers/mcp-handler.js deriveTokenKey, lib/redis.js bindTokenToSession / getSessionIdByToken)
  • E2E 통합 테스트 4종: llm-cli-smoke (CLI 바이너리 스모크), llm-chain-real (체인 실측 subprocess 기반), llm-timeout (latency / timeout 강제), morpheme-llm-real (MorphemeIndex end-to-end), local-embedding (transformers 모델 로드). 환경변수 가드(E2E_LLM_CLI 등)로 기본 SKIP. npm run test:integration:llm 스크립트 + tests/integration/README.md 실행 가이드. (tests/integration/)
  • tests/integration/_cleanup.js 공통 cleanup 모듈: Redis / DB pool 핸들 명시 해제로 Node 이벤트 루프 자연 종료 보장.

Changed

  • MorphemeIndex LLM timeout 상향: 15_000ms → 60_000ms. Gemini CLI / Ollama Cloud 실제 응답(20-40s)에 맞게 조정하여 반복적인 "all LLM providers failed" 패턴을 해소한다. (config/memory.js)
  • migration-007 확장: fragments + morpheme_dict 두 테이블을 루프로 처리하도록 flexible-embedding-dims 마이그레이션을 확장.
  • .env 샘플 갱신: LLM_FALLBACKScodex-cli / copilot-cli 예시 포함.

Fixed

  • FragmentReader / LinkStore 다중 경로의 keyId ANY() 래핑 누락: scalar keyId를 ANY($N)에 그대로 push하여 "비정상적인 배열 문자" PG 오류를 발생시키던 버그. v2.8.7에서 getByIds만 수정한 패턴을 searchByKeywords, searchByTopic, searchBySemantic, searchByTimeRange, searchAsOf, getLinkedFragments(2곳), getRCAChain에 일괄 적용. Array.isArray 래핑. (lib/memory/FragmentReader.js, lib/memory/LinkStore.js)
  • TemporalLinker ::integer[] 오캐스팅: fragments.key_id가 TEXT 컬럼인데 ::integer[] 캐스팅을 사용하여 "연산자 없음: text = integer" 에러가 발생하던 문제. ::text[]로 교체. (lib/memory/TemporalLinker.js)
  • 빈 POST body null crash: readJsonBody가 빈 body를 받아 JSON.parse(null)을 반환할 때 발생하던 unhandledRejection. handleMcpPost 진입부에서 null을 400 Invalid Request로 거부. injectSessionContext에도 null 가드를 이중 방어로 추가.
  • npm run test:integration:llm 서브프로세스 경합: --test-concurrency=1 플래그로 순차 실행을 강제하여 병렬 CLI 서브프로세스 간 경합을 제거.

Upgrade from v2.8.x

1. npm install — package.json 의존성 갱신. @huggingface/transformers 패키지가 신규 추가된다. 2. npm run migrate — migration-034(api_keys.default_mode ADD COLUMN), migration-034-v2.16.0-bundle(fragments.affect ADD COLUMN) 실행. 두 마이그레이션 모두 ADD COLUMN이므로 기존 데이터를 변경하지 않는다. 3. EMBEDDING_PROVIDER 검토 — 기본값(openai 계열)을 유지하면 추가 작업 없음. 로컬 임베딩으로 전환할 경우 EMBEDDING_PROVIDER=transformers를 설정하고 기존 OpenAI 임베딩과 혼합하지 않도록 scripts/backfill-embeddings.js로 전체 재생성 후 서버를 기동한다. 4. backfill-embeddings (조건부) — EMBEDDING_PROVIDER 를 변경한 경우만 해당. npm run backfill:embeddings로 embedding IS NULL 파편을 일괄 처리한다. 5. 서버 재시작 — 기동 시 scripts/check-embedding-consistency.js가 DB 차원과 설정 차원의 일치를 자동 검증하며, 불일치 시 즉시 기동을 중단하고 오류를 출력한다.

Breaking Changes

없음. 모든 신규 기능은 opt-in이다. Mode preset / affect / 로컬 임베딩은 기본값을 유지하면 기존 동작이 완전히 보존된다. migration-034(api_keys.default_mode), migration-034-v2.16.0-bundle(fragments.affect)는 ADD COLUMN이므로 기존 데이터에 영향 없다.

v2.8.7 — FragmentReader keyId ANY() 일괄 fix (2026-04-17)

Fixed

  • FragmentReader.getByIds PostgreSQL "malformed array literal" 에러: key_id = ANY($3) SQL에 단일 UUID 문자열을 그대로 바인딩하여 PG가 배열 파싱 시 실패했다. 호출 측이 keyId를 문자열로 전달하는 경우 배열로 래핑([keyId])하도록 수정. 영향 경로: FragmentSearch.fetch(missing IDs 조회), RememberPostProcessor.linkedTo 소유권 확인, SessionLinker.autoLinkSessionFragments — 간헐적 recall/remember/link 실패 원인이었다. (lib/memory/FragmentReader.js)

v2.8.6 — OAuth auto-register on trusted redirect_uri (2026-04-17)

Changed

  • 신뢰 redirect_uri에 한해 /authorize 자동 등록 허용: OAUTH_TRUSTED_ORIGINS 기반 isAllowedRedirectUri가 true인 경우, ALLOW_AUTO_DCR_REGISTER와 무관하게 미등록 client_id도 /authorize 진입 시 자동 등록된다. 실질적 보안 경계는 v2.8.5의 /token client_secret 검증이므로 auto-register 자체는 안전하다. 바인딩되지 않은 토큰(API 키 미포함 시)은 REJECT_NONAPIKEY_OAUTH=true 정책에 의해 auth.js에서 거부된다. (lib/handlers/oauth-handler.js)
  • 기본 신뢰 도메인 확인: claude.ai, chatgpt.com, platform.openai.com, copilot.microsoft.com, gemini.google.com 5개 사전 내장. OAUTH_TRUSTED_ORIGINS env로 추가 가능. (lib/config.js)

Impact

  • claude.ai 외 ChatGPT/Copilot/Gemini 등 OAuth DCR-less 클라이언트도 사전 수동 등록 없이 즉시 연결 가능. 사용자가 client_id에 임의 문자열 + client_secret에 API 키를 입력하기만 하면 됨.
  • 비신뢰 redirect_uri는 기존과 동일하게 ALLOW_AUTO_DCR_REGISTER=false 기본값에서 차단 (보안 유지).

v2.8.5 — claude.ai OAuth MCP 2025-06-18 compliance (2026-04-17)

Fixed

  • claude.ai OAuth 연결 실패 해결 (MCP 2025-06-18 spec 준수): claude.ai는 사용자가 connector UI에 입력한 client_id/authorize를 호출하고 POST /token body의 client_secret에 API 키를 전송한다. 다음 3개 수정으로 정상 tenant-격리된 OAuth 세션이 발급된다.

Added

  • /token#handleTokenclient_secret → API 키 바인딩: body의 client_secretvalidateApiKeyFromDB로 검증해 tokenData.is_api_key=true + bound_key_id=keyId를 주입. authorization_code와 refresh_token grant 모두 지원. 기존 auth.js의 bound_key_id 경로(v2.8.4)와 맞물려 keyId 격리 세션을 발급. (lib/oauth.js)
  • RFC 8707 resource 파라미터 저장: /authorize/token에서 받은 resource를 codeData/tokenData에 보존하여 토큰 audience 추적. (lib/oauth.js, lib/handlers/oauth-handler.js)

Changed

  • token_endpoint_auth_methods_supported 확장: ["none"]["none", "client_secret_post", "client_secret_basic"]. claude.ai의 client_secret_post 호출과 AS metadata 일치. (lib/oauth.js#getAuthServerMetadata)
  • bearer_methods_supported에서 query 제거: ["header", "query"]["header"]. MCP 스펙(2025-06-18 §249) "MUST NOT in URI query string" 준수. (lib/oauth.js#getResourceMetadata)
  • Protected Resource Metadata의 resource URI에 /mcp 경로 포함: ${baseUrl}${baseUrl}/mcp. claude.ai가 resource 필드를 MCP 엔드포인트로 사용하여 이전에는 /(root)로 POST하다 404를 받던 문제 해결. (lib/oauth.js#getResourceMetadata)

v2.8.4 — name-based DCR client_id + internal keyId binding (2026-04-17)

Changed

  • /register Authorization Bearer 바인딩 전략 변경: v2.8.3의 API 키 원문을 client_id로 사용하는 방식을 폐기. 원문 키가 URL·브라우저 히스토리·프록시 로그에 그대로 노출되는 문제를 해결. 이제 client_id = "<name>_<keyIdHex8>" (URL-safe 이름 + UUID 앞 8자 hex suffix)으로 등록한다. validateRedirectUri 엄격 검증이 기본 방어선이므로 보안 강도는 동일하게 유지된다. (lib/handlers/oauth-handler.js)

Added

  • client_name = "apikey:<keyId>" 내부 바인딩 마커: 스키마 변경 없이 oauth_clients.client_name 필드에 keyId UUID를 인코딩. /authorize 경로에서 이 마커를 파싱하여 validateApiKeyById로 tenant 격리 컨텍스트를 복원한다.
  • validateApiKeyById(id) 신규 함수 (lib/admin/ApiKeyStore.js): UUID 기반 API 키 조회. 원시 키 없이 keyId만으로 권한 정보(keyId, name, groupKeyIds, permissions, defaultWorkspace)를 반환.
  • validateApiKeyFromDB 반환 객체에 name 필드 추가: 기존 반환 구조를 확장하여 name 필드를 포함. 하위 호환 유지.
  • bound_key_id 필드 전파: codeDataaccessData/refreshDatavalidateAccessToken 반환 객체까지 bound_key_id가 완전 전파. refresh_token 갱신 시에도 승계됨.
  • validateAuthentication bound_key_id 우선 경로 (lib/auth.js): OAuth 토큰의 bound_key_id가 있으면 validateApiKeyById로 1순위 처리. 기존 is_api_key 경로는 2순위로 유지 (v2.8.3 호환). non-API-key OAuth 거부는 3순위.
  • 신규 메트릭 3종:
    • mcp_oauth_bound_client_registered_total: name-based binding 등록 성공 횟수
    • mcp_oauth_bound_client_authorized_total: bound_key_id 경로로 /authorize 진입 횟수
    • mcp_oauth_bound_client_authenticated_total: bound_key_id 경로 인증 성공 횟수
  • 신규 테스트 (tests/unit/oauth-name-based-client-id.test.js): 29개 케이스 (client_id 생성, client_name 마커, backward compat, bound_key_id 전파, refresh_token 승계, validateAuthentication 우선순위, 패턴 매칭 경계 케이스).

Notes

  • v2.8.3에서 전체 API 키 문자열을 client_id로 등록한 기존 Redis 토큰은 bound_key_id=null로 2순위 is_api_key 경로를 통해 정상 동작. backward compat 완전 보장.
  • DB 스키마 변경 없음. migration 추가 불필요.

v2.8.3 — DCR /register API key binding (2026-04-17)

Fixed

  • DCR /register Authorization 헤더 기반 client_id 바인딩: claude.ai 등 OAuth DCR 클라이언트가 POST /register 요청 시 Authorization: Bearer <API 키> 헤더로 보낸 API 키가 유효하면, 해당 API 키 문자열을 client_id로 사용하여 등록한다. 이후 /authorize 경로에서 validateApiKeyFromDB로 자연스럽게 is_api_key=true 경로를 타게 되어, Phase 2b의 non-API-key OAuth 거부 정책과 충돌 없이 정상 tenant 격리된 세션을 발급받는다. (lib/handlers/oauth-handler.js)

Notes

  • 별도 DB 스키마 변경 없음. 기존 mmcp_* 접두 client_id 플로우를 재활용한다.
  • Authorization 헤더 없거나 유효하지 않은 토큰이면 기존 랜덤 client_id로 등록하되, 그 클라이언트가 발급받은 토큰은 auth.js의 REJECT_NONAPIKEY_OAUTH=true 정책에 의해 여전히 거부된다.

v2.8.2 — MCP spec compliance + OAuth hardening (2026-04-17)

Security

  • non-API-key OAuth 클라이언트의 master 권한 취약점 차단: is_api_key=false OAuth 토큰으로 인증 시도 시 keyId=null 세션이 생성되어 모든 파편에 master 권한으로 접근할 수 있었던 취약점 차단. MCP_REJECT_NONAPIKEY_OAUTH=false로만 기존 동작 복원 가능. (lib/auth.js)
  • OAuth auto-registration 기본 비활성화: /authorize에서 미등록 client_id가 유효한 redirect_uri만 있으면 자동 등록되던 경로 차단. RFC 7591 POST /register 엔드포인트 경유 강제. MCP_ALLOW_AUTO_DCR_REGISTER=true로만 기존 동작 복원 가능. (lib/handlers/oauth-handler.js)

Added

  • Spec compliance (세션 404): sessionId 있으나 Redis에 없고 인증도 실패한 경우, 또는 세션 expired 상태인 경우 HTTP 404 Not Found + JSON-RPC -32000 "Session not found" 반환. MCP 2025-06-18 스펙 요구사항 준수.
  • Security (Origin 검증): MCP_STRICT_ORIGIN=true 설정 시 허용 목록(OAUTH_TRUSTED_ORIGINS + ALLOWED_ORIGINS + 기본 신뢰 도메인) 외 Origin에서 온 요청을 403으로 거부. DNS rebinding 공격 방어. 기본값 false (opt-in, 기존 동작 유지).
  • Spec compliance (Protocol-Version): initialize 이후 모든 요청에서 MCP-Protocol-Version 헤더 검증. 헤더 없으면 2025-03-26 fallback, 미지원 버전이면 400, 세션 negotiatedVersion과 불일치하면 400. initialize 요청은 검증 생략.
  • 세션 negotiatedVersion 필드: initialize 응답 완료 시 협상된 프로토콜 버전을 세션 데이터에 저장. 이후 요청의 MCP-Protocol-Version 대조에 활용.
  • MCP_REJECT_NONAPIKEY_OAUTH 환경변수 (기본 true): non-API-key OAuth 토큰 거부 제어. false 설정 시 하위 호환 모드.
  • MCP_ALLOW_AUTO_DCR_REGISTER 환경변수 (기본 false): OAuth 자동 클라이언트 등록 허용 제어. true 설정 시 기존 자동 등록 동작.
  • New env: MCP_STRICT_ORIGIN (기본 false).
  • New metrics: mcp_session_404_total, mcp_origin_rejected_total (label: origin), mcp_protocol_version_rejected_total (label: version), mcp_oauth_nonapikey_rejected_total, mcp_oauth_auto_register_blocked_total.

v2.8.1 — Session integrity + recovery (2026-04-17)

Added

  • 세션 ID 보존 복구: lib/sessions.jscreateStreamableSessionWithId(sessionId, ...) 추가. auto-recovery 경로에서 crypto.randomUUID() 대신 클라이언트가 보낸 원본 sessionId로 세션을 재생성하여 데이터 연속성 보장.
  • keyId 교차 검증 (403): 세션 복구 시 Redis의 기존 keyId와 재인증된 keyId가 불일치하면 403 Forbidden + JSON-RPC -32000 "Forbidden" 반환. recordTenantIsolationBlocked("session_recover_keyid_mismatch") 호출.
  • Redis 세션 저장 실패 메트릭 (mcp_redis_session_save_failure_total, label: operation): Redis saveSession catch 경로에서 자동 집계.
  • 세션 복구 결과 메트릭 (mcp_session_recovery_total, label: result = same_id_success | keyid_mismatch | not_found | new_session): auto-recovery 분기 전체 관측.
  • 세션 idle reflect 메트릭 (mcp_session_idle_reflect_total): 24h idle autoReflect 실행 시 카운트.
  • MCP_IDLE_REFLECT_HOURS 환경변수 (기본 24): cleanupExpiredSessions에서 이 시간 이상 비활성 세션에 중간 autoReflect 실행.
  • 세션 객체 lastReflectedAt 필드: 마지막 reflect 시각 추적. idle reflect 중복 실행 방지.

Fixed

  • Heartbeat 연속 실패 경로 autoReflect 누락: lib/sessions.js의 heartbeat interval에서 hbFailures >= SSE_MAX_HEARTBEAT_FAILURESsession.close() 직접 호출 대신 closeStreamableSession(sessionId)를 경유하도록 수정. 세션 종료 시 autoReflect가 반드시 실행됨.

---