@cyanheads/eur-lex-mcp-server 0.1.7 → 0.2.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 +1 -1
- package/CLAUDE.md +1 -1
- package/README.md +3 -3
- package/changelog/0.1.x/0.1.8.md +15 -0
- package/changelog/0.2.x/0.2.0.md +22 -0
- package/dist/mcp-server/tools/definitions/eurlex-browse-subjects.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-browse-subjects.tool.js +12 -0
- package/dist/mcp-server/tools/definitions/eurlex-browse-subjects.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.d.ts +8 -3
- package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.js +43 -7
- package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.d.ts +9 -4
- package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.js +56 -21
- package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.d.ts +5 -6
- package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.js +29 -50
- package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +21 -12
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/services/cellar-sparql/eli-resolution.d.ts +45 -0
- package/dist/services/cellar-sparql/eli-resolution.d.ts.map +1 -0
- package/dist/services/cellar-sparql/eli-resolution.js +71 -0
- package/dist/services/cellar-sparql/eli-resolution.js.map +1 -0
- package/package.json +1 -1
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** eur-lex-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
4
|
+
**Version:** 0.2.0
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.10.9`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
|
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** eur-lex-mcp-server
|
|
4
|
-
**Version:** 0.
|
|
4
|
+
**Version:** 0.2.0
|
|
5
5
|
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.10.9`
|
|
6
6
|
**Engines:** Bun ≥1.3.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/sdk` ^1.29.0
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/eur-lex-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/eur-lex-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -35,7 +35,7 @@ Seven tools covering EU legal research — document discovery, content retrieval
|
|
|
35
35
|
|:-----|:------------|
|
|
36
36
|
| `eurlex_search_documents` | Search EU legislation, treaties, and preparatory acts across the CELLAR corpus. Filters by document type, date range, EuroVoc concept, author institution, and in-force status. |
|
|
37
37
|
| `eurlex_get_document` | Fetch structured metadata and full text (HTML or Formex4 XML) for a work by CELEX number or ELI URI. |
|
|
38
|
-
| `eurlex_lookup_celex` | Resolve
|
|
38
|
+
| `eurlex_lookup_celex` | Resolve an EU legal citation — a CELEX number or an ELI URI — to the canonical CELLAR work. |
|
|
39
39
|
| `eurlex_get_cases` | Search CJEU and General Court case law — judgments, orders, and Advocate General opinions — by case number, party name, subject, or date range. |
|
|
40
40
|
| `eurlex_get_relations` | Traverse the CELLAR relationship graph: amendment chain, consolidated versions, legal basis, citation network, and national transposition measures. |
|
|
41
41
|
| `eurlex_browse_subjects` | Search the EuroVoc multilingual thesaurus to resolve human-readable terms to EuroVoc concept IDs — required before using the `eurovoc_concept` filter in `eurlex_search_documents`. |
|
|
@@ -71,7 +71,7 @@ Fetch the notice and full text of an EU legal act.
|
|
|
71
71
|
|
|
72
72
|
Resolve EU legal identifiers to canonical CELLAR works.
|
|
73
73
|
|
|
74
|
-
- Accepts CELEX numbers
|
|
74
|
+
- Accepts CELEX numbers and ELI URIs
|
|
75
75
|
- Auto-detects format with `identifier_type: "auto"` (default); set explicitly when auto-detection fails
|
|
76
76
|
- Returns work URI, confirmed CELEX number, document type, and date — the prerequisite step before `eurlex_get_document` or `eurlex_get_relations`
|
|
77
77
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "eurlex_lookup_celex now resolves ELI URIs via an exact cdm:resource_legal_eli match, with bare work-level ELIs retrying once with /oj; the never-functional oj identifier_type is removed"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.1.8 — 2026-06-30
|
|
8
|
+
|
|
9
|
+
## Removed
|
|
10
|
+
|
|
11
|
+
- **`oj` identifier_type** ([#5](https://github.com/cyanheads/eur-lex-mcp-server/issues/5)) — dropped from `eurlex_lookup_celex`; the enum now accepts `"celex"`, `"eli"`, and `"auto"` only. It never resolved an act: an Official Journal reference has no literal in CELLAR, an issue-level reference maps to multiple works (`OJ L 119/2016` → GDPR plus the Police and PNR Directives), and it carries no year. Removing dead, never-functional surface — not a behavior change for any working input.
|
|
12
|
+
|
|
13
|
+
## Fixed
|
|
14
|
+
|
|
15
|
+
- **`eurlex_lookup_celex` ELI resolution** ([#5](https://github.com/cyanheads/eur-lex-mcp-server/issues/5)) — the ELI branch ran a `CONTAINS(STR(?work), …)` substring scan over work URIs that never matched, so ELI lookups always returned `not_found`. ELIs now resolve by exact match on the canonical `cdm:resource_legal_eli` (`xsd:anyURI`) literal. A bare work-level ELI (`{type}/{year}/{number}`) misses CELLAR's `…/{number}/oj` manifestation literal, so it retries once with `/oj` appended — deterministic and one-to-one. Manifestation-suffixed ELIs (e.g. a `/YYYY-MM-DD` consolidated version) are excluded from the retry, so a missing consolidated version never falls back to the original act.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "eurlex_get_document accepts eli_uri and eurlex_get_relations accepts work_uri as functional identifier alternatives (exactly one of the pair required); eurlex_browse_subjects restricts results to EuroVoc concepts so every concept_uri is usable as an eurovoc_concept filter"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.2.0 — 2026-06-30
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`eli_uri` on `eurlex_get_document`** ([#8](https://github.com/cyanheads/eur-lex-mcp-server/issues/8)) — accepts a work-level ELI URI (e.g. `http://data.europa.eu/eli/reg/2016/679`, with or without `/oj`) as an alternative to `celex_number`, resolved to its CELLAR work by an exact `cdm:resource_legal_eli` match with a bare-work `/oj` retry. The resolution is now shared with `eurlex_lookup_celex` via the new `services/cellar-sparql/eli-resolution.ts`.
|
|
12
|
+
- **`work_uri` on `eurlex_get_relations`** ([#8](https://github.com/cyanheads/eur-lex-mcp-server/issues/8)) — accepts a CELLAR work resource URI used directly to seed the relation traversal, skipping the CELEX→work resolution step.
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **`celex_number` is now optional** on `eurlex_get_document` and `eurlex_get_relations` ([#8](https://github.com/cyanheads/eur-lex-mcp-server/issues/8)) — each call takes exactly one of its identifier pair. Passing neither or both raises a new `invalid_identifier_args` (`ValidationError`), and an empty-string field from form-based clients is treated as absent. Existing `celex_number`-only calls are unaffected.
|
|
17
|
+
- **`eurlex_get_relations` output** ([#8](https://github.com/cyanheads/eur-lex-mcp-server/issues/8)) — `work_uri` is now always present; `celex_number` is now optional, omitted when the work was addressed directly by `work_uri`.
|
|
18
|
+
|
|
19
|
+
## Fixed
|
|
20
|
+
|
|
21
|
+
- **Advertised URI alternatives were unreachable** ([#8](https://github.com/cyanheads/eur-lex-mcp-server/issues/8)) — `eli_uri` (`eurlex_get_document`) and `work_uri` (`eurlex_get_relations`) were documented as alternatives, but a required `celex_number` meant they could never be supplied alone. Both now resolve.
|
|
22
|
+
- **`eurlex_browse_subjects` returned unusable URIs** ([#11](https://github.com/cyanheads/eur-lex-mcp-server/issues/11)) — a `STRSTARTS` filter limits results to the `http://eurovoc.europa.eu/` namespace, so every returned `concept_uri` works in the `eurlex_search_documents` `eurovoc_concept` filter. Other Publications Office authority concepts (e.g. `class-sum-leg`, `fd_*`), which that filter cannot match, are no longer returned.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-browse-subjects.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-browse-subjects.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"eurlex-browse-subjects.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-browse-subjects.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAgBjE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;cAqIjC,CAAC"}
|
|
@@ -5,11 +5,22 @@
|
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { CellarSparqlService, getCellarSparqlService, } from '../../../services/cellar-sparql/cellar-sparql-service.js';
|
|
8
|
+
/**
|
|
9
|
+
* Namespace of actual EuroVoc concepts. CELLAR's skos:Concept space also holds
|
|
10
|
+
* other Publications Office authority concepts (class-sum-leg, fd_*, …) whose
|
|
11
|
+
* URIs the eurlex_search_documents `eurovoc_concept` filter accepts but cannot
|
|
12
|
+
* match — only `http://eurovoc.europa.eu/` concepts are bound by
|
|
13
|
+
* `cdm:work_is_about_concept_eurovoc`. Results are restricted to this namespace
|
|
14
|
+
* so every URI returned is usable in that filter (#11).
|
|
15
|
+
*/
|
|
16
|
+
const EUROVOC_CONCEPT_NAMESPACE = 'http://eurovoc.europa.eu/';
|
|
8
17
|
export const eurlex_browse_subjects = tool('eurlex_browse_subjects', {
|
|
9
18
|
title: 'Browse EuroVoc Subjects',
|
|
10
19
|
description: 'Search the EuroVoc multilingual thesaurus to resolve a human-readable term or keyword into EuroVoc concept IDs. ' +
|
|
11
20
|
'This tool is required before using the eurovoc_concept filter in eurlex_search_documents — ' +
|
|
12
21
|
'agents cannot guess numeric EuroVoc concept IDs. ' +
|
|
22
|
+
'Every returned concept_uri is a EuroVoc concept (http://eurovoc.europa.eu/…) directly usable in that filter; ' +
|
|
23
|
+
'other Publications Office authority concepts are excluded because the filter cannot match them. ' +
|
|
13
24
|
'Returns concept URI, preferred label in the requested language, concept code, and broader/narrower hierarchy hints. ' +
|
|
14
25
|
'EuroVoc covers all EU policy domains: agriculture, environment, finance, health, trade, transport, and more. ' +
|
|
15
26
|
'If no results are found in a non-English language, retry with language "en" and a broader English term.',
|
|
@@ -75,6 +86,7 @@ SELECT ?concept ?label ?code ?broaderLabel WHERE {
|
|
|
75
86
|
?broader skos:prefLabel ?broaderLabel .
|
|
76
87
|
FILTER(LANG(?broaderLabel) = "${lang}")
|
|
77
88
|
}
|
|
89
|
+
FILTER(STRSTARTS(STR(?concept), "${EUROVOC_CONCEPT_NAMESPACE}"))
|
|
78
90
|
FILTER(LANG(?label) = "${lang}")
|
|
79
91
|
FILTER(CONTAINS(LCASE(STR(?label)), "${keyword.replace(/"/g, '\\"')}"))
|
|
80
92
|
} LIMIT ${limit}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-browse-subjects.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-browse-subjects.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mDAAmD,CAAC;AAE3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC,wBAAwB,EAAE;IACnE,KAAK,EAAE,yBAAyB;IAChC,WAAW,EACT,kHAAkH;QAClH,6FAA6F;QAC7F,mDAAmD;QACnD,sHAAsH;QACtH,+GAA+G;QAC/G,yGAAyG;IAC3G,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE;IAC9E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CACP,+FAA+F,CAChG;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,KAAK,CAAC,cAAc,CAAC;aACrB,OAAO,CAAC,IAAI,CAAC;aACb,QAAQ,CAAC,gFAAgF,CAAC;QAC7F,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,sEAAsE,CAAC;KACpF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC;aACR,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,CAAC,yEAAyE,CAAC;YACtF,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,CAAC,4DAA4D,CAAC;YACzE,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;YAC7E,aAAa,EAAE,CAAC;iBACb,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,gEAAgE,CAAC;SAC9E,CAAC;aACD,QAAQ,CAAC,4EAA4E,CAAC,CAC1F;aACA,QAAQ,CAAC,oEAAoE,CAAC;QACjF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;KAC5E,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,aAAa;YACrB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,oEAAoE;YAC1E,QAAQ,EAAE,gFAAgF;SAC3F;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC;QACrC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;QACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAE1B,MAAM,MAAM,GAAG;;;;;;;;oCAQiB,IAAI;;
|
|
1
|
+
{"version":3,"file":"eurlex-browse-subjects.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-browse-subjects.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
export declare const eurlex_get_document: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
-
celex_number: z.ZodString
|
|
8
|
+
celex_number: z.ZodOptional<z.ZodString>;
|
|
9
9
|
eli_uri: z.ZodOptional<z.ZodString>;
|
|
10
10
|
language: z.ZodDefault<z.ZodString>;
|
|
11
11
|
format: z.ZodDefault<z.ZodEnum<{
|
|
@@ -28,10 +28,15 @@ export declare const eurlex_get_document: import("@cyanheads/mcp-ts-core").ToolD
|
|
|
28
28
|
language_fallback: z.ZodOptional<z.ZodString>;
|
|
29
29
|
content_format: z.ZodString;
|
|
30
30
|
}, z.core.$strip>, readonly [{
|
|
31
|
+
readonly reason: "invalid_identifier_args";
|
|
32
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
33
|
+
readonly when: "Neither celex_number nor eli_uri was provided, or both were.";
|
|
34
|
+
readonly recovery: "Provide exactly one of celex_number or eli_uri.";
|
|
35
|
+
}, {
|
|
31
36
|
readonly reason: "not_found";
|
|
32
37
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
33
|
-
readonly when: "CELEX number not found in CELLAR — the work does not exist in the corpus.";
|
|
34
|
-
readonly recovery: "Verify the
|
|
38
|
+
readonly when: "CELEX number or ELI URI not found in CELLAR — the work does not exist in the corpus.";
|
|
39
|
+
readonly recovery: "Verify the identifier or use eurlex_lookup_celex to confirm it exists.";
|
|
35
40
|
}, {
|
|
36
41
|
readonly reason: "language_unavailable";
|
|
37
42
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-get-document.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-document.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"eurlex-get-document.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-document.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAiBjE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgS9B,CAAC"}
|
|
@@ -6,6 +6,7 @@ import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { ENG_LANGUAGE_URI, resolveCorporateBodyLabel, resolveResourceTypeLabel, } from '../../../services/cellar-sparql/cdm-labels.js';
|
|
8
8
|
import { CellarSparqlService, getCellarSparqlService, } from '../../../services/cellar-sparql/cellar-sparql-service.js';
|
|
9
|
+
import { escapeSparqlLiteral, resolveEliToWork } from '../../../services/cellar-sparql/eli-resolution.js';
|
|
9
10
|
import { getEurLexContentService, } from '../../../services/eurlex-content/eurlex-content-service.js';
|
|
10
11
|
export const eurlex_get_document = tool('eurlex_get_document', {
|
|
11
12
|
title: 'Get EU Document',
|
|
@@ -22,12 +23,15 @@ export const eurlex_get_document = tool('eurlex_get_document', {
|
|
|
22
23
|
input: z.object({
|
|
23
24
|
celex_number: z
|
|
24
25
|
.string()
|
|
25
|
-
.
|
|
26
|
-
.describe('CELEX number of the act to fetch (e.g. 32016R0679 for GDPR).
|
|
26
|
+
.optional()
|
|
27
|
+
.describe('CELEX number of the act to fetch (e.g. 32016R0679 for GDPR). ' +
|
|
28
|
+
'Provide exactly one of celex_number or eli_uri.'),
|
|
27
29
|
eli_uri: z
|
|
28
30
|
.string()
|
|
29
31
|
.optional()
|
|
30
|
-
.describe('ELI URI
|
|
32
|
+
.describe('Work-level ELI URI of the act to fetch, resolved to its CELLAR work (e.g. ' +
|
|
33
|
+
'http://data.europa.eu/eli/reg/2016/679, with or without the /oj suffix). ' +
|
|
34
|
+
'Provide exactly one of celex_number or eli_uri.'),
|
|
31
35
|
language: z
|
|
32
36
|
.string()
|
|
33
37
|
.regex(/^[A-Za-z]{2,3}$/)
|
|
@@ -77,11 +81,17 @@ export const eurlex_get_document = tool('eurlex_get_document', {
|
|
|
77
81
|
content_format: z.string().describe('Format of the returned content: "html" or "xml".'),
|
|
78
82
|
}),
|
|
79
83
|
errors: [
|
|
84
|
+
{
|
|
85
|
+
reason: 'invalid_identifier_args',
|
|
86
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
87
|
+
when: 'Neither celex_number nor eli_uri was provided, or both were.',
|
|
88
|
+
recovery: 'Provide exactly one of celex_number or eli_uri.',
|
|
89
|
+
},
|
|
80
90
|
{
|
|
81
91
|
reason: 'not_found',
|
|
82
92
|
code: JsonRpcErrorCode.NotFound,
|
|
83
|
-
when: 'CELEX number not found in CELLAR — the work does not exist in the corpus.',
|
|
84
|
-
recovery: 'Verify the
|
|
93
|
+
when: 'CELEX number or ELI URI not found in CELLAR — the work does not exist in the corpus.',
|
|
94
|
+
recovery: 'Verify the identifier or use eurlex_lookup_celex to confirm it exists.',
|
|
85
95
|
},
|
|
86
96
|
{
|
|
87
97
|
reason: 'language_unavailable',
|
|
@@ -99,10 +109,36 @@ export const eurlex_get_document = tool('eurlex_get_document', {
|
|
|
99
109
|
async handler(input, ctx) {
|
|
100
110
|
const sparqlSvc = getCellarSparqlService();
|
|
101
111
|
const contentSvc = getEurLexContentService();
|
|
102
|
-
|
|
112
|
+
// Accept exactly one identifier: a CELEX number, or an ELI URI resolved to
|
|
113
|
+
// its CELLAR work. Treat empty/whitespace as absent so form-based clients
|
|
114
|
+
// that send "" for an omitted field route to the friendly guard, not -32602.
|
|
115
|
+
// An ELI is resolved to its CELLAR work via the shared #5 resolution
|
|
116
|
+
// (cdm:resource_legal_eli exact-match + bare-work /oj retry), then the rest
|
|
117
|
+
// of the flow (metadata + content) is keyed on the confirmed CELEX.
|
|
118
|
+
const celexInput = input.celex_number?.trim();
|
|
119
|
+
const eliInput = input.eli_uri?.trim();
|
|
120
|
+
let celexNumber;
|
|
121
|
+
if (eliInput && !celexInput) {
|
|
122
|
+
const binding = await resolveEliToWork(sparqlSvc, eliInput, ctx);
|
|
123
|
+
const resolvedCelex = binding && CellarSparqlService.bindingValue(binding, 'celexNumber');
|
|
124
|
+
if (!resolvedCelex) {
|
|
125
|
+
throw ctx.fail('not_found', `No CELLAR work found for ELI: ${eliInput}`, {
|
|
126
|
+
...ctx.recoveryFor('not_found'),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
celexNumber = resolvedCelex;
|
|
130
|
+
}
|
|
131
|
+
else if (celexInput && !eliInput) {
|
|
132
|
+
celexNumber = celexInput;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
throw ctx.fail('invalid_identifier_args', celexInput
|
|
136
|
+
? 'Provide only one of celex_number or eli_uri, not both.'
|
|
137
|
+
: 'Provide either celex_number or eli_uri.', { ...ctx.recoveryFor('invalid_identifier_args') });
|
|
138
|
+
}
|
|
103
139
|
const language = (input.language.trim().toUpperCase() || 'EN');
|
|
104
140
|
const format = input.format;
|
|
105
|
-
const safeCelexNumber = celexNumber
|
|
141
|
+
const safeCelexNumber = escapeSparqlLiteral(celexNumber);
|
|
106
142
|
// Step 1: Fetch metadata via SPARQL
|
|
107
143
|
const metaSparql = `
|
|
108
144
|
SELECT ?work ?celexNumber ?type ?date ?title ?inForce ?author ?legalBasis ?eurovoc WHERE {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-get-document.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-document.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAGL,uBAAuB,GACxB,MAAM,qDAAqD,CAAC;AAE7D,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,EAAE;IAC7D,KAAK,EAAE,iBAAiB;IACxB,WAAW,EACT,qFAAqF;QACrF,gHAAgH;QAChH,kEAAkE;QAClE,wFAAwF;QACxF,iDAAiD;QACjD,mHAAmH;QACnH,uEAAuE;QACvE,8EAA8E;QAC9E,4GAA4G;IAC9G,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAC9E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,
|
|
1
|
+
{"version":3,"file":"eurlex-get-document.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-document.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
export declare const eurlex_get_relations: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
8
|
-
celex_number: z.ZodString
|
|
8
|
+
celex_number: z.ZodOptional<z.ZodString>;
|
|
9
9
|
work_uri: z.ZodOptional<z.ZodString>;
|
|
10
10
|
relation_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
11
11
|
cites: "cites";
|
|
@@ -15,8 +15,8 @@ export declare const eurlex_get_relations: import("@cyanheads/mcp-ts-core").Tool
|
|
|
15
15
|
consolidated_version: "consolidated_version";
|
|
16
16
|
}>>>;
|
|
17
17
|
}, z.core.$strip>, z.ZodObject<{
|
|
18
|
-
celex_number: z.ZodString
|
|
19
|
-
work_uri: z.
|
|
18
|
+
celex_number: z.ZodOptional<z.ZodString>;
|
|
19
|
+
work_uri: z.ZodString;
|
|
20
20
|
relations: z.ZodArray<z.ZodObject<{
|
|
21
21
|
relation_type: z.ZodString;
|
|
22
22
|
direction: z.ZodString;
|
|
@@ -25,9 +25,14 @@ export declare const eurlex_get_relations: import("@cyanheads/mcp-ts-core").Tool
|
|
|
25
25
|
}, z.core.$strip>>;
|
|
26
26
|
total: z.ZodNumber;
|
|
27
27
|
}, z.core.$strip>, readonly [{
|
|
28
|
+
readonly reason: "invalid_identifier_args";
|
|
29
|
+
readonly code: JsonRpcErrorCode.ValidationError;
|
|
30
|
+
readonly when: "Neither celex_number nor work_uri was provided, or both were.";
|
|
31
|
+
readonly recovery: "Provide exactly one of celex_number or work_uri.";
|
|
32
|
+
}, {
|
|
28
33
|
readonly reason: "not_found";
|
|
29
34
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
30
|
-
readonly when: "CELEX
|
|
35
|
+
readonly when: "CELEX number not found in CELLAR — resolve the identifier with eurlex_lookup_celex first.";
|
|
31
36
|
readonly recovery: "Use eurlex_lookup_celex to confirm the CELEX number exists, then retry.";
|
|
32
37
|
}, {
|
|
33
38
|
readonly reason: "no_relations";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-get-relations.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-relations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"eurlex-get-relations.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-relations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA4BjE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkQ/B,CAAC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { CellarSparqlService, getCellarSparqlService, } from '../../../services/cellar-sparql/cellar-sparql-service.js';
|
|
8
|
+
import { escapeSparqlLiteral } from '../../../services/cellar-sparql/eli-resolution.js';
|
|
8
9
|
/** CDM relation predicates traversed by this tool. */
|
|
9
10
|
const CDM_RELATIONS = {
|
|
10
11
|
cites: 'cdm:work_cites_work',
|
|
@@ -34,12 +35,21 @@ export const eurlex_get_relations = tool('eurlex_get_relations', {
|
|
|
34
35
|
input: z.object({
|
|
35
36
|
celex_number: z
|
|
36
37
|
.string()
|
|
37
|
-
.
|
|
38
|
-
.describe('CELEX number of the work to traverse (e.g. 32016R0679).
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('CELEX number of the work to traverse (e.g. 32016R0679). ' +
|
|
40
|
+
'Provide exactly one of celex_number or work_uri.'),
|
|
39
41
|
work_uri: z
|
|
40
42
|
.string()
|
|
43
|
+
.refine((v) => !v ||
|
|
44
|
+
(v.startsWith('http') &&
|
|
45
|
+
!v.includes('>') &&
|
|
46
|
+
!v.includes('<') &&
|
|
47
|
+
!v.includes('"') &&
|
|
48
|
+
!v.includes(' ')), { message: 'work_uri must be a valid http URI with no angle brackets, quotes, or spaces.' })
|
|
41
49
|
.optional()
|
|
42
|
-
.describe('CELLAR work URI
|
|
50
|
+
.describe('CELLAR work resource URI to traverse (e.g. ' +
|
|
51
|
+
'http://publications.europa.eu/resource/cellar/3e485e15-11bd-11e6-ba9a-01aa75ed71a1). ' +
|
|
52
|
+
'Used directly without CELEX resolution. Provide exactly one of celex_number or work_uri.'),
|
|
43
53
|
relation_types: z
|
|
44
54
|
.array(z.enum(['cites', 'amends', 'amended_by', 'legal_basis', 'consolidated_version']))
|
|
45
55
|
.optional()
|
|
@@ -50,11 +60,12 @@ export const eurlex_get_relations = tool('eurlex_get_relations', {
|
|
|
50
60
|
output: z.object({
|
|
51
61
|
celex_number: z
|
|
52
62
|
.string()
|
|
53
|
-
.
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('CELEX number of the source work whose relations were traversed. ' +
|
|
65
|
+
'Absent when the work was addressed directly by work_uri.'),
|
|
54
66
|
work_uri: z
|
|
55
67
|
.string()
|
|
56
|
-
.
|
|
57
|
-
.describe('CELLAR URI of the source work (resolved from the CELEX number).'),
|
|
68
|
+
.describe('CELLAR URI of the source work (the work_uri input, or resolved from the CELEX).'),
|
|
58
69
|
relations: z
|
|
59
70
|
.array(z
|
|
60
71
|
.object({
|
|
@@ -75,10 +86,16 @@ export const eurlex_get_relations = tool('eurlex_get_relations', {
|
|
|
75
86
|
total: z.number().describe('Total number of direct CDM relations returned.'),
|
|
76
87
|
}),
|
|
77
88
|
errors: [
|
|
89
|
+
{
|
|
90
|
+
reason: 'invalid_identifier_args',
|
|
91
|
+
code: JsonRpcErrorCode.ValidationError,
|
|
92
|
+
when: 'Neither celex_number nor work_uri was provided, or both were.',
|
|
93
|
+
recovery: 'Provide exactly one of celex_number or work_uri.',
|
|
94
|
+
},
|
|
78
95
|
{
|
|
79
96
|
reason: 'not_found',
|
|
80
97
|
code: JsonRpcErrorCode.NotFound,
|
|
81
|
-
when: 'CELEX
|
|
98
|
+
when: 'CELEX number not found in CELLAR — resolve the identifier with eurlex_lookup_celex first.',
|
|
82
99
|
recovery: 'Use eurlex_lookup_celex to confirm the CELEX number exists, then retry.',
|
|
83
100
|
},
|
|
84
101
|
{
|
|
@@ -90,21 +107,37 @@ export const eurlex_get_relations = tool('eurlex_get_relations', {
|
|
|
90
107
|
],
|
|
91
108
|
async handler(input, ctx) {
|
|
92
109
|
const svc = getCellarSparqlService();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
110
|
+
// Accept exactly one identifier. Treat empty/whitespace as absent so
|
|
111
|
+
// form-based clients sending "" for an omitted field hit the friendly guard.
|
|
112
|
+
const celexNumber = input.celex_number?.trim();
|
|
113
|
+
const workUriInput = input.work_uri?.trim();
|
|
114
|
+
// Step 1: Determine the source work URI. A work_uri is the CELLAR work
|
|
115
|
+
// resource directly — use it as-is, skipping the CELEX→work resolution that
|
|
116
|
+
// would otherwise throw not_found before the URI could be used. A
|
|
117
|
+
// celex_number is resolved to its work first.
|
|
118
|
+
let workUri;
|
|
119
|
+
if (workUriInput && !celexNumber) {
|
|
120
|
+
workUri = workUriInput;
|
|
121
|
+
}
|
|
122
|
+
else if (celexNumber && !workUriInput) {
|
|
123
|
+
const resolveSparql = `
|
|
97
124
|
SELECT ?work WHERE {
|
|
98
125
|
?work cdm:resource_legal_id_celex ?celex .
|
|
99
|
-
FILTER(STR(?celex) = "${
|
|
126
|
+
FILTER(STR(?celex) = "${escapeSparqlLiteral(celexNumber)}")
|
|
100
127
|
} LIMIT 1`;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
128
|
+
const resolveBindings = await svc.query(resolveSparql, ctx);
|
|
129
|
+
if (resolveBindings.length === 0) {
|
|
130
|
+
throw ctx.fail('not_found', `No CELLAR work found for CELEX: ${celexNumber}`, {
|
|
131
|
+
...ctx.recoveryFor('not_found'),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
workUri = CellarSparqlService.bindingValue(resolveBindings[0], 'work') ?? '';
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
throw ctx.fail('invalid_identifier_args', celexNumber
|
|
138
|
+
? 'Provide only one of celex_number or work_uri, not both.'
|
|
139
|
+
: 'Provide either celex_number or work_uri.', { ...ctx.recoveryFor('invalid_identifier_args') });
|
|
106
140
|
}
|
|
107
|
-
const workUri = CellarSparqlService.bindingValue(resolveBindings[0], 'work') ?? input.work_uri ?? '';
|
|
108
141
|
// Step 2: Build relation type filter
|
|
109
142
|
const requestedTypes = input.relation_types ?? [
|
|
110
143
|
'cites',
|
|
@@ -143,7 +176,7 @@ SELECT ?relatedWork ?relatedCelex ?relationType ?direction WHERE {
|
|
|
143
176
|
resultCount: relationBindings.length,
|
|
144
177
|
});
|
|
145
178
|
if (relationBindings.length === 0) {
|
|
146
|
-
throw ctx.fail('no_relations', `Work ${celexNumber} has no CDM relations of the requested types.`, {
|
|
179
|
+
throw ctx.fail('no_relations', `Work ${celexNumber ?? workUri} has no CDM relations of the requested types.`, {
|
|
147
180
|
...ctx.recoveryFor('no_relations'),
|
|
148
181
|
});
|
|
149
182
|
}
|
|
@@ -170,14 +203,16 @@ SELECT ?relatedWork ?relatedCelex ?relationType ?direction WHERE {
|
|
|
170
203
|
relations.push(entry);
|
|
171
204
|
}
|
|
172
205
|
return {
|
|
173
|
-
celex_number: celexNumber,
|
|
206
|
+
...(celexNumber ? { celex_number: celexNumber } : {}),
|
|
174
207
|
work_uri: workUri,
|
|
175
208
|
relations,
|
|
176
209
|
total: relations.length,
|
|
177
210
|
};
|
|
178
211
|
},
|
|
179
212
|
format: (result) => {
|
|
180
|
-
const lines = [
|
|
213
|
+
const lines = [
|
|
214
|
+
`## Relations for ${result.celex_number ?? result.work_uri} (${result.total} found)\n`,
|
|
215
|
+
];
|
|
181
216
|
if (result.work_uri)
|
|
182
217
|
lines.push(`**Work URI:** ${result.work_uri}\n`);
|
|
183
218
|
const grouped = new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-get-relations.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-relations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mDAAmD,CAAC;
|
|
1
|
+
{"version":3,"file":"eurlex-get-relations.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-get-relations.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAEjF,sDAAsD;AACtD,MAAM,aAAa,GAA2B;IAC5C,KAAK,EAAE,qBAAqB;IAC5B,MAAM,EAAE,0CAA0C;IAClD,UAAU,EAAE,8CAA8C;IAC1D,WAAW,EAAE,4CAA4C;IACzD,oBAAoB,EAAE,6CAA6C;CACpE,CAAC;AAEF,8DAA8D;AAC9D,MAAM,iBAAiB,GAA2B;IAChD,4DAA4D,EAAE,OAAO;IACrE,iFAAiF,EAAE,QAAQ;IAC3F,qFAAqF,EACnF,YAAY;IACd,mFAAmF,EACjF,aAAa;IACf,oFAAoF,EAClF,sBAAsB;CACzB,CAAC;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,sBAAsB,EAAE;IAC/D,KAAK,EAAE,+BAA+B;IACtC,WAAW,EACT,6DAA6D;QAC7D,6GAA6G;QAC7G,oIAAoI;QACpI,wFAAwF;QACxF,+GAA+G;QAC/G,4CAA4C;QAC5C,0GAA0G;IAC5G,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAC9E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,0DAA0D;YACxD,kDAAkD,CACrD;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,MAAM,CACL,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC;YACF,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;gBACnB,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAChB,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAChB,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAChB,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EACrB,EAAE,OAAO,EAAE,8EAA8E,EAAE,CAC5F;aACA,QAAQ,EAAE;aACV,QAAQ,CACP,6CAA6C;YAC3C,uFAAuF;YACvF,0FAA0F,CAC7F;QACH,cAAc,EAAE,CAAC;aACd,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,sBAAsB,CAAC,CAAC,CAAC;aACvF,QAAQ,EAAE;aACV,QAAQ,CACP,gEAAgE;YAC9D,8FAA8F;YAC9F,6GAA6G,CAChH;KACJ,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,kEAAkE;YAChE,0DAA0D,CAC7D;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,CAAC,iFAAiF,CAAC;QAC9F,SAAS,EAAE,CAAC;aACT,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,aAAa,EAAE,CAAC;iBACb,MAAM,EAAE;iBACR,QAAQ,CACP,iFAAiF,CAClF;YACH,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,CACP,kFAAkF,CACnF;YACH,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;YACxE,oBAAoB,EAAE,CAAC;iBACpB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,iDAAiD,CAAC;SAC/D,CAAC;aACD,QAAQ,CAAC,mEAAmE,CAAC,CACjF;aACA,QAAQ,CAAC,8CAA8C,CAAC;QAC3D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC;KAC7E,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,yBAAyB;YACjC,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,+DAA+D;YACrE,QAAQ,EAAE,kDAAkD;SAC7D;QACD;YACE,MAAM,EAAE,WAAW;YACnB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,2FAA2F;YACjG,QAAQ,EAAE,yEAAyE;SACpF;QACD;YACE,MAAM,EAAE,cAAc;YACtB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,8DAA8D;YACpE,QAAQ,EACN,oFAAoF;SACvF;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,GAAG,GAAG,sBAAsB,EAAE,CAAC;QAErC,qEAAqE;QACrE,6EAA6E;QAC7E,MAAM,WAAW,GAAG,KAAK,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC;QAC/C,MAAM,YAAY,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;QAE5C,uEAAuE;QACvE,4EAA4E;QAC5E,kEAAkE;QAClE,8CAA8C;QAC9C,IAAI,OAAe,CAAC;QACpB,IAAI,YAAY,IAAI,CAAC,WAAW,EAAE,CAAC;YACjC,OAAO,GAAG,YAAY,CAAC;QACzB,CAAC;aAAM,IAAI,WAAW,IAAI,CAAC,YAAY,EAAE,CAAC;YACxC,MAAM,aAAa,GAAG;;;0BAGF,mBAAmB,CAAC,WAAW,CAAC;UAChD,CAAC;YAEL,MAAM,eAAe,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;YAC5D,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACjC,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,mCAAmC,WAAW,EAAE,EAAE;oBAC5E,GAAG,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC;iBAChC,CAAC,CAAC;YACL,CAAC;YACD,OAAO,GAAG,mBAAmB,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAC/E,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC,IAAI,CACZ,yBAAyB,EACzB,WAAW;gBACT,CAAC,CAAC,yDAAyD;gBAC3D,CAAC,CAAC,0CAA0C,EAC9C,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC,yBAAyB,CAAC,EAAE,CAClD,CAAC;QACJ,CAAC;QAED,qCAAqC;QACrC,MAAM,cAAc,GAAG,KAAK,CAAC,cAAc,IAAI;YAC7C,OAAO;YACP,QAAQ;YACR,YAAY;YACZ,aAAa;YACb,sBAAsB;SACvB,CAAC;QACF,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAE/E,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,oCAAoC,EAAE;gBACnE,GAAG,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC;aACnC,CAAC,CAAC;QACL,CAAC;QAED,0DAA0D;QAC1D,MAAM,cAAc,GAAG;;;;OAIpB,OAAO;;;+BAGiB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;;;kCAGlB,OAAO;;;+BAGV,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;;YAExC,CAAC;QAET,MAAM,gBAAgB,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;QAC9D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE;YACjC,WAAW;YACX,OAAO;YACP,WAAW,EAAE,gBAAgB,CAAC,MAAM;SACrC,CAAC,CAAC;QAEH,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,MAAM,GAAG,CAAC,IAAI,CACZ,cAAc,EACd,QAAQ,WAAW,IAAI,OAAO,+CAA+C,EAC7E;gBACE,GAAG,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC;aACnC,CACF,CAAC;QACJ,CAAC;QAED,wBAAwB;QACxB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,MAAM,SAAS,GAKV,EAAE,CAAC;QAER,KAAK,MAAM,CAAC,IAAI,gBAAgB,EAAE,CAAC;YACjC,MAAM,cAAc,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,EAAE,CAAC;YAChF,MAAM,YAAY,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc,CAAC,IAAI,EAAE,CAAC;YAC/E,MAAM,SAAS,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,UAAU,CAAC;YACjF,MAAM,GAAG,GAAG,GAAG,YAAY,IAAI,cAAc,IAAI,SAAS,EAAE,CAAC;YAE7D,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEd,MAAM,YAAY,GAAG,iBAAiB,CAAC,YAAY,CAAC,IAAI,YAAY,CAAC;YACrE,MAAM,YAAY,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YAEzE,MAAM,KAAK,GAA+B;gBACxC,aAAa,EAAE,YAAY;gBAC3B,SAAS;gBACT,gBAAgB,EAAE,cAAc;aACjC,CAAC;YACF,IAAI,YAAY;gBAAE,KAAK,CAAC,oBAAoB,GAAG,YAAY,CAAC;YAC5D,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC;QAED,OAAO;YACL,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,QAAQ,EAAE,OAAO;YACjB,SAAS;YACT,KAAK,EAAE,SAAS,CAAC,MAAM;SACxB,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,KAAK,GAAa;YACtB,oBAAoB,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,KAAK,WAAW;SACvF,CAAC;QACF,IAAI,MAAM,CAAC,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;QAEtE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;QAC3D,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC;YAClD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;YACrC,KAAK,CAAC,IAAI,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC;YAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,IAAI,CAAC,oBAAoB;oBACrC,CAAC,CAAC,GAAG,IAAI,CAAC,oBAAoB,KAAK,IAAI,CAAC,gBAAgB,GAAG;oBAC3D,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC;gBAC1B,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;YAC3B,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview eurlex_lookup_celex — Resolve
|
|
2
|
+
* @fileoverview eurlex_lookup_celex — Resolve an EU legal citation (CELEX number or ELI URI) to a canonical CELLAR work.
|
|
3
3
|
* @module mcp-server/tools/definitions/eurlex-lookup-celex
|
|
4
4
|
*/
|
|
5
5
|
import { z } from '@cyanheads/mcp-ts-core';
|
|
@@ -8,9 +8,8 @@ export declare const eurlex_lookup_celex: import("@cyanheads/mcp-ts-core").ToolD
|
|
|
8
8
|
identifier: z.ZodString;
|
|
9
9
|
identifier_type: z.ZodDefault<z.ZodEnum<{
|
|
10
10
|
auto: "auto";
|
|
11
|
-
celex: "celex";
|
|
12
11
|
eli: "eli";
|
|
13
|
-
|
|
12
|
+
celex: "celex";
|
|
14
13
|
}>>;
|
|
15
14
|
}, z.core.$strip>, z.ZodObject<{
|
|
16
15
|
found: z.ZodBoolean;
|
|
@@ -21,12 +20,12 @@ export declare const eurlex_lookup_celex: import("@cyanheads/mcp-ts-core").ToolD
|
|
|
21
20
|
}, z.core.$strip>, readonly [{
|
|
22
21
|
readonly reason: "not_found";
|
|
23
22
|
readonly code: JsonRpcErrorCode.NotFound;
|
|
24
|
-
readonly when: "The identifier resolves to no CELLAR work — check the CELEX/ELI
|
|
25
|
-
readonly recovery: "Verify the CELEX
|
|
23
|
+
readonly when: "The identifier resolves to no CELLAR work — check the CELEX/ELI format and try again.";
|
|
24
|
+
readonly recovery: "Verify the CELEX or ELI format, or try eurlex_search_documents to find the work by keyword.";
|
|
26
25
|
}, {
|
|
27
26
|
readonly reason: "ambiguous_identifier";
|
|
28
27
|
readonly code: JsonRpcErrorCode.ValidationError;
|
|
29
28
|
readonly when: "identifier_type is \"auto\" and the identifier format could not be determined.";
|
|
30
|
-
readonly recovery: "Supply identifier_type explicitly as \"celex\"
|
|
29
|
+
readonly recovery: "Supply identifier_type explicitly as \"celex\" or \"eli\" to resolve the ambiguity.";
|
|
31
30
|
}], undefined>;
|
|
32
31
|
//# sourceMappingURL=eurlex-lookup-celex.tool.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-lookup-celex.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-lookup-celex.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"eurlex-lookup-celex.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-lookup-celex.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAyBjE,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;cA8H9B,CAAC"}
|
|
@@ -1,47 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview eurlex_lookup_celex — Resolve
|
|
2
|
+
* @fileoverview eurlex_lookup_celex — Resolve an EU legal citation (CELEX number or ELI URI) to a canonical CELLAR work.
|
|
3
3
|
* @module mcp-server/tools/definitions/eurlex-lookup-celex
|
|
4
4
|
*/
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { CellarSparqlService, getCellarSparqlService, } from '../../../services/cellar-sparql/cellar-sparql-service.js';
|
|
8
|
+
import { escapeSparqlLiteral, isEliUri, resolveEliToWork, } from '../../../services/cellar-sparql/eli-resolution.js';
|
|
8
9
|
/** Detect CELEX number format: starts with a sector digit. */
|
|
9
10
|
function isCelex(identifier) {
|
|
10
11
|
return /^[1-9]\d{4}[A-Z]+\d+/.test(identifier.trim());
|
|
11
12
|
}
|
|
12
|
-
/** Detect ELI URI format: starts with http://data.europa.eu/eli/ */
|
|
13
|
-
function isEliUri(identifier) {
|
|
14
|
-
return identifier.trim().startsWith('http://data.europa.eu/eli/');
|
|
15
|
-
}
|
|
16
|
-
/** Detect Official Journal reference format: e.g. OJ L 119, 4.5.2016 or L:2016:119 */
|
|
17
|
-
function isOjRef(identifier) {
|
|
18
|
-
return /^OJ\s+[LC]\s+\d+/i.test(identifier.trim()) || /^[LC]:\d{4}:\d+/.test(identifier.trim());
|
|
19
|
-
}
|
|
20
13
|
function detectIdentifierType(identifier) {
|
|
21
14
|
if (isCelex(identifier))
|
|
22
15
|
return 'celex';
|
|
23
16
|
if (isEliUri(identifier))
|
|
24
17
|
return 'eli';
|
|
25
|
-
if (isOjRef(identifier))
|
|
26
|
-
return 'oj';
|
|
27
18
|
return null;
|
|
28
19
|
}
|
|
29
20
|
export const eurlex_lookup_celex = tool('eurlex_lookup_celex', {
|
|
30
21
|
title: 'Resolve EU Legal Citation',
|
|
31
|
-
description: 'Resolve
|
|
22
|
+
description: 'Resolve an EU legal citation — a CELEX number or an ELI URI — to the canonical CELLAR work. ' +
|
|
32
23
|
'Returns the work URI, confirmed CELEX number, document type, document date, and whether the work exists in the CELLAR corpus. ' +
|
|
33
24
|
'Use this to validate identifiers before passing them to eurlex_get_document or eurlex_get_relations. ' +
|
|
34
25
|
'CELEX format: {sector}{year}{type}{number} e.g. 32016R0679 (GDPR). ' +
|
|
35
|
-
'ELI format: http://data.europa.eu/eli/{type}/{year}/{number}/oj.
|
|
36
|
-
'OJ format: OJ L 119 or L:2016:119.',
|
|
26
|
+
'ELI format: http://data.europa.eu/eli/{type}/{year}/{number} — the /oj suffix is optional.',
|
|
37
27
|
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
38
28
|
input: z.object({
|
|
39
29
|
identifier: z
|
|
40
30
|
.string()
|
|
41
31
|
.min(1)
|
|
42
|
-
.describe('The EU legal citation to resolve: a CELEX number (e.g. 32016R0679)
|
|
32
|
+
.describe('The EU legal citation to resolve: a CELEX number (e.g. 32016R0679) or a work-level ELI URI (e.g. http://data.europa.eu/eli/reg/2016/679, with or without the /oj suffix).'),
|
|
43
33
|
identifier_type: z
|
|
44
|
-
.enum(['celex', 'eli', '
|
|
34
|
+
.enum(['celex', 'eli', 'auto'])
|
|
45
35
|
.default('auto')
|
|
46
36
|
.describe('Format of the identifier. Use "auto" to let the server detect the format automatically. ' +
|
|
47
37
|
'Supply explicitly if auto-detection fails or if the identifier is ambiguous.'),
|
|
@@ -62,14 +52,14 @@ export const eurlex_lookup_celex = tool('eurlex_lookup_celex', {
|
|
|
62
52
|
{
|
|
63
53
|
reason: 'not_found',
|
|
64
54
|
code: JsonRpcErrorCode.NotFound,
|
|
65
|
-
when: 'The identifier resolves to no CELLAR work — check the CELEX/ELI
|
|
66
|
-
recovery: 'Verify the CELEX
|
|
55
|
+
when: 'The identifier resolves to no CELLAR work — check the CELEX/ELI format and try again.',
|
|
56
|
+
recovery: 'Verify the CELEX or ELI format, or try eurlex_search_documents to find the work by keyword.',
|
|
67
57
|
},
|
|
68
58
|
{
|
|
69
59
|
reason: 'ambiguous_identifier',
|
|
70
60
|
code: JsonRpcErrorCode.ValidationError,
|
|
71
61
|
when: 'identifier_type is "auto" and the identifier format could not be determined.',
|
|
72
|
-
recovery: 'Supply identifier_type explicitly as "celex"
|
|
62
|
+
recovery: 'Supply identifier_type explicitly as "celex" or "eli" to resolve the ambiguity.',
|
|
73
63
|
},
|
|
74
64
|
],
|
|
75
65
|
async handler(input, ctx) {
|
|
@@ -88,52 +78,41 @@ export const eurlex_lookup_celex = tool('eurlex_lookup_celex', {
|
|
|
88
78
|
else {
|
|
89
79
|
effectiveType = input.identifier_type;
|
|
90
80
|
}
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
|
|
81
|
+
// ELI resolution (exact-match on cdm:resource_legal_eli, with the bare
|
|
82
|
+
// work-level /oj retry) is shared with eurlex_get_document — see
|
|
83
|
+
// services/cellar-sparql/eli-resolution.ts. The CELEX branch stays here: a
|
|
84
|
+
// direct exact-string match on the CELEX literal.
|
|
85
|
+
let binding;
|
|
94
86
|
if (effectiveType === 'celex') {
|
|
95
|
-
|
|
87
|
+
const celexQuery = `
|
|
96
88
|
SELECT ?work ?celexNumber ?type ?date WHERE {
|
|
97
89
|
?work cdm:resource_legal_id_celex ?celexNumber .
|
|
98
90
|
OPTIONAL { ?work cdm:work_has_resource-type ?type . }
|
|
99
91
|
OPTIONAL { ?work cdm:work_date_document ?date . }
|
|
100
|
-
FILTER(STR(?celexNumber) = "${
|
|
101
|
-
} LIMIT 5`;
|
|
102
|
-
}
|
|
103
|
-
else if (effectiveType === 'eli') {
|
|
104
|
-
// ELI URIs are mapped via cdm:work_id_document_official-journal or owl:sameAs
|
|
105
|
-
sparql = `
|
|
106
|
-
SELECT ?work ?celexNumber ?type ?date WHERE {
|
|
107
|
-
?work cdm:resource_legal_id_celex ?celexNumber .
|
|
108
|
-
OPTIONAL { ?work cdm:work_has_resource-type ?type . }
|
|
109
|
-
OPTIONAL { ?work cdm:work_date_document ?date . }
|
|
110
|
-
FILTER(CONTAINS(STR(?work), "${safeIdentifier}"))
|
|
92
|
+
FILTER(STR(?celexNumber) = "${escapeSparqlLiteral(identifier)}")
|
|
111
93
|
} LIMIT 5`;
|
|
94
|
+
const bindings = await svc.query(celexQuery, ctx);
|
|
95
|
+
binding = bindings[0] ?? null;
|
|
112
96
|
}
|
|
113
97
|
else {
|
|
114
|
-
|
|
115
|
-
sparql = `
|
|
116
|
-
SELECT ?work ?celexNumber ?type ?date WHERE {
|
|
117
|
-
?work cdm:resource_legal_id_celex ?celexNumber .
|
|
118
|
-
OPTIONAL { ?work cdm:work_has_resource-type ?type . }
|
|
119
|
-
OPTIONAL { ?work cdm:work_date_document ?date . }
|
|
120
|
-
FILTER(CONTAINS(LCASE(STR(?celexNumber)), LCASE("${safeIdentifier}")))
|
|
121
|
-
} LIMIT 5`;
|
|
98
|
+
binding = await resolveEliToWork(svc, identifier, ctx);
|
|
122
99
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
100
|
+
ctx.log.info('Citation lookup', {
|
|
101
|
+
identifier,
|
|
102
|
+
type: effectiveType,
|
|
103
|
+
found: binding !== null,
|
|
104
|
+
});
|
|
105
|
+
if (!binding) {
|
|
126
106
|
throw ctx.fail('not_found', `No CELLAR work found for identifier: ${identifier}`, {
|
|
127
107
|
...ctx.recoveryFor('not_found'),
|
|
128
108
|
});
|
|
129
109
|
}
|
|
130
|
-
const first = bindings[0];
|
|
131
110
|
return {
|
|
132
111
|
found: true,
|
|
133
|
-
work_uri: CellarSparqlService.bindingValue(
|
|
134
|
-
celex_number: CellarSparqlService.bindingValue(
|
|
135
|
-
resource_type: CellarSparqlService.bindingValue(
|
|
136
|
-
date: CellarSparqlService.bindingValue(
|
|
112
|
+
work_uri: CellarSparqlService.bindingValue(binding, 'work'),
|
|
113
|
+
celex_number: CellarSparqlService.bindingValue(binding, 'celexNumber'),
|
|
114
|
+
resource_type: CellarSparqlService.bindingValue(binding, 'type'),
|
|
115
|
+
date: CellarSparqlService.bindingValue(binding, 'date'),
|
|
137
116
|
};
|
|
138
117
|
},
|
|
139
118
|
format: (result) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eurlex-lookup-celex.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-lookup-celex.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,mDAAmD,CAAC;
|
|
1
|
+
{"version":3,"file":"eurlex-lookup-celex.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/eurlex-lookup-celex.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,7 +65,7 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
65
65
|
readonly when: "Virtuoso returned HTTP 200 with an error body — query malformed or timed out.";
|
|
66
66
|
readonly recovery: "Simplify the query or reduce the date range and retry.";
|
|
67
67
|
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
68
|
-
celex_number: import("zod").ZodString
|
|
68
|
+
celex_number: import("zod").ZodOptional<import("zod").ZodString>;
|
|
69
69
|
eli_uri: import("zod").ZodOptional<import("zod").ZodString>;
|
|
70
70
|
language: import("zod").ZodDefault<import("zod").ZodString>;
|
|
71
71
|
format: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
@@ -88,10 +88,15 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
88
88
|
language_fallback: import("zod").ZodOptional<import("zod").ZodString>;
|
|
89
89
|
content_format: import("zod").ZodString;
|
|
90
90
|
}, import("zod/v4/core").$strip>, readonly [{
|
|
91
|
+
readonly reason: "invalid_identifier_args";
|
|
92
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
93
|
+
readonly when: "Neither celex_number nor eli_uri was provided, or both were.";
|
|
94
|
+
readonly recovery: "Provide exactly one of celex_number or eli_uri.";
|
|
95
|
+
}, {
|
|
91
96
|
readonly reason: "not_found";
|
|
92
97
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
93
|
-
readonly when: "CELEX number not found in CELLAR — the work does not exist in the corpus.";
|
|
94
|
-
readonly recovery: "Verify the
|
|
98
|
+
readonly when: "CELEX number or ELI URI not found in CELLAR — the work does not exist in the corpus.";
|
|
99
|
+
readonly recovery: "Verify the identifier or use eurlex_lookup_celex to confirm it exists.";
|
|
95
100
|
}, {
|
|
96
101
|
readonly reason: "language_unavailable";
|
|
97
102
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
@@ -103,7 +108,7 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
103
108
|
readonly when: "EUR-Lex content API returned non-200 after language fallback attempts.";
|
|
104
109
|
readonly recovery: "The EUR-Lex content API may be temporarily unavailable. Retry after a short delay.";
|
|
105
110
|
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
106
|
-
celex_number: import("zod").ZodString
|
|
111
|
+
celex_number: import("zod").ZodOptional<import("zod").ZodString>;
|
|
107
112
|
work_uri: import("zod").ZodOptional<import("zod").ZodString>;
|
|
108
113
|
relation_types: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodEnum<{
|
|
109
114
|
cites: "cites";
|
|
@@ -113,8 +118,8 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
113
118
|
consolidated_version: "consolidated_version";
|
|
114
119
|
}>>>;
|
|
115
120
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
116
|
-
celex_number: import("zod").ZodString
|
|
117
|
-
work_uri: import("zod").
|
|
121
|
+
celex_number: import("zod").ZodOptional<import("zod").ZodString>;
|
|
122
|
+
work_uri: import("zod").ZodString;
|
|
118
123
|
relations: import("zod").ZodArray<import("zod").ZodObject<{
|
|
119
124
|
relation_type: import("zod").ZodString;
|
|
120
125
|
direction: import("zod").ZodString;
|
|
@@ -123,9 +128,14 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
123
128
|
}, import("zod/v4/core").$strip>>;
|
|
124
129
|
total: import("zod").ZodNumber;
|
|
125
130
|
}, import("zod/v4/core").$strip>, readonly [{
|
|
131
|
+
readonly reason: "invalid_identifier_args";
|
|
132
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
133
|
+
readonly when: "Neither celex_number nor work_uri was provided, or both were.";
|
|
134
|
+
readonly recovery: "Provide exactly one of celex_number or work_uri.";
|
|
135
|
+
}, {
|
|
126
136
|
readonly reason: "not_found";
|
|
127
137
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
128
|
-
readonly when: "CELEX
|
|
138
|
+
readonly when: "CELEX number not found in CELLAR — resolve the identifier with eurlex_lookup_celex first.";
|
|
129
139
|
readonly recovery: "Use eurlex_lookup_celex to confirm the CELEX number exists, then retry.";
|
|
130
140
|
}, {
|
|
131
141
|
readonly reason: "no_relations";
|
|
@@ -136,9 +146,8 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
136
146
|
identifier: import("zod").ZodString;
|
|
137
147
|
identifier_type: import("zod").ZodDefault<import("zod").ZodEnum<{
|
|
138
148
|
auto: "auto";
|
|
139
|
-
celex: "celex";
|
|
140
149
|
eli: "eli";
|
|
141
|
-
|
|
150
|
+
celex: "celex";
|
|
142
151
|
}>>;
|
|
143
152
|
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
144
153
|
found: import("zod").ZodBoolean;
|
|
@@ -149,13 +158,13 @@ export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolD
|
|
|
149
158
|
}, import("zod/v4/core").$strip>, readonly [{
|
|
150
159
|
readonly reason: "not_found";
|
|
151
160
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
152
|
-
readonly when: "The identifier resolves to no CELLAR work — check the CELEX/ELI
|
|
153
|
-
readonly recovery: "Verify the CELEX
|
|
161
|
+
readonly when: "The identifier resolves to no CELLAR work — check the CELEX/ELI format and try again.";
|
|
162
|
+
readonly recovery: "Verify the CELEX or ELI format, or try eurlex_search_documents to find the work by keyword.";
|
|
154
163
|
}, {
|
|
155
164
|
readonly reason: "ambiguous_identifier";
|
|
156
165
|
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ValidationError;
|
|
157
166
|
readonly when: "identifier_type is \"auto\" and the identifier format could not be determined.";
|
|
158
|
-
readonly recovery: "Supply identifier_type explicitly as \"celex\"
|
|
167
|
+
readonly recovery: "Supply identifier_type explicitly as \"celex\" or \"eli\" to resolve the ambiguity.";
|
|
159
168
|
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
160
169
|
sparql_query: import("zod").ZodString;
|
|
161
170
|
timeout_hint: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,eAAO,MAAM,kBAAkB
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAQ9B,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ELI URI → CELLAR work resolution, shared between eurlex_lookup_celex
|
|
3
|
+
* and eurlex_get_document. CELLAR stores the canonical OJ-manifestation ELI literal
|
|
4
|
+
* (`cdm:resource_legal_eli`, an `xsd:anyURI` literal), so a bare work-level ELI is
|
|
5
|
+
* normalized to its `/oj` form on a miss. Extracted from eurlex_lookup_celex (#5) so
|
|
6
|
+
* both tools resolve ELIs identically rather than duplicating the mechanism.
|
|
7
|
+
* @module services/cellar-sparql/eli-resolution
|
|
8
|
+
*/
|
|
9
|
+
import type { Context } from '@cyanheads/mcp-ts-core';
|
|
10
|
+
import type { CellarSparqlService } from './cellar-sparql-service.js';
|
|
11
|
+
import type { SparqlBinding } from './types.js';
|
|
12
|
+
/** ELI namespace prefix — all European Legislation Identifiers share this root. */
|
|
13
|
+
export declare const ELI_NAMESPACE = "http://data.europa.eu/eli/";
|
|
14
|
+
/** Detect ELI URI format: starts with http://data.europa.eu/eli/ */
|
|
15
|
+
export declare function isEliUri(identifier: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* A bare work-level ELI — `…/eli/{type}/{year}/{number}` with no manifestation
|
|
18
|
+
* suffix (no `/oj`, no `/YYYY-MM-DD` consolidation date). CELLAR stores the
|
|
19
|
+
* canonical OJ-manifestation literal (`…/{number}/oj`) rather than the bare
|
|
20
|
+
* work-level form, so these never match on exact lookup and must be normalized
|
|
21
|
+
* to their `/oj` form to resolve.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isBareWorkLevelEli(eli: string): boolean;
|
|
24
|
+
/** Escape backslashes then double-quotes for safe interpolation into a SPARQL string literal. */
|
|
25
|
+
export declare function escapeSparqlLiteral(value: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* ELI exact-match query: resolve the single work whose canonical ELI literal
|
|
28
|
+
* (`cdm:resource_legal_eli`, an `xsd:anyURI` literal) equals `safeEli`, reading
|
|
29
|
+
* its CELEX, type, and date. `safeEli` must be pre-escaped.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildEliQuery(safeEli: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve an ELI URI to its canonical CELLAR work binding.
|
|
34
|
+
*
|
|
35
|
+
* Exact-matches the ELI literal; a bare work-level ELI that misses is retried
|
|
36
|
+
* once with `/oj` appended — a deterministic, one-to-one normalization to the
|
|
37
|
+
* same act's canonical OJ manifestation. The retry is gated to bare work-level
|
|
38
|
+
* ELIs, so a manifestation-suffixed ELI (e.g. a `/YYYY-MM-DD` consolidated
|
|
39
|
+
* version) never silently falls back to the original act.
|
|
40
|
+
*
|
|
41
|
+
* Returns the first matching binding (with `?work ?celexNumber ?type ?date`),
|
|
42
|
+
* or `null` when the ELI resolves to no work.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveEliToWork(svc: Pick<CellarSparqlService, 'query'>, eli: string, ctx: Context): Promise<SparqlBinding | null>;
|
|
45
|
+
//# sourceMappingURL=eli-resolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eli-resolution.d.ts","sourceRoot":"","sources":["../../../src/services/cellar-sparql/eli-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,mFAAmF;AACnF,eAAO,MAAM,aAAa,+BAA+B,CAAC;AAE1D,oEAAoE;AACpE,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAIvD;AAED,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAQrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC,EACvC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAc/B"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ELI URI → CELLAR work resolution, shared between eurlex_lookup_celex
|
|
3
|
+
* and eurlex_get_document. CELLAR stores the canonical OJ-manifestation ELI literal
|
|
4
|
+
* (`cdm:resource_legal_eli`, an `xsd:anyURI` literal), so a bare work-level ELI is
|
|
5
|
+
* normalized to its `/oj` form on a miss. Extracted from eurlex_lookup_celex (#5) so
|
|
6
|
+
* both tools resolve ELIs identically rather than duplicating the mechanism.
|
|
7
|
+
* @module services/cellar-sparql/eli-resolution
|
|
8
|
+
*/
|
|
9
|
+
/** ELI namespace prefix — all European Legislation Identifiers share this root. */
|
|
10
|
+
export const ELI_NAMESPACE = 'http://data.europa.eu/eli/';
|
|
11
|
+
/** Detect ELI URI format: starts with http://data.europa.eu/eli/ */
|
|
12
|
+
export function isEliUri(identifier) {
|
|
13
|
+
return identifier.trim().startsWith(ELI_NAMESPACE);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A bare work-level ELI — `…/eli/{type}/{year}/{number}` with no manifestation
|
|
17
|
+
* suffix (no `/oj`, no `/YYYY-MM-DD` consolidation date). CELLAR stores the
|
|
18
|
+
* canonical OJ-manifestation literal (`…/{number}/oj`) rather than the bare
|
|
19
|
+
* work-level form, so these never match on exact lookup and must be normalized
|
|
20
|
+
* to their `/oj` form to resolve.
|
|
21
|
+
*/
|
|
22
|
+
export function isBareWorkLevelEli(eli) {
|
|
23
|
+
if (!eli.startsWith(ELI_NAMESPACE))
|
|
24
|
+
return false;
|
|
25
|
+
const path = eli.slice(ELI_NAMESPACE.length).replace(/\/+$/, '');
|
|
26
|
+
return /^[^/]+\/\d{4}\/[^/]+$/.test(path);
|
|
27
|
+
}
|
|
28
|
+
/** Escape backslashes then double-quotes for safe interpolation into a SPARQL string literal. */
|
|
29
|
+
export function escapeSparqlLiteral(value) {
|
|
30
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ELI exact-match query: resolve the single work whose canonical ELI literal
|
|
34
|
+
* (`cdm:resource_legal_eli`, an `xsd:anyURI` literal) equals `safeEli`, reading
|
|
35
|
+
* its CELEX, type, and date. `safeEli` must be pre-escaped.
|
|
36
|
+
*/
|
|
37
|
+
export function buildEliQuery(safeEli) {
|
|
38
|
+
return `
|
|
39
|
+
SELECT ?work ?celexNumber ?type ?date WHERE {
|
|
40
|
+
?work cdm:resource_legal_eli "${safeEli}"^^xsd:anyURI .
|
|
41
|
+
?work cdm:resource_legal_id_celex ?celexNumber .
|
|
42
|
+
OPTIONAL { ?work cdm:work_has_resource-type ?type . }
|
|
43
|
+
OPTIONAL { ?work cdm:work_date_document ?date . }
|
|
44
|
+
} LIMIT 5`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolve an ELI URI to its canonical CELLAR work binding.
|
|
48
|
+
*
|
|
49
|
+
* Exact-matches the ELI literal; a bare work-level ELI that misses is retried
|
|
50
|
+
* once with `/oj` appended — a deterministic, one-to-one normalization to the
|
|
51
|
+
* same act's canonical OJ manifestation. The retry is gated to bare work-level
|
|
52
|
+
* ELIs, so a manifestation-suffixed ELI (e.g. a `/YYYY-MM-DD` consolidated
|
|
53
|
+
* version) never silently falls back to the original act.
|
|
54
|
+
*
|
|
55
|
+
* Returns the first matching binding (with `?work ?celexNumber ?type ?date`),
|
|
56
|
+
* or `null` when the ELI resolves to no work.
|
|
57
|
+
*/
|
|
58
|
+
export async function resolveEliToWork(svc, eli, ctx) {
|
|
59
|
+
const trimmed = eli.trim();
|
|
60
|
+
let bindings = await svc.query(buildEliQuery(escapeSparqlLiteral(trimmed)), ctx);
|
|
61
|
+
if (bindings.length === 0 && isBareWorkLevelEli(trimmed)) {
|
|
62
|
+
const ojEli = `${trimmed.replace(/\/+$/, '')}/oj`;
|
|
63
|
+
ctx.log.debug('ELI exact-match missed; retrying with /oj manifestation', {
|
|
64
|
+
eli: trimmed,
|
|
65
|
+
ojEli,
|
|
66
|
+
});
|
|
67
|
+
bindings = await svc.query(buildEliQuery(escapeSparqlLiteral(ojEli)), ctx);
|
|
68
|
+
}
|
|
69
|
+
return bindings[0] ?? null;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=eli-resolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eli-resolution.js","sourceRoot":"","sources":["../../../src/services/cellar-sparql/eli-resolution.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,mFAAmF;AACnF,MAAM,CAAC,MAAM,aAAa,GAAG,4BAA4B,CAAC;AAE1D,oEAAoE;AACpE,MAAM,UAAU,QAAQ,CAAC,UAAkB;IACzC,OAAO,UAAU,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACjE,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAC/C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,OAAO;;kCAEyB,OAAO;;;;UAI/B,CAAC;AACX,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAuC,EACvC,GAAW,EACX,GAAY;IAEZ,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,QAAQ,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAEjF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,MAAM,KAAK,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC;QAClD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,yDAAyD,EAAE;YACvE,GAAG,EAAE,OAAO;YACZ,KAAK;SACN,CAAC,CAAC;QACH,QAAQ,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC7E,CAAC;IAED,OAAO,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC7B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/eur-lex-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"mcpName": "io.github.cyanheads/eur-lex-mcp-server",
|
|
5
5
|
"description": "Search EU legislation, CJEU case law, and treaties; traverse the CELLAR relationship graph; resolve EuroVoc concepts via MCP. STDIO or Streamable HTTP.",
|
|
6
6
|
"type": "module",
|
package/server.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"url": "https://github.com/cyanheads/eur-lex-mcp-server",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "0.
|
|
9
|
+
"version": "0.2.0",
|
|
10
10
|
"remotes": [
|
|
11
11
|
{
|
|
12
12
|
"type": "streamable-http",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
20
20
|
"identifier": "@cyanheads/eur-lex-mcp-server",
|
|
21
21
|
"runtimeHint": "bun",
|
|
22
|
-
"version": "0.
|
|
22
|
+
"version": "0.2.0",
|
|
23
23
|
"packageArguments": [
|
|
24
24
|
{
|
|
25
25
|
"type": "positional",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
77
77
|
"identifier": "@cyanheads/eur-lex-mcp-server",
|
|
78
78
|
"runtimeHint": "bun",
|
|
79
|
-
"version": "0.
|
|
79
|
+
"version": "0.2.0",
|
|
80
80
|
"packageArguments": [
|
|
81
81
|
{
|
|
82
82
|
"type": "positional",
|