@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.
- package/AGENTS.md +452 -0
- package/CLAUDE.md +452 -0
- package/Dockerfile +126 -0
- package/LICENSE +201 -0
- package/README.md +354 -0
- package/changelog/0.1.x/0.1.0.md +26 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +37 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +87 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/index.d.ts +12 -0
- package/dist/mcp-server/prompts/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/prompts/definitions/index.js +9 -0
- package/dist/mcp-server/prompts/definitions/index.js.map +1 -0
- package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.d.ts +14 -0
- package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.d.ts.map +1 -0
- package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.js +42 -0
- package/dist/mcp-server/prompts/definitions/vet-counterparty.prompt.js.map +1 -0
- package/dist/mcp-server/resources/definitions/designation.resource.d.ts +25 -0
- package/dist/mcp-server/resources/definitions/designation.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/designation.resource.js +57 -0
- package/dist/mcp-server/resources/definitions/designation.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/entity.resource.d.ts +17 -0
- package/dist/mcp-server/resources/definitions/entity.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/entity.resource.js +40 -0
- package/dist/mcp-server/resources/definitions/entity.resource.js.map +1 -0
- package/dist/mcp-server/resources/definitions/index.d.ts +32 -0
- package/dist/mcp-server/resources/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/index.js +11 -0
- package/dist/mcp-server/resources/definitions/index.js.map +1 -0
- package/dist/mcp-server/resources/definitions/sources.resource.d.ts +9 -0
- package/dist/mcp-server/resources/definitions/sources.resource.d.ts.map +1 -0
- package/dist/mcp-server/resources/definitions/sources.resource.js +50 -0
- package/dist/mcp-server/resources/definitions/sources.resource.js.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared.d.ts +13 -0
- package/dist/mcp-server/tools/definitions/_shared.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/_shared.js +13 -0
- package/dist/mcp-server/tools/definitions/_shared.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-designation.tool.d.ts +78 -0
- package/dist/mcp-server/tools/definitions/get-designation.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-designation.tool.js +168 -0
- package/dist/mcp-server/tools/definitions/get-designation.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-entity.tool.d.ts +55 -0
- package/dist/mcp-server/tools/definitions/get-entity.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-entity.tool.js +176 -0
- package/dist/mcp-server/tools/definitions/get-entity.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +306 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +21 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/list-sources.tool.d.ts +23 -0
- package/dist/mcp-server/tools/definitions/list-sources.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/list-sources.tool.js +106 -0
- package/dist/mcp-server/tools/definitions/list-sources.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/resolve-entity.tool.d.ts +51 -0
- package/dist/mcp-server/tools/definitions/resolve-entity.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/resolve-entity.tool.js +148 -0
- package/dist/mcp-server/tools/definitions/resolve-entity.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/screen-name.tool.d.ts +82 -0
- package/dist/mcp-server/tools/definitions/screen-name.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/screen-name.tool.js +172 -0
- package/dist/mcp-server/tools/definitions/screen-name.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/trace-ownership.tool.d.ts +74 -0
- package/dist/mcp-server/tools/definitions/trace-ownership.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/trace-ownership.tool.js +273 -0
- package/dist/mcp-server/tools/definitions/trace-ownership.tool.js.map +1 -0
- package/dist/services/screening/fixtures.d.ts +17 -0
- package/dist/services/screening/fixtures.d.ts.map +1 -0
- package/dist/services/screening/fixtures.js +162 -0
- package/dist/services/screening/fixtures.js.map +1 -0
- package/dist/services/screening/gleif-ingest.d.ts +68 -0
- package/dist/services/screening/gleif-ingest.d.ts.map +1 -0
- package/dist/services/screening/gleif-ingest.js +251 -0
- package/dist/services/screening/gleif-ingest.js.map +1 -0
- package/dist/services/screening/sanctions-ingest.d.ts +46 -0
- package/dist/services/screening/sanctions-ingest.d.ts.map +1 -0
- package/dist/services/screening/sanctions-ingest.js +688 -0
- package/dist/services/screening/sanctions-ingest.js.map +1 -0
- package/dist/services/screening/schema.d.ts +52 -0
- package/dist/services/screening/schema.d.ts.map +1 -0
- package/dist/services/screening/schema.js +125 -0
- package/dist/services/screening/schema.js.map +1 -0
- package/dist/services/screening/screening-service.d.ts +203 -0
- package/dist/services/screening/screening-service.d.ts.map +1 -0
- package/dist/services/screening/screening-service.js +702 -0
- package/dist/services/screening/screening-service.js.map +1 -0
- package/dist/services/screening/text-matching.d.ts +53 -0
- package/dist/services/screening/text-matching.d.ts.map +1 -0
- package/dist/services/screening/text-matching.js +514 -0
- package/dist/services/screening/text-matching.js.map +1 -0
- package/dist/services/screening/types.d.ts +154 -0
- package/dist/services/screening/types.d.ts.map +1 -0
- package/dist/services/screening/types.js +24 -0
- package/dist/services/screening/types.js.map +1 -0
- package/dist/services/screening/xml.d.ts +29 -0
- package/dist/services/screening/xml.d.ts.map +1 -0
- package/dist/services/screening/xml.js +46 -0
- package/dist/services/screening/xml.js.map +1 -0
- package/package.json +119 -0
- package/scripts/_mirror-context.ts +21 -0
- package/scripts/mirror-init.ts +66 -0
- package/scripts/mirror-refresh.ts +56 -0
- package/scripts/mirror-seed.ts +36 -0
- package/scripts/mirror-verify.ts +44 -0
- package/server.json +148 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `sanctions_list_sources` — provenance and freshness for any
|
|
3
|
+
* result. Lists the sanctions watchlists and GLEIF datasets currently loaded in
|
|
4
|
+
* the local mirror, each with its record count, source URL, license, and the
|
|
5
|
+
* mirror's readiness + as-of timestamp. Lets an agent judge staleness before
|
|
6
|
+
* trusting (or distrusting) a screen.
|
|
7
|
+
* @module mcp-server/tools/definitions/list-sources.tool
|
|
8
|
+
*/
|
|
9
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import { DEFAULT_SOURCE_URLS, getServerConfig } from '../../../config/server-config.js';
|
|
11
|
+
import { getScreeningService } from '../../../services/screening/screening-service.js';
|
|
12
|
+
import { SOURCE_LABELS } from '../../../services/screening/types.js';
|
|
13
|
+
const LICENSES = {
|
|
14
|
+
ofac_sdn: 'US Government public domain',
|
|
15
|
+
ofac_consolidated: 'US Government public domain',
|
|
16
|
+
eu: 'EU consolidated list — freely redistributable',
|
|
17
|
+
uk: 'Open Government Licence v3.0 (attribution required)',
|
|
18
|
+
un: 'Freely redistributable',
|
|
19
|
+
};
|
|
20
|
+
/** GLEIF golden copy is CC0 — cited but no attribution required. */
|
|
21
|
+
const GLEIF_LICENSE = 'CC0 1.0 Universal (public domain)';
|
|
22
|
+
export const listSourcesTool = tool('sanctions_list_sources', {
|
|
23
|
+
title: 'sanctions-screening-mcp-server: list sources',
|
|
24
|
+
description: "List the sanctions watchlists (OFAC SDN + Consolidated, EU, UK, UN) and GLEIF datasets currently loaded in the local mirror, each with its record count, source URL, license, and the mirror's readiness and as-of timestamp. Use this for provenance and freshness on any result — results are only as current as the last mirror refresh, and a not-ready mirror means screening cannot run yet. Attribution: UK data is under the Open Government Licence v3.0; all sources are cited here.",
|
|
25
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
26
|
+
input: z.object({}),
|
|
27
|
+
output: z.object({
|
|
28
|
+
sanctionsReady: z
|
|
29
|
+
.boolean()
|
|
30
|
+
.describe('True once the sanctions mirror has completed at least one full sync.'),
|
|
31
|
+
sanctionsAsOf: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe('ISO 8601 timestamp of the last completed sanctions sync, when available.'),
|
|
35
|
+
leiReady: z
|
|
36
|
+
.boolean()
|
|
37
|
+
.describe('True once the GLEIF (LEI) mirror has completed at least one full sync.'),
|
|
38
|
+
leiAsOf: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('ISO 8601 timestamp of the last completed GLEIF sync, when available.'),
|
|
42
|
+
sources: z
|
|
43
|
+
.array(z
|
|
44
|
+
.object({
|
|
45
|
+
code: z.string().describe('Source code (ofac_sdn, eu, …, or gleif).'),
|
|
46
|
+
label: z.string().describe('Human-readable source name.'),
|
|
47
|
+
recordCount: z.number().describe('Records currently loaded for this source.'),
|
|
48
|
+
url: z.string().describe('Upstream source URL the mirror harvests from.'),
|
|
49
|
+
license: z.string().describe('Redistribution license / terms for this source.'),
|
|
50
|
+
})
|
|
51
|
+
.describe('One loaded source with count, provenance, and license.'))
|
|
52
|
+
.describe('All loaded sources, sanctions lists then the GLEIF dataset.'),
|
|
53
|
+
}),
|
|
54
|
+
async handler(_input, ctx) {
|
|
55
|
+
const svc = getScreeningService();
|
|
56
|
+
const cfg = getServerConfig();
|
|
57
|
+
const [counts, sanctions, lei] = await Promise.all([
|
|
58
|
+
svc.sourceCounts(),
|
|
59
|
+
svc.sanctionsReadiness(),
|
|
60
|
+
svc.leiReadiness(),
|
|
61
|
+
]);
|
|
62
|
+
const urlFor = {
|
|
63
|
+
ofac_sdn: cfg.ofacSdnUrl,
|
|
64
|
+
ofac_consolidated: cfg.ofacConsolidatedUrl,
|
|
65
|
+
eu: cfg.euFsfUrl,
|
|
66
|
+
uk: cfg.ukSanctionsUrl,
|
|
67
|
+
un: cfg.unScUrl,
|
|
68
|
+
};
|
|
69
|
+
const sources = counts.map((s) => ({
|
|
70
|
+
code: s.code,
|
|
71
|
+
label: SOURCE_LABELS[s.code],
|
|
72
|
+
recordCount: s.recordCount,
|
|
73
|
+
url: urlFor[s.code],
|
|
74
|
+
license: LICENSES[s.code],
|
|
75
|
+
}));
|
|
76
|
+
sources.push({
|
|
77
|
+
code: 'gleif',
|
|
78
|
+
label: 'GLEIF LEI (Level 1 entities + Level 2 ownership)',
|
|
79
|
+
recordCount: lei.entityCount,
|
|
80
|
+
url: `${cfg.gleifGoldenCopyBaseUrl.replace(/\/$/, '')} (golden copy) — default ${DEFAULT_SOURCE_URLS.gleifGoldenCopyBase}`,
|
|
81
|
+
license: GLEIF_LICENSE,
|
|
82
|
+
});
|
|
83
|
+
ctx.log.debug('Listed sources', { sanctionsReady: sanctions.ready, leiReady: lei.ready });
|
|
84
|
+
return {
|
|
85
|
+
sanctionsReady: sanctions.ready,
|
|
86
|
+
...(sanctions.completedAt ? { sanctionsAsOf: sanctions.completedAt } : {}),
|
|
87
|
+
leiReady: lei.ready,
|
|
88
|
+
...(lei.completedAt ? { leiAsOf: lei.completedAt } : {}),
|
|
89
|
+
sources,
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
format: (r) => {
|
|
93
|
+
const lines = ['# Loaded sources', ''];
|
|
94
|
+
lines.push(`**Sanctions mirror:** ${r.sanctionsReady ? 'ready' : 'NOT ready'}${r.sanctionsAsOf ? ` (as of ${r.sanctionsAsOf})` : ''}`);
|
|
95
|
+
lines.push(`**GLEIF mirror:** ${r.leiReady ? 'ready' : 'NOT ready'}${r.leiAsOf ? ` (as of ${r.leiAsOf})` : ''}`);
|
|
96
|
+
lines.push('');
|
|
97
|
+
for (const s of r.sources) {
|
|
98
|
+
lines.push(`### ${s.label} (\`${s.code}\`)`);
|
|
99
|
+
lines.push(`**Records:** ${s.recordCount} | **License:** ${s.license}`);
|
|
100
|
+
lines.push(`**Source:** ${s.url}`);
|
|
101
|
+
lines.push('');
|
|
102
|
+
}
|
|
103
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=list-sources.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-sources.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/list-sources.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `sanctions_resolve_entity` — resolves a company/organization
|
|
3
|
+
* name (+ optional jurisdiction) to candidate GLEIF LEIs, ranked. The bridge
|
|
4
|
+
* from a free-text counterparty name to a stable global identifier other tools
|
|
5
|
+
* key off. Decision support: candidates to confirm, not an authoritative
|
|
6
|
+
* identification.
|
|
7
|
+
* @module mcp-server/tools/definitions/resolve-entity.tool
|
|
8
|
+
*/
|
|
9
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
11
|
+
export declare const resolveEntityTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
12
|
+
name: z.ZodString;
|
|
13
|
+
jurisdiction: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"">, z.ZodString]>>;
|
|
14
|
+
matchMode: z.ZodDefault<z.ZodEnum<{
|
|
15
|
+
strict: "strict";
|
|
16
|
+
fuzzy: "fuzzy";
|
|
17
|
+
}>>;
|
|
18
|
+
status: z.ZodDefault<z.ZodEnum<{
|
|
19
|
+
any: "any";
|
|
20
|
+
issued: "issued";
|
|
21
|
+
lapsed: "lapsed";
|
|
22
|
+
}>>;
|
|
23
|
+
minScore: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
25
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
26
|
+
matches: z.ZodArray<z.ZodObject<{
|
|
27
|
+
lei: z.ZodString;
|
|
28
|
+
legalName: z.ZodString;
|
|
29
|
+
matchedName: z.ZodString;
|
|
30
|
+
matchType: z.ZodEnum<{
|
|
31
|
+
exact: "exact";
|
|
32
|
+
strong: "strong";
|
|
33
|
+
approximate: "approximate";
|
|
34
|
+
}>;
|
|
35
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
jurisdiction: z.ZodOptional<z.ZodString>;
|
|
37
|
+
status: z.ZodOptional<z.ZodString>;
|
|
38
|
+
}, z.core.$strip>>;
|
|
39
|
+
}, z.core.$strip>, readonly [{
|
|
40
|
+
readonly reason: "mirror_not_ready";
|
|
41
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
42
|
+
readonly when: "The GLEIF (LEI) mirror has never completed an initial sync.";
|
|
43
|
+
readonly retryable: true;
|
|
44
|
+
readonly recovery: "Run the mirror:init lifecycle script to load the GLEIF golden copy, then retry; check sanctions_list_sources for readiness.";
|
|
45
|
+
}], {
|
|
46
|
+
readonly normalizedQuery: z.ZodString;
|
|
47
|
+
readonly matchModeUsed: z.ZodString;
|
|
48
|
+
readonly totalCount: z.ZodNumber;
|
|
49
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
50
|
+
}>;
|
|
51
|
+
//# sourceMappingURL=resolve-entity.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-entity.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/resolve-entity.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6J5B,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `sanctions_resolve_entity` — resolves a company/organization
|
|
3
|
+
* name (+ optional jurisdiction) to candidate GLEIF LEIs, ranked. The bridge
|
|
4
|
+
* from a free-text counterparty name to a stable global identifier other tools
|
|
5
|
+
* key off. Decision support: candidates to confirm, not an authoritative
|
|
6
|
+
* identification.
|
|
7
|
+
* @module mcp-server/tools/definitions/resolve-entity.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
|
+
export const resolveEntityTool = tool('sanctions_resolve_entity', {
|
|
13
|
+
title: 'sanctions-screening-mcp-server: resolve entity',
|
|
14
|
+
description: 'Resolve a company or organization name (with an optional ISO 3166-1 alpha-2 jurisdiction) to candidate GLEIF Legal Entity Identifiers (LEIs), ranked. This turns a free-text counterparty name into a stable global identifier that sanctions_get_entity and sanctions_trace_ownership key off. Strict mode (default) matches exact-normalized then all-tokens-present; fuzzy mode (or auto when strict is empty) adds Jaro-Winkler scoring labeled approximate with a raw 0–1 score. Returns potential matches to confirm against the GLEIF record — name resolution is a candidate ranking, not an authoritative identification.',
|
|
15
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
16
|
+
input: z.object({
|
|
17
|
+
name: z.string().min(1).describe('The company / organization name to resolve to an LEI.'),
|
|
18
|
+
jurisdiction: z
|
|
19
|
+
.union([
|
|
20
|
+
z.literal(''),
|
|
21
|
+
z
|
|
22
|
+
.string()
|
|
23
|
+
.regex(/^[A-Za-z]{2}$/, 'ISO 3166-1 alpha-2 code (e.g. US, GB)')
|
|
24
|
+
.describe('ISO 3166-1 alpha-2 jurisdiction code (e.g. US, GB).'),
|
|
25
|
+
])
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('Optional ISO 3166-1 alpha-2 jurisdiction filter (e.g. "US", "GB"). Empty string disables it.'),
|
|
28
|
+
matchMode: z
|
|
29
|
+
.enum(['strict', 'fuzzy'])
|
|
30
|
+
.default('strict')
|
|
31
|
+
.describe('strict (default): exact then all-tokens-present. fuzzy: also scored Jaro-Winkler.'),
|
|
32
|
+
status: z
|
|
33
|
+
.enum(['any', 'issued', 'lapsed'])
|
|
34
|
+
.default('issued')
|
|
35
|
+
.describe('Registration status filter: issued (default), lapsed, or any.'),
|
|
36
|
+
minScore: z
|
|
37
|
+
.number()
|
|
38
|
+
.min(0)
|
|
39
|
+
.max(1)
|
|
40
|
+
.optional()
|
|
41
|
+
.describe("Jaro-Winkler floor for fuzzy hits (0–1); defaults to the server's configured floor."),
|
|
42
|
+
limit: z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.min(1)
|
|
46
|
+
.max(50)
|
|
47
|
+
.default(10)
|
|
48
|
+
.describe('Maximum LEI candidates to return.'),
|
|
49
|
+
}),
|
|
50
|
+
output: z.object({
|
|
51
|
+
matches: z
|
|
52
|
+
.array(z
|
|
53
|
+
.object({
|
|
54
|
+
lei: z.string().describe('20-character GLEIF Legal Entity Identifier.'),
|
|
55
|
+
legalName: z.string().describe('Registered legal name of the entity.'),
|
|
56
|
+
matchedName: z
|
|
57
|
+
.string()
|
|
58
|
+
.describe('The name (legal or other/trading) that matched the query.'),
|
|
59
|
+
matchType: z
|
|
60
|
+
.enum(['exact', 'strong', 'approximate'])
|
|
61
|
+
.describe('exact = normalized equality; strong = all tokens present; approximate = fuzzy.'),
|
|
62
|
+
score: z
|
|
63
|
+
.number()
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('Raw Jaro-Winkler similarity (0–1) for approximate hits only — a real measurement.'),
|
|
66
|
+
jurisdiction: z
|
|
67
|
+
.string()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe('Legal jurisdiction (ISO code), when published.'),
|
|
70
|
+
status: z.string().optional().describe('Registration status (e.g. ISSUED, LAPSED).'),
|
|
71
|
+
})
|
|
72
|
+
.describe('One LEI candidate — confirm against the GLEIF record before relying on it.'))
|
|
73
|
+
.describe('Ranked LEI candidates, highest-confidence first.'),
|
|
74
|
+
}),
|
|
75
|
+
enrichment: {
|
|
76
|
+
normalizedQuery: z.string().describe('The name as the server folded it for matching.'),
|
|
77
|
+
matchModeUsed: z
|
|
78
|
+
.string()
|
|
79
|
+
.describe('The match mode actually applied (strict may upgrade to fuzzy).'),
|
|
80
|
+
totalCount: z.number().describe('Number of LEI candidates returned.'),
|
|
81
|
+
notice: z.string().optional().describe('Guidance when no LEI matched and how to broaden.'),
|
|
82
|
+
},
|
|
83
|
+
errors: [
|
|
84
|
+
{
|
|
85
|
+
reason: 'mirror_not_ready',
|
|
86
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
87
|
+
when: 'The GLEIF (LEI) mirror has never completed an initial sync.',
|
|
88
|
+
retryable: true,
|
|
89
|
+
recovery: 'Run the mirror:init lifecycle script to load the GLEIF golden copy, then retry; check sanctions_list_sources for readiness.',
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
async handler(input, ctx) {
|
|
93
|
+
const svc = getScreeningService();
|
|
94
|
+
if (!(await svc.leiReady())) {
|
|
95
|
+
throw ctx.fail('mirror_not_ready', 'The local GLEIF (LEI) mirror is not yet populated.', {
|
|
96
|
+
...ctx.recoveryFor('mirror_not_ready'),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const jurisdiction = input.jurisdiction ? input.jurisdiction.toUpperCase() : undefined;
|
|
100
|
+
const result = await svc.resolveEntity({
|
|
101
|
+
query: input.name,
|
|
102
|
+
...(jurisdiction ? { jurisdiction } : {}),
|
|
103
|
+
matchMode: input.matchMode,
|
|
104
|
+
status: input.status,
|
|
105
|
+
...(input.minScore !== undefined ? { minScore: input.minScore } : {}),
|
|
106
|
+
limit: input.limit,
|
|
107
|
+
}, ctx);
|
|
108
|
+
ctx.enrich({ normalizedQuery: result.normalizedQuery, matchModeUsed: result.modeUsed });
|
|
109
|
+
ctx.enrich.total(result.matches.length);
|
|
110
|
+
if (result.matches.length === 0) {
|
|
111
|
+
ctx.enrich.notice(`No LEI candidate for "${input.name}"${jurisdiction ? ` in ${jurisdiction}` : ''} (mode: ${result.modeUsed}). ` +
|
|
112
|
+
'Try matchMode:"fuzzy", drop the jurisdiction/status filter, or set status:"any" — an unmatched name is not proof the entity has no LEI.');
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
matches: result.matches.map((m) => ({
|
|
116
|
+
lei: m.lei,
|
|
117
|
+
legalName: m.legalName,
|
|
118
|
+
matchedName: m.matchedName,
|
|
119
|
+
matchType: m.matchType,
|
|
120
|
+
...(m.score !== undefined ? { score: m.score } : {}),
|
|
121
|
+
...(m.jurisdiction ? { jurisdiction: m.jurisdiction } : {}),
|
|
122
|
+
...(m.status ? { status: m.status } : {}),
|
|
123
|
+
})),
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
format: (r) => {
|
|
127
|
+
if (r.matches.length === 0)
|
|
128
|
+
return [{ type: 'text', text: '**No LEI candidates found.**' }];
|
|
129
|
+
const lines = [`**${r.matches.length} LEI candidate(s)** — confirm before relying on:\n`];
|
|
130
|
+
for (const m of r.matches) {
|
|
131
|
+
const scoreStr = m.score !== undefined ? ` · score ${m.score.toFixed(3)}` : '';
|
|
132
|
+
lines.push(`### ${m.legalName} — ${m.matchType}${scoreStr}`);
|
|
133
|
+
lines.push(`**LEI:** \`${m.lei}\``);
|
|
134
|
+
lines.push(`**Matched on:** "${m.matchedName}"`);
|
|
135
|
+
const meta = [
|
|
136
|
+
m.jurisdiction ? `Jurisdiction: ${m.jurisdiction}` : null,
|
|
137
|
+
m.status ? `Status: ${m.status}` : null,
|
|
138
|
+
]
|
|
139
|
+
.filter(Boolean)
|
|
140
|
+
.join(' | ');
|
|
141
|
+
if (meta)
|
|
142
|
+
lines.push(`**${meta}**`);
|
|
143
|
+
lines.push('');
|
|
144
|
+
}
|
|
145
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
//# sourceMappingURL=resolve-entity.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-entity.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/resolve-entity.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `sanctions_screen_name` — the 80% entry point. Screens a name
|
|
3
|
+
* against all loaded watchlists (OFAC SDN + Consolidated, EU, UK, UN) at once,
|
|
4
|
+
* alias- and fuzzy-aware, and returns scored potential matches with source
|
|
5
|
+
* provenance. This is decision support, NOT a compliance determination: a hit is
|
|
6
|
+
* a candidate to verify against the official source, and an empty result is
|
|
7
|
+
* never a clearance.
|
|
8
|
+
* @module mcp-server/tools/definitions/screen-name.tool
|
|
9
|
+
*/
|
|
10
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
12
|
+
export declare const screenNameTool: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
entityType: z.ZodDefault<z.ZodEnum<{
|
|
15
|
+
any: "any";
|
|
16
|
+
person: "person";
|
|
17
|
+
organization: "organization";
|
|
18
|
+
vessel: "vessel";
|
|
19
|
+
aircraft: "aircraft";
|
|
20
|
+
}>>;
|
|
21
|
+
matchMode: z.ZodDefault<z.ZodEnum<{
|
|
22
|
+
strict: "strict";
|
|
23
|
+
fuzzy: "fuzzy";
|
|
24
|
+
}>>;
|
|
25
|
+
minScore: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
sources: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
27
|
+
ofac_sdn: "ofac_sdn";
|
|
28
|
+
ofac_consolidated: "ofac_consolidated";
|
|
29
|
+
eu: "eu";
|
|
30
|
+
uk: "uk";
|
|
31
|
+
un: "un";
|
|
32
|
+
}>>>;
|
|
33
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
35
|
+
hits: z.ZodArray<z.ZodObject<{
|
|
36
|
+
source: z.ZodEnum<{
|
|
37
|
+
ofac_sdn: "ofac_sdn";
|
|
38
|
+
ofac_consolidated: "ofac_consolidated";
|
|
39
|
+
eu: "eu";
|
|
40
|
+
uk: "uk";
|
|
41
|
+
un: "un";
|
|
42
|
+
}>;
|
|
43
|
+
sourceLabel: z.ZodString;
|
|
44
|
+
sourceEntryId: z.ZodString;
|
|
45
|
+
entityType: z.ZodEnum<{
|
|
46
|
+
unknown: "unknown";
|
|
47
|
+
person: "person";
|
|
48
|
+
organization: "organization";
|
|
49
|
+
vessel: "vessel";
|
|
50
|
+
aircraft: "aircraft";
|
|
51
|
+
}>;
|
|
52
|
+
primaryName: z.ZodString;
|
|
53
|
+
matchedName: z.ZodString;
|
|
54
|
+
matchedNameType: z.ZodEnum<{
|
|
55
|
+
primary: "primary";
|
|
56
|
+
aka: "aka";
|
|
57
|
+
fka: "fka";
|
|
58
|
+
"low-quality-aka": "low-quality-aka";
|
|
59
|
+
}>;
|
|
60
|
+
matchType: z.ZodEnum<{
|
|
61
|
+
exact: "exact";
|
|
62
|
+
strong: "strong";
|
|
63
|
+
approximate: "approximate";
|
|
64
|
+
}>;
|
|
65
|
+
score: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
program: z.ZodOptional<z.ZodString>;
|
|
67
|
+
designationDate: z.ZodOptional<z.ZodString>;
|
|
68
|
+
}, z.core.$strip>>;
|
|
69
|
+
caveat: z.ZodString;
|
|
70
|
+
}, z.core.$strip>, readonly [{
|
|
71
|
+
readonly reason: "mirror_not_ready";
|
|
72
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
73
|
+
readonly when: "The sanctions mirror has never completed an initial sync.";
|
|
74
|
+
readonly retryable: true;
|
|
75
|
+
readonly recovery: "Run the mirror:init lifecycle script to load the sanctions lists, then retry; check sanctions_list_sources for readiness.";
|
|
76
|
+
}], {
|
|
77
|
+
readonly normalizedQuery: z.ZodString;
|
|
78
|
+
readonly matchModeUsed: z.ZodString;
|
|
79
|
+
readonly totalCount: z.ZodNumber;
|
|
80
|
+
readonly notice: z.ZodOptional<z.ZodString>;
|
|
81
|
+
}>;
|
|
82
|
+
//# sourceMappingURL=screen-name.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-name.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/screen-name.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA4CjE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgJzB,CAAC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `sanctions_screen_name` — the 80% entry point. Screens a name
|
|
3
|
+
* against all loaded watchlists (OFAC SDN + Consolidated, EU, UK, UN) at once,
|
|
4
|
+
* alias- and fuzzy-aware, and returns scored potential matches with source
|
|
5
|
+
* provenance. This is decision support, NOT a compliance determination: a hit is
|
|
6
|
+
* a candidate to verify against the official source, and an empty result is
|
|
7
|
+
* never a clearance.
|
|
8
|
+
* @module mcp-server/tools/definitions/screen-name.tool
|
|
9
|
+
*/
|
|
10
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
11
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
12
|
+
import { getScreeningService } from '../../../services/screening/screening-service.js';
|
|
13
|
+
import { SOURCE_CODES, SOURCE_LABELS } from '../../../services/screening/types.js';
|
|
14
|
+
import { SCREENING_CAVEAT } from './_shared.js';
|
|
15
|
+
const SOURCE_ENUM = z.enum(['ofac_sdn', 'ofac_consolidated', 'eu', 'uk', 'un']);
|
|
16
|
+
const HitSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
source: SOURCE_ENUM.describe('Which watchlist this candidate is on — its provenance.'),
|
|
19
|
+
sourceLabel: z.string().describe('Human-readable name of the source list.'),
|
|
20
|
+
sourceEntryId: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("The list's own entry ID — pass to sanctions_get_designation for the full record."),
|
|
23
|
+
entityType: z
|
|
24
|
+
.enum(['person', 'organization', 'vessel', 'aircraft', 'unknown'])
|
|
25
|
+
.describe('Entity classification as published by the source.'),
|
|
26
|
+
primaryName: z.string().describe('Primary published name of the designated entity.'),
|
|
27
|
+
matchedName: z.string().describe('The specific name or alias string that matched the query.'),
|
|
28
|
+
matchedNameType: z
|
|
29
|
+
.enum(['primary', 'aka', 'fka', 'low-quality-aka'])
|
|
30
|
+
.describe('Provenance of the matched name: primary, a.k.a., f.k.a., or a low-quality a.k.a.'),
|
|
31
|
+
matchType: z
|
|
32
|
+
.enum(['exact', 'strong', 'approximate'])
|
|
33
|
+
.describe('exact = normalized name equality; strong = all query tokens present; approximate = fuzzy/phonetic.'),
|
|
34
|
+
score: z
|
|
35
|
+
.number()
|
|
36
|
+
.optional()
|
|
37
|
+
.describe('Raw Jaro-Winkler similarity (0–1) for approximate hits only — a real measurement, not a confidence verdict. Absent for exact/strong hits.'),
|
|
38
|
+
program: z
|
|
39
|
+
.string()
|
|
40
|
+
.optional()
|
|
41
|
+
.describe('Sanctioning program / regime, when published by the source.'),
|
|
42
|
+
designationDate: z
|
|
43
|
+
.string()
|
|
44
|
+
.optional()
|
|
45
|
+
.describe('Designation date as published, when available.'),
|
|
46
|
+
})
|
|
47
|
+
.describe('One potential match — a candidate to verify, never a determination.');
|
|
48
|
+
export const screenNameTool = tool('sanctions_screen_name', {
|
|
49
|
+
title: 'sanctions-screening-mcp-server: screen name',
|
|
50
|
+
description: 'Screen a name (person, company, vessel, aircraft) against all loaded sanctions watchlists at once — OFAC SDN + Consolidated, EU, UK, and UN — alias- and fuzzy-aware. Returns scored potential matches with the source list, sanctioning program, designation date, and the matched alias. Strict mode (default) matches exact-normalized then all-tokens-present; fuzzy mode (or auto when strict is empty) adds Jaro-Winkler and phonetic matching and labels hits approximate with a raw 0–1 similarity score. This is a screening AID for a human/compliance review, NOT a compliance determination: a hit means "review this candidate against the official source," and an empty result never means "cleared."',
|
|
51
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
52
|
+
input: z.object({
|
|
53
|
+
name: z
|
|
54
|
+
.string()
|
|
55
|
+
.min(1)
|
|
56
|
+
.describe('The name to screen (person, organization, vessel, or aircraft).'),
|
|
57
|
+
entityType: z
|
|
58
|
+
.enum(['any', 'person', 'organization', 'vessel', 'aircraft'])
|
|
59
|
+
.default('any')
|
|
60
|
+
.describe('Restrict to one entity class, or "any" (default) to screen across all.'),
|
|
61
|
+
matchMode: z
|
|
62
|
+
.enum(['strict', 'fuzzy'])
|
|
63
|
+
.default('strict')
|
|
64
|
+
.describe('strict (default): exact-normalized then all-tokens-present. fuzzy: also scored Jaro-Winkler + phonetic. Strict auto-falls-back to fuzzy when it finds nothing.'),
|
|
65
|
+
minScore: z
|
|
66
|
+
.number()
|
|
67
|
+
.min(0)
|
|
68
|
+
.max(1)
|
|
69
|
+
.optional()
|
|
70
|
+
.describe("Jaro-Winkler similarity floor for fuzzy hits (0–1). Applies to fuzzy mode only; defaults to the server's configured floor."),
|
|
71
|
+
sources: z
|
|
72
|
+
.array(SOURCE_ENUM)
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('Restrict to specific source lists. Omit to screen all loaded lists.'),
|
|
75
|
+
limit: z
|
|
76
|
+
.number()
|
|
77
|
+
.int()
|
|
78
|
+
.min(1)
|
|
79
|
+
.max(100)
|
|
80
|
+
.default(25)
|
|
81
|
+
.describe('Maximum number of potential matches to return.'),
|
|
82
|
+
}),
|
|
83
|
+
output: z.object({
|
|
84
|
+
hits: z.array(HitSchema).describe('Scored potential matches, highest-confidence first.'),
|
|
85
|
+
caveat: z
|
|
86
|
+
.string()
|
|
87
|
+
.describe('Decision-support caveat — this is a screening aid, not a compliance determination.'),
|
|
88
|
+
}),
|
|
89
|
+
enrichment: {
|
|
90
|
+
normalizedQuery: z.string().describe('The name as the server folded it for matching.'),
|
|
91
|
+
matchModeUsed: z
|
|
92
|
+
.string()
|
|
93
|
+
.describe('The match mode actually applied (strict may auto-upgrade to fuzzy on empty).'),
|
|
94
|
+
totalCount: z.number().describe('Number of potential matches returned.'),
|
|
95
|
+
notice: z
|
|
96
|
+
.string()
|
|
97
|
+
.optional()
|
|
98
|
+
.describe('Guidance when no candidate matched — how to broaden, and what an empty result does NOT mean.'),
|
|
99
|
+
},
|
|
100
|
+
errors: [
|
|
101
|
+
{
|
|
102
|
+
reason: 'mirror_not_ready',
|
|
103
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
104
|
+
when: 'The sanctions mirror has never completed an initial sync.',
|
|
105
|
+
retryable: true,
|
|
106
|
+
recovery: 'Run the mirror:init lifecycle script to load the sanctions lists, then retry; check sanctions_list_sources for readiness.',
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
async handler(input, ctx) {
|
|
110
|
+
const svc = getScreeningService();
|
|
111
|
+
if (!(await svc.sanctionsReady())) {
|
|
112
|
+
throw ctx.fail('mirror_not_ready', 'The local sanctions mirror is not yet populated.', {
|
|
113
|
+
...ctx.recoveryFor('mirror_not_ready'),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const sources = input.sources && input.sources.length > 0 ? input.sources : [...SOURCE_CODES];
|
|
117
|
+
const result = await svc.screenName({
|
|
118
|
+
query: input.name,
|
|
119
|
+
entityType: input.entityType,
|
|
120
|
+
matchMode: input.matchMode,
|
|
121
|
+
...(input.minScore !== undefined ? { minScore: input.minScore } : {}),
|
|
122
|
+
sources,
|
|
123
|
+
limit: input.limit,
|
|
124
|
+
}, ctx);
|
|
125
|
+
ctx.enrich({ normalizedQuery: result.normalizedQuery, matchModeUsed: result.modeUsed });
|
|
126
|
+
ctx.enrich.total(result.hits.length);
|
|
127
|
+
if (result.hits.length === 0) {
|
|
128
|
+
ctx.enrich.notice(`No potential match for "${input.name}" across the selected lists (mode: ${result.modeUsed}). ` +
|
|
129
|
+
'This is NOT a clearance — the entity may be listed under a name variant the mirror does not index, ' +
|
|
130
|
+
'or under a transliteration. Try matchMode:"fuzzy", a broader name, or verify directly against the official source.');
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
hits: result.hits.map((h) => ({
|
|
134
|
+
source: h.source,
|
|
135
|
+
sourceLabel: SOURCE_LABELS[h.source],
|
|
136
|
+
sourceEntryId: h.sourceEntryId,
|
|
137
|
+
entityType: h.entityType,
|
|
138
|
+
primaryName: h.primaryName,
|
|
139
|
+
matchedName: h.matchedName,
|
|
140
|
+
matchedNameType: h.matchedNameType,
|
|
141
|
+
matchType: h.matchType,
|
|
142
|
+
...(h.score !== undefined ? { score: h.score } : {}),
|
|
143
|
+
...(h.program ? { program: h.program } : {}),
|
|
144
|
+
...(h.designationDate ? { designationDate: h.designationDate } : {}),
|
|
145
|
+
})),
|
|
146
|
+
caveat: SCREENING_CAVEAT,
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
format: (result) => {
|
|
150
|
+
const lines = [];
|
|
151
|
+
if (result.hits.length === 0) {
|
|
152
|
+
lines.push('**No potential matches found.**');
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
lines.push(`**${result.hits.length} potential match(es)** — candidates to verify, not determinations:\n`);
|
|
156
|
+
for (const h of result.hits) {
|
|
157
|
+
const scoreStr = h.score !== undefined ? ` · score ${h.score.toFixed(3)}` : '';
|
|
158
|
+
lines.push(`### ${h.primaryName} — ${h.matchType}${scoreStr}`);
|
|
159
|
+
lines.push(`**List:** ${h.sourceLabel} (\`${h.source}\`) | **Entry ID:** ${h.sourceEntryId} | **Type:** ${h.entityType}`);
|
|
160
|
+
lines.push(`**Matched on:** "${h.matchedName}" (${h.matchedNameType})`);
|
|
161
|
+
if (h.program)
|
|
162
|
+
lines.push(`**Program:** ${h.program}`);
|
|
163
|
+
if (h.designationDate)
|
|
164
|
+
lines.push(`**Designated:** ${h.designationDate}`);
|
|
165
|
+
lines.push('');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
lines.push(`> ${result.caveat}`);
|
|
169
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
//# sourceMappingURL=screen-name.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"screen-name.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/screen-name.tool.ts"],"names":[],"mappings":"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"}
|