@xache/mcp-server 0.4.0 → 0.5.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 +72 -0
- package/package.json +5 -6
- package/src/index.ts +712 -65
package/README.md
CHANGED
|
@@ -182,6 +182,78 @@ Extract insights from this API integration session and contribute any valuable p
|
|
|
182
182
|
Domain: "api-integration"
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
+
### Knowledge Graph
|
|
186
|
+
|
|
187
|
+
#### `xache_graph_extract`
|
|
188
|
+
|
|
189
|
+
Extract entities and relationships from text into the knowledge graph.
|
|
190
|
+
|
|
191
|
+
**Parameters:**
|
|
192
|
+
- `trace` (required): The text to extract entities from
|
|
193
|
+
- `domain` (optional): Domain hint (e.g., "engineering", "customer-support")
|
|
194
|
+
- `mode` (optional): LLM mode - "byok" or "xache-managed"
|
|
195
|
+
- `provider` (optional): LLM provider
|
|
196
|
+
- `model` (optional): Specific model to use
|
|
197
|
+
|
|
198
|
+
#### `xache_graph_load`
|
|
199
|
+
|
|
200
|
+
Load the full knowledge graph.
|
|
201
|
+
|
|
202
|
+
**Parameters:**
|
|
203
|
+
- `entityTypes` (optional): Filter to specific entity types
|
|
204
|
+
- `validAt` (optional): Load graph at a specific time (ISO8601)
|
|
205
|
+
|
|
206
|
+
#### `xache_graph_query`
|
|
207
|
+
|
|
208
|
+
Query the knowledge graph around a specific entity.
|
|
209
|
+
|
|
210
|
+
**Parameters:**
|
|
211
|
+
- `startEntity` (required): Entity name to start from
|
|
212
|
+
- `depth` (optional): Number of hops (default: 2)
|
|
213
|
+
|
|
214
|
+
#### `xache_graph_ask`
|
|
215
|
+
|
|
216
|
+
Ask a natural language question about the knowledge graph.
|
|
217
|
+
|
|
218
|
+
**Parameters:**
|
|
219
|
+
- `question` (required): The question to ask
|
|
220
|
+
- `mode` (optional): LLM mode
|
|
221
|
+
- `provider` (optional): LLM provider
|
|
222
|
+
|
|
223
|
+
#### `xache_graph_add_entity`
|
|
224
|
+
|
|
225
|
+
Add an entity to the knowledge graph.
|
|
226
|
+
|
|
227
|
+
**Parameters:**
|
|
228
|
+
- `name` (required): Entity name
|
|
229
|
+
- `type` (required): Entity type (person, organization, tool, concept, etc.)
|
|
230
|
+
- `summary` (optional): Brief description
|
|
231
|
+
|
|
232
|
+
#### `xache_graph_add_relationship`
|
|
233
|
+
|
|
234
|
+
Create a relationship between two entities.
|
|
235
|
+
|
|
236
|
+
**Parameters:**
|
|
237
|
+
- `fromEntity` (required): Source entity name
|
|
238
|
+
- `toEntity` (required): Target entity name
|
|
239
|
+
- `type` (required): Relationship type (works_at, knows, uses, manages, etc.)
|
|
240
|
+
- `description` (optional): Relationship description
|
|
241
|
+
|
|
242
|
+
#### `xache_graph_merge_entities`
|
|
243
|
+
|
|
244
|
+
Merge two entities into one. The source is superseded and the target is updated.
|
|
245
|
+
|
|
246
|
+
**Parameters:**
|
|
247
|
+
- `sourceName` (required): Entity to merge FROM
|
|
248
|
+
- `targetName` (required): Entity to merge INTO
|
|
249
|
+
|
|
250
|
+
#### `xache_graph_entity_history`
|
|
251
|
+
|
|
252
|
+
Get the full version history of an entity.
|
|
253
|
+
|
|
254
|
+
**Parameters:**
|
|
255
|
+
- `name` (required): Entity name to look up
|
|
256
|
+
|
|
185
257
|
### Reputation
|
|
186
258
|
|
|
187
259
|
#### `xache_check_reputation`
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xache/mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for Xache Protocol - collective intelligence, verifiable memory,
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "MCP server for Xache Protocol - collective intelligence, verifiable memory, and reputation for AI agents",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"xache-mcp": "./dist/index.js"
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"agents",
|
|
20
20
|
"collective-intelligence",
|
|
21
21
|
"memory",
|
|
22
|
-
"extraction",
|
|
23
22
|
"blockchain",
|
|
24
23
|
"receipts",
|
|
25
24
|
"reputation"
|
|
@@ -28,12 +27,12 @@
|
|
|
28
27
|
"license": "MIT",
|
|
29
28
|
"repository": {
|
|
30
29
|
"type": "git",
|
|
31
|
-
"url": "https://github.com/
|
|
30
|
+
"url": "https://github.com/oliveskin/xache"
|
|
32
31
|
},
|
|
33
32
|
"homepage": "https://xache.xyz",
|
|
34
33
|
"dependencies": {
|
|
35
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
36
|
-
"@xache/sdk": "^5.
|
|
34
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
35
|
+
"@xache/sdk": "^5.5.0",
|
|
37
36
|
"zod": "^3.22.0"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
package/src/index.ts
CHANGED
|
@@ -47,7 +47,13 @@ import {
|
|
|
47
47
|
ListToolsRequestSchema,
|
|
48
48
|
Tool,
|
|
49
49
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
50
|
-
import {
|
|
50
|
+
import {
|
|
51
|
+
XacheClient,
|
|
52
|
+
type DID,
|
|
53
|
+
type LLMProvider,
|
|
54
|
+
type LLMApiFormat,
|
|
55
|
+
type SubjectContext,
|
|
56
|
+
} from '@xache/sdk';
|
|
51
57
|
import crypto from 'crypto';
|
|
52
58
|
|
|
53
59
|
// =============================================================================
|
|
@@ -84,77 +90,14 @@ function getDID(): DID {
|
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
function validateConfig(): void {
|
|
87
|
-
// Required: wallet address
|
|
88
93
|
if (!config.walletAddress) {
|
|
89
94
|
console.error('Error: XACHE_WALLET_ADDRESS environment variable is required');
|
|
90
95
|
process.exit(1);
|
|
91
96
|
}
|
|
92
|
-
|
|
93
|
-
// Required: private key
|
|
94
97
|
if (!config.privateKey) {
|
|
95
98
|
console.error('Error: XACHE_PRIVATE_KEY environment variable is required');
|
|
96
99
|
process.exit(1);
|
|
97
100
|
}
|
|
98
|
-
|
|
99
|
-
// Validate chain
|
|
100
|
-
if (!['base', 'solana'].includes(config.chain)) {
|
|
101
|
-
console.error('Error: XACHE_CHAIN must be "base" or "solana"');
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Validate wallet address format based on chain
|
|
106
|
-
if (config.chain === 'solana') {
|
|
107
|
-
// Solana: base58 (32-44 chars)
|
|
108
|
-
if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(config.walletAddress)) {
|
|
109
|
-
console.error('Error: Invalid Solana wallet address format');
|
|
110
|
-
process.exit(1);
|
|
111
|
-
}
|
|
112
|
-
} else {
|
|
113
|
-
// EVM: 0x + 40 hex chars
|
|
114
|
-
if (!/^0x[a-fA-F0-9]{40}$/.test(config.walletAddress)) {
|
|
115
|
-
console.error('Error: Invalid EVM wallet address format (expected 0x + 40 hex chars)');
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Validate private key format (hex string)
|
|
121
|
-
const cleanKey = config.privateKey.startsWith('0x')
|
|
122
|
-
? config.privateKey.slice(2)
|
|
123
|
-
: config.privateKey;
|
|
124
|
-
if (!/^[a-fA-F0-9]{64}$/.test(cleanKey) && !/^[a-fA-F0-9]{128}$/.test(cleanKey)) {
|
|
125
|
-
console.error('Error: XACHE_PRIVATE_KEY must be a 64 or 128 character hex string');
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Validate API URL format
|
|
130
|
-
try {
|
|
131
|
-
new URL(config.apiUrl);
|
|
132
|
-
} catch {
|
|
133
|
-
console.error('Error: XACHE_API_URL is not a valid URL');
|
|
134
|
-
process.exit(1);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Validate LLM provider if specified
|
|
138
|
-
if (config.llmProvider && !SUPPORTED_PROVIDERS.includes(config.llmProvider)) {
|
|
139
|
-
console.error(`Error: XACHE_LLM_PROVIDER must be one of: ${SUPPORTED_PROVIDERS.join(', ')}`);
|
|
140
|
-
process.exit(1);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Validate LLM endpoint URL if specified
|
|
144
|
-
if (config.llmEndpoint) {
|
|
145
|
-
try {
|
|
146
|
-
new URL(config.llmEndpoint);
|
|
147
|
-
} catch {
|
|
148
|
-
console.error('Error: XACHE_LLM_ENDPOINT is not a valid URL');
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Validate LLM format
|
|
154
|
-
if (!['openai', 'anthropic', 'cohere'].includes(config.llmFormat)) {
|
|
155
|
-
console.error('Error: XACHE_LLM_FORMAT must be "openai", "anthropic", or "cohere"');
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
101
|
}
|
|
159
102
|
|
|
160
103
|
// =============================================================================
|
|
@@ -165,6 +108,21 @@ function hashPattern(pattern: string): string {
|
|
|
165
108
|
return crypto.createHash('sha256').update(pattern).digest('hex');
|
|
166
109
|
}
|
|
167
110
|
|
|
111
|
+
function getDefaultSubjectContext(): SubjectContext {
|
|
112
|
+
return { scope: 'GLOBAL' };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function buildSubjectContext(args: Record<string, unknown>): SubjectContext {
|
|
116
|
+
const subject = args.subject as Record<string, unknown> | undefined;
|
|
117
|
+
if (!subject) return getDefaultSubjectContext();
|
|
118
|
+
return {
|
|
119
|
+
scope: (subject.scope as SubjectContext['scope']) || 'GLOBAL',
|
|
120
|
+
subjectId: subject.subjectId as string | undefined,
|
|
121
|
+
segmentId: subject.segmentId as string | undefined,
|
|
122
|
+
tenantId: subject.tenantId as string | undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
168
126
|
// =============================================================================
|
|
169
127
|
// Tool Definitions
|
|
170
128
|
// =============================================================================
|
|
@@ -265,6 +223,16 @@ const TOOLS: Tool[] = [
|
|
|
265
223
|
enum: ['hot', 'warm', 'cold'],
|
|
266
224
|
description: 'Storage tier (default: warm)',
|
|
267
225
|
},
|
|
226
|
+
subject: {
|
|
227
|
+
type: 'object',
|
|
228
|
+
description: 'Optional subject context for memory scoping',
|
|
229
|
+
properties: {
|
|
230
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'], description: 'Memory scope (default: GLOBAL)' },
|
|
231
|
+
subjectId: { type: 'string', description: 'HMAC-derived subject ID (64 hex chars)' },
|
|
232
|
+
segmentId: { type: 'string', description: 'Segment identifier' },
|
|
233
|
+
tenantId: { type: 'string', description: 'Tenant identifier' },
|
|
234
|
+
},
|
|
235
|
+
},
|
|
268
236
|
},
|
|
269
237
|
required: ['data'],
|
|
270
238
|
},
|
|
@@ -279,6 +247,16 @@ const TOOLS: Tool[] = [
|
|
|
279
247
|
type: 'string',
|
|
280
248
|
description: 'The storage key from when the memory was stored',
|
|
281
249
|
},
|
|
250
|
+
subject: {
|
|
251
|
+
type: 'object',
|
|
252
|
+
description: 'Optional subject context for memory scoping',
|
|
253
|
+
properties: {
|
|
254
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'], description: 'Memory scope (default: GLOBAL)' },
|
|
255
|
+
subjectId: { type: 'string', description: 'HMAC-derived subject ID (64 hex chars)' },
|
|
256
|
+
segmentId: { type: 'string', description: 'Segment identifier' },
|
|
257
|
+
tenantId: { type: 'string', description: 'Tenant identifier' },
|
|
258
|
+
},
|
|
259
|
+
},
|
|
282
260
|
},
|
|
283
261
|
required: ['storageKey'],
|
|
284
262
|
},
|
|
@@ -297,6 +275,16 @@ const TOOLS: Tool[] = [
|
|
|
297
275
|
type: 'number',
|
|
298
276
|
description: 'Max results (default 20)',
|
|
299
277
|
},
|
|
278
|
+
subject: {
|
|
279
|
+
type: 'object',
|
|
280
|
+
description: 'Optional subject context for memory scoping',
|
|
281
|
+
properties: {
|
|
282
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'], description: 'Memory scope (default: GLOBAL)' },
|
|
283
|
+
subjectId: { type: 'string', description: 'HMAC-derived subject ID (64 hex chars)' },
|
|
284
|
+
segmentId: { type: 'string', description: 'Segment identifier' },
|
|
285
|
+
tenantId: { type: 'string', description: 'Tenant identifier' },
|
|
286
|
+
},
|
|
287
|
+
},
|
|
300
288
|
},
|
|
301
289
|
required: [],
|
|
302
290
|
},
|
|
@@ -401,6 +389,300 @@ const TOOLS: Tool[] = [
|
|
|
401
389
|
required: ['trace', 'domain'],
|
|
402
390
|
},
|
|
403
391
|
},
|
|
392
|
+
|
|
393
|
+
// =========================================================================
|
|
394
|
+
// Knowledge Graph Tools
|
|
395
|
+
// =========================================================================
|
|
396
|
+
{
|
|
397
|
+
name: 'xache_graph_extract',
|
|
398
|
+
description:
|
|
399
|
+
'Extract entities and relationships from an agent trace into the knowledge graph. Uses LLM to identify people, organizations, tools, concepts, and their relationships. Automatically stores results.',
|
|
400
|
+
inputSchema: {
|
|
401
|
+
type: 'object',
|
|
402
|
+
properties: {
|
|
403
|
+
trace: {
|
|
404
|
+
type: 'string',
|
|
405
|
+
description: 'The agent trace/conversation to extract entities and relationships from',
|
|
406
|
+
},
|
|
407
|
+
domain: {
|
|
408
|
+
type: 'string',
|
|
409
|
+
description: 'Domain hint for better extraction (e.g., "customer-support", "engineering")',
|
|
410
|
+
},
|
|
411
|
+
mode: {
|
|
412
|
+
type: 'string',
|
|
413
|
+
enum: ['api-key', 'endpoint', 'xache-managed'],
|
|
414
|
+
description: 'LLM mode (default: auto-detected from env vars)',
|
|
415
|
+
},
|
|
416
|
+
provider: {
|
|
417
|
+
type: 'string',
|
|
418
|
+
enum: ['anthropic', 'openai', 'google', 'mistral', 'groq', 'together', 'fireworks', 'cohere', 'xai', 'deepseek'],
|
|
419
|
+
description: 'LLM provider for api-key mode (default: anthropic)',
|
|
420
|
+
},
|
|
421
|
+
model: {
|
|
422
|
+
type: 'string',
|
|
423
|
+
description: 'Specific model to use (optional)',
|
|
424
|
+
},
|
|
425
|
+
confidenceThreshold: {
|
|
426
|
+
type: 'number',
|
|
427
|
+
description: 'Minimum confidence for extraction (0.0-1.0, default: 0.7)',
|
|
428
|
+
},
|
|
429
|
+
maxEntities: {
|
|
430
|
+
type: 'number',
|
|
431
|
+
description: 'Maximum entities to extract (default: provider limit)',
|
|
432
|
+
},
|
|
433
|
+
subject: {
|
|
434
|
+
type: 'object',
|
|
435
|
+
description: 'Subject context for graph scoping',
|
|
436
|
+
properties: {
|
|
437
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
438
|
+
subjectId: { type: 'string' },
|
|
439
|
+
segmentId: { type: 'string' },
|
|
440
|
+
tenantId: { type: 'string' },
|
|
441
|
+
},
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
required: ['trace'],
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: 'xache_graph_load',
|
|
449
|
+
description:
|
|
450
|
+
'Load the full knowledge graph. Returns all entities and relationships. Optionally filter by entity type or load a historical snapshot.',
|
|
451
|
+
inputSchema: {
|
|
452
|
+
type: 'object',
|
|
453
|
+
properties: {
|
|
454
|
+
entityTypes: {
|
|
455
|
+
type: 'array',
|
|
456
|
+
items: { type: 'string' },
|
|
457
|
+
description: 'Filter to specific entity types (e.g., ["person", "organization"])',
|
|
458
|
+
},
|
|
459
|
+
validAt: {
|
|
460
|
+
type: 'string',
|
|
461
|
+
description: 'Load graph as it existed at this time (ISO8601 date string)',
|
|
462
|
+
},
|
|
463
|
+
subject: {
|
|
464
|
+
type: 'object',
|
|
465
|
+
description: 'Subject context for graph scoping',
|
|
466
|
+
properties: {
|
|
467
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
468
|
+
subjectId: { type: 'string' },
|
|
469
|
+
segmentId: { type: 'string' },
|
|
470
|
+
tenantId: { type: 'string' },
|
|
471
|
+
},
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
required: [],
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
name: 'xache_graph_query',
|
|
479
|
+
description:
|
|
480
|
+
'Query a subgraph around a specific entity. Returns the entity and all connected entities/relationships within the specified depth.',
|
|
481
|
+
inputSchema: {
|
|
482
|
+
type: 'object',
|
|
483
|
+
properties: {
|
|
484
|
+
startEntity: {
|
|
485
|
+
type: 'string',
|
|
486
|
+
description: 'Name of the starting entity (e.g., "John Smith", "Acme Corp")',
|
|
487
|
+
},
|
|
488
|
+
depth: {
|
|
489
|
+
type: 'number',
|
|
490
|
+
description: 'Number of hops from start entity (default: 2)',
|
|
491
|
+
},
|
|
492
|
+
relationshipTypes: {
|
|
493
|
+
type: 'array',
|
|
494
|
+
items: { type: 'string' },
|
|
495
|
+
description: 'Filter to specific relationship types (e.g., ["works_at", "manages"])',
|
|
496
|
+
},
|
|
497
|
+
validAt: {
|
|
498
|
+
type: 'string',
|
|
499
|
+
description: 'Query as of this point in time (ISO8601)',
|
|
500
|
+
},
|
|
501
|
+
subject: {
|
|
502
|
+
type: 'object',
|
|
503
|
+
description: 'Subject context for graph scoping',
|
|
504
|
+
properties: {
|
|
505
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
506
|
+
subjectId: { type: 'string' },
|
|
507
|
+
segmentId: { type: 'string' },
|
|
508
|
+
tenantId: { type: 'string' },
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
required: ['startEntity'],
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
name: 'xache_graph_ask',
|
|
517
|
+
description:
|
|
518
|
+
'Ask a natural language question about the knowledge graph. Uses LLM to analyze the graph and generate an answer with source citations.',
|
|
519
|
+
inputSchema: {
|
|
520
|
+
type: 'object',
|
|
521
|
+
properties: {
|
|
522
|
+
question: {
|
|
523
|
+
type: 'string',
|
|
524
|
+
description: 'Natural language question (e.g., "Who manages the engineering team?")',
|
|
525
|
+
},
|
|
526
|
+
mode: {
|
|
527
|
+
type: 'string',
|
|
528
|
+
enum: ['api-key', 'endpoint', 'xache-managed'],
|
|
529
|
+
description: 'LLM mode (default: auto-detected from env vars)',
|
|
530
|
+
},
|
|
531
|
+
provider: {
|
|
532
|
+
type: 'string',
|
|
533
|
+
enum: ['anthropic', 'openai', 'google', 'mistral', 'groq', 'together', 'fireworks', 'cohere', 'xai', 'deepseek'],
|
|
534
|
+
description: 'LLM provider for api-key mode (default: anthropic)',
|
|
535
|
+
},
|
|
536
|
+
model: {
|
|
537
|
+
type: 'string',
|
|
538
|
+
description: 'Specific model to use (optional)',
|
|
539
|
+
},
|
|
540
|
+
subject: {
|
|
541
|
+
type: 'object',
|
|
542
|
+
description: 'Subject context for graph scoping',
|
|
543
|
+
properties: {
|
|
544
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
545
|
+
subjectId: { type: 'string' },
|
|
546
|
+
segmentId: { type: 'string' },
|
|
547
|
+
tenantId: { type: 'string' },
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
required: ['question'],
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
name: 'xache_graph_add_entity',
|
|
556
|
+
description:
|
|
557
|
+
'Manually add an entity to the knowledge graph. Use when you want to explicitly create a person, organization, tool, concept, etc.',
|
|
558
|
+
inputSchema: {
|
|
559
|
+
type: 'object',
|
|
560
|
+
properties: {
|
|
561
|
+
name: {
|
|
562
|
+
type: 'string',
|
|
563
|
+
description: 'Entity display name (e.g., "John Smith", "React")',
|
|
564
|
+
},
|
|
565
|
+
type: {
|
|
566
|
+
type: 'string',
|
|
567
|
+
description: 'Entity type: "person", "organization", "tool", "concept", "location", "event", "product", "project", or custom',
|
|
568
|
+
},
|
|
569
|
+
summary: {
|
|
570
|
+
type: 'string',
|
|
571
|
+
description: 'Brief description of the entity',
|
|
572
|
+
},
|
|
573
|
+
attributes: {
|
|
574
|
+
type: 'object',
|
|
575
|
+
description: 'Arbitrary key-value attributes',
|
|
576
|
+
},
|
|
577
|
+
subject: {
|
|
578
|
+
type: 'object',
|
|
579
|
+
description: 'Subject context for graph scoping',
|
|
580
|
+
properties: {
|
|
581
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
582
|
+
subjectId: { type: 'string' },
|
|
583
|
+
segmentId: { type: 'string' },
|
|
584
|
+
tenantId: { type: 'string' },
|
|
585
|
+
},
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
required: ['name', 'type'],
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
name: 'xache_graph_add_relationship',
|
|
593
|
+
description:
|
|
594
|
+
'Create a relationship between two entities in the knowledge graph. Both entities must already exist.',
|
|
595
|
+
inputSchema: {
|
|
596
|
+
type: 'object',
|
|
597
|
+
properties: {
|
|
598
|
+
fromEntity: {
|
|
599
|
+
type: 'string',
|
|
600
|
+
description: 'Source entity name',
|
|
601
|
+
},
|
|
602
|
+
toEntity: {
|
|
603
|
+
type: 'string',
|
|
604
|
+
description: 'Target entity name',
|
|
605
|
+
},
|
|
606
|
+
type: {
|
|
607
|
+
type: 'string',
|
|
608
|
+
description: 'Relationship type: "works_at", "knows", "uses", "manages", "reports_to", "part_of", "created", "owns", "located_in", "related_to", or custom',
|
|
609
|
+
},
|
|
610
|
+
description: {
|
|
611
|
+
type: 'string',
|
|
612
|
+
description: 'Human-readable description of the relationship',
|
|
613
|
+
},
|
|
614
|
+
attributes: {
|
|
615
|
+
type: 'object',
|
|
616
|
+
description: 'Arbitrary key-value attributes',
|
|
617
|
+
},
|
|
618
|
+
subject: {
|
|
619
|
+
type: 'object',
|
|
620
|
+
description: 'Subject context for graph scoping',
|
|
621
|
+
properties: {
|
|
622
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
623
|
+
subjectId: { type: 'string' },
|
|
624
|
+
segmentId: { type: 'string' },
|
|
625
|
+
tenantId: { type: 'string' },
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
required: ['fromEntity', 'toEntity', 'type'],
|
|
630
|
+
},
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
name: 'xache_graph_merge_entities',
|
|
634
|
+
description:
|
|
635
|
+
'Merge two entities into one. The source entity is superseded and the target entity is updated with merged attributes. Relationships are transferred.',
|
|
636
|
+
inputSchema: {
|
|
637
|
+
type: 'object',
|
|
638
|
+
properties: {
|
|
639
|
+
sourceName: {
|
|
640
|
+
type: 'string',
|
|
641
|
+
description: 'Entity to merge FROM (will be superseded)',
|
|
642
|
+
},
|
|
643
|
+
targetName: {
|
|
644
|
+
type: 'string',
|
|
645
|
+
description: 'Entity to merge INTO (will be updated)',
|
|
646
|
+
},
|
|
647
|
+
subject: {
|
|
648
|
+
type: 'object',
|
|
649
|
+
description: 'Subject context for graph scoping',
|
|
650
|
+
properties: {
|
|
651
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
652
|
+
subjectId: { type: 'string' },
|
|
653
|
+
segmentId: { type: 'string' },
|
|
654
|
+
tenantId: { type: 'string' },
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
required: ['sourceName', 'targetName'],
|
|
659
|
+
},
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
name: 'xache_graph_entity_history',
|
|
663
|
+
description:
|
|
664
|
+
'Get the full version history of an entity. Shows how the entity has changed over time, including all temporal versions.',
|
|
665
|
+
inputSchema: {
|
|
666
|
+
type: 'object',
|
|
667
|
+
properties: {
|
|
668
|
+
name: {
|
|
669
|
+
type: 'string',
|
|
670
|
+
description: 'Entity name to look up history for',
|
|
671
|
+
},
|
|
672
|
+
subject: {
|
|
673
|
+
type: 'object',
|
|
674
|
+
description: 'Subject context for graph scoping',
|
|
675
|
+
properties: {
|
|
676
|
+
scope: { type: 'string', enum: ['SUBJECT', 'SEGMENT', 'GLOBAL'] },
|
|
677
|
+
subjectId: { type: 'string' },
|
|
678
|
+
segmentId: { type: 'string' },
|
|
679
|
+
tenantId: { type: 'string' },
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
required: ['name'],
|
|
684
|
+
},
|
|
685
|
+
},
|
|
404
686
|
];
|
|
405
687
|
|
|
406
688
|
// =============================================================================
|
|
@@ -803,6 +1085,347 @@ async function handleExtractAndContribute(
|
|
|
803
1085
|
return output;
|
|
804
1086
|
}
|
|
805
1087
|
|
|
1088
|
+
// =============================================================================
|
|
1089
|
+
// Graph Tool Handlers
|
|
1090
|
+
// =============================================================================
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Build LLM config from args + env vars (shared by graph extract/ask and extraction tools)
|
|
1094
|
+
*/
|
|
1095
|
+
function buildLLMConfig(args: {
|
|
1096
|
+
mode?: 'api-key' | 'endpoint' | 'xache-managed';
|
|
1097
|
+
provider?: LLMProvider;
|
|
1098
|
+
model?: string;
|
|
1099
|
+
}): { llmConfig: Record<string, unknown>; modeDescription: string } {
|
|
1100
|
+
let mode = args.mode;
|
|
1101
|
+
if (!mode) {
|
|
1102
|
+
if (config.llmEndpoint) mode = 'endpoint';
|
|
1103
|
+
else if (config.llmApiKey && config.llmProvider) mode = 'api-key';
|
|
1104
|
+
else mode = 'xache-managed';
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
const provider = args.provider || config.llmProvider || 'anthropic';
|
|
1108
|
+
const model = args.model || config.llmModel || undefined;
|
|
1109
|
+
|
|
1110
|
+
if (mode === 'api-key') {
|
|
1111
|
+
if (!config.llmApiKey) {
|
|
1112
|
+
throw new Error('api-key mode requires XACHE_LLM_API_KEY environment variable.');
|
|
1113
|
+
}
|
|
1114
|
+
if (!SUPPORTED_PROVIDERS.includes(provider)) {
|
|
1115
|
+
throw new Error(`Unsupported provider: ${provider}. Supported: ${SUPPORTED_PROVIDERS.join(', ')}`);
|
|
1116
|
+
}
|
|
1117
|
+
return {
|
|
1118
|
+
llmConfig: { type: 'api-key' as const, provider, apiKey: config.llmApiKey, model },
|
|
1119
|
+
modeDescription: `api-key (${provider})`,
|
|
1120
|
+
};
|
|
1121
|
+
} else if (mode === 'endpoint') {
|
|
1122
|
+
if (!config.llmEndpoint) {
|
|
1123
|
+
throw new Error('endpoint mode requires XACHE_LLM_ENDPOINT environment variable.');
|
|
1124
|
+
}
|
|
1125
|
+
return {
|
|
1126
|
+
llmConfig: {
|
|
1127
|
+
type: 'endpoint' as const,
|
|
1128
|
+
url: config.llmEndpoint,
|
|
1129
|
+
authToken: config.llmAuthToken || undefined,
|
|
1130
|
+
format: config.llmFormat,
|
|
1131
|
+
model,
|
|
1132
|
+
},
|
|
1133
|
+
modeDescription: `endpoint (${config.llmEndpoint.substring(0, 40)}...)`,
|
|
1134
|
+
};
|
|
1135
|
+
} else {
|
|
1136
|
+
return {
|
|
1137
|
+
llmConfig: {
|
|
1138
|
+
type: 'xache-managed' as const,
|
|
1139
|
+
provider: provider === 'anthropic' || provider === 'openai' ? provider : 'anthropic',
|
|
1140
|
+
model,
|
|
1141
|
+
},
|
|
1142
|
+
modeDescription: `xache-managed (${provider})`,
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
async function handleGraphExtract(
|
|
1148
|
+
client: XacheClient,
|
|
1149
|
+
args: {
|
|
1150
|
+
trace: string;
|
|
1151
|
+
domain?: string;
|
|
1152
|
+
mode?: 'api-key' | 'endpoint' | 'xache-managed';
|
|
1153
|
+
provider?: LLMProvider;
|
|
1154
|
+
model?: string;
|
|
1155
|
+
confidenceThreshold?: number;
|
|
1156
|
+
maxEntities?: number;
|
|
1157
|
+
subject?: Record<string, unknown>;
|
|
1158
|
+
}
|
|
1159
|
+
): Promise<string> {
|
|
1160
|
+
const { llmConfig, modeDescription } = buildLLMConfig(args);
|
|
1161
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1162
|
+
|
|
1163
|
+
const result = await client.graph.extract({
|
|
1164
|
+
trace: args.trace,
|
|
1165
|
+
llmConfig: llmConfig as any,
|
|
1166
|
+
subject,
|
|
1167
|
+
options: {
|
|
1168
|
+
contextHint: args.domain,
|
|
1169
|
+
confidenceThreshold: args.confidenceThreshold ?? 0.7,
|
|
1170
|
+
maxEntities: args.maxEntities,
|
|
1171
|
+
},
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
const entities = result.entities || [];
|
|
1175
|
+
const relationships = result.relationships || [];
|
|
1176
|
+
|
|
1177
|
+
if (entities.length === 0 && relationships.length === 0) {
|
|
1178
|
+
return 'No entities or relationships extracted from trace.';
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
let output = `Extracted ${entities.length} entities and ${relationships.length} relationships.\n`;
|
|
1182
|
+
output += `Mode: ${modeDescription}\n`;
|
|
1183
|
+
|
|
1184
|
+
if (entities.length > 0) {
|
|
1185
|
+
output += '\nEntities:\n';
|
|
1186
|
+
for (const e of entities) {
|
|
1187
|
+
output += ` • ${e.name} [${e.type}]${e.isNew ? ' (new)' : ''}${e.updated ? ' (updated)' : ''}\n`;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
if (relationships.length > 0) {
|
|
1192
|
+
output += '\nRelationships:\n';
|
|
1193
|
+
for (const r of relationships) {
|
|
1194
|
+
output += ` • ${r.from} → ${r.type} → ${r.to}${r.isNew ? ' (new)' : ''}\n`;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
if (result.temporalUpdates && result.temporalUpdates.length > 0) {
|
|
1199
|
+
output += `\n${result.temporalUpdates.length} temporal update(s) detected.`;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
output += `\nStored: ${result.stored} items`;
|
|
1203
|
+
return output;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
async function handleGraphLoad(
|
|
1207
|
+
client: XacheClient,
|
|
1208
|
+
args: {
|
|
1209
|
+
entityTypes?: string[];
|
|
1210
|
+
validAt?: string;
|
|
1211
|
+
subject?: Record<string, unknown>;
|
|
1212
|
+
}
|
|
1213
|
+
): Promise<string> {
|
|
1214
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1215
|
+
|
|
1216
|
+
const graph = await client.graph.load({
|
|
1217
|
+
subject,
|
|
1218
|
+
entityTypes: args.entityTypes,
|
|
1219
|
+
validAt: args.validAt,
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
const data = graph.toJSON();
|
|
1223
|
+
const entities = data.entities || [];
|
|
1224
|
+
const relationships = data.relationships || [];
|
|
1225
|
+
|
|
1226
|
+
if (entities.length === 0) {
|
|
1227
|
+
return 'Knowledge graph is empty.';
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
let output = `Knowledge graph: ${entities.length} entities, ${relationships.length} relationships\n`;
|
|
1231
|
+
|
|
1232
|
+
output += '\nEntities:\n';
|
|
1233
|
+
for (const e of entities) {
|
|
1234
|
+
output += ` • ${e.name} [${e.type}]`;
|
|
1235
|
+
if (e.summary) output += ` — ${e.summary.substring(0, 80)}`;
|
|
1236
|
+
output += '\n';
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
if (relationships.length > 0) {
|
|
1240
|
+
output += '\nRelationships:\n';
|
|
1241
|
+
for (const r of relationships) {
|
|
1242
|
+
output += ` • ${r.fromKey.substring(0, 8)}... → ${r.type} → ${r.toKey.substring(0, 8)}...`;
|
|
1243
|
+
if (r.description) output += ` (${r.description.substring(0, 60)})`;
|
|
1244
|
+
output += '\n';
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
return output;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
async function handleGraphQuery(
|
|
1252
|
+
client: XacheClient,
|
|
1253
|
+
args: {
|
|
1254
|
+
startEntity: string;
|
|
1255
|
+
depth?: number;
|
|
1256
|
+
relationshipTypes?: string[];
|
|
1257
|
+
validAt?: string;
|
|
1258
|
+
subject?: Record<string, unknown>;
|
|
1259
|
+
}
|
|
1260
|
+
): Promise<string> {
|
|
1261
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1262
|
+
|
|
1263
|
+
const graph = await client.graph.query({
|
|
1264
|
+
subject,
|
|
1265
|
+
startEntity: args.startEntity,
|
|
1266
|
+
depth: args.depth ?? 2,
|
|
1267
|
+
relationshipTypes: args.relationshipTypes,
|
|
1268
|
+
validAt: args.validAt,
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
const data = graph.toJSON();
|
|
1272
|
+
const entities = data.entities || [];
|
|
1273
|
+
const relationships = data.relationships || [];
|
|
1274
|
+
|
|
1275
|
+
if (entities.length === 0) {
|
|
1276
|
+
return `No entities found connected to "${args.startEntity}".`;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
let output = `Subgraph around "${args.startEntity}": ${entities.length} entities, ${relationships.length} relationships\n`;
|
|
1280
|
+
|
|
1281
|
+
output += '\nEntities:\n';
|
|
1282
|
+
for (const e of entities) {
|
|
1283
|
+
output += ` • ${e.name} [${e.type}]`;
|
|
1284
|
+
if (e.summary) output += ` — ${e.summary.substring(0, 80)}`;
|
|
1285
|
+
output += '\n';
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
if (relationships.length > 0) {
|
|
1289
|
+
output += '\nRelationships:\n';
|
|
1290
|
+
for (const r of relationships) {
|
|
1291
|
+
output += ` • ${r.fromKey.substring(0, 8)}... → ${r.type} → ${r.toKey.substring(0, 8)}...`;
|
|
1292
|
+
if (r.description) output += ` (${r.description.substring(0, 60)})`;
|
|
1293
|
+
output += '\n';
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
return output;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
async function handleGraphAsk(
|
|
1301
|
+
client: XacheClient,
|
|
1302
|
+
args: {
|
|
1303
|
+
question: string;
|
|
1304
|
+
mode?: 'api-key' | 'endpoint' | 'xache-managed';
|
|
1305
|
+
provider?: LLMProvider;
|
|
1306
|
+
model?: string;
|
|
1307
|
+
subject?: Record<string, unknown>;
|
|
1308
|
+
}
|
|
1309
|
+
): Promise<string> {
|
|
1310
|
+
const { llmConfig, modeDescription } = buildLLMConfig(args);
|
|
1311
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1312
|
+
|
|
1313
|
+
const answer = await client.graph.ask({
|
|
1314
|
+
subject,
|
|
1315
|
+
question: args.question,
|
|
1316
|
+
llmConfig: llmConfig as any,
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
let output = `Answer: ${answer.answer}\n`;
|
|
1320
|
+
output += `Confidence: ${(answer.confidence * 100).toFixed(0)}%\n`;
|
|
1321
|
+
output += `Mode: ${modeDescription}\n`;
|
|
1322
|
+
|
|
1323
|
+
if (answer.sources && answer.sources.length > 0) {
|
|
1324
|
+
output += '\nSources:\n';
|
|
1325
|
+
for (const s of answer.sources) {
|
|
1326
|
+
output += ` • ${s.name} [${s.type}]\n`;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
return output;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
async function handleGraphAddEntity(
|
|
1334
|
+
client: XacheClient,
|
|
1335
|
+
args: {
|
|
1336
|
+
name: string;
|
|
1337
|
+
type: string;
|
|
1338
|
+
summary?: string;
|
|
1339
|
+
attributes?: Record<string, unknown>;
|
|
1340
|
+
subject?: Record<string, unknown>;
|
|
1341
|
+
}
|
|
1342
|
+
): Promise<string> {
|
|
1343
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1344
|
+
|
|
1345
|
+
const entity = await client.graph.addEntity({
|
|
1346
|
+
subject,
|
|
1347
|
+
name: args.name,
|
|
1348
|
+
type: args.type,
|
|
1349
|
+
summary: args.summary,
|
|
1350
|
+
attributes: args.attributes,
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
return `Created entity "${entity.name}" [${entity.type}]\nKey: ${entity.key}\nStorage Key: ${entity.storageKey}`;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
async function handleGraphAddRelationship(
|
|
1357
|
+
client: XacheClient,
|
|
1358
|
+
args: {
|
|
1359
|
+
fromEntity: string;
|
|
1360
|
+
toEntity: string;
|
|
1361
|
+
type: string;
|
|
1362
|
+
description?: string;
|
|
1363
|
+
attributes?: Record<string, unknown>;
|
|
1364
|
+
subject?: Record<string, unknown>;
|
|
1365
|
+
}
|
|
1366
|
+
): Promise<string> {
|
|
1367
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1368
|
+
|
|
1369
|
+
const rel = await client.graph.addRelationship({
|
|
1370
|
+
subject,
|
|
1371
|
+
from: args.fromEntity,
|
|
1372
|
+
to: args.toEntity,
|
|
1373
|
+
type: args.type,
|
|
1374
|
+
description: args.description,
|
|
1375
|
+
attributes: args.attributes,
|
|
1376
|
+
});
|
|
1377
|
+
|
|
1378
|
+
return `Created relationship: ${args.fromEntity} → ${rel.type} → ${args.toEntity}\nStorage Key: ${rel.storageKey}`;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
async function handleGraphMergeEntities(
|
|
1382
|
+
client: XacheClient,
|
|
1383
|
+
args: {
|
|
1384
|
+
sourceName: string;
|
|
1385
|
+
targetName: string;
|
|
1386
|
+
subject?: Record<string, unknown>;
|
|
1387
|
+
}
|
|
1388
|
+
): Promise<string> {
|
|
1389
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1390
|
+
|
|
1391
|
+
const merged = await client.graph.mergeEntities({
|
|
1392
|
+
subject,
|
|
1393
|
+
sourceName: args.sourceName,
|
|
1394
|
+
targetName: args.targetName,
|
|
1395
|
+
});
|
|
1396
|
+
|
|
1397
|
+
return `Merged "${args.sourceName}" into "${args.targetName}".\nResult: ${merged.name} [${merged.type}] (v${merged.version})\nKey: ${merged.key}`;
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
async function handleGraphEntityHistory(
|
|
1401
|
+
client: XacheClient,
|
|
1402
|
+
args: {
|
|
1403
|
+
name: string;
|
|
1404
|
+
subject?: Record<string, unknown>;
|
|
1405
|
+
}
|
|
1406
|
+
): Promise<string> {
|
|
1407
|
+
const subject = buildSubjectContext(args as Record<string, unknown>);
|
|
1408
|
+
|
|
1409
|
+
const versions = await client.graph.getEntityHistory({
|
|
1410
|
+
subject,
|
|
1411
|
+
name: args.name,
|
|
1412
|
+
});
|
|
1413
|
+
|
|
1414
|
+
if (versions.length === 0) {
|
|
1415
|
+
return `No history found for entity "${args.name}".`;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
let output = `History for "${args.name}": ${versions.length} version(s)\n`;
|
|
1419
|
+
|
|
1420
|
+
for (const v of versions) {
|
|
1421
|
+
output += `\n v${v.version} — ${v.name} [${v.type}]`;
|
|
1422
|
+
if (v.summary) output += `\n Summary: ${v.summary.substring(0, 100)}`;
|
|
1423
|
+
output += `\n Valid: ${v.validFrom}${v.validTo ? ` → ${v.validTo}` : ' → current'}`;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
return output;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
806
1429
|
// =============================================================================
|
|
807
1430
|
// Server Setup
|
|
808
1431
|
// =============================================================================
|
|
@@ -813,7 +1436,7 @@ async function main(): Promise<void> {
|
|
|
813
1436
|
const server = new Server(
|
|
814
1437
|
{
|
|
815
1438
|
name: 'xache-mcp-server',
|
|
816
|
-
version: '0.
|
|
1439
|
+
version: '0.3.0',
|
|
817
1440
|
},
|
|
818
1441
|
{
|
|
819
1442
|
capabilities: {
|
|
@@ -872,6 +1495,30 @@ async function main(): Promise<void> {
|
|
|
872
1495
|
case 'xache_extract_and_contribute':
|
|
873
1496
|
result = await handleExtractAndContribute(client, args as any);
|
|
874
1497
|
break;
|
|
1498
|
+
case 'xache_graph_extract':
|
|
1499
|
+
result = await handleGraphExtract(client, args as any);
|
|
1500
|
+
break;
|
|
1501
|
+
case 'xache_graph_load':
|
|
1502
|
+
result = await handleGraphLoad(client, args as any);
|
|
1503
|
+
break;
|
|
1504
|
+
case 'xache_graph_query':
|
|
1505
|
+
result = await handleGraphQuery(client, args as any);
|
|
1506
|
+
break;
|
|
1507
|
+
case 'xache_graph_ask':
|
|
1508
|
+
result = await handleGraphAsk(client, args as any);
|
|
1509
|
+
break;
|
|
1510
|
+
case 'xache_graph_add_entity':
|
|
1511
|
+
result = await handleGraphAddEntity(client, args as any);
|
|
1512
|
+
break;
|
|
1513
|
+
case 'xache_graph_add_relationship':
|
|
1514
|
+
result = await handleGraphAddRelationship(client, args as any);
|
|
1515
|
+
break;
|
|
1516
|
+
case 'xache_graph_merge_entities':
|
|
1517
|
+
result = await handleGraphMergeEntities(client, args as any);
|
|
1518
|
+
break;
|
|
1519
|
+
case 'xache_graph_entity_history':
|
|
1520
|
+
result = await handleGraphEntityHistory(client, args as any);
|
|
1521
|
+
break;
|
|
875
1522
|
default:
|
|
876
1523
|
throw new Error(`Unknown tool: ${name}`);
|
|
877
1524
|
}
|