legal-data-hunter 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/README.md +60 -0
- package/bin/setup.js +306 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Legal Data Hunter — MCP Setup
|
|
2
|
+
|
|
3
|
+
Connect your AI to **18M+ legal documents worldwide** with one command.
|
|
4
|
+
|
|
5
|
+
Works with Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, and any MCP-compatible client.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx legal-data-hunter setup
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This detects your installed AI clients and configures them automatically. On first use, you'll be prompted to sign in via your browser — no API key needed.
|
|
14
|
+
|
|
15
|
+
## Options
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx legal-data-hunter setup # Interactive setup
|
|
19
|
+
npx legal-data-hunter setup --yes # Auto-configure all detected clients
|
|
20
|
+
npx legal-data-hunter setup -c cursor # Configure Cursor only
|
|
21
|
+
npx legal-data-hunter setup --list # List detected clients
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Alternative: `add-mcp`
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx add-mcp https://legaldatahunter.com/mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Alternative: Manual Config
|
|
31
|
+
|
|
32
|
+
Add to your client's MCP config (`.mcp.json`, `claude_desktop_config.json`, etc.):
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"legal-data-hunter": {
|
|
38
|
+
"type": "streamable-http",
|
|
39
|
+
"url": "https://legaldatahunter.com/mcp"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## What You Get
|
|
46
|
+
|
|
47
|
+
| Tool | Description |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| `search` | Hybrid semantic + keyword search across 18M+ documents |
|
|
50
|
+
| `get_document` | Retrieve full text and metadata by source + ID |
|
|
51
|
+
| `resolve_reference` | Resolve loose citations (ECLI, article numbers, case numbers) |
|
|
52
|
+
| `discover_countries` | List available countries with document counts |
|
|
53
|
+
| `discover_sources` | List data sources for a specific country |
|
|
54
|
+
| `get_filters` | Get available filter values for a source |
|
|
55
|
+
|
|
56
|
+
## Links
|
|
57
|
+
|
|
58
|
+
- [Connect Guide](https://legaldatahunter.com/connect)
|
|
59
|
+
- [API Docs](https://legaldatahunter.com/docs)
|
|
60
|
+
- [GitHub](https://github.com/worldwidelaw/legal-sources)
|
package/bin/setup.js
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
const readline = require("readline");
|
|
8
|
+
|
|
9
|
+
const MCP_URL = "https://legaldatahunter.com/mcp";
|
|
10
|
+
const SERVER_NAME = "legal-data-hunter";
|
|
11
|
+
const MCP_ENTRY = {
|
|
12
|
+
type: "streamable-http",
|
|
13
|
+
url: MCP_URL,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// ── Client definitions ──────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
const HOME = os.homedir();
|
|
19
|
+
const IS_WIN = process.platform === "win32";
|
|
20
|
+
const IS_MAC = process.platform === "darwin";
|
|
21
|
+
|
|
22
|
+
function appData() {
|
|
23
|
+
if (IS_WIN) return process.env.APPDATA || path.join(HOME, "AppData", "Roaming");
|
|
24
|
+
if (IS_MAC) return path.join(HOME, "Library", "Application Support");
|
|
25
|
+
return process.env.XDG_CONFIG_HOME || path.join(HOME, ".config");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const CLIENTS = [
|
|
29
|
+
{
|
|
30
|
+
id: "claude-code",
|
|
31
|
+
name: "Claude Code (global)",
|
|
32
|
+
path: path.join(HOME, ".claude.json"),
|
|
33
|
+
wrap: false, // top-level mcpServers
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "claude-code-project",
|
|
37
|
+
name: "Claude Code (project)",
|
|
38
|
+
path: path.join(process.cwd(), ".mcp.json"),
|
|
39
|
+
wrap: false,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "claude-desktop",
|
|
43
|
+
name: "Claude Desktop",
|
|
44
|
+
path: IS_WIN
|
|
45
|
+
? path.join(appData(), "Claude", "claude_desktop_config.json")
|
|
46
|
+
: IS_MAC
|
|
47
|
+
? path.join(appData(), "Claude", "claude_desktop_config.json")
|
|
48
|
+
: path.join(appData(), "Claude", "claude_desktop_config.json"),
|
|
49
|
+
wrap: false,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "cursor",
|
|
53
|
+
name: "Cursor (global)",
|
|
54
|
+
path: path.join(HOME, ".cursor", "mcp.json"),
|
|
55
|
+
wrap: false,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "cursor-project",
|
|
59
|
+
name: "Cursor (project)",
|
|
60
|
+
path: path.join(process.cwd(), ".cursor", "mcp.json"),
|
|
61
|
+
wrap: false,
|
|
62
|
+
requireDir: true, // only if .cursor/ dir exists
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: "vscode",
|
|
66
|
+
name: "VS Code (project)",
|
|
67
|
+
path: path.join(process.cwd(), ".vscode", "mcp.json"),
|
|
68
|
+
wrap: false,
|
|
69
|
+
requireDir: true,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: "lawvable",
|
|
73
|
+
name: "Lawvable (project)",
|
|
74
|
+
path: path.join(process.cwd(), ".vscode", "mcp.json"), // VS Code fork, same config path
|
|
75
|
+
wrap: false,
|
|
76
|
+
requireDir: true,
|
|
77
|
+
aliasOf: "vscode", // skip if VS Code already handled this path
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "windsurf",
|
|
81
|
+
name: "Windsurf",
|
|
82
|
+
path: path.join(HOME, ".codeium", "windsurf", "mcp_config.json"),
|
|
83
|
+
wrap: false,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: "copilot",
|
|
87
|
+
name: "GitHub Copilot CLI",
|
|
88
|
+
path: path.join(HOME, ".copilot", "mcp-config.json"),
|
|
89
|
+
wrap: false,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: "junie",
|
|
93
|
+
name: "JetBrains Junie (project)",
|
|
94
|
+
path: path.join(process.cwd(), ".junie", "mcp", "mcp.json"),
|
|
95
|
+
wrap: false,
|
|
96
|
+
requireDir: true,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: "junie-global",
|
|
100
|
+
name: "JetBrains Junie (global)",
|
|
101
|
+
path: path.join(HOME, ".junie", "mcp", "mcp.json"),
|
|
102
|
+
wrap: false,
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
function detect() {
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
return CLIENTS.filter((c) => {
|
|
111
|
+
// Deduplicate: skip if another client already claimed this config path
|
|
112
|
+
if (c.aliasOf && seen.has(c.path)) return false;
|
|
113
|
+
|
|
114
|
+
let detected = false;
|
|
115
|
+
if (c.requireDir) {
|
|
116
|
+
detected = fs.existsSync(path.dirname(c.path));
|
|
117
|
+
} else if (c.id === "claude-code") {
|
|
118
|
+
detected = fs.existsSync(path.join(HOME, ".claude")) || fs.existsSync(c.path);
|
|
119
|
+
} else if (["claude-desktop", "cursor", "windsurf", "copilot", "junie-global"].includes(c.id)) {
|
|
120
|
+
detected = fs.existsSync(path.dirname(c.path));
|
|
121
|
+
} else {
|
|
122
|
+
detected = fs.existsSync(c.path);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (detected) seen.add(c.path);
|
|
126
|
+
return detected;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function readJson(filePath) {
|
|
131
|
+
try {
|
|
132
|
+
return JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
133
|
+
} catch {
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function writeJson(filePath, data) {
|
|
139
|
+
const dir = path.dirname(filePath);
|
|
140
|
+
if (!fs.existsSync(dir)) {
|
|
141
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
142
|
+
}
|
|
143
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function configure(client) {
|
|
147
|
+
const config = readJson(client.path);
|
|
148
|
+
if (!config.mcpServers) config.mcpServers = {};
|
|
149
|
+
|
|
150
|
+
if (config.mcpServers[SERVER_NAME]) {
|
|
151
|
+
const existing = config.mcpServers[SERVER_NAME];
|
|
152
|
+
if (existing.url === MCP_URL) {
|
|
153
|
+
console.log(` \u2713 ${client.name} — already configured`);
|
|
154
|
+
return "skipped";
|
|
155
|
+
}
|
|
156
|
+
// Update URL if different
|
|
157
|
+
console.log(` \u2713 ${client.name} — updated (URL changed)`);
|
|
158
|
+
} else {
|
|
159
|
+
console.log(` \u2713 ${client.name} — configured`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
config.mcpServers[SERVER_NAME] = { ...MCP_ENTRY };
|
|
163
|
+
writeJson(client.path, config);
|
|
164
|
+
return "configured";
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function ask(question) {
|
|
168
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
169
|
+
return new Promise((resolve) => {
|
|
170
|
+
rl.question(question, (answer) => {
|
|
171
|
+
rl.close();
|
|
172
|
+
resolve(answer.trim().toLowerCase());
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── CLI ──────────────────────────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
async function main() {
|
|
180
|
+
const args = process.argv.slice(2);
|
|
181
|
+
const autoYes = args.includes("--yes") || args.includes("-y");
|
|
182
|
+
const clientFilter = (() => {
|
|
183
|
+
const idx = args.indexOf("--client");
|
|
184
|
+
if (idx !== -1 && args[idx + 1]) return args[idx + 1];
|
|
185
|
+
const idxC = args.indexOf("-c");
|
|
186
|
+
if (idxC !== -1 && args[idxC + 1]) return args[idxC + 1];
|
|
187
|
+
return null;
|
|
188
|
+
})();
|
|
189
|
+
|
|
190
|
+
// Help
|
|
191
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
192
|
+
console.log(`
|
|
193
|
+
legal-data-hunter setup
|
|
194
|
+
|
|
195
|
+
Connect your AI to 18M+ legal documents worldwide via MCP.
|
|
196
|
+
Detects installed AI agents and writes the config automatically.
|
|
197
|
+
|
|
198
|
+
Usage:
|
|
199
|
+
npx legal-data-hunter setup [options]
|
|
200
|
+
|
|
201
|
+
Options:
|
|
202
|
+
--yes, -y Non-interactive mode (configure all detected clients)
|
|
203
|
+
--client, -c Target a specific client (claude-code, cursor, vscode, etc.)
|
|
204
|
+
--list List detected clients without configuring
|
|
205
|
+
--help, -h Show this help message
|
|
206
|
+
|
|
207
|
+
Examples:
|
|
208
|
+
npx legal-data-hunter setup # Interactive setup
|
|
209
|
+
npx legal-data-hunter setup --yes # Auto-configure all detected clients
|
|
210
|
+
npx legal-data-hunter setup -c cursor # Configure Cursor only
|
|
211
|
+
|
|
212
|
+
On first use in any client, you'll be prompted to sign in with
|
|
213
|
+
GitHub or Google via your browser. No API key needed.
|
|
214
|
+
|
|
215
|
+
Learn more: https://legaldatahunter.com/connect
|
|
216
|
+
`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
console.log();
|
|
221
|
+
console.log(" Legal Data Hunter — MCP Setup");
|
|
222
|
+
console.log(" Search 18M+ legal documents worldwide from your AI");
|
|
223
|
+
console.log();
|
|
224
|
+
|
|
225
|
+
// Detect clients
|
|
226
|
+
let clients = detect();
|
|
227
|
+
|
|
228
|
+
if (clientFilter) {
|
|
229
|
+
clients = clients.filter(
|
|
230
|
+
(c) => c.id === clientFilter || c.id.startsWith(clientFilter)
|
|
231
|
+
);
|
|
232
|
+
if (clients.length === 0) {
|
|
233
|
+
console.log(` No matching client found for "${clientFilter}".`);
|
|
234
|
+
console.log(` Available: ${CLIENTS.map((c) => c.id).join(", ")}`);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// List mode
|
|
240
|
+
if (args.includes("--list")) {
|
|
241
|
+
if (clients.length === 0) {
|
|
242
|
+
console.log(" No MCP-compatible AI clients detected.");
|
|
243
|
+
} else {
|
|
244
|
+
console.log(" Detected clients:");
|
|
245
|
+
clients.forEach((c) => console.log(` - ${c.name} (${c.path})`));
|
|
246
|
+
}
|
|
247
|
+
console.log();
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (clients.length === 0) {
|
|
252
|
+
console.log(" No MCP-compatible AI clients detected.");
|
|
253
|
+
console.log();
|
|
254
|
+
console.log(" You can manually add this to your client's MCP config:");
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(` {`);
|
|
257
|
+
console.log(` "mcpServers": {`);
|
|
258
|
+
console.log(` "${SERVER_NAME}": {`);
|
|
259
|
+
console.log(` "type": "streamable-http",`);
|
|
260
|
+
console.log(` "url": "${MCP_URL}"`);
|
|
261
|
+
console.log(` }`);
|
|
262
|
+
console.log(` }`);
|
|
263
|
+
console.log(` }`);
|
|
264
|
+
console.log();
|
|
265
|
+
console.log(" Learn more: https://legaldatahunter.com/connect");
|
|
266
|
+
console.log();
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
console.log(" Detected clients:");
|
|
271
|
+
clients.forEach((c, i) => console.log(` ${i + 1}. ${c.name}`));
|
|
272
|
+
console.log();
|
|
273
|
+
|
|
274
|
+
if (!autoYes) {
|
|
275
|
+
const answer = await ask(" Configure all detected clients? [Y/n] ");
|
|
276
|
+
if (answer && answer !== "y" && answer !== "yes") {
|
|
277
|
+
console.log(" Aborted.");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
console.log();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Configure
|
|
284
|
+
let configured = 0;
|
|
285
|
+
for (const client of clients) {
|
|
286
|
+
const result = configure(client);
|
|
287
|
+
if (result === "configured") configured++;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
console.log();
|
|
291
|
+
if (configured > 0) {
|
|
292
|
+
console.log(" Done! On first use, you'll be prompted to sign in via your browser.");
|
|
293
|
+
console.log(" No API key needed — authentication is handled automatically (OAuth).");
|
|
294
|
+
} else {
|
|
295
|
+
console.log(" All clients were already configured. Nothing to do.");
|
|
296
|
+
}
|
|
297
|
+
console.log();
|
|
298
|
+
console.log(" MCP URL: " + MCP_URL);
|
|
299
|
+
console.log(" Docs: https://legaldatahunter.com/connect");
|
|
300
|
+
console.log();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
main().catch((err) => {
|
|
304
|
+
console.error("Error:", err.message);
|
|
305
|
+
process.exit(1);
|
|
306
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "legal-data-hunter",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Connect your AI to 18M+ legal documents worldwide via MCP. One command to configure Claude, Cursor, VS Code, and more.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"legal-data-hunter": "bin/setup.js"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"mcp",
|
|
10
|
+
"model-context-protocol",
|
|
11
|
+
"legal",
|
|
12
|
+
"ai",
|
|
13
|
+
"claude",
|
|
14
|
+
"cursor",
|
|
15
|
+
"vscode",
|
|
16
|
+
"law",
|
|
17
|
+
"case-law",
|
|
18
|
+
"legislation"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://legaldatahunter.com/connect",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/worldwidelaw/legal-sources"
|
|
24
|
+
},
|
|
25
|
+
"author": "Legal Data Hunter",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=16"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"bin/setup.js",
|
|
32
|
+
"README.md"
|
|
33
|
+
]
|
|
34
|
+
}
|