@cyanheads/sanctions-screening-mcp-server 0.1.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.
Files changed (110) hide show
  1. package/AGENTS.md +452 -0
  2. package/CLAUDE.md +452 -0
  3. package/Dockerfile +126 -0
  4. package/LICENSE +201 -0
  5. package/README.md +354 -0
  6. package/changelog/0.1.x/0.1.0.md +26 -0
  7. package/changelog/template.md +127 -0
  8. package/dist/config/server-config.d.ts +37 -0
  9. package/dist/config/server-config.d.ts.map +1 -0
  10. package/dist/config/server-config.js +87 -0
  11. package/dist/config/server-config.js.map +1 -0
  12. package/dist/index.d.ts +11 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +70 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/mcp-server/prompts/definitions/index.d.ts +12 -0
  17. package/dist/mcp-server/prompts/definitions/index.d.ts.map +1 -0
  18. package/dist/mcp-server/prompts/definitions/index.js +9 -0
  19. package/dist/mcp-server/prompts/definitions/index.js.map +1 -0
  20. package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.d.ts +14 -0
  21. package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.d.ts.map +1 -0
  22. package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.js +42 -0
  23. package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.js.map +1 -0
  24. package/dist/mcp-server/resources/definitions/designation.resource.d.ts +25 -0
  25. package/dist/mcp-server/resources/definitions/designation.resource.d.ts.map +1 -0
  26. package/dist/mcp-server/resources/definitions/designation.resource.js +57 -0
  27. package/dist/mcp-server/resources/definitions/designation.resource.js.map +1 -0
  28. package/dist/mcp-server/resources/definitions/entity.resource.d.ts +17 -0
  29. package/dist/mcp-server/resources/definitions/entity.resource.d.ts.map +1 -0
  30. package/dist/mcp-server/resources/definitions/entity.resource.js +40 -0
  31. package/dist/mcp-server/resources/definitions/entity.resource.js.map +1 -0
  32. package/dist/mcp-server/resources/definitions/index.d.ts +32 -0
  33. package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
  34. package/dist/mcp-server/resources/definitions/index.js +11 -0
  35. package/dist/mcp-server/resources/definitions/index.js.map +1 -0
  36. package/dist/mcp-server/resources/definitions/sources.resource.d.ts +9 -0
  37. package/dist/mcp-server/resources/definitions/sources.resource.d.ts.map +1 -0
  38. package/dist/mcp-server/resources/definitions/sources.resource.js +50 -0
  39. package/dist/mcp-server/resources/definitions/sources.resource.js.map +1 -0
  40. package/dist/mcp-server/tools/definitions/_shared.d.ts +13 -0
  41. package/dist/mcp-server/tools/definitions/_shared.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/definitions/_shared.js +13 -0
  43. package/dist/mcp-server/tools/definitions/_shared.js.map +1 -0
  44. package/dist/mcp-server/tools/definitions/get-designation.tool.d.ts +78 -0
  45. package/dist/mcp-server/tools/definitions/get-designation.tool.d.ts.map +1 -0
  46. package/dist/mcp-server/tools/definitions/get-designation.tool.js +168 -0
  47. package/dist/mcp-server/tools/definitions/get-designation.tool.js.map +1 -0
  48. package/dist/mcp-server/tools/definitions/get-entity.tool.d.ts +55 -0
  49. package/dist/mcp-server/tools/definitions/get-entity.tool.d.ts.map +1 -0
  50. package/dist/mcp-server/tools/definitions/get-entity.tool.js +176 -0
  51. package/dist/mcp-server/tools/definitions/get-entity.tool.js.map +1 -0
  52. package/dist/mcp-server/tools/definitions/index.d.ts +306 -0
  53. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
  54. package/dist/mcp-server/tools/definitions/index.js +21 -0
  55. package/dist/mcp-server/tools/definitions/index.js.map +1 -0
  56. package/dist/mcp-server/tools/definitions/list-sources.tool.d.ts +23 -0
  57. package/dist/mcp-server/tools/definitions/list-sources.tool.d.ts.map +1 -0
  58. package/dist/mcp-server/tools/definitions/list-sources.tool.js +106 -0
  59. package/dist/mcp-server/tools/definitions/list-sources.tool.js.map +1 -0
  60. package/dist/mcp-server/tools/definitions/resolve-entity.tool.d.ts +51 -0
  61. package/dist/mcp-server/tools/definitions/resolve-entity.tool.d.ts.map +1 -0
  62. package/dist/mcp-server/tools/definitions/resolve-entity.tool.js +148 -0
  63. package/dist/mcp-server/tools/definitions/resolve-entity.tool.js.map +1 -0
  64. package/dist/mcp-server/tools/definitions/screen-name.tool.d.ts +82 -0
  65. package/dist/mcp-server/tools/definitions/screen-name.tool.d.ts.map +1 -0
  66. package/dist/mcp-server/tools/definitions/screen-name.tool.js +172 -0
  67. package/dist/mcp-server/tools/definitions/screen-name.tool.js.map +1 -0
  68. package/dist/mcp-server/tools/definitions/trace-ownership.tool.d.ts +74 -0
  69. package/dist/mcp-server/tools/definitions/trace-ownership.tool.d.ts.map +1 -0
  70. package/dist/mcp-server/tools/definitions/trace-ownership.tool.js +273 -0
  71. package/dist/mcp-server/tools/definitions/trace-ownership.tool.js.map +1 -0
  72. package/dist/services/screening/fixtures.d.ts +17 -0
  73. package/dist/services/screening/fixtures.d.ts.map +1 -0
  74. package/dist/services/screening/fixtures.js +162 -0
  75. package/dist/services/screening/fixtures.js.map +1 -0
  76. package/dist/services/screening/gleif-ingest.d.ts +68 -0
  77. package/dist/services/screening/gleif-ingest.d.ts.map +1 -0
  78. package/dist/services/screening/gleif-ingest.js +251 -0
  79. package/dist/services/screening/gleif-ingest.js.map +1 -0
  80. package/dist/services/screening/sanctions-ingest.d.ts +46 -0
  81. package/dist/services/screening/sanctions-ingest.d.ts.map +1 -0
  82. package/dist/services/screening/sanctions-ingest.js +688 -0
  83. package/dist/services/screening/sanctions-ingest.js.map +1 -0
  84. package/dist/services/screening/schema.d.ts +52 -0
  85. package/dist/services/screening/schema.d.ts.map +1 -0
  86. package/dist/services/screening/schema.js +125 -0
  87. package/dist/services/screening/schema.js.map +1 -0
  88. package/dist/services/screening/screening-service.d.ts +203 -0
  89. package/dist/services/screening/screening-service.d.ts.map +1 -0
  90. package/dist/services/screening/screening-service.js +702 -0
  91. package/dist/services/screening/screening-service.js.map +1 -0
  92. package/dist/services/screening/text-matching.d.ts +53 -0
  93. package/dist/services/screening/text-matching.d.ts.map +1 -0
  94. package/dist/services/screening/text-matching.js +514 -0
  95. package/dist/services/screening/text-matching.js.map +1 -0
  96. package/dist/services/screening/types.d.ts +154 -0
  97. package/dist/services/screening/types.d.ts.map +1 -0
  98. package/dist/services/screening/types.js +24 -0
  99. package/dist/services/screening/types.js.map +1 -0
  100. package/dist/services/screening/xml.d.ts +29 -0
  101. package/dist/services/screening/xml.d.ts.map +1 -0
  102. package/dist/services/screening/xml.js +46 -0
  103. package/dist/services/screening/xml.js.map +1 -0
  104. package/package.json +119 -0
  105. package/scripts/_mirror-context.ts +21 -0
  106. package/scripts/mirror-init.ts +66 -0
  107. package/scripts/mirror-refresh.ts +56 -0
  108. package/scripts/mirror-seed.ts +36 -0
  109. package/scripts/mirror-verify.ts +44 -0
  110. package/server.json +148 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * @fileoverview `sanctions_trace_ownership` — the GLEIF Level 2 ownership graph
