@cyanheads/eur-lex-mcp-server 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/AGENTS.md +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +1 -1
  4. package/changelog/0.4.x/0.4.1.md +14 -0
  5. package/changelog/0.4.x/0.4.2.md +16 -0
  6. package/dist/mcp-server/resources/definitions/eurlex-document-relations.resource.d.ts.map +1 -1
  7. package/dist/mcp-server/resources/definitions/eurlex-document-relations.resource.js +17 -51
  8. package/dist/mcp-server/resources/definitions/eurlex-document-relations.resource.js.map +1 -1
  9. package/dist/mcp-server/resources/definitions/eurlex-document.resource.d.ts.map +1 -1
  10. package/dist/mcp-server/resources/definitions/eurlex-document.resource.js +3 -3
  11. package/dist/mcp-server/resources/definitions/eurlex-document.resource.js.map +1 -1
  12. package/dist/mcp-server/tools/definitions/eurlex-get-cases.tool.d.ts.map +1 -1
  13. package/dist/mcp-server/tools/definitions/eurlex-get-cases.tool.js +66 -19
  14. package/dist/mcp-server/tools/definitions/eurlex-get-cases.tool.js.map +1 -1
  15. package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.d.ts.map +1 -1
  16. package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.js +1 -2
  17. package/dist/mcp-server/tools/definitions/eurlex-get-document.tool.js.map +1 -1
  18. package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.js +19 -76
  20. package/dist/mcp-server/tools/definitions/eurlex-get-relations.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.d.ts +0 -5
  22. package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.d.ts.map +1 -1
  23. package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.js +6 -10
  24. package/dist/mcp-server/tools/definitions/eurlex-lookup-celex.tool.js.map +1 -1
  25. package/dist/mcp-server/tools/definitions/eurlex-query-sparql.tool.d.ts.map +1 -1
  26. package/dist/mcp-server/tools/definitions/eurlex-query-sparql.tool.js +5 -3
  27. package/dist/mcp-server/tools/definitions/eurlex-query-sparql.tool.js.map +1 -1
  28. package/dist/mcp-server/tools/definitions/eurlex-search-documents.tool.d.ts.map +1 -1
  29. package/dist/mcp-server/tools/definitions/eurlex-search-documents.tool.js +70 -22
  30. package/dist/mcp-server/tools/definitions/eurlex-search-documents.tool.js.map +1 -1
  31. package/dist/mcp-server/tools/definitions/index.d.ts +0 -5
  32. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  33. package/dist/services/cellar-sparql/cellar-sparql-service.d.ts +25 -2
  34. package/dist/services/cellar-sparql/cellar-sparql-service.d.ts.map +1 -1
  35. package/dist/services/cellar-sparql/cellar-sparql-service.js +34 -5
  36. package/dist/services/cellar-sparql/cellar-sparql-service.js.map +1 -1
  37. package/dist/services/cellar-sparql/relation-traversal.d.ts +28 -0
  38. package/dist/services/cellar-sparql/relation-traversal.d.ts.map +1 -0
  39. package/dist/services/cellar-sparql/relation-traversal.js +103 -0
  40. package/dist/services/cellar-sparql/relation-traversal.js.map +1 -0
  41. package/package.json +1 -1
  42. package/server.json +3 -3
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @fileoverview Shared CELLAR CDM relation traversal, used by the
3
+ * eurlex_get_relations tool and the eurlex://document/{celex}/relations
4
+ * resource. Owns the relation-type → CDM predicate + direction model so both
5
+ * surfaces resolve relations identically.
6
+ * @module services/cellar-sparql/relation-traversal
7
+ */
8
+ import { CellarSparqlService } from './cellar-sparql-service.js';
9
+ /** The relation types this server exposes over the CDM graph. */
10
+ export const RELATION_TYPES = [
11
+ 'cites',
12
+ 'amends',
13
+ 'amended_by',
14
+ 'legal_basis',
15
+ 'consolidated_version',
16
+ ];
17
+ /**
18
+ * Per-relation-type CDM traversal spec: the predicate to follow and the
19
+ * direction(s) relative to the source work.
20
+ *
21
+ * CELLAR models amendment and consolidation one-directionally, so two types are
22
+ * the INCOMING side of a predicate whose name reads the other way — the
23
+ * dedicated `…amended_by…` and `…has_consolidated_version…` predicates carry
24
+ * zero triples:
25
+ * - `amended_by` is the incoming side of `…amends…` (`?amender amends <work>`).
26
+ * - `consolidated_version` is the incoming side of
27
+ * `…act_consolidated_consolidates…` (the consolidated act points back to the
28
+ * base; there is no forward `…has_consolidated_version…` link).
29
+ *
30
+ * `amends` and `legal_basis` are outgoing-only — their incoming rows describe a
31
+ * different relation (what amends this / what is based on this) and belong under
32
+ * `amended_by` and another work's `legal_basis`, not here. `cites` is symmetric
33
+ * ("citation graph"), so both directions are surfaced and tagged via `?direction`.
34
+ */
35
+ const RELATION_SPECS = {
36
+ cites: { predicate: 'cdm:work_cites_work', direction: 'both' },
37
+ amends: { predicate: 'cdm:resource_legal_amends_resource_legal', direction: 'outgoing' },
38
+ amended_by: { predicate: 'cdm:resource_legal_amends_resource_legal', direction: 'incoming' },
39
+ legal_basis: { predicate: 'cdm:resource_legal_based_on_resource_legal', direction: 'outgoing' },
40
+ consolidated_version: {
41
+ predicate: 'cdm:act_consolidated_consolidates_resource_legal',
42
+ direction: 'incoming',
43
+ },
44
+ };
45
+ /**
46
+ * Default per-type result cap. Each relation type is queried independently with
47
+ * its own LIMIT so a high-volume type (e.g. `cites`) can't starve rarer types
48
+ * under a single shared cap. The service caps further if MAX_SPARQL_RESULTS is
49
+ * lower than this.
50
+ */
51
+ export const DEFAULT_PER_TYPE_LIMIT = 100;
52
+ /** Build a single-relation-type SPARQL query for the given predicate + direction. */
53
+ function buildRelationQuery(workUri, spec, limit) {
54
+ const outgoing = `{
55
+ <${workUri}> ${spec.predicate} ?relatedWork .
56
+ OPTIONAL { ?relatedWork cdm:resource_legal_id_celex ?relatedCelex . }
57
+ BIND("outgoing" AS ?direction)
58
+ }`;
59
+ const incoming = `{
60
+ ?relatedWork ${spec.predicate} <${workUri}> .
61
+ OPTIONAL { ?relatedWork cdm:resource_legal_id_celex ?relatedCelex . }
62
+ BIND("incoming" AS ?direction)
63
+ }`;
64
+ const body = spec.direction === 'outgoing'
65
+ ? outgoing
66
+ : spec.direction === 'incoming'
67
+ ? incoming
68
+ : `${outgoing} UNION ${incoming}`;
69
+ return `SELECT ?relatedWork ?relatedCelex ?direction WHERE {
70
+ ${body}
71
+ } LIMIT ${limit}`;
72
+ }
73
+ /**
74
+ * Traverse the requested CDM relation types for a work — one query per type, run
75
+ * concurrently — and return de-duplicated relations tagged with their type and
76
+ * direction. Each type is resolved through its own query (and its own LIMIT) so
77
+ * the per-type caps are independent.
78
+ */
79
+ export async function traverseRelations(svc, workUri, types, ctx, perTypeLimit = DEFAULT_PER_TYPE_LIMIT) {
80
+ const perType = await Promise.all(types.map(async (type) => ({
81
+ type,
82
+ bindings: await svc.query(buildRelationQuery(workUri, RELATION_SPECS[type], perTypeLimit), ctx),
83
+ })));
84
+ const seen = new Set();
85
+ const relations = [];
86
+ for (const { type, bindings } of perType) {
87
+ for (const b of bindings) {
88
+ const relatedWorkUri = CellarSparqlService.bindingValue(b, 'relatedWork') ?? '';
89
+ const direction = CellarSparqlService.bindingValue(b, 'direction') === 'incoming' ? 'incoming' : 'outgoing';
90
+ const key = `${type}|${direction}|${relatedWorkUri}`;
91
+ if (seen.has(key))
92
+ continue;
93
+ seen.add(key);
94
+ const relation = { relationType: type, direction, relatedWorkUri };
95
+ const relatedCelex = CellarSparqlService.bindingValue(b, 'relatedCelex');
96
+ if (relatedCelex)
97
+ relation.relatedCelexNumber = relatedCelex;
98
+ relations.push(relation);
99
+ }
100
+ }
101
+ return relations;
102
+ }
103
+ //# sourceMappingURL=relation-traversal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation-traversal.js","sourceRoot":"","sources":["../../../src/services/cellar-sparql/relation-traversal.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/eur-lex-mcp-server",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
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.4.0",
9
+ "version": "0.4.2",
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.4.0",
22
+ "version": "0.4.2",
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.4.0",
79
+ "version": "0.4.2",
80
80
  "packageArguments": [
81
81
  {
82
82
  "type": "positional",