rag-memory-epf-mcp 3.5.2 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -4
- package/dist/index.d.ts +96 -9
- package/dist/index.js +1324 -270
- package/dist/src/backfillCoordinator.d.ts +59 -0
- package/dist/src/backfillCoordinator.js +552 -0
- package/dist/src/backup/preflight.d.ts +5 -0
- package/dist/src/backup/preflight.js +185 -0
- package/dist/src/embeddingGate.d.ts +68 -0
- package/dist/src/embeddingGate.js +227 -0
- package/dist/src/migrations/migrations.d.ts +2 -0
- package/dist/src/migrations/migrations.js +181 -0
- package/dist/src/modelCache.d.ts +33 -0
- package/dist/src/modelCache.js +235 -0
- package/dist/src/observations/history.d.ts +8 -0
- package/dist/src/observations/history.js +64 -0
- package/dist/src/observations/lifecycle.d.ts +45 -0
- package/dist/src/observations/lifecycle.js +101 -0
- package/dist/src/observations/projection.d.ts +3 -0
- package/dist/src/observations/projection.js +31 -0
- package/dist/src/observations/schema.d.ts +1 -0
- package/dist/src/observations/schema.js +115 -0
- package/dist/src/tools/graph-query-tools.js +29 -5
- package/dist/src/tools/knowledge-graph-tools.d.ts +14 -0
- package/dist/src/tools/knowledge-graph-tools.js +244 -5
- package/dist/src/tools/tool-registry.d.ts +7 -0
- package/dist/src/tools/tool-registry.js +43 -3
- package/dist/src/tools/types.d.ts +1 -0
- package/docs/UPDATING.md +178 -0
- package/package.json +9 -5
|
@@ -563,7 +563,8 @@ Supports both merge (additive) and replace (clear + import) modes.
|
|
|
563
563
|
- Replace mode provides clean import without conflicts
|
|
564
564
|
- Handles partial imports (entities only, relations only, etc.)
|
|
565
565
|
- Reports imported and skipped counts for verification
|
|
566
|
-
- Supports full
|
|
566
|
+
- Supports the full exportGraph format, including the v13 observation lifecycle tables
|
|
567
|
+
(revision history, provenance and events survive a round-trip)
|
|
567
568
|
</features>
|
|
568
569
|
|
|
569
570
|
<bestPractices>
|
|
@@ -587,12 +588,35 @@ Supports both merge (additive) and replace (clear + import) modes.
|
|
|
587
588
|
- Full replace: {"data": {"entities": [...], "relations": [...], "documents": [...]}, "merge": false}
|
|
588
589
|
- Entities only: {"data": {"entities": [{"id": "abc", "name": "Test", "entityType": "CONCEPT", "observations": ["fact1"]}]}}
|
|
589
590
|
</examples>`;
|
|
591
|
+
// dump 의 행은 객체다. z.any() 로 두면 광고 스키마에 type:'string' fallback 으로 나가
|
|
592
|
+
// listTools 계약이 실제 입력과 어긋난다. z.record 는 "문자열 키를 가진 객체"로 광고되고
|
|
593
|
+
// 비객체 입력을 거부한다(advisor beta r3 남은 P2).
|
|
594
|
+
const dumpRow = () => z.record(z.any());
|
|
590
595
|
const importGraphSchema = {
|
|
591
596
|
data: z.object({
|
|
592
|
-
entities: z.array(
|
|
593
|
-
relations: z.array(
|
|
594
|
-
documents: z.array(
|
|
595
|
-
|
|
597
|
+
entities: z.array(dumpRow()).optional().describe('Array of entity objects to import'),
|
|
598
|
+
relations: z.array(dumpRow()).optional().describe('Array of relation objects to import'),
|
|
599
|
+
documents: z.array(dumpRow()).optional().describe('Array of document objects to import'),
|
|
600
|
+
// v13: 이 네 배열이 스키마에 없으면 z.object().parse() 가 조용히 버린다. 그러면
|
|
601
|
+
// exportGraph 가 낸 완전한 dump 를 MCP 로 되돌릴 때 revision history·provenance·
|
|
602
|
+
// event log 가 전부 사라지고 legacy 관찰로 재생성된다 — 백업/복원이 조용히
|
|
603
|
+
// 손실 연산이 된다(advisor beta 발견 1, MCP 왕복으로 실측).
|
|
604
|
+
observation_roots: z.array(dumpRow()).optional()
|
|
605
|
+
.describe('Array of observation root rows (v13 lifecycle). Required to preserve history on restore'),
|
|
606
|
+
entity_observations: z.array(dumpRow()).optional()
|
|
607
|
+
.describe('Array of observation revision rows (v13 lifecycle)'),
|
|
608
|
+
observation_sources: z.array(dumpRow()).optional()
|
|
609
|
+
.describe('Array of observation provenance rows (v13 lifecycle)'),
|
|
610
|
+
observation_events: z.array(dumpRow()).optional()
|
|
611
|
+
.describe('Array of observation event rows (v13 lifecycle)'),
|
|
612
|
+
metadata: z.record(z.any()).optional()
|
|
613
|
+
.describe('Export metadata (exportedAt, version, counts). Ignored on import'),
|
|
614
|
+
// strict: dump 의 모든 정상 키를 위에 열거했으므로, 모르는 키는 **거부**한다.
|
|
615
|
+
// 기본 strip 은 모르는 테이블을 조용히 버리고(그게 lifecycle 4배열에서 실제로
|
|
616
|
+
// 일어난 일이다), passthrough 는 그것을 manager 까지 흘려보내 거기서 다시 조용히
|
|
617
|
+
// 무시된다 — 둘 다 같은 미래 데이터 손실 경로다. 지원하지 않는 dump 는 크게 실패해야
|
|
618
|
+
// 운영자가 엔진을 올린다(advisor beta r3).
|
|
619
|
+
}).strict().describe('A graph dump as produced by exportGraph, including the v13 observation lifecycle tables'),
|
|
596
620
|
merge: z.boolean().optional().default(true).describe('If true (default), merge with existing data. If false, clear existing data first.'),
|
|
597
621
|
};
|
|
598
622
|
export const importGraphTool = {
|
|
@@ -6,6 +6,13 @@ export declare const hybridSearchTool: ToolDefinition;
|
|
|
6
6
|
export declare const embedAllEntitiesTool: ToolDefinition;
|
|
7
7
|
export declare const getDetailedContextTool: ToolDefinition;
|
|
8
8
|
export declare const updateRelationsTool: ToolDefinition;
|
|
9
|
+
export declare const retractObservationTool: ToolDefinition;
|
|
10
|
+
export declare const restoreObservationTool: ToolDefinition;
|
|
11
|
+
export declare const approveObservationTool: ToolDefinition;
|
|
12
|
+
export declare const declineObservationTool: ToolDefinition;
|
|
13
|
+
export declare const correctObservationTool: ToolDefinition;
|
|
14
|
+
export declare const purgeObservationTool: ToolDefinition;
|
|
15
|
+
export declare const getObservationHistoryTool: ToolDefinition;
|
|
9
16
|
export declare const knowledgeGraphTools: {
|
|
10
17
|
createEntities: ToolDefinition;
|
|
11
18
|
createRelations: ToolDefinition;
|
|
@@ -14,4 +21,11 @@ export declare const knowledgeGraphTools: {
|
|
|
14
21
|
hybridSearch: ToolDefinition;
|
|
15
22
|
embedAllEntities: ToolDefinition;
|
|
16
23
|
getDetailedContext: ToolDefinition;
|
|
24
|
+
correctObservation: ToolDefinition;
|
|
25
|
+
retractObservation: ToolDefinition;
|
|
26
|
+
restoreObservation: ToolDefinition;
|
|
27
|
+
approveObservation: ToolDefinition;
|
|
28
|
+
declineObservation: ToolDefinition;
|
|
29
|
+
purgeObservation: ToolDefinition;
|
|
30
|
+
getObservationHistory: ToolDefinition;
|
|
17
31
|
};
|
|
@@ -73,6 +73,15 @@ const createEntitiesSchema = {
|
|
|
73
73
|
name: z.string().describe('The unique name/identifier of the entity'),
|
|
74
74
|
entityType: z.string().describe('The category or type of the entity (e.g., PERSON, CONCEPT, TECHNOLOGY)'),
|
|
75
75
|
observations: z.array(z.string()).describe('Array of contextual observations about the entity'),
|
|
76
|
+
// v13: 아래 두 필드는 addObservations 와 같은 의미다. 스키마에 없으면 전달되지 않는다.
|
|
77
|
+
status: z.enum(['active', 'provisional']).optional()
|
|
78
|
+
.describe("'provisional' hides the observations from search until approveObservation. Default 'active'"),
|
|
79
|
+
sources: z.array(z.object({
|
|
80
|
+
source_kind: z.enum(['document', 'conversation', 'decision', 'import'])
|
|
81
|
+
.describe('What kind of thing these observations came from'),
|
|
82
|
+
source_ref: z.string().describe('Identifier of the source'),
|
|
83
|
+
source_hash: z.string().optional().describe('Optional content hash of the source'),
|
|
84
|
+
})).optional().describe('Provenance. Omit if genuinely unknown - do not invent a source'),
|
|
76
85
|
})).describe('Array of entities to create in the knowledge graph'),
|
|
77
86
|
};
|
|
78
87
|
export const createEntitiesTool = {
|
|
@@ -189,8 +198,10 @@ Observations provide the factual foundation that supports entity existence and p
|
|
|
189
198
|
|
|
190
199
|
<importantNotes>
|
|
191
200
|
- (!important!) **Entity must exist** - this tool only adds to existing entities
|
|
192
|
-
- (!important!)
|
|
193
|
-
|
|
201
|
+
- (!important!) Duplicates are filtered - repeating existing text with a **new** sources entry
|
|
202
|
+
adds evidence to the existing revision and returns null for that position
|
|
203
|
+
- (!important!) Observations are cumulative. **This tool never replaces anything** - use
|
|
204
|
+
correctObservation to supersede and retractObservation to withdraw
|
|
194
205
|
- (!important!) **Be specific and factual** - observations should be verifiable statements
|
|
195
206
|
</importantNotes>
|
|
196
207
|
|
|
@@ -200,21 +211,24 @@ Observations provide the factual foundation that supports entity existence and p
|
|
|
200
211
|
- When updating entity knowledge from new sources
|
|
201
212
|
- When refining and expanding entity descriptions
|
|
202
213
|
- **Before making knowledge-based decisions** - ensure entities have sufficient context
|
|
203
|
-
- When
|
|
214
|
+
- When *expanding* incomplete entity information. **To correct a wrong observation use
|
|
215
|
+
correctObservation** - adding a second, contradicting observation leaves both in search
|
|
204
216
|
</whenToUseThisTool>
|
|
205
217
|
|
|
206
218
|
<features>
|
|
207
219
|
- Batch addition of observations to multiple entities
|
|
208
220
|
- Automatic duplicate filtering - no redundant observations
|
|
209
221
|
- Supports rich textual observations with context
|
|
210
|
-
-
|
|
222
|
+
- Stable observation ids returned in observation_ids, aligned 1:1 with contents
|
|
223
|
+
- Real revision history: see correctObservation and getObservationHistory
|
|
211
224
|
- Integrates with document processing workflows
|
|
212
225
|
- Enables incremental knowledge building
|
|
213
226
|
</features>
|
|
214
227
|
|
|
215
228
|
<bestPractices>
|
|
216
229
|
- Keep observations factual and specific rather than general
|
|
217
|
-
-
|
|
230
|
+
- Put provenance in the sources field, not in the text. A source written in prose cannot be
|
|
231
|
+
queried, deduplicated, or attached to a later revision
|
|
218
232
|
- Use consistent terminology across observations
|
|
219
233
|
- Add complementary observations that provide different perspectives
|
|
220
234
|
- Include temporal information when relevant ("As of 2024...")
|
|
@@ -232,10 +246,22 @@ Observations provide the factual foundation that supports entity existence and p
|
|
|
232
246
|
- Person details: {"observations": [{"entityName": "Marie Curie", "contents": ["First woman to win Nobel Prize", "Won Nobel Prizes in two different sciences"]}]}
|
|
233
247
|
- Technology evolution: {"observations": [{"entityName": "React", "contents": ["React 18 introduced concurrent features", "Widely adopted for enterprise applications"]}]}
|
|
234
248
|
</examples>`;
|
|
249
|
+
// v13: provenance 와 status 는 스키마에 있어야 실제로 전달된다. validateToolArgs 가
|
|
250
|
+
// z.object(...).parse() 로 검증하므로 스키마에 없는 키는 조용히 버려진다.
|
|
251
|
+
const sourceInputSchema = z.object({
|
|
252
|
+
source_kind: z.enum(['document', 'conversation', 'decision', 'import'])
|
|
253
|
+
.describe('What kind of thing this observation came from'),
|
|
254
|
+
source_ref: z.string().describe('Identifier of the source (document id, decision id, ...)'),
|
|
255
|
+
source_hash: z.string().optional().describe('Optional content hash of the source'),
|
|
256
|
+
}).describe('Where this observation came from');
|
|
235
257
|
const addObservationsSchema = {
|
|
236
258
|
observations: z.array(z.object({
|
|
237
259
|
entityName: z.string().describe('Name of the existing entity to add observations to'),
|
|
238
260
|
contents: z.array(z.string()).describe('Array of new observation strings to add'),
|
|
261
|
+
status: z.enum(['active', 'provisional']).optional()
|
|
262
|
+
.describe("'provisional' hides it from search until approveObservation. Default 'active'"),
|
|
263
|
+
sources: z.array(sourceInputSchema).optional()
|
|
264
|
+
.describe('Provenance. Omit if genuinely unknown - do not invent a source'),
|
|
239
265
|
})).describe('Array of observation additions for specific entities'),
|
|
240
266
|
};
|
|
241
267
|
export const addObservationsTool = {
|
|
@@ -538,6 +564,211 @@ export const updateRelationsTool = {
|
|
|
538
564
|
schema: updateRelationsSchema,
|
|
539
565
|
annotations: { idempotentHint: true },
|
|
540
566
|
};
|
|
567
|
+
// === OBSERVATION LIFECYCLE TOOLS (v13, spec §6.1 / §6.2) ===
|
|
568
|
+
// 상태 전이 4종은 인자와 형태가 같다. 같은 문장을 네 번 복사하면 한 곳만 고치는
|
|
569
|
+
// drift 가 생기므로 팩토리로 만든다.
|
|
570
|
+
const transitionTool = (a) => ({
|
|
571
|
+
capability: {
|
|
572
|
+
description: `${a.verb} an observation revision (${a.from} -> ${a.to})`,
|
|
573
|
+
parameters: {
|
|
574
|
+
type: 'object',
|
|
575
|
+
properties: {
|
|
576
|
+
observation_id: { type: 'string', description: 'The revision to transition' },
|
|
577
|
+
reason: { type: 'string', description: 'Why this transition happened' },
|
|
578
|
+
},
|
|
579
|
+
required: a.reasonRequired ? ['observation_id', 'reason'] : ['observation_id'],
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
description: () => `<description>
|
|
583
|
+
${a.verb} an observation revision: status '${a.from}' becomes '${a.to}'.
|
|
584
|
+
**This is a state change, not a deletion** - the revision and its text survive and stay
|
|
585
|
+
visible through getObservationHistory.
|
|
586
|
+
</description>
|
|
587
|
+
|
|
588
|
+
<importantNotes>
|
|
589
|
+
- (!important!) Only '${a.from}' revisions can be ${a.to === 'active' ? 'moved to active' : a.to}; the transition table rejects anything else
|
|
590
|
+
- (!important!) 'superseded' is terminal - correct it into a new revision instead
|
|
591
|
+
- (!important!) Ordinary search returns only 'active' revisions, so this changes what search sees
|
|
592
|
+
- (!important!) ${a.extra}
|
|
593
|
+
</importantNotes>
|
|
594
|
+
|
|
595
|
+
<whenToUseThisTool>
|
|
596
|
+
- ${a.extra}
|
|
597
|
+
- When you need the record of the change to survive, not just the current text
|
|
598
|
+
</whenToUseThisTool>
|
|
599
|
+
|
|
600
|
+
<parameters>
|
|
601
|
+
- observation_id: The revision id, from addObservations/createEntities or getObservationHistory (string, required)
|
|
602
|
+
- reason: Why (string, ${a.reasonRequired ? 'required' : 'optional but strongly recommended'})
|
|
603
|
+
</parameters>`,
|
|
604
|
+
schema: {
|
|
605
|
+
observation_id: z.string().describe('The observation revision id to transition'),
|
|
606
|
+
...(a.reasonRequired
|
|
607
|
+
? { reason: z.string().describe('Why this transition happened') }
|
|
608
|
+
: { reason: z.string().optional().describe('Why this transition happened') }),
|
|
609
|
+
},
|
|
610
|
+
});
|
|
611
|
+
export const retractObservationTool = transitionTool({
|
|
612
|
+
verb: 'Retract', from: 'active', to: 'retracted', reasonRequired: false,
|
|
613
|
+
extra: 'Use this when a fact turned out to be wrong or no longer holds and there is no replacement text',
|
|
614
|
+
});
|
|
615
|
+
export const restoreObservationTool = transitionTool({
|
|
616
|
+
verb: 'Restore', from: 'retracted', to: 'active', reasonRequired: false,
|
|
617
|
+
extra: 'Use this when a retraction itself was a mistake',
|
|
618
|
+
});
|
|
619
|
+
export const approveObservationTool = transitionTool({
|
|
620
|
+
verb: 'Approve', from: 'provisional', to: 'active', reasonRequired: false,
|
|
621
|
+
extra: 'Use this to accept a provisional observation so search starts returning it',
|
|
622
|
+
});
|
|
623
|
+
export const declineObservationTool = transitionTool({
|
|
624
|
+
verb: 'Decline', from: 'provisional', to: 'retracted', reasonRequired: true,
|
|
625
|
+
extra: 'Use this to reject a provisional observation while keeping the fact that it was proposed',
|
|
626
|
+
});
|
|
627
|
+
const correctObservationDescription = () => `<description>
|
|
628
|
+
Replace the text of an observation while keeping the previous version as history.
|
|
629
|
+
**This is the tool to use when a stored fact is wrong.** Overwriting loses the correction;
|
|
630
|
+
this supersedes the old revision so both the mistake and the fix stay retrievable.
|
|
631
|
+
</description>
|
|
632
|
+
|
|
633
|
+
<importantNotes>
|
|
634
|
+
- (!important!) The old revision becomes 'superseded' and the new one becomes 'active'
|
|
635
|
+
- (!important!) The new revision keeps the old one's position in the entity's observation array
|
|
636
|
+
- (!important!) Only an 'active' revision can be corrected
|
|
637
|
+
- (!important!) Ordinary search returns only the new text; the old text is reachable through getObservationHistory
|
|
638
|
+
</importantNotes>
|
|
639
|
+
|
|
640
|
+
<whenToUseThisTool>
|
|
641
|
+
- When an observation states something that is now known to be false (change_kind: 'correction')
|
|
642
|
+
- When the world changed and the old statement was true at the time (change_kind: 'world_change')
|
|
643
|
+
- **Instead of deleting and re-adding** - that loses the link between the two
|
|
644
|
+
</whenToUseThisTool>
|
|
645
|
+
|
|
646
|
+
<parameters>
|
|
647
|
+
- observation_id: The active revision to correct (string, required)
|
|
648
|
+
- content: The corrected text (string, required)
|
|
649
|
+
- change_kind: 'correction' (it was wrong) or 'world_change' (it stopped being true). Default 'correction'
|
|
650
|
+
- reason: Why (string, optional but strongly recommended)
|
|
651
|
+
</parameters>
|
|
652
|
+
|
|
653
|
+
<examples>
|
|
654
|
+
- {"observation_id": "…", "content": "Uses FTS5 for keyword search", "change_kind": "correction", "reason": "verified in source"}
|
|
655
|
+
</examples>`;
|
|
656
|
+
export const correctObservationTool = {
|
|
657
|
+
capability: {
|
|
658
|
+
description: 'Supersede an observation revision with corrected text, keeping the old one as history',
|
|
659
|
+
parameters: {
|
|
660
|
+
type: 'object',
|
|
661
|
+
properties: {
|
|
662
|
+
observation_id: { type: 'string', description: 'The active revision to correct' },
|
|
663
|
+
content: { type: 'string', description: 'The corrected text' },
|
|
664
|
+
change_kind: { type: 'string', description: "'correction' or 'world_change'" },
|
|
665
|
+
reason: { type: 'string', description: 'Why this correction happened' },
|
|
666
|
+
},
|
|
667
|
+
required: ['observation_id', 'content'],
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
description: correctObservationDescription,
|
|
671
|
+
schema: {
|
|
672
|
+
observation_id: z.string().describe('The active observation revision to correct'),
|
|
673
|
+
content: z.string().describe('The corrected observation text'),
|
|
674
|
+
change_kind: z.enum(['correction', 'world_change']).optional()
|
|
675
|
+
.describe("'correction' = it was wrong; 'world_change' = it stopped being true. Default 'correction'"),
|
|
676
|
+
reason: z.string().optional().describe('Why this correction happened'),
|
|
677
|
+
},
|
|
678
|
+
};
|
|
679
|
+
const purgeObservationDescription = () => `<description>
|
|
680
|
+
**DESTRUCTIVE.** Physically delete an observation revision and every later revision of the same
|
|
681
|
+
root. History is gone afterwards - there is no undo.
|
|
682
|
+
</description>
|
|
683
|
+
|
|
684
|
+
<importantNotes>
|
|
685
|
+
- (!important!) **retractObservation is almost always what you want.** It hides the fact from
|
|
686
|
+
search while keeping the record
|
|
687
|
+
- (!important!) You must pass confirm='PURGE'; any other value refuses
|
|
688
|
+
- (!important!) This is a **suffix purge**: purging revision 2 of a 3-revision chain removes 3 then 2
|
|
689
|
+
- (!important!) The root row is kept so the observation's array position stays reserved
|
|
690
|
+
- (!important!) Events for purged revisions are removed too
|
|
691
|
+
</importantNotes>
|
|
692
|
+
|
|
693
|
+
<whenToUseThisTool>
|
|
694
|
+
- When content must be erased for legal or privacy reasons, not because it is wrong
|
|
695
|
+
- **Never** as the normal way to remove an observation
|
|
696
|
+
</whenToUseThisTool>
|
|
697
|
+
|
|
698
|
+
<parameters>
|
|
699
|
+
- observation_id: The revision to purge from (string, required)
|
|
700
|
+
- confirm: Must be exactly 'PURGE' (string, required)
|
|
701
|
+
</parameters>`;
|
|
702
|
+
export const purgeObservationTool = {
|
|
703
|
+
capability: {
|
|
704
|
+
description: 'DESTRUCTIVE: physically delete an observation revision and its successors',
|
|
705
|
+
parameters: {
|
|
706
|
+
type: 'object',
|
|
707
|
+
properties: {
|
|
708
|
+
observation_id: { type: 'string', description: 'The revision to purge from' },
|
|
709
|
+
confirm: { type: 'string', description: "Must be exactly 'PURGE'" },
|
|
710
|
+
},
|
|
711
|
+
required: ['observation_id', 'confirm'],
|
|
712
|
+
},
|
|
713
|
+
},
|
|
714
|
+
description: purgeObservationDescription,
|
|
715
|
+
schema: {
|
|
716
|
+
observation_id: z.string().describe('The observation revision to purge from'),
|
|
717
|
+
confirm: z.literal('PURGE').describe("Must be exactly 'PURGE' - this destroys history"),
|
|
718
|
+
},
|
|
719
|
+
annotations: { destructiveHint: true },
|
|
720
|
+
};
|
|
721
|
+
const getObservationHistoryDescription = () => `<description>
|
|
722
|
+
Return the full revision history of observations: every version, its status, its provenance, and
|
|
723
|
+
the events that changed it.
|
|
724
|
+
**Past versions come out here and nowhere else - ordinary search returns only 'active' revisions.**
|
|
725
|
+
</description>
|
|
726
|
+
|
|
727
|
+
<importantNotes>
|
|
728
|
+
- (!important!) The response is always \`{ roots: [...] }\` - one root per logical observation
|
|
729
|
+
- (!important!) Each root holds its revisions in order (revision_no ascending), oldest first
|
|
730
|
+
- (!important!) Use this to answer "was this ever different?" or "where did this come from?"
|
|
731
|
+
- (!important!) Exactly one selector is required
|
|
732
|
+
</importantNotes>
|
|
733
|
+
|
|
734
|
+
<whenToUseThisTool>
|
|
735
|
+
- When you need to know whether a fact was corrected, and what it used to say
|
|
736
|
+
- When you need the provenance (which document or decision) behind an observation
|
|
737
|
+
- Before trusting a surprising fact - check whether it was already retracted or superseded
|
|
738
|
+
- When auditing what changed in an entity's knowledge over time
|
|
739
|
+
</whenToUseThisTool>
|
|
740
|
+
|
|
741
|
+
<parameters>
|
|
742
|
+
- entity_name: All observations of this entity (string, optional)
|
|
743
|
+
- observation_id: The root that this revision belongs to (string, optional)
|
|
744
|
+
- root_id: One specific logical observation (string, optional)
|
|
745
|
+
</parameters>
|
|
746
|
+
|
|
747
|
+
<examples>
|
|
748
|
+
- {"entity_name": "claude-mem"}
|
|
749
|
+
- {"observation_id": "…"}
|
|
750
|
+
</examples>`;
|
|
751
|
+
export const getObservationHistoryTool = {
|
|
752
|
+
capability: {
|
|
753
|
+
description: 'Full revision history of observations - the only surface for non-active revisions',
|
|
754
|
+
parameters: {
|
|
755
|
+
type: 'object',
|
|
756
|
+
properties: {
|
|
757
|
+
entity_name: { type: 'string', description: 'All observations of this entity' },
|
|
758
|
+
observation_id: { type: 'string', description: 'The root this revision belongs to' },
|
|
759
|
+
root_id: { type: 'string', description: 'One specific logical observation' },
|
|
760
|
+
},
|
|
761
|
+
required: [],
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
description: getObservationHistoryDescription,
|
|
765
|
+
schema: {
|
|
766
|
+
entity_name: z.string().optional().describe('All observations of this entity'),
|
|
767
|
+
observation_id: z.string().optional().describe('The root that this revision belongs to'),
|
|
768
|
+
root_id: z.string().optional().describe('One specific logical observation'),
|
|
769
|
+
},
|
|
770
|
+
annotations: { readOnlyHint: true },
|
|
771
|
+
};
|
|
541
772
|
// Export all knowledge graph tools
|
|
542
773
|
export const knowledgeGraphTools = {
|
|
543
774
|
createEntities: createEntitiesTool,
|
|
@@ -547,4 +778,12 @@ export const knowledgeGraphTools = {
|
|
|
547
778
|
hybridSearch: hybridSearchTool,
|
|
548
779
|
embedAllEntities: embedAllEntitiesTool,
|
|
549
780
|
getDetailedContext: getDetailedContextTool,
|
|
781
|
+
// v13 observation lifecycle
|
|
782
|
+
correctObservation: correctObservationTool,
|
|
783
|
+
retractObservation: retractObservationTool,
|
|
784
|
+
restoreObservation: restoreObservationTool,
|
|
785
|
+
approveObservation: approveObservationTool,
|
|
786
|
+
declineObservation: declineObservationTool,
|
|
787
|
+
purgeObservation: purgeObservationTool,
|
|
788
|
+
getObservationHistory: getObservationHistoryTool,
|
|
550
789
|
};
|
|
@@ -28,6 +28,13 @@ export declare const allTools: {
|
|
|
28
28
|
hybridSearch: ToolDefinition;
|
|
29
29
|
embedAllEntities: ToolDefinition;
|
|
30
30
|
getDetailedContext: ToolDefinition;
|
|
31
|
+
correctObservation: ToolDefinition;
|
|
32
|
+
retractObservation: ToolDefinition;
|
|
33
|
+
restoreObservation: ToolDefinition;
|
|
34
|
+
approveObservation: ToolDefinition;
|
|
35
|
+
declineObservation: ToolDefinition;
|
|
36
|
+
purgeObservation: ToolDefinition;
|
|
37
|
+
getObservationHistory: ToolDefinition;
|
|
31
38
|
};
|
|
32
39
|
export declare const globalSettings: {
|
|
33
40
|
version: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { knowledgeGraphTools } from './knowledge-graph-tools.js';
|
|
3
4
|
import { ragTools } from './rag-tools.js';
|
|
4
5
|
import { graphQueryTools } from './graph-query-tools.js';
|
|
@@ -12,9 +13,12 @@ export const allTools = {
|
|
|
12
13
|
...graphAnalyticsTools,
|
|
13
14
|
...migrationTools,
|
|
14
15
|
};
|
|
15
|
-
// Global settings for tool descriptions
|
|
16
|
+
// Global settings for tool descriptions.
|
|
17
|
+
// version 은 package.json 이 정본이다. 하드코딩하면 릴리스마다 이 값만 옛 버전으로
|
|
18
|
+
// 남아 도구 문서가 거짓을 말한다(실제로 3.1.0 에 멈춰 있었다 — advisor beta r3 남은 P2).
|
|
19
|
+
const PKG = JSON.parse(readFileSync(new URL('../../../package.json', import.meta.url), 'utf8'));
|
|
16
20
|
export const globalSettings = {
|
|
17
|
-
version:
|
|
21
|
+
version: PKG.version,
|
|
18
22
|
systemName: 'RAG Knowledge Graph MCP Server',
|
|
19
23
|
defaultTimeout: 60,
|
|
20
24
|
};
|
|
@@ -41,6 +45,10 @@ export function convertToMCPTool(name, toolDef) {
|
|
|
41
45
|
type: 'object',
|
|
42
46
|
properties,
|
|
43
47
|
required,
|
|
48
|
+
// validateToolArgs 가 최상위를 strict 로 검증한다. 광고 스키마가 그걸 말하지
|
|
49
|
+
// 않으면 클라이언트는 여분 필드가 허용된다고 읽고 서버에서 거부당한다
|
|
50
|
+
// (advisor beta r3: 계약 표현 불일치).
|
|
51
|
+
additionalProperties: false,
|
|
44
52
|
},
|
|
45
53
|
...(toolDef.annotations && { annotations: toolDef.annotations }),
|
|
46
54
|
};
|
|
@@ -90,6 +98,10 @@ function zodTypeToJsonSchema(zodType, fieldName) {
|
|
|
90
98
|
description: def.description || `${fieldName} object`,
|
|
91
99
|
properties: objectProperties,
|
|
92
100
|
required: objectRequired,
|
|
101
|
+
// 런타임이 strict 면 광고도 strict 라고 말해야 한다. 안 그러면 클라이언트가
|
|
102
|
+
// 여분 키를 허용된다고 읽고 서버에서 거부당한다 — importGraph.data 가
|
|
103
|
+
// 정확히 그 상태였다(advisor beta r4 남은 P2).
|
|
104
|
+
...(def.unknownKeys === 'strict' && { additionalProperties: false }),
|
|
93
105
|
};
|
|
94
106
|
case 'ZodRecord':
|
|
95
107
|
return {
|
|
@@ -97,6 +109,30 @@ function zodTypeToJsonSchema(zodType, fieldName) {
|
|
|
97
109
|
description: def.description || `${fieldName} record`,
|
|
98
110
|
additionalProperties: true,
|
|
99
111
|
};
|
|
112
|
+
// Enums and literals used to fall through to the string fallback, which dropped the
|
|
113
|
+
// allowed values from the advertised schema even though parse() still enforced them.
|
|
114
|
+
// A client that cannot see the values guesses, and the guess is rejected server-side.
|
|
115
|
+
case 'ZodEnum':
|
|
116
|
+
return {
|
|
117
|
+
type: 'string',
|
|
118
|
+
description: def.description || `${fieldName} parameter`,
|
|
119
|
+
enum: [...def.values],
|
|
120
|
+
};
|
|
121
|
+
case 'ZodLiteral':
|
|
122
|
+
return {
|
|
123
|
+
type: typeof def.value === 'number' ? 'number'
|
|
124
|
+
: typeof def.value === 'boolean' ? 'boolean' : 'string',
|
|
125
|
+
description: def.description || `${fieldName} parameter`,
|
|
126
|
+
enum: [def.value],
|
|
127
|
+
};
|
|
128
|
+
// union 도 같은 fallback 함정이었다: deleteDocuments 의 documentIds 는
|
|
129
|
+
// string | string[] 인데 광고 스키마에 type:'string' 으로 나가 배열을 보내면
|
|
130
|
+
// 클라이언트가 계약 위반이라고 읽는다. anyOf 로 정직하게 노출한다.
|
|
131
|
+
case 'ZodUnion':
|
|
132
|
+
return {
|
|
133
|
+
description: def.description || `${fieldName} parameter`,
|
|
134
|
+
anyOf: def.options.map((o, i) => zodTypeToJsonSchema(o, `${fieldName} option ${i}`)),
|
|
135
|
+
};
|
|
100
136
|
case 'ZodOptional':
|
|
101
137
|
const innerSchema = zodTypeToJsonSchema(def.innerType, fieldName);
|
|
102
138
|
return {
|
|
@@ -143,7 +179,11 @@ export function validateToolArgs(toolName, args) {
|
|
|
143
179
|
if (!toolDef) {
|
|
144
180
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
145
181
|
}
|
|
146
|
-
|
|
182
|
+
// strict: 알 수 없는 최상위 인자는 거부한다. 기본 strip 은 오래된 호출자를
|
|
183
|
+
// **조용히** 통과시킨다 — v3.6 의 index 기반 관찰 지정(`{observation_id, index}`,
|
|
184
|
+
// `{observation_index}`)이 아무 오류 없이 무시되고, 호출자는 자기가 지정한
|
|
185
|
+
// revision 이 아닌 다른 것이 처리됐다는 사실을 모른다(spec T6, advisor beta 발견 4-1).
|
|
186
|
+
const schema = z.object(toolDef.schema).strict();
|
|
147
187
|
return schema.parse(args);
|
|
148
188
|
}
|
|
149
189
|
/**
|