@jurislm/judicial-mcp 1.3.0 → 1.6.3
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 +68 -9
- package/bin/judicial-mcp.ts +2 -0
- package/package.json +30 -17
- package/src/index.ts +20 -0
- package/src/public-judgment-source.ts +487 -0
- package/src/regulation-cache.ts +38 -0
- package/src/regulation-source.ts +536 -0
- package/src/response.ts +74 -0
- package/src/server.ts +70 -0
- package/src/source-error.ts +50 -0
- package/src/tools.ts +409 -0
- package/types/index.d.ts +1 -113
- package/types/public-judgment-source.d.ts +2 -0
- package/types/regulation-cache.d.ts +8 -0
- package/types/regulation-source.d.ts +29 -0
- package/types/response.d.ts +20 -0
- package/types/server.d.ts +3 -0
- package/types/source-error.d.ts +14 -0
- package/types/tools.d.ts +236 -0
- package/bin/judicial-mcp.js +0 -18
- package/src/index.js +0 -76
- package/src/response.js +0 -44
- package/src/tools.js +0 -360
package/README.md
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
# @jurislm/judicial-mcp
|
|
2
2
|
|
|
3
|
-
MCP (Model Context Protocol) server for
|
|
3
|
+
MCP (Model Context Protocol) server for Taiwan's Judicial Yuan public judgments and open data, plus current regulations from the Ministry of Justice National Laws and Regulations Database. It provides 10 tools.
|
|
4
|
+
|
|
5
|
+
## Public Judgment Search
|
|
6
|
+
|
|
7
|
+
`search_judgments` searches the Judicial Yuan's public judgment website. `fetch_judgment_text` retrieves the full text for a result. Both tools use the public website and do not require an API token or Judicial Yuan account.
|
|
8
|
+
|
|
9
|
+
Search accepts any combination of these filters (at least one is required):
|
|
10
|
+
|
|
11
|
+
| Field | Meaning |
|
|
12
|
+
|-------|---------|
|
|
13
|
+
| `keyword` | Keyword in judgment text, up to 128 characters |
|
|
14
|
+
| `court` | Official court name or code, up to 80 characters |
|
|
15
|
+
| `year` | Decision year as a Gregorian or Minguo integer |
|
|
16
|
+
| `caseNumber` | Case number, either digits or a full form such as `113年度訴字第1234號` |
|
|
17
|
+
| `limit` | Results per page, 1–10; defaults to 5 |
|
|
18
|
+
| `page` | Official result page, 1–50; defaults to 1 |
|
|
19
|
+
| `offset` | Starting row within an official result page, 0–19; defaults to 0 |
|
|
20
|
+
|
|
21
|
+
Each search result includes `case_id` (pass this as `caseId` to `fetch_judgment_text`), `case_number`, `date` (ISO date or `null`), `court`, `cause`, an optional `summary`, `source_url`, `search_source_url`, `retrieved_at`, `cache`, `truncated`, `partial`, and `source_version`. The search response also includes `count`, `ambiguous`, `results`, `source_url`, `retrieved_at`, `cache`, `truncated`, `partial`, `next_page`, `next_offset`, and `source_version`. Follow both `next_page` and `next_offset` to retrieve every result; `next_offset` may point to another batch on the same official page. An `ambiguous` case-number search returns its candidates for you to choose from rather than selecting one.
|
|
22
|
+
|
|
23
|
+
The full-text response includes `case_id`, `date`, `full_text`, `source_url`, `retrieved_at`, `cache`, `truncated`, `partial`, and `source_version`. Text is capped at 40,000 characters; when that cap is reached, `truncated` and `partial` are `true`. `cache.status` is `not_cached`; `source_version` is `null` when the official source provides no version identifier.
|
|
24
|
+
|
|
25
|
+
Only an explicit no-matches response from the official site is returned as an empty result. Upstream denial or failure, an unrecognized page, or a missing judgment is returned as an MCP error (`isError: true`) with `error.code`, `error.message`, `error.source_url`, and `error.retrieved_at`.
|
|
26
|
+
|
|
27
|
+
## Regulation Lookup
|
|
28
|
+
|
|
29
|
+
`query_regulation` looks up one article by law name and article number in the Ministry of Justice's [National Laws and Regulations Database](https://law.moj.gov.tw/). The official autocomplete lookup is tokenless. HTML pages are scraped only through a Firecrawl service configured with `FIRECRAWL_API_URL`; set `FIRECRAWL_API_KEY` when that service requires a key. If Firecrawl is unavailable, the tool returns a source error without a direct-HTTP HTML fallback.
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"lawName": "民法",
|
|
34
|
+
"articleNumber": "1"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The tool resolves only a unique exact law-name match after normalizing whitespace and the common `台` / `臺` spelling. It returns candidates with `status: "ambiguous"` when the name does not resolve uniquely; it never chooses a fuzzy match. Article numbers use Arabic numerals and may include a hyphen, such as `1` or `1-1`.
|
|
39
|
+
|
|
40
|
+
Successful results include the regulation name and official identifier, one article's text, the official page URL, the lookup URL, retrieval time, and version metadata. The official page supplies consolidated current text; this tool does not provide historical versions. Amendment, promulgation, and effective dates are returned as ISO dates when the official page states them. Missing dates are `null` and mark the result `partial`; a pending or mixed effective date is identified in `version.effective_status`. `source_version` is the published amendment date, falling back to the promulgation date.
|
|
41
|
+
|
|
42
|
+
Responses cap article text at 30,000 characters. `truncated` and `partial` are `true` when text is capped or required version details are missing. `cache.status` is `miss`, `hit`, `refreshed`, `revalidated`, or `not_cached`. A process-local least-recently-used cache holds at most 100 exact law/article lookups for 15 minutes. Set `refresh: true` to bypass the cache. Expired entries are looked up and scraped again through Firecrawl; if an upstream refresh fails, the tool returns an error and does not serve stale text as current.
|
|
43
|
+
|
|
44
|
+
Upstream failures and unrecognized page changes are MCP errors with `error.code`, `error.message`, `error.source_url`, and `error.retrieved_at`. Confirmed no-match, abolished-law, and missing-article responses have distinct codes.
|
|
4
45
|
|
|
5
46
|
## Tools
|
|
6
47
|
|
|
@@ -8,8 +49,15 @@ MCP (Model Context Protocol) server for [Taiwan Judicial Yuan](https://www.judic
|
|
|
8
49
|
- `auth_token` — Get authorization token for judgment API (uses `JUDICIAL_USER` / `JUDICIAL_PASSWORD` env vars by default)
|
|
9
50
|
- `member_token` — Get member token for open data API (uses `JUDICIAL_USER` / `JUDICIAL_PASSWORD` env vars by default)
|
|
10
51
|
|
|
11
|
-
### Judgments (2 tools)
|
|
12
|
-
- `
|
|
52
|
+
### Public Judgments (2 tools)
|
|
53
|
+
- `search_judgments` — Search public judgments without a token
|
|
54
|
+
- `fetch_judgment_text` — Get a judgment's full text by `case_id`, without a token
|
|
55
|
+
|
|
56
|
+
### Regulations (1 tool)
|
|
57
|
+
- `query_regulation` — Get one current regulation article and official version metadata, without a token
|
|
58
|
+
|
|
59
|
+
### Token-based Judgments (2 tools)
|
|
60
|
+
- `list_judgments` — Get the judgment change list (requires `auth_token`)
|
|
13
61
|
- `get_judgment` — Get judgment content by JID (requires `auth_token`)
|
|
14
62
|
|
|
15
63
|
### Open Data (3 tools)
|
|
@@ -21,14 +69,23 @@ MCP (Model Context Protocol) server for [Taiwan Judicial Yuan](https://www.judic
|
|
|
21
69
|
|
|
22
70
|
### Environment Variables
|
|
23
71
|
|
|
72
|
+
The public judgment search tools do not require credentials. These variables are used by the existing token-based judgment and open-data tools:
|
|
73
|
+
|
|
24
74
|
```bash
|
|
25
75
|
JUDICIAL_USER=your_username
|
|
26
76
|
JUDICIAL_PASSWORD=your_password
|
|
27
77
|
```
|
|
28
78
|
|
|
79
|
+
Regulation lookup also needs a Firecrawl service base URL. The server appends `/v1/scrape` and sends raw-HTML scrape requests only for official Ministry of Justice pages. The key is read from the environment and is optional when Firecrawl is configured to allow keyless access. Use HTTPS when the configured service is remote; a key is sent over HTTP only to a loopback address.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
FIRECRAWL_API_URL=https://your-firecrawl-host
|
|
83
|
+
FIRECRAWL_API_KEY=your_service_key
|
|
84
|
+
```
|
|
85
|
+
|
|
29
86
|
### Usage with Claude Code (via bunx)
|
|
30
87
|
|
|
31
|
-
|
|
88
|
+
Install Bun first, then add this stdio server to your MCP configuration (`.mcp.json` or `~/.claude/settings.json`). The public judgment tools work without credentials; regulation lookup needs the Firecrawl environment settings above:
|
|
32
89
|
|
|
33
90
|
```json
|
|
34
91
|
{
|
|
@@ -37,8 +94,8 @@ Add to your MCP configuration (`.mcp.json` or `~/.claude/settings.json`):
|
|
|
37
94
|
"command": "bunx",
|
|
38
95
|
"args": ["@jurislm/judicial-mcp@latest"],
|
|
39
96
|
"env": {
|
|
40
|
-
"
|
|
41
|
-
"
|
|
97
|
+
"FIRECRAWL_API_URL": "https://your-firecrawl-host",
|
|
98
|
+
"FIRECRAWL_API_KEY": "your_service_key"
|
|
42
99
|
}
|
|
43
100
|
}
|
|
44
101
|
}
|
|
@@ -63,9 +120,11 @@ export JUDICIAL_PASSWORD=your_password
|
|
|
63
120
|
## Development
|
|
64
121
|
|
|
65
122
|
```bash
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
123
|
+
bun install --frozen-lockfile
|
|
124
|
+
bun run test
|
|
125
|
+
bun run lint
|
|
126
|
+
bun run typecheck
|
|
127
|
+
bun run build:types
|
|
69
128
|
```
|
|
70
129
|
|
|
71
130
|
## License
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jurislm/judicial-mcp",
|
|
3
|
-
"version": "1.3
|
|
3
|
+
"version": "1.6.3",
|
|
4
4
|
"description": "MCP server for accessing Taiwan Judicial Yuan open data and judgments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -22,18 +22,20 @@
|
|
|
22
22
|
"name": "Terry Chen",
|
|
23
23
|
"email": "zxtw17985321@gmail.com"
|
|
24
24
|
},
|
|
25
|
-
"type": "
|
|
26
|
-
"main": "src/index.
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "src/index.ts",
|
|
27
27
|
"types": "types/index.d.ts",
|
|
28
28
|
"scripts": {
|
|
29
|
-
"start": "
|
|
30
|
-
"dev": "
|
|
31
|
-
"
|
|
32
|
-
"test
|
|
33
|
-
"test:
|
|
34
|
-
"
|
|
35
|
-
"lint
|
|
36
|
-
"
|
|
29
|
+
"start": "bun src/index.ts",
|
|
30
|
+
"dev": "bun src/index.ts",
|
|
31
|
+
"typecheck": "tsc --noEmit -p tsconfig.check.json",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"test:coverage": "vitest run --coverage",
|
|
35
|
+
"lint": "eslint --max-warnings=0",
|
|
36
|
+
"lint:fix": "eslint --fix --max-warnings=0",
|
|
37
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
38
|
+
"prepublishOnly": "bun run typecheck && bun run test && bun run lint && bun run build:types"
|
|
37
39
|
},
|
|
38
40
|
"files": [
|
|
39
41
|
"src",
|
|
@@ -42,18 +44,29 @@
|
|
|
42
44
|
"README.md"
|
|
43
45
|
],
|
|
44
46
|
"bin": {
|
|
45
|
-
"judicial-mcp": "bin/judicial-mcp.
|
|
47
|
+
"judicial-mcp": "bin/judicial-mcp.ts"
|
|
46
48
|
},
|
|
47
49
|
"dependencies": {
|
|
48
50
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
51
|
"axios": "^1.6.0",
|
|
52
|
+
"cheerio": "^1.2.0",
|
|
50
53
|
"dotenv": "^17.0.0"
|
|
51
54
|
},
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"oxlint": "^0.15.0"
|
|
55
|
+
"engines": {
|
|
56
|
+
"bun": ">=1.1.0"
|
|
55
57
|
},
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
+
"packageManager": "bun@1.4.3",
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@eslint/js": "^9.0.0",
|
|
61
|
+
"@types/node": "^26.6.5",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^8.62.0",
|
|
63
|
+
"@typescript-eslint/parser": "^8.62.0",
|
|
64
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
65
|
+
"eslint": "^9.0.0",
|
|
66
|
+
"eslint-config-prettier": "^10.0.0",
|
|
67
|
+
"globals": "^16.0.0",
|
|
68
|
+
"prettier": "^3.0.0",
|
|
69
|
+
"typescript": "^5.0.0",
|
|
70
|
+
"vitest": "^3.0.0"
|
|
58
71
|
}
|
|
59
72
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// MCP 使用 stdio transport,stdout 只能輸出 JSON-RPC 訊息。
|
|
2
|
+
// 覆寫必須在所有 import 模組初始化之前生效。
|
|
3
|
+
// ESM static import 會被 hoist 至頂層程式碼之前執行,因此這裡不放任何 static import,
|
|
4
|
+
// 改用 dynamic import 確保覆寫先於所有依賴模組的初始化。
|
|
5
|
+
const safeSerialize = (value: unknown): string => {
|
|
6
|
+
if (typeof value === 'string') return value
|
|
7
|
+
try {
|
|
8
|
+
const s = JSON.stringify(value)
|
|
9
|
+
return s === undefined ? String(value) : s
|
|
10
|
+
} catch {
|
|
11
|
+
return String(value)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
console.log = console.info = console.warn = (...args: unknown[]) =>
|
|
16
|
+
process.stderr.write(args.map(safeSerialize).join(' ') + '\n')
|
|
17
|
+
|
|
18
|
+
await import('./server.js')
|
|
19
|
+
|
|
20
|
+
export {}
|