accurlex-mcp-server 0.4.1 → 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.
- package/package.json +1 -1
- package/src/index.js +17 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "accurlex-mcp-server",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server for accurLex Chinese legal AI — legal Q&A, contract review, law lookup, document drafting",
|
|
6
6
|
"keywords": ["mcp", "legal", "chinese-law", "contract-review", "accurlex", "ai"],
|
package/src/index.js
CHANGED
|
@@ -24,11 +24,12 @@ const BEARER_TOKEN = (process.env.ACCURLEX_BEARER_TOKEN || '').trim();
|
|
|
24
24
|
|
|
25
25
|
const TEXT_FILE_EXTENSIONS = new Set(['.txt', '.text', '.md', '.json', '.csv']);
|
|
26
26
|
const MAX_INPUT_CHARS = 10000;
|
|
27
|
+
const MAX_INPUT_CHARS_PAID = 30000;
|
|
27
28
|
|
|
28
29
|
const server = new Server(
|
|
29
30
|
{
|
|
30
31
|
name: 'accurlex-mcp-server',
|
|
31
|
-
version: '0.4.
|
|
32
|
+
version: '0.4.2',
|
|
32
33
|
},
|
|
33
34
|
{
|
|
34
35
|
capabilities: {
|
|
@@ -44,7 +45,7 @@ const tools = [
|
|
|
44
45
|
inputSchema: {
|
|
45
46
|
type: 'object',
|
|
46
47
|
properties: {
|
|
47
|
-
question: { type: 'string', maxLength:
|
|
48
|
+
question: { type: 'string', maxLength: 30000, description: 'The legal question to analyze (free/deep: max 10000 chars, expert: max 30000 chars).' },
|
|
48
49
|
mode: {
|
|
49
50
|
type: 'string',
|
|
50
51
|
enum: ['deep', 'expert'],
|
|
@@ -62,7 +63,7 @@ const tools = [
|
|
|
62
63
|
required: ['role', 'content'],
|
|
63
64
|
},
|
|
64
65
|
},
|
|
65
|
-
context_text: { type: 'string', maxLength:
|
|
66
|
+
context_text: { type: 'string', maxLength: 30000, description: 'Optional background facts or extracted file text (free/deep: max 10000 chars, expert: max 30000 chars).' },
|
|
66
67
|
},
|
|
67
68
|
required: ['question'],
|
|
68
69
|
},
|
|
@@ -76,13 +77,13 @@ const tools = [
|
|
|
76
77
|
properties: {
|
|
77
78
|
contract_text: {
|
|
78
79
|
type: 'string',
|
|
79
|
-
maxLength:
|
|
80
|
-
description: 'The contract text to review. Combined with standpoint must not exceed
|
|
80
|
+
maxLength: 30000,
|
|
81
|
+
description: 'The contract text to review. Combined with standpoint must not exceed 30000 chars.',
|
|
81
82
|
},
|
|
82
83
|
file_ref: { type: 'string', description: 'Local plaintext file path as alternative to contract_text.' },
|
|
83
84
|
standpoint: {
|
|
84
85
|
type: 'string',
|
|
85
|
-
maxLength:
|
|
86
|
+
maxLength: 30000,
|
|
86
87
|
description: 'Your review standpoint and requirements, e.g. "我是甲方(买方),请重点审查付款条款和违约责任".',
|
|
87
88
|
},
|
|
88
89
|
reviewer_name: { type: 'string', maxLength: 40, description: 'Reviewer name for the opinion header, e.g. "张律师".' },
|
|
@@ -97,7 +98,7 @@ const tools = [
|
|
|
97
98
|
type: 'object',
|
|
98
99
|
properties: {
|
|
99
100
|
document_type: { type: 'string', description: 'Document type, e.g. "民事起诉状", "答辩状", "代理词".' },
|
|
100
|
-
facts: { type: 'string', maxLength:
|
|
101
|
+
facts: { type: 'string', maxLength: 30000, description: 'Key facts and claims (max 30000 chars).' },
|
|
101
102
|
case_file_refs: {
|
|
102
103
|
type: 'array',
|
|
103
104
|
items: { type: 'string' },
|
|
@@ -174,10 +175,11 @@ async function handleLegalQa(args) {
|
|
|
174
175
|
assertConfigured(PROXY_BASE_URL, 'ACCURLEX_PROXY_BASE_URL is required');
|
|
175
176
|
|
|
176
177
|
const question = asNonEmptyString(args.question, 'question');
|
|
177
|
-
if (question.length > MAX_INPUT_CHARS) {
|
|
178
|
-
throw withCode(new Error(`问题字数超出上限(${question.length}/${MAX_INPUT_CHARS})`), 'input_too_long');
|
|
179
|
-
}
|
|
180
178
|
const mode = args.mode === 'expert' ? 'expert' : 'deep';
|
|
179
|
+
const charLimit = mode === 'expert' ? MAX_INPUT_CHARS_PAID : MAX_INPUT_CHARS;
|
|
180
|
+
if (question.length > charLimit) {
|
|
181
|
+
throw withCode(new Error(`问题字数超出上限(${question.length}/${charLimit})`), 'input_too_long');
|
|
182
|
+
}
|
|
181
183
|
const history = Array.isArray(args.history) ? args.history : [];
|
|
182
184
|
const contextText = optionalString(args.context_text);
|
|
183
185
|
const route = mode === 'expert' ? '/ask_stream' : '/ask_free_stream';
|
|
@@ -219,11 +221,11 @@ async function handleContractReview(args) {
|
|
|
219
221
|
const standpoint = asNonEmptyString(args.standpoint, 'standpoint');
|
|
220
222
|
const contractText = await resolveTextInput(args.contract_text, args.file_ref, 'contract_text');
|
|
221
223
|
|
|
222
|
-
// Enforce combined character limit (
|
|
224
|
+
// Enforce combined character limit (contract review is always paid: 30000 chars)
|
|
223
225
|
const totalLen = contractText.length + standpoint.length;
|
|
224
|
-
if (totalLen >
|
|
226
|
+
if (totalLen > MAX_INPUT_CHARS_PAID) {
|
|
225
227
|
throw withCode(
|
|
226
|
-
new Error(`合同文本+审查立场总字数超出上限(${totalLen}/${
|
|
228
|
+
new Error(`合同文本+审查立场总字数超出上限(${totalLen}/${MAX_INPUT_CHARS_PAID}),请精简输入`),
|
|
227
229
|
'input_too_long',
|
|
228
230
|
);
|
|
229
231
|
}
|
|
@@ -262,8 +264,8 @@ async function handleDraftDocument(args) {
|
|
|
262
264
|
|
|
263
265
|
const documentType = asNonEmptyString(args.document_type, 'document_type');
|
|
264
266
|
const facts = asNonEmptyString(args.facts, 'facts');
|
|
265
|
-
if (facts.length >
|
|
266
|
-
throw withCode(new Error(`事实描述字数超出上限(${facts.length}/${
|
|
267
|
+
if (facts.length > MAX_INPUT_CHARS_PAID) {
|
|
268
|
+
throw withCode(new Error(`事实描述字数超出上限(${facts.length}/${MAX_INPUT_CHARS_PAID})`), 'input_too_long');
|
|
267
269
|
}
|
|
268
270
|
const referenceTexts = await resolveManyTextFiles(args.case_file_refs);
|
|
269
271
|
const styleText = optionalString(args.style_file_ref)
|