dicom-mcp 1.2.1 → 1.2.5
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/CHANGELOG.md +39 -0
- package/dicom_mcp/server.py +78 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,45 @@
|
|
|
5
5
|
格式遵循 [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
版本号遵循 [Semantic Versioning](https://semver.org/)。
|
|
7
7
|
|
|
8
|
+
## [1.2.5] - 2025-01-13
|
|
9
|
+
|
|
10
|
+
### 改进
|
|
11
|
+
|
|
12
|
+
- **支持多格式密码提取**: 增强密码识别的灵活性
|
|
13
|
+
- 支持:`安全码:8492`、`密码:8492`、`password:8492`、`code:8492`、`验证码:8492`
|
|
14
|
+
- 同时支持半角冒号 `:` 和全角冒号 `:`
|
|
15
|
+
- 自动清理 URL 中的密码部分
|
|
16
|
+
- 添加诊断日志显示提取的密码
|
|
17
|
+
|
|
18
|
+
## [1.2.4] - 2025-01-13
|
|
19
|
+
|
|
20
|
+
### 改进
|
|
21
|
+
|
|
22
|
+
- **标准化安全码提取**: 简化并规范化密码提取逻辑
|
|
23
|
+
- 只支持标准格式:`URL 安全码:8492` 或 `URL 安全码:8492`
|
|
24
|
+
- 自动清理 URL 中的安全码部分
|
|
25
|
+
- 添加诊断日志显示提取的密码
|
|
26
|
+
- 代码更清晰,性能更好
|
|
27
|
+
|
|
28
|
+
## [1.2.3] - 2025-01-13
|
|
29
|
+
|
|
30
|
+
### 新功能
|
|
31
|
+
|
|
32
|
+
- **自动密码提取**: 从 URL 中自动识别和提取安全码/密码
|
|
33
|
+
- 支持多种格式:`安全码:8492`、`密码:8492`、`password:8492`、`code:8492`
|
|
34
|
+
- 用户只需粘贴原始链接,无需手动提取密码
|
|
35
|
+
- 自动清理 URL,将密码传递给下载脚本
|
|
36
|
+
- 例如:`https://ylyyx.shdc.org.cn/code.html?... 安全码:8492`
|
|
37
|
+
|
|
38
|
+
## [1.2.2] - 2025-01-13
|
|
39
|
+
|
|
40
|
+
### 新功能
|
|
41
|
+
|
|
42
|
+
- **安全码/密码支持**: 支持需要安全码(password)的医院链接
|
|
43
|
+
- 添加 `password` 参数到 `download_dicom` 和 `batch_download_dicom` 工具
|
|
44
|
+
- 自动将密码传递给底层下载脚本
|
|
45
|
+
- 用法:提供 URL 和密码参数即可自动填入
|
|
46
|
+
|
|
8
47
|
## [1.2.1] - 2025-01-13
|
|
9
48
|
|
|
10
49
|
### 改进
|
package/dicom_mcp/server.py
CHANGED
|
@@ -128,6 +128,9 @@ class BatchDownloadRequest(BaseModel):
|
|
|
128
128
|
)
|
|
129
129
|
mode: str = Field(default="all", description="Download mode")
|
|
130
130
|
headless: bool = Field(default=True, description="Run in headless mode")
|
|
131
|
+
password: Optional[str] = Field(
|
|
132
|
+
default=None, description="Password/share code if required by the site"
|
|
133
|
+
)
|
|
131
134
|
create_zip: bool = Field(default=True, description="Create ZIP archives")
|
|
132
135
|
max_rounds: int = Field(
|
|
133
136
|
default=_DEFAULT_MAX_ROUNDS,
|
|
@@ -232,6 +235,7 @@ async def run_multi_download(
|
|
|
232
235
|
provider: str = "auto",
|
|
233
236
|
mode: str = "all",
|
|
234
237
|
headless: bool = True,
|
|
238
|
+
password: Optional[str] = None,
|
|
235
239
|
create_zip: bool = True,
|
|
236
240
|
max_rounds: int = 3,
|
|
237
241
|
step_wait_ms: int = 40,
|
|
@@ -277,6 +281,9 @@ async def run_multi_download(
|
|
|
277
281
|
else:
|
|
278
282
|
cmd.append("--no-headless")
|
|
279
283
|
|
|
284
|
+
if password:
|
|
285
|
+
cmd.extend(["--password", password])
|
|
286
|
+
|
|
280
287
|
if not create_zip:
|
|
281
288
|
cmd.append("--no-zip")
|
|
282
289
|
|
|
@@ -376,6 +383,50 @@ async def run_multi_download(
|
|
|
376
383
|
pass
|
|
377
384
|
|
|
378
385
|
|
|
386
|
+
# ============================================================================
|
|
387
|
+
# Helper Functions for Password Extraction
|
|
388
|
+
# ============================================================================
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _extract_password_from_url(url: str) -> tuple[str, Optional[str]]:
|
|
392
|
+
"""
|
|
393
|
+
Extract password/security code from URL string.
|
|
394
|
+
|
|
395
|
+
Supports multiple formats:
|
|
396
|
+
- URL 安全码:8492 or URL 安全码:8492
|
|
397
|
+
- URL 密码:8492 or URL 密码:8492
|
|
398
|
+
- URL password:8492 or URL password:8492
|
|
399
|
+
- URL code:8492 or URL code:8492
|
|
400
|
+
- URL 验证码:8492 or URL 验证码:8492
|
|
401
|
+
|
|
402
|
+
Returns: (clean_url, password)
|
|
403
|
+
"""
|
|
404
|
+
import re
|
|
405
|
+
|
|
406
|
+
# Pattern: look for various password indicators with both half-width and full-width colons
|
|
407
|
+
patterns = [
|
|
408
|
+
r'\s*安全码[::]\s*(\d+)', # 安全码:8492 or 安全码:8492
|
|
409
|
+
r'\s*密码[::]\s*(\d+)', # 密码:8492 or 密码:8492
|
|
410
|
+
r'\s*验证码[::]\s*(\d+)', # 验证码:8492 or 验证码:8492
|
|
411
|
+
r'\s*password[::]\s*(\S+)', # password:8492 or password:8492
|
|
412
|
+
r'\s*code[::]\s*(\d+)', # code:8492 or code:8492
|
|
413
|
+
]
|
|
414
|
+
|
|
415
|
+
password = None
|
|
416
|
+
clean_url = url
|
|
417
|
+
|
|
418
|
+
for pattern in patterns:
|
|
419
|
+
match = re.search(pattern, url)
|
|
420
|
+
if match:
|
|
421
|
+
password = match.group(1)
|
|
422
|
+
# Remove password from URL
|
|
423
|
+
clean_url = re.sub(pattern, '', url).strip()
|
|
424
|
+
print(f"[dicom-mcp] 提取密码: {password}", file=sys.stderr)
|
|
425
|
+
break
|
|
426
|
+
|
|
427
|
+
return clean_url, password
|
|
428
|
+
|
|
429
|
+
|
|
379
430
|
# ============================================================================
|
|
380
431
|
# MCP Tools
|
|
381
432
|
# ============================================================================
|
|
@@ -391,14 +442,22 @@ async def download_dicom(request: DownloadRequest) -> DownloadResult:
|
|
|
391
442
|
- fz: 复肿 (ylyyx.shdc.org.cn)
|
|
392
443
|
- nyfy: 宁夏总医院 (zhyl.nyfy.com.cn)
|
|
393
444
|
- cloud: *.medicalimagecloud.com and other cloud-based systems
|
|
445
|
+
|
|
446
|
+
Automatically extracts password/security code from URL if present.
|
|
447
|
+
Formats: "URL 安全码:8492", "URL password:8492", etc.
|
|
394
448
|
"""
|
|
449
|
+
# Auto-extract password from URL if not explicitly provided
|
|
450
|
+
clean_url, extracted_password = _extract_password_from_url(request.url)
|
|
451
|
+
password = request.password or extracted_password
|
|
452
|
+
|
|
395
453
|
os.makedirs(request.output_dir, exist_ok=True)
|
|
396
454
|
results = await run_multi_download(
|
|
397
|
-
[
|
|
455
|
+
[clean_url],
|
|
398
456
|
request.output_dir,
|
|
399
457
|
provider=request.provider or "auto",
|
|
400
458
|
mode=request.mode,
|
|
401
459
|
headless=request.headless,
|
|
460
|
+
password=password,
|
|
402
461
|
create_zip=request.create_zip,
|
|
403
462
|
max_rounds=request.max_rounds,
|
|
404
463
|
step_wait_ms=request.step_wait_ms,
|
|
@@ -418,14 +477,31 @@ async def batch_download_dicom(request: BatchDownloadRequest) -> list[DownloadRe
|
|
|
418
477
|
|
|
419
478
|
Each URL gets its own subdirectory. Supports auto-detection of provider
|
|
420
479
|
based on domain, or manual provider specification.
|
|
480
|
+
|
|
481
|
+
Automatically extracts password/security code from URL if present.
|
|
482
|
+
Formats: "URL 安全码:8492", "URL password:8492", etc.
|
|
421
483
|
"""
|
|
484
|
+
# Auto-extract passwords from URLs
|
|
485
|
+
clean_urls = []
|
|
486
|
+
extracted_password = None
|
|
487
|
+
|
|
488
|
+
for url in request.urls:
|
|
489
|
+
clean_url, pwd = _extract_password_from_url(url)
|
|
490
|
+
clean_urls.append(clean_url)
|
|
491
|
+
# Use first extracted password if no explicit password provided
|
|
492
|
+
if not extracted_password and pwd:
|
|
493
|
+
extracted_password = pwd
|
|
494
|
+
|
|
495
|
+
password = request.password or extracted_password
|
|
496
|
+
|
|
422
497
|
os.makedirs(request.output_parent, exist_ok=True)
|
|
423
498
|
return await run_multi_download(
|
|
424
|
-
|
|
499
|
+
clean_urls,
|
|
425
500
|
request.output_parent,
|
|
426
501
|
provider=request.provider,
|
|
427
502
|
mode=request.mode,
|
|
428
503
|
headless=request.headless,
|
|
504
|
+
password=password,
|
|
429
505
|
create_zip=request.create_zip,
|
|
430
506
|
max_rounds=request.max_rounds,
|
|
431
507
|
step_wait_ms=request.step_wait_ms,
|