contradiction-mcp 0.3.2 → 0.3.4

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/dist/server.js CHANGED
@@ -16,7 +16,7 @@ function checkScope(scope, options) {
16
16
  }
17
17
  export function createMcpServer(options) {
18
18
  const name = options.name || 'contradiction-mcp';
19
- const version = options.version || '0.3.1';
19
+ const version = options.version || '0.3.4';
20
20
  const reviewService = options.reviewService ?? (options.dbManager ? new ReviewService(options.dbManager) : undefined);
21
21
  const resolutionAdvisor = options.resolutionAdvisor ?? new ResolutionAdvisor();
22
22
  const metricsService = options.metricsService ?? globalMetrics;
@@ -33,13 +33,38 @@ export function createMcpServer(options) {
33
33
  });
34
34
  const registerTool = (toolName, description, schema,
35
35
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
- handler) => {
37
- if (!schema || Object.keys(schema).length === 0) {
38
- server.registerTool(toolName, { description }, handler);
36
+ handler, annotations, outputSchema) => {
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ const toolConfig = { description };
39
+ if (schema && Object.keys(schema).length > 0) {
40
+ toolConfig.inputSchema = schema;
39
41
  }
40
- else {
41
- server.registerTool(toolName, { description, inputSchema: schema }, handler);
42
+ if (annotations) {
43
+ toolConfig.annotations = annotations;
42
44
  }
45
+ if (outputSchema) {
46
+ toolConfig.outputSchema = outputSchema;
47
+ }
48
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
49
+ const wrappedHandler = async (args) => {
50
+ const res = await handler(args);
51
+ if (outputSchema && res && !res.isError && res.structuredContent === undefined) {
52
+ if (Array.isArray(res.content) && res.content[0]?.text) {
53
+ try {
54
+ res.structuredContent = JSON.parse(res.content[0].text);
55
+ }
56
+ catch {
57
+ res.structuredContent = {};
58
+ }
59
+ }
60
+ else {
61
+ res.structuredContent = {};
62
+ }
63
+ }
64
+ return res;
65
+ };
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ server.registerTool(toolName, toolConfig, wrappedHandler);
43
68
  };
44
69
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
70
  server.tool = registerTool;
@@ -47,7 +72,7 @@ export function createMcpServer(options) {
47
72
  // CANONICAL TOOLSET (12 VERB_NOUN TOOLS)
48
73
  // ==========================================
49
74
  // 1. Tool: check_health
50
- registerTool('check_health', 'Checks the operational status of the Contradiction MCP server, including SQLite database connectivity, storage metrics, active connectors, and runtime diagnostics. Read-only and safe to invoke frequently for readiness and liveness probing.', {
75
+ registerTool('contradiction.health.check', 'Checks the operational status of the Contradiction MCP server, including SQLite database connectivity, storage metrics, active connectors, and runtime diagnostics. Read-only and safe to invoke frequently for readiness and liveness probing.', {
51
76
  verbose: z
52
77
  .boolean()
53
78
  .optional()
@@ -83,9 +108,36 @@ export function createMcpServer(options) {
83
108
  ],
84
109
  };
85
110
  }
111
+ }, {
112
+ readOnlyHint: true,
113
+ destructiveHint: false,
114
+ idempotentHint: true,
115
+ openWorldHint: false,
116
+ }, {
117
+ status: z
118
+ .string()
119
+ .optional()
120
+ .describe('Overall server operational health status (healthy, degraded, unhealthy)'),
121
+ server: z
122
+ .record(z.string(), z.unknown())
123
+ .optional()
124
+ .describe('Server metadata, version, and uptime'),
125
+ mcp: z
126
+ .record(z.string(), z.unknown())
127
+ .optional()
128
+ .describe('MCP protocol implementation details'),
129
+ database: z
130
+ .record(z.string(), z.unknown())
131
+ .optional()
132
+ .describe('SQLite storage and table status'),
133
+ timestamp: z.string().optional().describe('ISO-8601 status check timestamp'),
134
+ metrics: z
135
+ .record(z.string(), z.unknown())
136
+ .optional()
137
+ .describe('Operational snapshot metrics'),
86
138
  });
87
139
  // 2. Tool: list_sources
88
- registerTool('list_sources', 'Lists all registered external data source connectors (document, website, github) and ingested source entities tracked by the system, including source IDs, synchronization timestamps, and claim counts. Read-only operation. Use this tool to inspect available data sources before initiating scans or synchronization.', {
140
+ registerTool('contradiction.sources.list', 'Lists all registered external data source connectors (document, website, github) and ingested source entities tracked by the system, including source IDs, synchronization timestamps, and claim counts. Read-only operation. Use this tool to inspect available data sources before initiating scans or synchronization.', {
89
141
  type: z
90
142
  .enum(['document', 'website', 'github'])
91
143
  .optional()
@@ -136,9 +188,25 @@ export function createMcpServer(options) {
136
188
  ],
137
189
  };
138
190
  }
191
+ }, {
192
+ readOnlyHint: true,
193
+ destructiveHint: false,
194
+ idempotentHint: true,
195
+ openWorldHint: false,
196
+ }, {
197
+ count: z.number().optional().describe('Number of registered connector instances'),
198
+ connectors: z
199
+ .array(z.record(z.string(), z.unknown()))
200
+ .optional()
201
+ .describe('Registered connector configurations'),
202
+ sourcesCount: z.number().optional().describe('Number of ingested source records returned'),
203
+ sources: z
204
+ .array(z.record(z.string(), z.unknown()))
205
+ .optional()
206
+ .describe('Ingested source entity records'),
139
207
  });
140
208
  // 3. Tool: test_connection
141
- registerTool('test_connection', 'Validates connectivity, authentication, and accessibility for an external data source or connector (such as a GitHub repository, web URL, or local file) without persisting any data or modifying state. Use this tool to verify credentials and target reachability prior to running synchronization.', {
209
+ registerTool('contradiction.sources.test', 'Validates connectivity, authentication, and accessibility for an external data source or connector (such as a GitHub repository, web URL, or local file) without persisting any data or modifying state. Use this tool to verify credentials and target reachability prior to running synchronization.', {
142
210
  connector: z
143
211
  .enum(['github', 'website', 'document'])
144
212
  .describe('The connector type to validate (github, website, document)'),
@@ -217,9 +285,19 @@ export function createMcpServer(options) {
217
285
  ],
218
286
  };
219
287
  }
288
+ }, {
289
+ readOnlyHint: true,
290
+ destructiveHint: false,
291
+ idempotentHint: true,
292
+ openWorldHint: true,
293
+ }, {
294
+ connector: z.string().optional().describe('Connector type tested'),
295
+ target: z.string().optional().describe('Target identifier validated'),
296
+ accessible: z.boolean().optional().describe('Whether target was accessible'),
297
+ message: z.string().optional().describe('Diagnostic connection message'),
220
298
  });
221
299
  // 4. Tool: sync_source
222
- registerTool('sync_source', 'Ingests and synchronizes one or more external data sources (local document file, public website URL, or GitHub repository), extracts factual claims with exact line provenance, idempotently updates SQLite storage, and triggers automatic contradiction discovery. Mutating and idempotent operation. Supports single source ingestion or concurrent batch synchronization.', {
300
+ registerTool('contradiction.sources.sync', 'Ingests and synchronizes one or more external data sources (local document file, public website URL, or GitHub repository), extracts factual claims with exact line provenance, idempotently updates SQLite storage, and triggers automatic contradiction discovery. Mutating and idempotent operation. Supports single source ingestion or concurrent batch synchronization.', {
223
301
  connector: z
224
302
  .string()
225
303
  .describe('The external source connector to synchronize (document for local files, website for URLs, github for repositories)'),
@@ -346,9 +424,21 @@ export function createMcpServer(options) {
346
424
  ],
347
425
  };
348
426
  }
427
+ }, {
428
+ readOnlyHint: false,
429
+ destructiveHint: false,
430
+ idempotentHint: true,
431
+ openWorldHint: true,
432
+ }, {
433
+ status: z.string().optional().describe('Status of synchronization'),
434
+ connector: z.string().optional().describe('Connector used for sync'),
435
+ repository: z.string().optional().describe('Source name or repository synced'),
436
+ claimsCreated: z.number().optional().describe('Number of new claims created'),
437
+ claimsUpdated: z.number().optional().describe('Number of existing claims updated'),
438
+ durationMs: z.number().optional().describe('Sync execution duration in milliseconds'),
349
439
  });
350
440
  // 5. Tool: scan_contradictions
351
- registerTool('scan_contradictions', 'Discovers conflicting and inconsistent factual assertions across connected sources. Can scan the entire database, or scope the scan to a specific source, file, or single claim. Uses deterministic candidate grouping, entity resolution, and value comparison algorithms to detect and persist contradictions without duplicates. Mutating and idempotent.', {
441
+ registerTool('contradiction.conflicts.scan', 'Discovers conflicting and inconsistent factual assertions across connected sources. Can scan the entire database, or scope the scan to a specific source, file, or single claim. Uses deterministic candidate grouping, entity resolution, and value comparison algorithms to detect and persist contradictions without duplicates. Mutating and idempotent.', {
352
442
  sourceId: z
353
443
  .string()
354
444
  .optional()
@@ -417,9 +507,24 @@ export function createMcpServer(options) {
417
507
  ],
418
508
  };
419
509
  }
510
+ }, {
511
+ readOnlyHint: false,
512
+ destructiveHint: false,
513
+ idempotentHint: true,
514
+ openWorldHint: false,
515
+ }, {
516
+ count: z.number().optional().describe('Total number of contradictions detected'),
517
+ contradictions: z
518
+ .array(z.record(z.string(), z.unknown()))
519
+ .optional()
520
+ .describe('Detected contradiction records'),
521
+ scannedCount: z
522
+ .number()
523
+ .optional()
524
+ .describe('Total number of claim candidate pairs evaluated'),
420
525
  });
421
526
  // 6. Tool: analyze_claim_pair
422
- registerTool('analyze_claim_pair', 'Performs deep comparative analysis between two factual claims to determine whether they contradict each other. Evaluates semantic meaning, value differences, numeric/temporal ranges, and contextual dimensions (environment divergence, scope, source roles). Returns contradiction classification, severity, confidence score, and detailed explanation. Read-only operation.', {
527
+ registerTool('contradiction.claims.analyze', 'Performs deep comparative analysis between two factual claims to determine whether they contradict each other. Evaluates semantic meaning, value differences, numeric/temporal ranges, and contextual dimensions (environment divergence, scope, source roles). Returns contradiction classification, severity, confidence score, and detailed explanation. Read-only operation.', {
423
528
  claimAId: z.string().min(1).describe('The unique ID of the first claim'),
424
529
  claimBId: z.string().min(1).describe('The unique ID of the second claim'),
425
530
  explainContext: z
@@ -469,9 +574,30 @@ export function createMcpServer(options) {
469
574
  ],
470
575
  };
471
576
  }
577
+ }, {
578
+ readOnlyHint: true,
579
+ destructiveHint: false,
580
+ idempotentHint: true,
581
+ openWorldHint: false,
582
+ }, {
583
+ hasContradiction: z
584
+ .boolean()
585
+ .optional()
586
+ .describe('Whether a factual conflict was detected between the claims'),
587
+ severity: z
588
+ .string()
589
+ .nullable()
590
+ .optional()
591
+ .describe('Contradiction severity: LOW, MEDIUM, HIGH, CRITICAL'),
592
+ confidence: z.number().optional().describe('Confidence score between 0.0 and 1.0'),
593
+ explanation: z
594
+ .string()
595
+ .optional()
596
+ .describe('Detailed explanation of contradiction rationale'),
597
+ suggestedAction: z.string().nullable().optional().describe('Recommended resolution action'),
472
598
  });
473
599
  // 7. Tool: list_claims
474
- registerTool('list_claims', 'Queries stored factual assertions and claims extracted from connected sources with flexible filtering by subject, predicate, source, environment, and value type. Read-only operation. Use this tool to explore known facts, find subjects with multiple assertions, or inspect extracted data.', {
600
+ registerTool('contradiction.claims.list', 'Queries stored factual assertions and claims extracted from connected sources with flexible filtering by subject, predicate, source, environment, and value type. Read-only operation. Use this tool to explore known facts, find subjects with multiple assertions, or inspect extracted data.', {
475
601
  subject: z
476
602
  .string()
477
603
  .optional()
@@ -534,9 +660,21 @@ export function createMcpServer(options) {
534
660
  ],
535
661
  };
536
662
  }
663
+ }, {
664
+ readOnlyHint: true,
665
+ destructiveHint: false,
666
+ idempotentHint: true,
667
+ openWorldHint: false,
668
+ }, {
669
+ count: z.number().optional().describe('Number of claims returned in current page'),
670
+ total: z.number().optional().describe('Total count of claims matching filters'),
671
+ claims: z
672
+ .array(z.record(z.string(), z.unknown()))
673
+ .optional()
674
+ .describe('List of retrieved factual claims'),
537
675
  });
538
676
  // 8. Tool: get_claim
539
- registerTool('get_claim', 'Retrieves complete details for a single factual claim by ID, including its subject, predicate, current and normalized values, provenance evidence, originating source metadata, and chronological historical value transitions over time. Read-only operation.', {
677
+ registerTool('contradiction.claims.get', 'Retrieves complete details for a single factual claim by ID, including its subject, predicate, current and normalized values, provenance evidence, originating source metadata, and chronological historical value transitions over time. Read-only operation.', {
540
678
  claimId: z.string().min(1).describe('The unique ID of the claim to retrieve'),
541
679
  includeHistory: z
542
680
  .boolean()
@@ -577,9 +715,24 @@ export function createMcpServer(options) {
577
715
  ],
578
716
  };
579
717
  }
718
+ }, {
719
+ readOnlyHint: true,
720
+ destructiveHint: false,
721
+ idempotentHint: true,
722
+ openWorldHint: false,
723
+ }, {
724
+ claim: z
725
+ .record(z.string(), z.unknown())
726
+ .nullable()
727
+ .optional()
728
+ .describe('Retrieved claim record'),
729
+ history: z
730
+ .array(z.record(z.string(), z.unknown()))
731
+ .optional()
732
+ .describe('Chronological history of claim values'),
580
733
  });
581
734
  // 9. Tool: list_contradictions
582
- registerTool('list_contradictions', 'Queries stored contradiction records from the database with filtering by resolution status, severity level, contradiction type, and confidence score. Returns enriched contradiction records with associated claim summaries and originating source details. Read-only operation. Use this tool to prioritize and triage conflicts.', {
735
+ registerTool('contradiction.conflicts.list', 'Queries stored contradiction records from the database with filtering by resolution status, severity level, contradiction type, and confidence score. Returns enriched contradiction records with associated claim summaries and originating source details. Read-only operation. Use this tool to prioritize and triage conflicts.', {
583
736
  status: z
584
737
  .enum(ContradictionStatuses)
585
738
  .optional()
@@ -677,9 +830,21 @@ export function createMcpServer(options) {
677
830
  ],
678
831
  };
679
832
  }
833
+ }, {
834
+ readOnlyHint: true,
835
+ destructiveHint: false,
836
+ idempotentHint: true,
837
+ openWorldHint: false,
838
+ }, {
839
+ count: z.number().optional().describe('Number of contradictions returned in current page'),
840
+ total: z.number().optional().describe('Total count of contradictions matching filter'),
841
+ contradictions: z
842
+ .array(z.record(z.string(), z.unknown()))
843
+ .optional()
844
+ .describe('List of contradiction records'),
680
845
  });
681
846
  // 10. Tool: get_contradiction
682
- registerTool('get_contradiction', 'Retrieves complete details of a single contradiction record by ID, including full representations of both conflicting claims, originating source metadata, exact line evidence snippets, and chronological audit trail of all review and resolution actions. Read-only operation.', {
847
+ registerTool('contradiction.conflicts.get', 'Retrieves complete details of a single contradiction record by ID, including full representations of both conflicting claims, originating source metadata, exact line evidence snippets, and chronological audit trail of all review and resolution actions. Read-only operation.', {
683
848
  contradictionId: z
684
849
  .string()
685
850
  .min(1)
@@ -724,9 +889,24 @@ export function createMcpServer(options) {
724
889
  ],
725
890
  };
726
891
  }
892
+ }, {
893
+ readOnlyHint: true,
894
+ destructiveHint: false,
895
+ idempotentHint: true,
896
+ openWorldHint: false,
897
+ }, {
898
+ contradiction: z
899
+ .record(z.string(), z.unknown())
900
+ .nullable()
901
+ .optional()
902
+ .describe('Full contradiction details'),
903
+ auditTrail: z
904
+ .array(z.record(z.string(), z.unknown()))
905
+ .optional()
906
+ .describe('Review and resolution audit history'),
727
907
  });
728
908
  // 11. Tool: advise_resolution
729
- registerTool('advise_resolution', 'Generates deterministic authority, freshness, and evidence comparison between conflicting claims to advise an AI agent or human reviewer on which claim likely represents current truth and recommended remediation steps. Read-only deterministic calculation.', {
909
+ registerTool('contradiction.conflicts.advise', 'Generates deterministic authority, freshness, and evidence comparison between conflicting claims to advise an AI agent or human reviewer on which claim likely represents current truth and recommended remediation steps. Read-only deterministic calculation.', {
730
910
  contradictionId: z
731
911
  .string()
732
912
  .min(1)
@@ -760,9 +940,25 @@ export function createMcpServer(options) {
760
940
  ],
761
941
  };
762
942
  }
943
+ }, {
944
+ readOnlyHint: true,
945
+ destructiveHint: false,
946
+ idempotentHint: true,
947
+ openWorldHint: false,
948
+ }, {
949
+ contradictionId: z.string().optional().describe('ID of the analyzed contradiction'),
950
+ recommendedAction: z
951
+ .string()
952
+ .optional()
953
+ .describe('Recommended action: accept_source_a, accept_source_b, update_both, investigate'),
954
+ confidence: z.number().optional().describe('Confidence score from 0.0 to 1.0'),
955
+ rationale: z
956
+ .string()
957
+ .optional()
958
+ .describe('Authority and temporal rationale for the resolution advice'),
763
959
  });
764
960
  // 12. Tool: resolve_contradiction
765
- registerTool('resolve_contradiction', 'Updates the lifecycle status and audit trail of a contradiction record. Supports marking as REVIEWED, resolving as RESOLVED with an authoritative chosen claim, dismissing as DISMISSED (acceptable divergence), or reopening back to OPEN. Preserves an immutable audit trail of reviewer identity, decision reason, and timestamp. Mutating operation.', {
961
+ registerTool('contradiction.conflicts.resolve', 'Updates the lifecycle status and audit trail of a contradiction record. Supports marking as REVIEWED, resolving as RESOLVED with an authoritative chosen claim, dismissing as DISMISSED (acceptable divergence), or reopening back to OPEN. Preserves an immutable audit trail of reviewer identity, decision reason, and timestamp. Mutating operation.', {
766
962
  contradictionId: z
767
963
  .string()
768
964
  .min(1)
@@ -848,6 +1044,15 @@ export function createMcpServer(options) {
848
1044
  ],
849
1045
  };
850
1046
  }
1047
+ }, {
1048
+ readOnlyHint: false,
1049
+ destructiveHint: false,
1050
+ idempotentHint: true,
1051
+ openWorldHint: false,
1052
+ }, {
1053
+ id: z.string().optional().describe('ID of the updated contradiction'),
1054
+ status: z.string().optional().describe('Updated contradiction lifecycle status'),
1055
+ chosenClaimId: z.string().nullable().optional().describe('Authoritative claim ID chosen'),
851
1056
  });
852
1057
  // ==========================================
853
1058
  // BACKWARDS COMPATIBILITY ROUTING SHIM
@@ -862,11 +1067,29 @@ export function createMcpServer(options) {
862
1067
  rawRequestHandlers.set('tools/call', async (request, ctx) => {
863
1068
  const toolName = request.params?.name;
864
1069
  const args = request.params?.arguments || {};
865
- if (toolName === 'health_check') {
866
- request.params.name = 'check_health';
1070
+ // Map canonical snake_case to dot-notation names
1071
+ const canonicalMap = {
1072
+ check_health: 'contradiction.health.check',
1073
+ list_sources: 'contradiction.sources.list',
1074
+ test_connection: 'contradiction.sources.test',
1075
+ sync_source: 'contradiction.sources.sync',
1076
+ scan_contradictions: 'contradiction.conflicts.scan',
1077
+ analyze_claim_pair: 'contradiction.claims.analyze',
1078
+ list_claims: 'contradiction.claims.list',
1079
+ get_claim: 'contradiction.claims.get',
1080
+ list_contradictions: 'contradiction.conflicts.list',
1081
+ get_contradiction: 'contradiction.conflicts.get',
1082
+ advise_resolution: 'contradiction.conflicts.advise',
1083
+ resolve_contradiction: 'contradiction.conflicts.resolve',
1084
+ };
1085
+ if (canonicalMap[toolName]) {
1086
+ request.params.name = canonicalMap[toolName];
1087
+ }
1088
+ else if (toolName === 'health_check') {
1089
+ request.params.name = 'contradiction.health.check';
867
1090
  }
868
1091
  else if (toolName === 'list_connectors') {
869
- request.params.name = 'list_sources';
1092
+ request.params.name = 'contradiction.sources.list';
870
1093
  }
871
1094
  else if (toolName === 'test_github_connection') {
872
1095
  if (!args.owner || !args.repo) {
@@ -880,7 +1103,7 @@ export function createMcpServer(options) {
880
1103
  ],
881
1104
  };
882
1105
  }
883
- request.params.name = 'test_connection';
1106
+ request.params.name = 'contradiction.sources.test';
884
1107
  request.params.arguments = {
885
1108
  connector: 'github',
886
1109
  target: `${args.owner}/${args.repo}`,
@@ -888,7 +1111,7 @@ export function createMcpServer(options) {
888
1111
  };
889
1112
  }
890
1113
  else if (toolName === 'sync_document') {
891
- request.params.name = 'sync_source';
1114
+ request.params.name = 'contradiction.sources.sync';
892
1115
  request.params.arguments = {
893
1116
  connector: 'document',
894
1117
  source: args.filePath,
@@ -901,7 +1124,7 @@ export function createMcpServer(options) {
901
1124
  };
902
1125
  }
903
1126
  else if (toolName === 'sync_website') {
904
- request.params.name = 'sync_source';
1127
+ request.params.name = 'contradiction.sources.sync';
905
1128
  request.params.arguments = {
906
1129
  connector: 'website',
907
1130
  source: args.url,
@@ -910,7 +1133,7 @@ export function createMcpServer(options) {
910
1133
  };
911
1134
  }
912
1135
  else if (toolName === 'sync_github_repository') {
913
- request.params.name = 'sync_source';
1136
+ request.params.name = 'contradiction.sources.sync';
914
1137
  request.params.arguments = {
915
1138
  connector: 'github',
916
1139
  source: `${args.owner}/${args.repo}`,
@@ -919,7 +1142,7 @@ export function createMcpServer(options) {
919
1142
  };
920
1143
  }
921
1144
  else if (toolName === 'sync_sources') {
922
- request.params.name = 'sync_source';
1145
+ request.params.name = 'contradiction.sources.sync';
923
1146
  request.params.arguments = {
924
1147
  connector: 'document',
925
1148
  source: 'batch',
@@ -928,7 +1151,7 @@ export function createMcpServer(options) {
928
1151
  };
929
1152
  }
930
1153
  else if (toolName === 'scan_for_contradictions') {
931
- request.params.name = 'scan_contradictions';
1154
+ request.params.name = 'contradiction.conflicts.scan';
932
1155
  request.params.arguments = {
933
1156
  limit: args.limit,
934
1157
  minConfidence: args.minConfidence,
@@ -936,14 +1159,14 @@ export function createMcpServer(options) {
936
1159
  };
937
1160
  }
938
1161
  else if (toolName === 'scan_claim_for_contradictions') {
939
- request.params.name = 'scan_contradictions';
1162
+ request.params.name = 'contradiction.conflicts.scan';
940
1163
  request.params.arguments = {
941
1164
  claimId: args.claimId,
942
1165
  minConfidence: args.minConfidence,
943
1166
  };
944
1167
  }
945
1168
  else if (toolName === 'scan_source_for_contradictions') {
946
- request.params.name = 'scan_contradictions';
1169
+ request.params.name = 'contradiction.conflicts.scan';
947
1170
  request.params.arguments = {
948
1171
  sourceId: args.sourceId,
949
1172
  minConfidence: args.minConfidence,
@@ -952,7 +1175,7 @@ export function createMcpServer(options) {
952
1175
  };
953
1176
  }
954
1177
  else if (toolName === 'explain_claim_relationship') {
955
- request.params.name = 'analyze_claim_pair';
1178
+ request.params.name = 'contradiction.claims.analyze';
956
1179
  request.params.arguments = {
957
1180
  claimAId: args.claimAId,
958
1181
  claimBId: args.claimBId,
@@ -960,7 +1183,7 @@ export function createMcpServer(options) {
960
1183
  };
961
1184
  }
962
1185
  else if (toolName === 'review_contradiction') {
963
- request.params.name = 'resolve_contradiction';
1186
+ request.params.name = 'contradiction.conflicts.resolve';
964
1187
  request.params.arguments = {
965
1188
  contradictionId: args.contradictionId,
966
1189
  action: 'REVIEW',
@@ -969,7 +1192,7 @@ export function createMcpServer(options) {
969
1192
  };
970
1193
  }
971
1194
  else if (toolName === 'dismiss_contradiction') {
972
- request.params.name = 'resolve_contradiction';
1195
+ request.params.name = 'contradiction.conflicts.resolve';
973
1196
  request.params.arguments = {
974
1197
  contradictionId: args.contradictionId,
975
1198
  action: 'DISMISS',
@@ -979,7 +1202,7 @@ export function createMcpServer(options) {
979
1202
  };
980
1203
  }
981
1204
  else if (toolName === 'reopen_contradiction') {
982
- request.params.name = 'resolve_contradiction';
1205
+ request.params.name = 'contradiction.conflicts.resolve';
983
1206
  request.params.arguments = {
984
1207
  contradictionId: args.contradictionId,
985
1208
  action: 'REOPEN',
@@ -989,19 +1212,23 @@ export function createMcpServer(options) {
989
1212
  };
990
1213
  }
991
1214
  else if (toolName === 'get_contradiction_history') {
992
- request.params.name = 'get_contradiction';
1215
+ request.params.name = 'contradiction.conflicts.get';
993
1216
  request.params.arguments = {
994
1217
  contradictionId: args.contradictionId,
995
1218
  includeAuditHistory: true,
996
1219
  };
997
1220
  }
998
1221
  else if (toolName === 'get_claim_history') {
999
- request.params.name = 'get_claim';
1222
+ request.params.name = 'contradiction.claims.get';
1000
1223
  request.params.arguments = {
1001
1224
  claimId: args.claimId,
1002
1225
  includeHistory: true,
1003
1226
  };
1004
1227
  }
1228
+ // Safety fallback: if request.params.name is still in canonicalMap, map to dot notation
1229
+ if (canonicalMap[request.params.name]) {
1230
+ request.params.name = canonicalMap[request.params.name];
1231
+ }
1005
1232
  return canonicalCallHandler(request, ctx);
1006
1233
  });
1007
1234
  // --- MCP RESOURCES ---