3
+ * for an LEI: direct and ultimate parents and children, with relationship type,
4
+ * traversed breadth-first to a bounded depth. Optionally screens every node
5
+ * against the watchlists — beneficial-ownership screening that single-list tools
6
+ * can't do, and the cross-source workflow that justifies one server over two.
7
+ * @module mcp-server/tools/definitions/trace-ownership.tool
8
+ */
9
+ import { z } from '@cyanheads/mcp-ts-core';
10
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
11
+ export declare const traceOwnershipTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
12
+ lei: z.ZodString;
13
+ direction: z.ZodDefault<z.ZodEnum<{
14
+ parents: "parents";
15
+ children: "children";
16
+ both: "both";
17
+ }>>;
18
+ depth: z.ZodDefault<z.ZodNumber>;
19
+ screenNodes: z.ZodDefault<z.ZodBoolean>;
20
+ }, z.core.$strip>, z.ZodObject<{
21
+ rootLei: z.ZodString;
22
+ nodes: z.ZodArray<z.ZodObject<{
23
+ lei: z.ZodString;
24
+ legalName: z.ZodString;
25
+ jurisdiction: z.ZodOptional<z.ZodString>;
26
+ status: z.ZodOptional<z.ZodString>;
27
+ depth: z.ZodNumber;
28
+ role: z.ZodEnum<{
29
+ root: "root";
30
+ parent: "parent";
31
+ child: "child";
32
+ }>;
33
+ sanctionsHits: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
+ source: z.ZodEnum<{
35
+ ofac_sdn: "ofac_sdn";
36
+ ofac_consolidated: "ofac_consolidated";
37
+ eu: "eu";
38
+ uk: "uk";
39
+ un: "un";
40
+ }>;
41
+ sourceLabel: z.ZodString;
42
+ sourceEntryId: z.ZodString;
43
+ primaryName: z.ZodString;
44
+ matchedName: z.ZodString;
45
+ matchType: z.ZodEnum<{
46
+ exact: "exact";
47
+ strong: "strong";
48
+ approximate: "approximate";
49
+ }>;
50
+ score: z.ZodOptional<z.ZodNumber>;
51
+ }, z.core.$strip>>>;
52
+ }, z.core.$strip>>;
53
+ edges: z.ZodArray<z.ZodObject<{
54
+ childLei: z.ZodString;
55
+ parentLei: z.ZodString;
56
+ relationshipType: z.ZodString;
57
+ relationshipStatus: z.ZodOptional<z.ZodString>;
58
+ }, z.core.$strip>>;
59
+ screenedNodeCount: z.ZodNumber;
60
+ flaggedNodeCount: z.ZodNumber;
61
+ caveat: z.ZodString;
62
+ }, z.core.$strip>, readonly [{
63
+ readonly reason: "lei_not_found";
64
+ readonly code: JsonRpcErrorCode.NotFound;
65
+ readonly when: "No GLEIF entity exists for the root LEI in the mirror.";
66
+ readonly recovery: "Resolve the entity name with sanctions_resolve_entity to obtain a valid root LEI first.";
67
+ }, {
68
+ readonly reason: "mirror_not_ready";
69
+ readonly code: JsonRpcErrorCode.ServiceUnavailable;
70
+ readonly when: "The GLEIF (LEI) mirror has never completed an initial sync.";
71
+ readonly retryable: true;
72
+ readonly recovery: "Run the mirror:init lifecycle script to load the GLEIF golden copy + relationships, then retry.";
73
+ }], undefined>;
74
+ //# sourceMappingURL=trace-ownership.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-ownership.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/trace-ownership.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAyEjE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoP7B,CAAC"}
@@ -0,0 +1,273 @@
1
+ /**
2
+ * @fileoverview `sanctions_trace_ownership` — the GLEIF Level 2 ownership graph
3
+ * for an LEI: direct and ultimate parents and children, with relationship type,
4
+ * traversed breadth-first to a bounded depth. Optionally screens every node
5
+ * against the watchlists — beneficial-ownership screening that single-list tools
6
+ * can't do, and the cross-source workflow that justifies one server over two.
7
+ * @module mcp-server/tools/definitions/trace-ownership.tool
8
+ */
9
+ import { tool, z } from '@cyanheads/mcp-ts-core';
10
+ import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
11
+ import { getScreeningService } from '../../../services/screening/screening-service.js';
12
+ import { SOURCE_CODES, SOURCE_LABELS } from '../../../services/screening/types.js';
13
+ import { SCREENING_CAVEAT } from './_shared.js';
14
+ const LEI_RE = /^[A-Z0-9]{18}[0-9]{2}$/;
15
+ /**
16
+ * Breadth-first traversal over the relationship table to `depth`, in the
17
+ * requested direction(s). Returns nodes (deduped) and edges. The traversal is
18
+ * bounded by `depth` and by the relationship table itself (the mirror's corpus),
19
+ * so it terminates even on cyclic ownership structures via the visited set.
20
+ */
21
+ async function traverse(svc, rootLei, direction, depth) {
22
+ const nodes = new Map();
23
+ const edges = [];
24
+ const seenEdges = new Set();
25
+ nodes.set(rootLei, { lei: rootLei, legalName: rootLei, depth: 0, role: 'root' });
26
+ let frontier = [rootLei];
27
+ for (let level = 0; level < depth && frontier.length > 0; level++) {
28
+ const next = [];
29
+ for (const lei of frontier) {
30
+ const rels = await svc.getRelationships(lei, direction);
31
+ for (const rel of rels) {
32
+ const edgeKey = `${rel.childLei}|${rel.parentLei}|${rel.relationshipType}`;
33
+ if (!seenEdges.has(edgeKey)) {
34
+ seenEdges.add(edgeKey);
35
+ edges.push({
36
+ childLei: rel.childLei,
37
+ parentLei: rel.parentLei,
38
+ relationshipType: rel.relationshipType,
39
+ ...(rel.relationshipStatus ? { relationshipStatus: rel.relationshipStatus } : {}),
40
+ });
41
+ }
42
+ // The neighbor is whichever end of the edge isn't `lei`.
43
+ const neighbor = rel.childLei === lei ? rel.parentLei : rel.childLei;
44
+ const role = rel.childLei === lei ? 'parent' : 'child';
45
+ if (!nodes.has(neighbor)) {
46
+ nodes.set(neighbor, { lei: neighbor, legalName: neighbor, depth: level + 1, role });
47
+ next.push(neighbor);
48
+ }
49
+ }
50
+ }
51
+ frontier = next;
52
+ }
53
+ return { nodes, edges };
54
+ }
55
+ export const traceOwnershipTool = tool('sanctions_trace_ownership', {
56
+ title: 'sanctions-screening-mcp-server: trace ownership',
57
+ description: 'Trace the GLEIF Level 2 corporate-ownership graph for an LEI: direct and ultimate parents and/or children, traversed breadth-first to a bounded depth, with relationship type for each edge. Set screen_nodes to also screen every entity in the graph against all loaded watchlists — beneficial-ownership screening that resolves "is anyone in this ownership chain sanctioned." Each per-node screen is a screening AID: hits are candidates to verify, and an empty result for a node is not a clearance of that node. Requires a valid 20-character LEI (use sanctions_resolve_entity to obtain one).',
58
+ annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
59
+ input: z.object({
60
+ lei: z
61
+ .string()
62
+ .regex(LEI_RE, 'LEI must be 20 chars: 18 alphanumerics + 2 check digits.')
63
+ .describe('The 20-character GLEIF LEI at the root of the ownership graph.'),
64
+ direction: z
65
+ .enum(['parents', 'children', 'both'])
66
+ .default('both')
67
+ .describe('Walk parents (who owns it), children (what it owns), or both (default).'),
68
+ depth: z
69
+ .number()
70
+ .int()
71
+ .min(1)
72
+ .max(5)
73
+ .default(3)
74
+ .describe('Maximum traversal depth from the root entity (1–5).'),
75
+ screenNodes: z
76
+ .boolean()
77
+ .default(false)
78
+ .describe("When true, screen every node's legal name against all watchlists for beneficial-ownership screening."),
79
+ }),
80
+ output: z.object({
81
+ rootLei: z.string().describe('The LEI the traversal started from.'),
82
+ nodes: z
83
+ .array(z
84
+ .object({
85
+ lei: z.string().describe("The node's LEI."),
86
+ legalName: z
87
+ .string()
88
+ .describe("The node's legal name (the LEI itself if not hydrated)."),
89
+ jurisdiction: z.string().optional().describe('Jurisdiction (ISO code), when known.'),
90
+ status: z.string().optional().describe('GLEIF registration status, when known.'),
91
+ depth: z.number().describe('Breadth-first depth from the root (root = 0).'),
92
+ role: z
93
+ .enum(['root', 'parent', 'child'])
94
+ .describe('Position relative to the traversal.'),
95
+ sanctionsHits: z
96
+ .array(z
97
+ .object({
98
+ source: z
99
+ .enum(['ofac_sdn', 'ofac_consolidated', 'eu', 'uk', 'un'])
100
+ .describe('Watchlist the candidate is on.'),
101
+ sourceLabel: z.string().describe('Human-readable source list name.'),
102
+ sourceEntryId: z
103
+ .string()
104
+ .describe('Source entry ID — pass to sanctions_get_designation.'),
105
+ primaryName: z.string().describe('Primary published name of the designation.'),
106
+ matchedName: z.string().describe('The name/alias that matched this node.'),
107
+ matchType: z
108
+ .enum(['exact', 'strong', 'approximate'])
109
+ .describe('Match classification.'),
110
+ score: z
111
+ .number()
112
+ .optional()
113
+ .describe('Raw Jaro-Winkler similarity (0–1) for approximate hits only.'),
114
+ })
115
+ .describe('A potential watchlist match on this node — verify, do not assume.'))
116
+ .optional()
117
+ .describe('Per-node screening results, present only when screen_nodes is true.'),
118
+ })
119
+ .describe('One entity in the ownership graph.'))
120
+ .describe('All entities reached in the traversal, including the root.'),
121
+ edges: z
122
+ .array(z
123
+ .object({
124
+ childLei: z.string().describe('LEI of the owned (child) entity.'),
125
+ parentLei: z.string().describe('LEI of the owning (parent) entity.'),
126
+ relationshipType: z
127
+ .string()
128
+ .describe('GLEIF relationship type (e.g. IS_DIRECTLY_CONSOLIDATED_BY).'),
129
+ relationshipStatus: z
130
+ .string()
131
+ .optional()
132
+ .describe('Relationship status, when published.'),
133
+ })
134
+ .describe('One directed ownership edge (child is consolidated by parent).'))
135
+ .describe('Directed ownership edges between the nodes.'),
136
+ screenedNodeCount: z
137
+ .number()
138
+ .describe('How many nodes were screened (0 when screen_nodes is false).'),
139
+ flaggedNodeCount: z
140
+ .number()
141
+ .describe('How many screened nodes had at least one potential watchlist match.'),
142
+ caveat: z
143
+ .string()
144
+ .describe('Decision-support caveat — node screening is an aid, not a determination.'),
145
+ }),
146
+ errors: [
147
+ {
148
+ reason: 'lei_not_found',
149
+ code: JsonRpcErrorCode.NotFound,
150
+ when: 'No GLEIF entity exists for the root LEI in the mirror.',
151
+ recovery: 'Resolve the entity name with sanctions_resolve_entity to obtain a valid root LEI first.',
152
+ },
153
+ {
154
+ reason: 'mirror_not_ready',
155
+ code: JsonRpcErrorCode.ServiceUnavailable,
156
+ when: 'The GLEIF (LEI) mirror has never completed an initial sync.',
157
+ retryable: true,
158
+ recovery: 'Run the mirror:init lifecycle script to load the GLEIF golden copy + relationships, then retry.',
159
+ },
160
+ ],
161
+ async handler(input, ctx) {
162
+ const svc = getScreeningService();
163
+ if (!(await svc.leiReady())) {
164
+ throw ctx.fail('mirror_not_ready', 'The local GLEIF (LEI) mirror is not yet populated.', {
165
+ ...ctx.recoveryFor('mirror_not_ready'),
166
+ });
167
+ }
168
+ const root = await svc.getLeiEntity(input.lei);
169
+ if (!root) {
170
+ throw ctx.fail('lei_not_found', `No GLEIF entity with LEI "${input.lei}".`, {
171
+ ...ctx.recoveryFor('lei_not_found'),
172
+ });
173
+ }
174
+ const { nodes, edges } = await traverse(svc, input.lei, input.direction, input.depth);
175
+ // Hydrate node names/jurisdictions in one batch.
176
+ const hydrated = await svc.getLeiEntitiesBatch([...nodes.keys()]);
177
+ const byLei = new Map(hydrated.map((e) => [e.lei, e]));
178
+ for (const node of nodes.values()) {
179
+ const e = byLei.get(node.lei);
180
+ if (e) {
181
+ node.legalName = e.legalName;
182
+ if (e.jurisdiction)
183
+ node.jurisdiction = e.jurisdiction;
184
+ if (e.status)
185
+ node.status = e.status;
186
+ }
187
+ }
188
+ const sanctionsReady = await svc.sanctionsReady();
189
+ let screenedNodeCount = 0;
190
+ let flaggedNodeCount = 0;
191
+ const screensByLei = new Map();
192
+ if (input.screenNodes && sanctionsReady) {
193
+ for (const node of nodes.values()) {
194
+ const screen = await svc.screenName({
195
+ query: node.legalName,
196
+ entityType: 'any',
197
+ matchMode: 'strict',
198
+ // Per-node cross-reference: strict only. Auto-fuzzy would flag nearly
199
+ // every node on a single shared common token, defeating the signal.
200
+ autoFallback: false,
201
+ sources: [...SOURCE_CODES],
202
+ limit: 10,
203
+ }, ctx);
204
+ screenedNodeCount++;
205
+ if (screen.hits.length > 0)
206
+ flaggedNodeCount++;
207
+ screensByLei.set(node.lei, screen.hits);
208
+ }
209
+ }
210
+ const orderedNodes = [...nodes.values()].sort((a, b) => a.depth - b.depth);
211
+ return {
212
+ rootLei: input.lei,
213
+ nodes: orderedNodes.map((node) => {
214
+ const hits = screensByLei.get(node.lei);
215
+ return {
216
+ lei: node.lei,
217
+ legalName: node.legalName,
218
+ ...(node.jurisdiction ? { jurisdiction: node.jurisdiction } : {}),
219
+ ...(node.status ? { status: node.status } : {}),
220
+ depth: node.depth,
221
+ role: node.role,
222
+ ...(input.screenNodes && sanctionsReady
223
+ ? {
224
+ sanctionsHits: (hits ?? []).map((h) => ({
225
+ source: h.source,
226
+ sourceLabel: SOURCE_LABELS[h.source],
227
+ sourceEntryId: h.sourceEntryId,
228
+ primaryName: h.primaryName,
229
+ matchedName: h.matchedName,
230
+ matchType: h.matchType,
231
+ ...(h.score !== undefined ? { score: h.score } : {}),
232
+ })),
233
+ }
234
+ : {}),
235
+ };
236
+ }),
237
+ edges,
238
+ screenedNodeCount,
239
+ flaggedNodeCount,
240
+ caveat: SCREENING_CAVEAT,
241
+ };
242
+ },
243
+ format: (r) => {
244
+ const lines = [`# Ownership graph for \`${r.rootLei}\``, ''];
245
+ lines.push(`**${r.nodes.length} node(s), ${r.edges.length} edge(s).**`);
246
+ if (r.screenedNodeCount > 0) {
247
+ lines.push(`**Screened ${r.screenedNodeCount} node(s); ${r.flaggedNodeCount} had potential matches.**`);
248
+ }
249
+ lines.push('\n## Entities');
250
+ for (const node of r.nodes) {
251
+ const meta = [node.jurisdiction, node.status].filter(Boolean).join(', ');
252
+ lines.push(`- **${node.legalName}** \`${node.lei}\` — ${node.role}, depth ${node.depth}${meta ? ` (${meta})` : ''}`);
253
+ if (node.sanctionsHits && node.sanctionsHits.length > 0) {
254
+ for (const h of node.sanctionsHits) {
255
+ const scoreStr = h.score !== undefined ? ` · score ${h.score.toFixed(3)}` : '';
256
+ lines.push(` - ⚠ ${h.primaryName} — ${h.sourceLabel} (\`${h.source}\`, entry ${h.sourceEntryId}): matched "${h.matchedName}" — ${h.matchType}${scoreStr}`);
257
+ }
258
+ }
259
+ else if (node.sanctionsHits) {
260
+ lines.push(' - No potential matches (not a clearance).');
261
+ }
262
+ }
263
+ if (r.edges.length > 0) {
264
+ lines.push('\n## Ownership edges');
265
+ for (const e of r.edges) {
266
+ lines.push(`- \`${e.childLei}\` ${e.relationshipType} \`${e.parentLei}\`${e.relationshipStatus ? ` (${e.relationshipStatus})` : ''}`);
267
+ }
268
+ }
269
+ lines.push(`\n> ${r.caveat}`);
270
+ return [{ type: 'text', text: lines.join('\n') }];
271
+ },
272
+ });
273
+ //# sourceMappingURL=trace-ownership.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-ownership.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/trace-ownership.tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @fileoverview Small synthetic fixture mirror — a handful of designations (one
3
+ * per source, with aliases and transliteration-class variants) plus a couple of
4
+ * GLEIF entities and an ownership relationship. Lets `bun run test` exercise the
5
+ * matching engine, the tools, and ownership tracing WITHOUT downloading the real
6
+ * multi-source corpus (which loads out-of-band via `mirror:init`). The names
7
+ * here are invented for testing — they are NOT real sanctions designations.
8
+ * @module services/screening/fixtures
9
+ */
10
+ import type { NormalizedDesignation, NormalizedLeiEntity, NormalizedLeiRelationship } from '../../services/screening/types.js';
11
+ /** Invented designations spanning all five sources, with aliases for fuzzy tests. */
12
+ export declare const FIXTURE_DESIGNATIONS: NormalizedDesignation[];
13
+ /** Two invented GLEIF entities — a parent and a subsidiary — for resolution + tracing. */
14
+ export declare const FIXTURE_LEI_ENTITIES: NormalizedLeiEntity[];
15
+ /** Testland Holdings PLC ultimately consolidates Fictional Trading Company LLC. */
16
+ export declare const FIXTURE_LEI_RELATIONSHIPS: NormalizedLeiRelationship[];
17
+ //# sourceMappingURL=fixtures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../../src/services/screening/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACnB,yBAAyB,EAC1B,MAAM,+BAA+B,CAAC;AAEvC,qFAAqF;AACrF,eAAO,MAAM,oBAAoB,EAAE,qBAAqB,EAiHvD,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,oBAAoB,EAAE,mBAAmB,EAyBrD,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,EAAE,yBAAyB,EAQhE,CAAC"}
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @fileoverview Small synthetic fixture mirror — a handful of designations (one
3
+ * per source, with aliases and transliteration-class variants) plus a couple of
4
+ * GLEIF entities and an ownership relationship. Lets `bun run test` exercise the
5
+ * matching engine, the tools, and ownership tracing WITHOUT downloading the real
6
+ * multi-source corpus (which loads out-of-band via `mirror:init`). The names
7
+ * here are invented for testing — they are NOT real sanctions designations.
8
+ * @module services/screening/fixtures
9
+ */
10
+ /** Invented designations spanning all five sources, with aliases for fuzzy tests. */
11
+ export const FIXTURE_DESIGNATIONS = [
12
+ {
13
+ id: 'ofac_sdn:FX-1001',
14
+ source: 'ofac_sdn',
15
+ sourceEntryId: 'FX-1001',
16
+ entityType: 'person',
17
+ primaryName: 'Ivan Testovich Volkov',
18
+ program: 'TEST-PROGRAM',
19
+ designationDate: '2021-03-15',
20
+ payload: {
21
+ // 'Volkov' / 'Wolkow' is a transliteration-class pair for the phonetic test.
22
+ aliases: [
23
+ { name: 'Ivan Wolkow', nameType: 'aka' },
24
+ { name: 'I. T. Volkov', nameType: 'aka' },
25
+ { name: 'Vanya Volkov', nameType: 'low-quality-aka' },
26
+ ],
27
+ identifiers: [{ type: 'Passport', value: 'X1234567', country: 'Testland' }],
28
+ addresses: [{ full: '1 Test Street, Testograd, Testland', country: 'Testland' }],
29
+ datesOfBirth: [{ date: '1970-01-01', place: 'Testograd' }],
30
+ nationalities: ['Testland'],
31
+ remarks: 'Synthetic test designation — not a real person.',
32
+ },
33
+ },
34
+ {
35
+ id: 'ofac_consolidated:FX-2002',
36
+ source: 'ofac_consolidated',
37
+ sourceEntryId: 'FX-2002',
38
+ entityType: 'organization',
39
+ primaryName: 'Fictional Trading Company LLC',
40
+ program: 'TEST-CONS',
41
+ designationDate: '2022-06-01',
42
+ payload: {
43
+ aliases: [
44
+ { name: 'Fictional Trading Co', nameType: 'aka' },
45
+ { name: 'FTC LLC', nameType: 'aka' },
46
+ ],
47
+ identifiers: [],
48
+ addresses: [{ full: '99 Commerce Way, Testopolis', country: 'Testland' }],
49
+ datesOfBirth: [],
50
+ nationalities: [],
51
+ },
52
+ },
53
+ {
54
+ id: 'eu:FX-3003',
55
+ source: 'eu',
56
+ sourceEntryId: 'FX-3003',
57
+ entityType: 'person',
58
+ primaryName: 'Katarina Beispiel',
59
+ program: 'EU-TEST-REGIME',
60
+ designationDate: '2023-02-20',
61
+ payload: {
62
+ aliases: [{ name: 'Katarina Example', nameType: 'aka' }],
63
+ identifiers: [],
64
+ addresses: [],
65
+ datesOfBirth: [{ date: '1985-05-05' }],
66
+ nationalities: ['Beispielland'],
67
+ },
68
+ },
69
+ {
70
+ id: 'uk:FX-4004',
71
+ source: 'uk',
72
+ sourceEntryId: 'FX-4004',
73
+ entityType: 'vessel',
74
+ primaryName: 'MV Phantom Voyager',
75
+ program: 'UK-TEST-SHIPPING',
76
+ designationDate: '2024-09-10',
77
+ payload: {
78
+ aliases: [{ name: 'Phantom Voyager', nameType: 'aka' }],
79
+ identifiers: [{ type: 'IMO', value: '1234567' }],
80
+ addresses: [],
81
+ datesOfBirth: [],
82
+ nationalities: [],
83
+ },
84
+ },
85
+ {
86
+ // Transliteration-class case: published as "Mohammed", queryable as
87
+ // "Muhammad" — the two share a Double-Metaphone key (MHMT), which is how the
88
+ // phonetic fallback catches a romanization the strict/JW paths would miss.
89
+ id: 'un:FX-6006',
90
+ source: 'un',
91
+ sourceEntryId: 'FX-6006',
92
+ entityType: 'person',
93
+ primaryName: 'Mohammed Al-Testi',
94
+ program: 'UN-TEST-1267',
95
+ designationDate: '2019-04-12',
96
+ payload: {
97
+ aliases: [{ name: 'Mohammed Testi', nameType: 'aka' }],
98
+ identifiers: [],
99
+ addresses: [],
100
+ datesOfBirth: [{ date: '1975-07-07' }],
101
+ nationalities: ['Testland'],
102
+ },
103
+ },
104
+ {
105
+ id: 'un:FX-5005',
106
+ source: 'un',
107
+ sourceEntryId: 'FX-5005',
108
+ entityType: 'organization',
109
+ primaryName: 'Imaginary Front Organisation',
110
+ program: 'UN-TEST-1267',
111
+ designationDate: '2020-11-30',
112
+ payload: {
113
+ aliases: [
114
+ { name: 'Imaginary Front Org', nameType: 'aka' },
115
+ { name: 'IFO', nameType: 'low-quality-aka' },
116
+ ],
117
+ identifiers: [],
118
+ addresses: [{ full: 'PO Box 1, Nowhere City' }],
119
+ datesOfBirth: [],
120
+ nationalities: [],
121
+ remarks: 'Synthetic UN test entry.',
122
+ },
123
+ },
124
+ ];
125
+ /** Two invented GLEIF entities — a parent and a subsidiary — for resolution + tracing. */
126
+ export const FIXTURE_LEI_ENTITIES = [
127
+ {
128
+ lei: '5493001KJTIIGC8Y1R12',
129
+ legalName: 'Fictional Trading Company LLC',
130
+ otherNames: ['Fictional Trading Co'],
131
+ jurisdiction: 'US',
132
+ status: 'ISSUED',
133
+ legalAddress: '99 Commerce Way, Testopolis, US',
134
+ headquartersAddress: '99 Commerce Way, Testopolis, US',
135
+ registrationAuthorityId: 'RA000665',
136
+ registrationAuthorityEntityId: 'TEST-REG-1',
137
+ lastUpdate: '2026-01-15T10:00:00Z',
138
+ },
139
+ {
140
+ lei: '529900T8BM49AURSDO55',
141
+ legalName: 'Testland Holdings PLC',
142
+ otherNames: ['Testland Holdings'],
143
+ jurisdiction: 'GB',
144
+ status: 'ISSUED',
145
+ legalAddress: '1 Holding Square, London, GB',
146
+ headquartersAddress: '1 Holding Square, London, GB',
147
+ registrationAuthorityId: 'RA000585',
148
+ registrationAuthorityEntityId: 'TEST-REG-2',
149
+ lastUpdate: '2026-01-10T10:00:00Z',
150
+ },
151
+ ];
152
+ /** Testland Holdings PLC ultimately consolidates Fictional Trading Company LLC. */
153
+ export const FIXTURE_LEI_RELATIONSHIPS = [
154
+ {
155
+ childLei: '5493001KJTIIGC8Y1R12',
156
+ parentLei: '529900T8BM49AURSDO55',
157
+ relationshipType: 'IS_ULTIMATELY_CONSOLIDATED_BY',
158
+ relationshipStatus: 'ACTIVE',
159
+ relationshipPeriod: '2020-01-01',
160
+ },
161
+ ];
162
+ //# sourceMappingURL=fixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../../src/services/screening/fixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview GLEIF ingester — the heaviest leg. Resolves the latest
3
+ * golden-copy (full) or delta download URLs from the GLEIF Golden Copy API,
4
+ * streams the ZIP-compressed file, and normalizes LEI-CDF Level 1 (who-is-who)
5
+ * and RR-CDF Level 2 (who-owns-whom) records onto {@link NormalizedLeiEntity} /
6
+ * {@link NormalizedLeiRelationship}. Level 1 init is ~3.3M records / ~490 MB
7
+ * compressed (May 2026) — it runs out-of-band via `mirror:init`, never on the
8
+ * request path; refresh uses the 8-hour deltas keyed on a checkpoint.
9
+ *
10
+ * The normalization functions are the testable core (exercised by the synthetic
11
+ * fixture). The download/decompress wiring is documented and resilient; the real
12
+ * corpus loads out-of-band.
13
+ * @module services/screening/gleif-ingest
14
+ */
15
+ import type { NormalizedLeiEntity, NormalizedLeiRelationship } from '../../services/screening/types.js';
16
+ /** Which GLEIF dataset + window to fetch. */
17
+ export type GleifFileKind = 'lei2-full' | 'lei2-delta' | 'rr-full' | 'rr-delta';
18
+ /**
19
+ * Resolve the download URL for a GLEIF golden-copy or delta file. The Golden
20
+ * Copy API exposes a JSON index of the latest publications per file type and
21
+ * delta window; we read it and return the matching `.xml.gz` download link.
22
+ *
23
+ * @param kind Which dataset + window.
24
+ * @param delta Delta window when `kind` is a delta variant (e.g. `'LastDay'`, `'IntraDay'`).
25
+ */
26
+ export declare function resolveGleifFileUrl(kind: GleifFileKind, signal: AbortSignal, delta?: 'IntraDay' | 'LastDay' | 'WeeklyFullFiles'): Promise<string>;
27
+ /**
28
+ * Download a GLEIF golden-copy / delta file and return the decompressed XML.
29
+ * The golden-copy downloads are **ZIP** containers (`PK\x03\x04`) wrapping a
30
+ * single XML entry — not gzip; the delta `.gz` files are gzip. Detection is by
31
+ * magic bytes (the URL suffix is unreliable behind the storage redirect), with a
32
+ * plain-XML fallback.
33
+ *
34
+ * NOTE (memory): this buffers and decompresses the whole file in memory. The
35
+ * Level 1 golden copy is ~3.3M records / ~900 MB compressed; decompressing and
36
+ * DOM-parsing it whole needs multiple GB of heap. A production `mirror:init`
37
+ * against the full L1 file requires a streaming ZIP → SAX pipeline; until then,
38
+ * real L1 ingest is bounded by available memory. Deltas and L2 are far smaller
39
+ * and fit comfortably.
40
+ */
41
+ export declare function downloadGleifXml(url: string, signal: AbortSignal): Promise<string>;
42
+ /** Decompress a downloaded GLEIF buffer by detecting ZIP / gzip / plain by magic bytes. */
43
+ export declare function decompressGleifBuffer(buf: Buffer): string;
44
+ /**
45
+ * Extract the first file entry from a ZIP buffer (stored or deflate). GLEIF
46
+ * golden-copy ZIPs wrap exactly one XML file, so a single-entry reader is
47
+ * sufficient — it reads the local file header, then inflates the entry's raw
48
+ * deflate stream (or returns it verbatim when stored).
49
+ */
50
+ export declare function extractFirstZipEntry(buf: Buffer): string;
51
+ /**
52
+ * Parse an LEI-CDF Level 1 XML document into normalized entity records. The
53
+ * record root is `<LEIRecords><LEIRecord>`; each carries an `<LEI>`, an
54
+ * `<Entity>` (legal name, other names, addresses, jurisdiction, status), and a
55
+ * `<Registration>` (registration status, last-update, RA).
56
+ */
57
+ export declare function parseLeiLevel1(doc: Record<string, unknown>): NormalizedLeiEntity[];
58
+ /**
59
+ * Parse an RR-CDF Level 2 XML document into normalized relationship records.
60
+ * The record root is `<RelationshipRecords><RelationshipRecord>`; each carries a
61
+ * `<Relationship>` with a start node (child), end node (parent), and type.
62
+ */
63
+ export declare function parseLeiLevel2(doc: Record<string, unknown>): NormalizedLeiRelationship[];
64
+ /** Fetch + decompress + parse Level 1 from a resolved URL. */
65
+ export declare function harvestLeiLevel1(url: string, signal: AbortSignal): Promise<NormalizedLeiEntity[]>;
66
+ /** Fetch + decompress + parse Level 2 from a resolved URL. */
67
+ export declare function harvestLeiLevel2(url: string, signal: AbortSignal): Promise<NormalizedLeiRelationship[]>;
68
+ //# sourceMappingURL=gleif-ingest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gleif-ingest.d.ts","sourceRoot":"","sources":["../../../src/services/screening/gleif-ingest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAKpG,6CAA6C;AAC7C,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,GAAG,UAAU,CAAC;AA2BhF;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,WAAW,EACnB,KAAK,GAAE,UAAU,GAAG,SAAS,GAAG,iBAA6B,GAC5D,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAclF;AAED,2FAA2F;AAC3F,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIzD;AAUD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAsBxD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,mBAAmB,EAAE,CASlF;AAuDD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,yBAAyB,EAAE,CAgBxF;AA6BD,8DAA8D;AAC9D,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAIhC;AAED,8DAA8D;AAC9D,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAItC"}