@iflow-mcp/georgejeffers-uk-case-law-mcp 1.0.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/2288_process.log +4 -0
- package/LICENSE +131 -0
- package/README.md +112 -0
- package/bun.lock +213 -0
- package/dist/cases.d.ts +4 -0
- package/dist/cases.d.ts.map +1 -0
- package/dist/cases.js +32 -0
- package/dist/cases.js.map +1 -0
- package/dist/formatters.d.ts +21 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +164 -0
- package/dist/formatters.js.map +1 -0
- package/dist/search.d.ts +13 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +81 -0
- package/dist/search.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +191 -0
- package/dist/server.js.map +1 -0
- package/dist/test.d.ts +3 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +247 -0
- package/dist/test.js.map +1 -0
- package/dist/tna-client.d.ts +21 -0
- package/dist/tna-client.d.ts.map +1 -0
- package/dist/tna-client.js +394 -0
- package/dist/tna-client.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/language.json +1 -0
- package/package.json +1 -0
- package/package_name +1 -0
- package/push_info.json +5 -0
- package/src/cases.ts +36 -0
- package/src/formatters.ts +226 -0
- package/src/search.ts +108 -0
- package/src/server.ts +227 -0
- package/src/test.ts +283 -0
- package/src/tna-client.ts +495 -0
- package/src/types.ts +59 -0
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
// src/tna-client.ts
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// THE NATIONAL ARCHIVES API CLIENT
|
|
4
|
+
// ============================================================================
|
|
5
|
+
//
|
|
6
|
+
// Handles all communication with the TNA Find Case Law API.
|
|
7
|
+
//
|
|
8
|
+
// Rate limits: 1,000 requests per 5-minute rolling window
|
|
9
|
+
// No authentication required.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
import { XMLParser } from 'fast-xml-parser';
|
|
12
|
+
const TNA_BASE_URL = 'https://caselaw.nationalarchives.gov.uk';
|
|
13
|
+
// Generate URLs for a document
|
|
14
|
+
function generateDocumentUrls(documentUri) {
|
|
15
|
+
const normalizedUri = documentUri.startsWith('/') ? documentUri.substring(1) : documentUri;
|
|
16
|
+
return {
|
|
17
|
+
web: `${TNA_BASE_URL}/${normalizedUri}`,
|
|
18
|
+
pdf: `${TNA_BASE_URL}/${normalizedUri}/data.pdf`,
|
|
19
|
+
xml: `${TNA_BASE_URL}/${normalizedUri}/data.xml`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Rate limiting: simple token bucket
|
|
23
|
+
export const RATE_LIMIT_MAX_REQUESTS = 900; // Stay under 1000 limit
|
|
24
|
+
export const RATE_LIMIT_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
|
|
25
|
+
let requestCount = 0;
|
|
26
|
+
let windowStart = Date.now();
|
|
27
|
+
async function checkRateLimit() {
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
if (now - windowStart > RATE_LIMIT_WINDOW_MS) {
|
|
30
|
+
// Reset window
|
|
31
|
+
requestCount = 0;
|
|
32
|
+
windowStart = now;
|
|
33
|
+
}
|
|
34
|
+
if (requestCount >= RATE_LIMIT_MAX_REQUESTS) {
|
|
35
|
+
const waitTime = RATE_LIMIT_WINDOW_MS - (now - windowStart);
|
|
36
|
+
console.error(`Rate limit reached, waiting ${waitTime}ms`);
|
|
37
|
+
await new Promise(resolve => setTimeout(resolve, waitTime));
|
|
38
|
+
requestCount = 0;
|
|
39
|
+
windowStart = Date.now();
|
|
40
|
+
}
|
|
41
|
+
requestCount++;
|
|
42
|
+
}
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// COURT CODE MAPPING
|
|
45
|
+
// ============================================================================
|
|
46
|
+
// Map user-friendly court names to TNA API codes
|
|
47
|
+
export const COURT_CODE_MAP = {
|
|
48
|
+
supreme_court: ['uksc'],
|
|
49
|
+
court_of_appeal: ['ewca/civ', 'ewca/crim'],
|
|
50
|
+
high_court: [
|
|
51
|
+
'ewhc/ch', 'ewhc/qb', 'ewhc/kb', 'ewhc/admin',
|
|
52
|
+
'ewhc/comm', 'ewhc/patents', 'ewhc/ipec', 'ewhc/tcc', 'ewhc/fam'
|
|
53
|
+
],
|
|
54
|
+
tribunals: ['eat', 'ukut/iac', 'ukut/lc', 'ukut/aac'],
|
|
55
|
+
};
|
|
56
|
+
// Map legal areas to relevant courts
|
|
57
|
+
export const LEGAL_AREA_COURTS = {
|
|
58
|
+
intellectual_property: ['ewhc/patents', 'ewhc/ipec', 'ewhc/ch'],
|
|
59
|
+
commercial: ['ewhc/comm', 'ewhc/ch'],
|
|
60
|
+
employment: ['eat'],
|
|
61
|
+
immigration: ['ukut/iac'],
|
|
62
|
+
family: ['ewhc/fam'],
|
|
63
|
+
};
|
|
64
|
+
export async function searchTna(params) {
|
|
65
|
+
await checkRateLimit();
|
|
66
|
+
const url = new URL(`${TNA_BASE_URL}/atom.xml`);
|
|
67
|
+
url.searchParams.set('query', params.query);
|
|
68
|
+
url.searchParams.set('order', '-date'); // Newest first
|
|
69
|
+
url.searchParams.set('per_page', String(Math.min(params.limit || 50, 50)));
|
|
70
|
+
if (params.page) {
|
|
71
|
+
url.searchParams.set('page', String(params.page));
|
|
72
|
+
}
|
|
73
|
+
// Note: Court filtering via API is currently disabled due to API format issues
|
|
74
|
+
// The TNA API returns 400 for court parameter. Filter results locally instead.
|
|
75
|
+
// TODO: Investigate correct court filter format when TNA API docs are updated
|
|
76
|
+
// Note: TNA API doesn't have native year filtering in search
|
|
77
|
+
// We filter results after fetching
|
|
78
|
+
const response = await fetch(url.toString(), {
|
|
79
|
+
headers: {
|
|
80
|
+
'Accept': 'application/atom+xml',
|
|
81
|
+
'User-Agent': 'UKCaseLawMCP/1.0',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
if (response.status === 429) {
|
|
86
|
+
throw new Error('TNA API rate limit exceeded. Please wait a few minutes.');
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`TNA API error: ${response.status} ${response.statusText}`);
|
|
89
|
+
}
|
|
90
|
+
const xml = await response.text();
|
|
91
|
+
const results = parseAtomFeed(xml);
|
|
92
|
+
// Apply year filtering
|
|
93
|
+
return results.filter(r => {
|
|
94
|
+
if (!r.date)
|
|
95
|
+
return true;
|
|
96
|
+
const year = new Date(r.date).getFullYear();
|
|
97
|
+
if (params.yearFrom && year < params.yearFrom)
|
|
98
|
+
return false;
|
|
99
|
+
if (params.yearTo && year > params.yearTo)
|
|
100
|
+
return false;
|
|
101
|
+
return true;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function parseAtomFeed(xml) {
|
|
105
|
+
const parser = new XMLParser({
|
|
106
|
+
ignoreAttributes: false,
|
|
107
|
+
attributeNamePrefix: '@_',
|
|
108
|
+
});
|
|
109
|
+
const feed = parser.parse(xml);
|
|
110
|
+
// Handle empty results
|
|
111
|
+
if (!feed.feed || !feed.feed.entry) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
// Normalize to array (single result comes as object)
|
|
115
|
+
const entries = Array.isArray(feed.feed.entry)
|
|
116
|
+
? feed.feed.entry
|
|
117
|
+
: [feed.feed.entry];
|
|
118
|
+
return entries.map((entry) => {
|
|
119
|
+
// Extract neutral citation and document slug from identifier elements
|
|
120
|
+
let neutralCitation = null;
|
|
121
|
+
let documentSlug = null;
|
|
122
|
+
if (entry['tna:identifier']) {
|
|
123
|
+
const identifiers = Array.isArray(entry['tna:identifier'])
|
|
124
|
+
? entry['tna:identifier']
|
|
125
|
+
: [entry['tna:identifier']];
|
|
126
|
+
const ncn = identifiers.find((i) => i['@_type'] === 'ukncn');
|
|
127
|
+
if (ncn) {
|
|
128
|
+
neutralCitation = ncn['@_value'];
|
|
129
|
+
// The slug is in the same identifier element
|
|
130
|
+
documentSlug = ncn['@_slug'] || null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Fall back to extracting URI from the alternate link if slug not found
|
|
134
|
+
if (!documentSlug && entry.link) {
|
|
135
|
+
const links = Array.isArray(entry.link) ? entry.link : [entry.link];
|
|
136
|
+
const xmlLink = links.find((l) => l['@_type'] === 'application/akn+xml');
|
|
137
|
+
if (xmlLink?.['@_href']) {
|
|
138
|
+
// Extract slug from URL like https://caselaw.../ewca/civ/2025/1633/data.xml
|
|
139
|
+
const match = xmlLink['@_href'].match(/nationalarchives\.gov\.uk\/(.+)\/data\.xml$/);
|
|
140
|
+
if (match?.[1]) {
|
|
141
|
+
documentSlug = match[1];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Extract snippet - handle cases where summary is an object or empty
|
|
146
|
+
let snippet = '';
|
|
147
|
+
if (entry.summary) {
|
|
148
|
+
if (typeof entry.summary === 'string') {
|
|
149
|
+
snippet = entry.summary;
|
|
150
|
+
}
|
|
151
|
+
else if (entry.summary['#text']) {
|
|
152
|
+
snippet = entry.summary['#text'];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const docUri = documentSlug || entry['tna:uri'] || extractUriFromId(entry.id);
|
|
156
|
+
// Handle title being string or object
|
|
157
|
+
let title = 'Untitled';
|
|
158
|
+
if (typeof entry.title === 'string') {
|
|
159
|
+
title = entry.title;
|
|
160
|
+
}
|
|
161
|
+
else if (entry.title && typeof entry.title === 'object' && entry.title['#text']) {
|
|
162
|
+
title = entry.title['#text'];
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
documentUri: docUri,
|
|
166
|
+
neutralCitation,
|
|
167
|
+
title,
|
|
168
|
+
court: entry.author?.name || 'Unknown Court',
|
|
169
|
+
date: entry.published ? entry.published.substring(0, 10) : null,
|
|
170
|
+
snippet,
|
|
171
|
+
source: 'tna',
|
|
172
|
+
score: 1.0, // TNA doesn't provide relevance scores
|
|
173
|
+
urls: generateDocumentUrls(docUri),
|
|
174
|
+
};
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function extractUriFromId(id) {
|
|
178
|
+
// ID format: https://caselaw.nationalarchives.gov.uk/ewca/civ/2007/588
|
|
179
|
+
const match = id.match(/nationalarchives\.gov\.uk\/(.+)$/);
|
|
180
|
+
return match?.[1] ?? id;
|
|
181
|
+
}
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// GET CASE CONTENT
|
|
184
|
+
// ============================================================================
|
|
185
|
+
export async function getTnaCaseContent(uri) {
|
|
186
|
+
await checkRateLimit();
|
|
187
|
+
// Normalize URI (remove leading slash if present)
|
|
188
|
+
const normalizedUri = uri.startsWith('/') ? uri.substring(1) : uri;
|
|
189
|
+
const url = `${TNA_BASE_URL}/${normalizedUri}/data.xml`;
|
|
190
|
+
const response = await fetch(url, {
|
|
191
|
+
headers: {
|
|
192
|
+
'Accept': 'application/xml',
|
|
193
|
+
'User-Agent': 'UKCaseLawMCP/1.0',
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
if (!response.ok) {
|
|
197
|
+
if (response.status === 404) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
throw new Error(`TNA API error: ${response.status} ${response.statusText}`);
|
|
201
|
+
}
|
|
202
|
+
const xml = await response.text();
|
|
203
|
+
return parseLegalDocML(xml, normalizedUri);
|
|
204
|
+
}
|
|
205
|
+
// ============================================================================
|
|
206
|
+
// LEGALDOCML PARSER
|
|
207
|
+
// ============================================================================
|
|
208
|
+
//
|
|
209
|
+
// TNA uses Akoma Ntoso (LegalDocML) XML format.
|
|
210
|
+
// Key namespaces:
|
|
211
|
+
// - akn: http://docs.oasis-open.org/legaldocml/ns/akn/3.0
|
|
212
|
+
// - uk: https://caselaw.nationalarchives.gov.uk/akn
|
|
213
|
+
// ============================================================================
|
|
214
|
+
function parseLegalDocML(xml, uri) {
|
|
215
|
+
const parser = new XMLParser({
|
|
216
|
+
ignoreAttributes: false,
|
|
217
|
+
attributeNamePrefix: '@_',
|
|
218
|
+
removeNSPrefix: true, // Remove namespace prefixes for easier access
|
|
219
|
+
});
|
|
220
|
+
const doc = parser.parse(xml);
|
|
221
|
+
// Navigate to the judgment content
|
|
222
|
+
const akomaNtoso = doc.akomaNtoso || doc['akn:akomaNtoso'] || {};
|
|
223
|
+
const judgment = akomaNtoso.judgment || {};
|
|
224
|
+
const meta = judgment.meta || {};
|
|
225
|
+
const judgmentBody = judgment.judgmentBody || {};
|
|
226
|
+
// Extract metadata
|
|
227
|
+
const identification = meta.identification || {};
|
|
228
|
+
const frbrWork = identification.FRBRWork || {};
|
|
229
|
+
// Get title
|
|
230
|
+
let title = 'Untitled';
|
|
231
|
+
if (frbrWork.FRBRname && frbrWork.FRBRname['@_value']) {
|
|
232
|
+
title = frbrWork.FRBRname['@_value'];
|
|
233
|
+
}
|
|
234
|
+
// Get date
|
|
235
|
+
let date = null;
|
|
236
|
+
if (frbrWork.FRBRdate && frbrWork.FRBRdate['@_date']) {
|
|
237
|
+
date = frbrWork.FRBRdate['@_date'];
|
|
238
|
+
}
|
|
239
|
+
// Get neutral citation
|
|
240
|
+
let neutralCitation = null;
|
|
241
|
+
const proprietary = meta.proprietary || {};
|
|
242
|
+
if (proprietary.cite) {
|
|
243
|
+
neutralCitation = proprietary.cite;
|
|
244
|
+
}
|
|
245
|
+
// Get court
|
|
246
|
+
let court = 'Unknown';
|
|
247
|
+
let courtName = 'Unknown Court';
|
|
248
|
+
if (proprietary.court) {
|
|
249
|
+
court = proprietary.court;
|
|
250
|
+
}
|
|
251
|
+
if (proprietary.courtName) {
|
|
252
|
+
courtName = proprietary.courtName;
|
|
253
|
+
}
|
|
254
|
+
// Extract judges from header
|
|
255
|
+
const judges = [];
|
|
256
|
+
const header = judgment.header || {};
|
|
257
|
+
if (header.judge) {
|
|
258
|
+
const judgeElements = Array.isArray(header.judge) ? header.judge : [header.judge];
|
|
259
|
+
for (const j of judgeElements) {
|
|
260
|
+
if (typeof j === 'string') {
|
|
261
|
+
judges.push(j);
|
|
262
|
+
}
|
|
263
|
+
else if (j['#text']) {
|
|
264
|
+
judges.push(j['#text']);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Extract paragraphs from judgment body
|
|
269
|
+
const paragraphs = [];
|
|
270
|
+
extractParagraphs(judgmentBody, paragraphs);
|
|
271
|
+
return {
|
|
272
|
+
metadata: {
|
|
273
|
+
documentUri: uri,
|
|
274
|
+
neutralCitation,
|
|
275
|
+
title,
|
|
276
|
+
court,
|
|
277
|
+
courtName,
|
|
278
|
+
date,
|
|
279
|
+
source: 'tna',
|
|
280
|
+
urls: generateDocumentUrls(uri),
|
|
281
|
+
},
|
|
282
|
+
paragraphs,
|
|
283
|
+
judges,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function extractParagraphs(node, paragraphs, depth = 0) {
|
|
287
|
+
if (!node || typeof node !== 'object')
|
|
288
|
+
return;
|
|
289
|
+
// Look for paragraph elements
|
|
290
|
+
if (node.paragraph || node.p) {
|
|
291
|
+
const paraElements = node.paragraph || node.p;
|
|
292
|
+
const paras = Array.isArray(paraElements) ? paraElements : [paraElements];
|
|
293
|
+
for (const para of paras) {
|
|
294
|
+
// Get paragraph number - handle number, string, or object with #text
|
|
295
|
+
let paraNum = paragraphs.length + 1;
|
|
296
|
+
if (para.num !== undefined && para.num !== null) {
|
|
297
|
+
if (typeof para.num === 'number') {
|
|
298
|
+
paraNum = para.num;
|
|
299
|
+
}
|
|
300
|
+
else if (typeof para.num === 'string') {
|
|
301
|
+
const match = para.num.match(/\d+/);
|
|
302
|
+
if (match?.[0]) {
|
|
303
|
+
paraNum = parseInt(match[0], 10);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else if (typeof para.num === 'object' && para.num['#text']) {
|
|
307
|
+
const numText = String(para.num['#text']);
|
|
308
|
+
const match = numText.match(/\d+/);
|
|
309
|
+
if (match?.[0]) {
|
|
310
|
+
paraNum = parseInt(match[0], 10);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Get paragraph text
|
|
315
|
+
let text = '';
|
|
316
|
+
if (para.content) {
|
|
317
|
+
text = extractText(para.content);
|
|
318
|
+
}
|
|
319
|
+
else if (para['#text']) {
|
|
320
|
+
text = para['#text'];
|
|
321
|
+
}
|
|
322
|
+
else {
|
|
323
|
+
text = extractText(para);
|
|
324
|
+
}
|
|
325
|
+
if (text.trim()) {
|
|
326
|
+
paragraphs.push({
|
|
327
|
+
number: paraNum,
|
|
328
|
+
text: text.trim(),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
// Recurse into child nodes
|
|
334
|
+
for (const key of Object.keys(node)) {
|
|
335
|
+
if (key.startsWith('@_') || key === '#text')
|
|
336
|
+
continue;
|
|
337
|
+
extractParagraphs(node[key], paragraphs, depth + 1);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function extractText(node) {
|
|
341
|
+
if (typeof node === 'string')
|
|
342
|
+
return node;
|
|
343
|
+
if (typeof node !== 'object' || node === null)
|
|
344
|
+
return '';
|
|
345
|
+
let text = '';
|
|
346
|
+
if (node['#text']) {
|
|
347
|
+
text += node['#text'];
|
|
348
|
+
}
|
|
349
|
+
for (const key of Object.keys(node)) {
|
|
350
|
+
if (key.startsWith('@_') || key === '#text')
|
|
351
|
+
continue;
|
|
352
|
+
const child = node[key];
|
|
353
|
+
if (Array.isArray(child)) {
|
|
354
|
+
for (const item of child) {
|
|
355
|
+
text += ' ' + extractText(item);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
text += ' ' + extractText(child);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return text.replace(/\s+/g, ' ').trim();
|
|
363
|
+
}
|
|
364
|
+
// ============================================================================
|
|
365
|
+
// CITATION PARSING
|
|
366
|
+
// ============================================================================
|
|
367
|
+
// Convert neutral citation to TNA URI
|
|
368
|
+
export function citationToUri(citation) {
|
|
369
|
+
// Pattern: [YEAR] COURT NUMBER
|
|
370
|
+
// Examples:
|
|
371
|
+
// [2024] UKSC 1 -> uksc/2024/1
|
|
372
|
+
// [2007] EWCA Civ 588 -> ewca/civ/2007/588
|
|
373
|
+
// [2023] EWHC 123 (Patents) -> ewhc/patents/2023/123
|
|
374
|
+
const match = citation.match(/\[(\d{4})\]\s+(\w+)\s+(?:(\w+)\s+)?(\d+)/);
|
|
375
|
+
if (!match)
|
|
376
|
+
return null;
|
|
377
|
+
const year = match[1];
|
|
378
|
+
const court1 = match[2];
|
|
379
|
+
const court2 = match[3];
|
|
380
|
+
const number = match[4];
|
|
381
|
+
if (!year || !court1 || !number)
|
|
382
|
+
return null;
|
|
383
|
+
const courtParts = [court1.toLowerCase()];
|
|
384
|
+
if (court2) {
|
|
385
|
+
courtParts.push(court2.toLowerCase());
|
|
386
|
+
}
|
|
387
|
+
// Handle subdivision in parentheses like (Patents)
|
|
388
|
+
const subdivMatch = citation.match(/\((\w+)\)/);
|
|
389
|
+
if (subdivMatch?.[1]) {
|
|
390
|
+
courtParts.push(subdivMatch[1].toLowerCase());
|
|
391
|
+
}
|
|
392
|
+
return `${courtParts.join('/')}/${year}/${number}`;
|
|
393
|
+
}
|
|
394
|
+
//# sourceMappingURL=tna-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tna-client.js","sourceRoot":"","sources":["../src/tna-client.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface DocumentUrls {
|
|
2
|
+
web: string;
|
|
3
|
+
pdf: string;
|
|
4
|
+
xml: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CaseMetadata {
|
|
7
|
+
id?: string;
|
|
8
|
+
documentUri: string;
|
|
9
|
+
neutralCitation: string | null;
|
|
10
|
+
title: string;
|
|
11
|
+
court: string;
|
|
12
|
+
courtName: string;
|
|
13
|
+
date: string | null;
|
|
14
|
+
source: 'tna' | 'bailii';
|
|
15
|
+
urls: DocumentUrls;
|
|
16
|
+
}
|
|
17
|
+
export interface CaseParagraph {
|
|
18
|
+
number: number;
|
|
19
|
+
text: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CaseContent {
|
|
22
|
+
metadata: CaseMetadata;
|
|
23
|
+
paragraphs: CaseParagraph[];
|
|
24
|
+
judges?: string[];
|
|
25
|
+
parties?: {
|
|
26
|
+
claimants: string[];
|
|
27
|
+
defendants: string[];
|
|
28
|
+
};
|
|
29
|
+
truncated: boolean;
|
|
30
|
+
remainingParagraphs: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SearchResult {
|
|
33
|
+
documentUri: string;
|
|
34
|
+
neutralCitation: string | null;
|
|
35
|
+
title: string;
|
|
36
|
+
court: string;
|
|
37
|
+
date: string | null;
|
|
38
|
+
snippet: string;
|
|
39
|
+
source: 'tna' | 'bailii';
|
|
40
|
+
score: number;
|
|
41
|
+
urls: DocumentUrls;
|
|
42
|
+
}
|
|
43
|
+
export interface CitationResult {
|
|
44
|
+
citation: string;
|
|
45
|
+
title: string;
|
|
46
|
+
court: string;
|
|
47
|
+
date: string | null;
|
|
48
|
+
relationship: 'citing' | 'cited';
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC;IACzB,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;IACF,SAAS,EAAE,OAAO,CAAC;IACnB,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,YAAY,EAAE,QAAQ,GAAG,OAAO,CAAC;CAClC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,+EAA+E;AAC/E,0BAA0B;AAC1B,+EAA+E"}
|
package/language.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nodejs
|
package/package.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name": "@iflow-mcp/georgejeffers-uk-case-law-mcp", "version": "1.0.0", "description": "Model Context Protocol (MCP) server for searching UK case law via The National Archives API", "module": "src/server.ts", "main": "dist/server.js", "type": "module", "license": "PolyForm-Noncommercial-1.0.0", "author": "George Jefferson", "repository": {"type": "git", "url": "https://github.com/georgejeffers/uk-case-law-mcp-server"}, "keywords": ["mcp", "model-context-protocol", "claude", "legal", "case-law", "uk-law", "national-archives"], "scripts": {"start": "node dist/server.js", "dev": "bun --watch run src/server.ts", "test": "bun run src/test.ts", "typecheck": "tsc --noEmit", "build": "tsc"}, "bin": {"iflow-mcp-georgejeffers-uk-case-law-mcp": "dist/server.js"}, "devDependencies": {"@types/bun": "latest", "@types/node": "^22.0.0", "typescript": "^5.7.0"}, "dependencies": {"@modelcontextprotocol/sdk": "^1.25.1", "fast-xml-parser": "^5.3.3", "zod": "^4.2.1"}}
|
package/package_name
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@iflow-mcp/georgejeffers-uk-case-law-mcp
|
package/push_info.json
ADDED
package/src/cases.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/cases.ts
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// CASE RETRIEVAL
|
|
4
|
+
// ============================================================================
|
|
5
|
+
|
|
6
|
+
import { getTnaCaseContent, citationToUri } from './tna-client.js';
|
|
7
|
+
import type { CaseContent } from './types.js';
|
|
8
|
+
|
|
9
|
+
export async function getCaseByUri(uri: string): Promise<CaseContent | null> {
|
|
10
|
+
// Try TNA first
|
|
11
|
+
const tnaResult = await getTnaCaseContent(uri);
|
|
12
|
+
if (tnaResult) {
|
|
13
|
+
return {
|
|
14
|
+
metadata: tnaResult.metadata,
|
|
15
|
+
paragraphs: tnaResult.paragraphs,
|
|
16
|
+
judges: tnaResult.judges,
|
|
17
|
+
truncated: false,
|
|
18
|
+
remainingParagraphs: 0,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// TODO: Fall back to local database when PostgreSQL is configured
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function getCaseByCitation(citation: string): Promise<CaseContent | null> {
|
|
27
|
+
// Convert citation to URI and try TNA
|
|
28
|
+
const uri = citationToUri(citation);
|
|
29
|
+
if (uri) {
|
|
30
|
+
const result = await getCaseByUri(uri);
|
|
31
|
+
if (result) return result;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// TODO: Fall back to local search by citation when PostgreSQL is configured
|
|
35
|
+
return null;
|
|
36
|
+
}
|