mcpField
D
Doktor

Doktor

本地服务
avfatihsozer.com法律与政务05 天前更新

关于 Doktor

Doktor 是面向土耳其医生的 TypeScript/Node.js MCP 服务框架,用官方法规和有理由的高等法院判决生成有来源依据的法律信息包,不提供定论式法律意见。

主要功能

  1. 01搜索并获取官方卫生法规
  2. 02分类医疗法律问题
  3. 03筛选并去重判例
  4. 04生成带来源追踪的信息包
  5. 05支持实时与模拟数据源

适用场景

  1. 01查询患者知情同意相关法规
  2. 02查看案件相关的有理由判决
  3. 03核对引用条文及来源轨迹

MCP 相关

它提供问题分类、法规与判例搜索、判决全文获取以及法律信息包生成和深入查询等工具。响应标注数据来源,法规工具可选择实时或模拟数据源。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"afsozer-doktor": {
"command": "npx",
"args": [
"-y",
"doktor-mcp"
]
}
}
}
启动命令npx -y doktor-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npmdoktor-mcp0.59.2

工具

8

收录的工具列表 · 更新于 5 天前

参数类型必填说明
questionstring是
sourceModeenum否mock | live | snapshot

详细介绍

Doktor MCP

Beta 版本 — 当前版本请查看 package.json 和 CHANGELOG.md。

DOI

项目页面: avfatihsozer.com/projeler/doktor-mcp · English: README.en.md

doktor-mcp 是一个独立的 TypeScript/Node.js MCP 框架,面向医生生成基于来源的法律信息包。它不会给出一概而论的最终法律意见,也不会告诉医生该怎么做。它会将问题与官方法规文本及附有理由的高等法院判决文本相匹配;在不作确定性断言的前提下,可以提供基于来源的条件性评估(例如,“来源显示出这种倾向”)。

适配器边界为以下来源预留:

  • legislation(法规)
  • yargitay
  • danistay
  • aym

一般互联网文章、博客、新闻、律师事务所宣传页面和论坛不是本项目的来源输入。

来源引擎移植(Source Engine Port)

来源引擎层提供了在线适配器所需的可靠性增强:

  • Bedesten 请求使用共享的 HttpClient 和 RateLimiter 路径,其中包含有限次数的重试、Retry-After 处理、指数退避(backoff)、抖动(jitter)和请求遥测。
  • 在线来源错误保持结构化且仅包含 JSON。来源诊断信息可以携带重试次数、backoff 时长、状态和内容类型,且不会向 CLI JSON 输出写入日志。
  • src/sources/sourceRegistry.ts 为法规和判例来源提供精简的来源能力、速率限制和缓存策略元数据。
  • Bedesten/Yargıtay 适配器会将仅含元数据的判决排除在已验证判例输出之外;如果官方法规的官方搜索、文档获取或条款提取无法支持引文,则会返回结构化的 unavailable 结果。

在线法规状态

在线官方法规适配器已连接到可选的 MCP 工具流程:

  • 适配器:LiveOfficialLegislationAdapter
  • 官方来源:土耳其共和国总统府法规信息系统 — mevzuat.gov.tr
  • 搜索能力:官方 MevzuatDatatable 搜索请求解析器
  • 全文能力:官方 MevzuatMetin 文档获取
  • 当前提取依据:适用于已匹配法规的 PDF 文本提取和条款解析

医疗法规是首条在线匹配路径。患者权利和知情同意问题使用《患者权利条例》4847 的官方生成 PDF 路径(包括匹配条款 24 和 26)。医疗法匹配还涵盖《医疗伦理条例》、《关于行医及其分支执业方式的法律》和《卫生服务基本法》。KVKK 第 6 条可在医疗专属来源之后,作为个人健康数据和隐私问题的补充一般法规使用。

如果官方文档不是可提取的格式,或无法提取匹配条款,在线适配器会返回结构化的 unavailable 输出,而不是生成结论。

在线来源错误使用以下约定:

{
  "status": "unavailable",
  "source": "mevzuat.gov.tr",
  "errorCode": "provision_not_found",
  "message": "Official text was retrieved but the mapped article could not be extracted.",
  "retryable": false,
  "recommendedNextStep": "Inspect the official text parser before using this provision in an answer."
}

MVP 范围

骨架包含:

  • MCP 服务注册和工具处理器骨架
  • 正式法规证据、法院判决证据、分类、判例状态和法律信息包的类型契约
  • 模拟法规和高等法院适配器
  • 用于正式来源验证的实时法规适配器
  • 面向实时法规的 MCP sourceMode 路由
  • 以医疗健康为优先的法规映射和来源追踪(source trace)元数据
  • 医疗健康法律工作流组件:
    • 问题分类器
    • 法规映射器
    • 判例筛选器
    • 答案编译器
  • 本地 JSON 冒烟测试命令
  • 针对首批来源安全规则的 Vitest 覆盖

判例筛选器目前提供以下状态:

  • precedent_usable:有全文、法律理由和事实相关性
  • limited_value:有全文,但相关性较弱
  • procedural_only:没有实体理由;仅有程序性文本、仅有维持原判或仅有撤销判决
  • metadata_only:没有全文,只有案卷元数据
  • no_reasoning:有全文,但没有法律理由

只有 precedent_usable 记录会进入编译包中的已验证判例部分。

响应契约(Response Contract)

所有工具响应都带有 dataOrigin 字段。该字段用于说明响应的来源:

dataOrigin含义
"mock"响应包含 fixture(虚构)数据。不是真实法规或判决。
"live"响应来自实时来源(mevzuat.gov.tr、Bedesten、Danıştay)。
"snapshot"响应是预先保存的实时来源快照。
"computed"响应仅为计算结果(例如分类器)。不包含来源数据。
"client-provided"响应基于客户端提供的输入。

当 dataOrigin: "mock" 时,响应还带有 mockDataWarning 字段:

{
  "dataOrigin": "mock",
  "mockDataWarning": "BU YANIT KURGU (FIXTURE) VERİSİDİR. Gerçek mevzuat veya mahkeme kararı DEĞİLDİR. Gerçek kaynaklar için sourceMode: 'live' kullanın."
}

此警告会强制添加,不可遗漏,以防止模拟数据看起来像真实法规引文。不会在 shortAnswer 等面向医生的文本字段前添加额外前缀;顶层的 dataOrigin 和 mockDataWarning 字段已足够。

prepare_doctor_legal_information_pack 响应还带有 packId 字段。这是一个以 "pack-" 为前缀的 6 位十六进制标识符(例如 "pack-3f9a2c")。您可以将 packId 传给 drill_down_pack_item 工具,以便详细查看特定条款或判决,而无需重新生成信息包。packId 会在服务器内存中保存 30 分钟。

结构化信息包围绕所需的面向医生的部分组织:

  1. shortAnswer
  2. legalClassification
    • criminal
    • civilCompensation
    • disciplinaryAdministrative
    • patientRights
    • privacyKvkk
    • professionalEthics
  3. relevantLegislation
    • 法规名称
    • 条款编号
    • 从来源条文逐字复制的引文
    • 与事件的关联
  4. verifiedHighCourtPrecedents
    • 法院/庭、日期、案号/判决号
    • 事实摘要、法律评估、结果
    • 相似/差异说明
  5. missingInformation
  6. lawyerReviewPoints

每条法规记录都带有来源文档 ID 和逐字复制的来源引文。每条已验证判例记录都必须通过有理由判例筛选器。

有意不纳入范围

MVP 不包含:

  • 实时 AYM 高等法院客户端(AYM 判决信息库是仅提供 HTML 的界面;没有 JSON API — 标记为 synthetic_only)
  • 缺少来源引用或条件性表述的定性风险等级评分(“风险等级高/低”)
  • 紧急行动指示
  • 起诉状或辩护文书撰写
  • 最终法律结论
  • “存在责任”或“不存在责任”等定性表述
  • 工具可以提供有来源依据的条件性评估(例如“来源倾向于支持某种观点”),但绝不会给出定性的最终裁决
  • 未经 MCP 来源记录验证、仅基于模型的法律主张

v0.44.0 中的新功能

  • assessmentTone:可选参数("strict" | "grounded-advisory",默认值:"grounded-advisory")。在 strict 模式下仅返回来源列表(不进行评估)。在 grounded-advisory 模式下,会添加包含基于来源的条件式评估的 preliminaryAssessment。
  • preliminaryAssessment:可选响应字段,包含 summary 和 sentences[]。每个句子都包含 text、sourceRef 和 sourceLabel。句子使用判例中的实际结论/理由以及法规中的原文摘录片段——绝不使用套话。
  • 法规生效元数据:条款包含 inForce、lastAmendedDate 和 repealed 字段(默认绝不假定条款“有效”)。
  • 判决去重:跨来源的重复项(例如,同一判决同时来自 Yargıtay 和 Bedesten)会被去重;保留信息最丰富的版本。
  • 完整的土耳其语变音符号策略:所有面向医生的文本均使用正确的土耳其字符(不使用 ASCII 替代字符)。
  • 完整版本历史请参阅 CHANGELOG.md。稳定性级别请参阅 COMPATIBILITY.md。

速率限制为实时客户端预留:预期行为是,在发生实际拦截或来源错误后进行自适应退避,以应对正常的公共来源流量;并非在没有压力证据时进行激进限制。

MCP 工具

  • classify_medical_legal_question
  • search_health_legislation
  • get_legislation_provisions
  • search_health_precedents
  • filter_reasoned_precedents
  • prepare_doctor_legal_information_pack
  • drill_down_pack_item — 后续提问:使用 packId 深入了解特定条款/判决,无需重新生成信息包。示例:{ "packId": "pack-3f9a2c", "followUpQuestion": "madde 24 ne diyor?" }
  • get_decision_full_text — 获取特定法院判决的全文。示例:{ "documentId": "yargitay:99001", "sourceMode": "live" }
响应约定说明

所有工具响应均包含 dataOrigin 字段("mock"、"live"、"snapshot"、"computed"、"client-provided")。在 Mock 模式下会添加 mockDataWarning 字段。

调用 prepare_doctor_legal_information_pack 时,可以添加 includeDiagnostics: true 参数,以获取完整审计跟踪(选择诊断信息、来源跟踪等)。

面向法规的 MCP 输入接受可选的 sourceMode:

{
  "question": "kişisel sağlık verisi mahremiyet",
  "sourceMode": "live"
}

sourceMode 默认为 "live"(自 0.59.0 起);如需使用 fixture 数据,必须显式指定 "mock"。 search_health_legislation、get_legislation_provisions 和 prepare_doctor_legal_information_pack 可以使用 "live"。实时信息包 保持相同的 MVP 结构,并且仅当官方法规来源无法返回经验证的条款时,才会添加 sourceUnavailable。

Mock 模式使用本地 fixture 条款。实时模式使用来自 mevzuat.gov.tr 的官方法规文本,以及实时 Yargıtay 和 Danıştay 判例适配器。AYM 仅支持 Mock,在实时模式下会被禁用,而不会作为回退选项使用。

健康法规优先级

实时匹配层会将医生的问题归入以下健康法律主题组:

  • 知情同意 / 同意
  • 医疗干预
  • 患者权利
  • 患者隐私
  • 个人健康数据
  • 记录、病历和出院小结
  • 紧急干预
  • 转诊和会诊
  • 医生的注意义务
  • 职业道德

每个匹配项都包含目标法规、目标条款编号、搜索词、选择理由和健康法律优先级。匹配到多个主题时,信息包会将主要健康法规排在辅助性通用法规之前。例如,涉及个人健康数据隐私的问题可能会优先返回《患者权利条例》,而不是 KVKK;KVKK 不会被用作与医生问题无关的宽泛回退选项。

来源追踪(Source Trace)

sourceTrace 用于审核实时法规输出,而非提供法律理由。每条追踪记录都展示某项规定如何从医疗法律映射,关联到官方文档和条款提取步骤:

  • 原始 query
  • matchedHealthMapping,以及未匹配映射时尝试过的映射候选项
  • officialSearchRequest、官方搜索结果数量和精简的官方结果
  • selectedSearchResult 和 selectedResultReason
  • 落地页/详情页 URL,以及直接或生成的 PDF URL
  • contentType、提取方法、提取的条款编号和获取耗时

实时 search_health_legislation 会在选定的规定旁附带追踪记录。实时 get_legislation_provisions 会在每项返回的规定中附带追踪记录。实时 prepare_doctor_legal_information_pack 会在相关法规条目和包级 sourceTrace 数组中保留追踪记录;因此,汇编的引文可对照同一条提取出的规定进行核验。

即使实时数据包不可用(unavailable),也会保留审核上下文:

{
  "sourceUnavailable": [
    {
      "status": "unavailable",
      "source": "mevzuat.gov.tr",
      "errorCode": "document_not_found",
      "sourceTrace": [
        {
          "query": "bilinmeyen konu",
          "matchedHealthMapping": null,
          "attemptedHealthMappings": ["mevzuat:7.5.4847", "mevzuat:1.5.6698"]
        }
      ]
    }
  ]
}

matchedHealthMapping 和 selectedResultReason 会展示主题类别、医疗法律优先级,以及选定映射属于主要医疗法规还是辅助性一般法规。追踪字段仅解释来源选择和提取过程,不会生成法律主张,也绝不能替代官方规定的原文。

规定排序(Provision Ranking)

实时规定排序会在官方条款提取后运行确定性评分。它会为数据包选出一组精简的来源条款;不会生成条款文本、法律建议或定论式法律结论。

排序信号:

  • 医生查询词
  • 匹配的医疗法律主题类别
  • 映射搜索词
  • 提取的条款以可用标题开头时的条款标题文本
  • 提取条款文本中的关键词匹配
  • 匹配条款列表加分
  • 医疗法律优先级和主要/辅助角色顺序

实时追踪记录会展示 candidateArticleNumbers、rankedArticleNumbers、rejectedArticleNumbers 和 rankingMethod。每项返回的实时规定还会附带自身的确定性评分、匹配词、排序理由,以及是否来自人工匹配的条款列表。实时适配器会将单份法规文档限制在一组较小的已排序条款内,目前最多三项规定。提取出的匹配条款优先;只有在提取结果中没有匹配条款时,才会考虑高信号的排序备用条款。追踪记录会保留已选中和已拒绝候选项的轨迹。

对于 KVKK、个人健康数据和隐私问题,角色仍为 supporting_general。在排序或数据包排序中,它不会取代主要医疗法规。Yargıtay、Danıştay 和 AYM 适配器仍为模拟适配器。

选择诊断(Selection Diagnostics)

选择诊断提供来源选择的简明审核视图:sourceTrace 仍包含官方请求、文档、提取、候选项、排序和 unavailable 详情;诊断则会概述选中了什么,无需完整查看追踪记录。

精简诊断包括:

  • query 和 sourceMode
  • 选定的法规和规定数量
  • 每项选定法规的角色、主题类别、优先级、条款编号、被拒绝条款编号摘要和选择理由
  • 每项选定规定的评分、匹配词、最佳排序理由和匹配条款标记
  • unavailable 和警告数量

实时摘要示例:

{
  "selectionDiagnostics": {
    "query": "kisisel saglik verisi mahremiyet",
    "sourceMode": "live",
    "selectedLegislationCount": 2,
    "selectedProvisionCount": 2,
    "selectedLegislations": [
      {
        "legislationName": "Hasta Haklari Yonetmeligi",
        "legislationRole": "health_primary",
        "topicCluster": "patient_privacy",
        "selectedArticleNumbers": ["21"]
      },
      {
        "legislationName": "Kisisel Verilerin Korunmasi Kanunu",
        "legislationRole": "supporting_general",
        "topicCluster": "personal_health_data",
        "selectedArticleNumbers": ["6"]
      }
    ],
    "unavailableCount": 0
  }
}

诊断仅为审核元数据。它不能替代官方规定引文,不会生成法律主张,并会将 KVKK 保持在辅助性一般法规角色。Yargıtay、Danıştay 和 AYM 适配器仍为模拟适配器。

判决来源追踪(判决来源追踪)

DecisionSourceTrace 会审计每个候选法院判决的判决处理流程。 它是 LegislationSourceTrace 在判例方面的对应结构。每条追踪记录包含:

  • 原始 query
  • source 和 court(yargitay / danistay / aym)
  • searchRequest(模拟适配器使用 null)
  • searchResultsCount 和 selectedResult
  • documentId / sourceId
  • fullTextAvailable 和 fullTextRetrievalMethod
  • retrievedAt
  • eligibilityStatus — 判例筛选结果
  • eligibilityReasons — 判决满足的正向标准
  • exclusionReasons — 如有,判决被排除的具体原因
  • 如果获取失败,则包含 error

判决来源追踪仅包含审计元数据。它们不会生成法律理由,且除非判决通过所有资格标准,否则绝不会将其加入数据包。

附理由判决的资格评估

assessDecisionEligibility(位于 src/health/decisionEligibility.ts)会应用判例筛选规则,并返回结构化的 EligibilityResult,其中包含状态、正向资格理由和排除理由。

如果符合以下任一条件,判决将从已验证判例部分排除:

  • fullTextAvailable: false — 完整判决文本不可用(→ metadata_only)
  • legalReasoning 为空或缺失(→ no_reasoning)
  • 判决文本仅包含纯程序性标记:salt onama、salt bozma、usul karar (→ procedural_only)
  • 法律理由仅为 onama 或 bozma,且不包含实体内容 (→ procedural_only)
  • 缺少将判决与医疗法律事件关联起来的 relevanceNote(→ limited_value)

只有 precedent_usable 判决会进入数据包的 verifiedHighCourtPrecedents 部分。 limited_value、procedural_only、no_reasoning 和 metadata_only 判决将被排除。

判例诊断(判例诊断)

PrecedentSelectionDiagnostics 是用于判决选择的紧凑审计视图,对应法规方面的 LegislationSelectionDiagnostics。它会在每个 prepare_doctor_legal_information_pack 响应以及 filter_reasoned_precedents 工具响应中以 precedentDiagnostics 的形式出现。

诊断信息包含:

  • query — 原始问题
  • selectedPrecedentCount / excludedDecisionCount
  • selectedPrecedents[] — 法院、审判庭、日期、案号/判决号、状态、匹配的医疗主题和资格理由
  • excludedDecisions[] — 法院、日期、状态和排除理由

诊断信息仅概述选择与排除情况,不提供法律解释,也不会向数据包中添加任何判决。

实时 Yargıtay 适配器

首个实时法院判决适配器:LiveYargitayAdapter (src/sources/yargitay/liveYargitayAdapter.ts)。Danıştay 和 AYM 仍使用 mock 适配器。

**来源和端点:**目标地址为 https://bedesten.adalet.gov.tr/emsal-karar/searchDocuments,并使用 YARGITAYKARARI 筛选条件。JSON POST 请求体包含健康法搜索词。遇到 429 和 5xx 错误时, 会采用自适应退避策略重试三次。

sourceMode: "live" 下的先例行为:

  • search_health_precedents 使用实时 Yargıtay 适配器;Danıştay 和 AYM 仍使用 mock 适配器。
  • 使用 sourceMode: "live" 时,prepare_doctor_legal_information_pack 除实时法规外, 还会搜索实时 Yargıtay 判决。
  • 健康法搜索词根据分类后的问题进行匹配:riza/rıza/onam → "aydınlatılmış rıza",tibbi/müdahale → "tıbbi müdahale",等等。
  • 只有 precedent_usable 判决会进入 verifiedHighCourtPrecedents。其他判决的 排除原因都会记录到 precedentDiagnostics.excludedDecisions 中。

DecisionSourceTrace 实时示例:

{
  "query": "aydınlatılmış rıza",
  "source": "yargitay",
  "court": "yargitay",
  "searchRequest": {
    "url": "https://bedesten.adalet.gov.tr/emsal-karar/searchDocuments",
    "phrase": "aydınlatılmış rıza",
    "pageSize": 5
  },
  "searchResultsCount": 12,
  "selectedResult": { "documentId": "yargitay:99001" },
  "selectedResultReason": "Health law term 'aydınlatılmış rıza' matched Yargıtay emsal search.",
  "fullTextAvailable": true,
  "fullTextRetrievalMethod": "html-text",
  "retrievedAt": "2026-05-22T10:00:00.000Z",
  "eligibilityStatus": "precedent_usable",
  "eligibilityReasons": [
    "Tam karar metni mevcut.",
    "Hukuki gerekçe alanı dolu.",
    "Sağlık hukuku olayıyla bağlantı kurulmuş.",
    "Emsal olarak kullanılabilir."
  ],
  "exclusionReasons": []
}

**实时来源错误行为:**如果无法访问 bedesten.adalet.gov.tr,或返回无法解析的 响应,适配器会返回结构化的 unavailable 结果:

{
  "status": "unavailable",
  "source": "yargitay.gov.tr",
  "errorCode": "source_error",
  "message": "Yargıtay request failed: fetch failed",
  "retryable": true,
  "recommendedNextStep": "Retry after checking network access to bedesten.adalet.gov.tr.",
  "sourceTrace": [{ "query": "aydınlatılmış rıza", "searchRequest": { ... } }]
}

不会编造任何判决。信息包会继续使用 mock Danıştay 和 AYM 结果,并在 Yargıtay 来源的 precedentDiagnostics 中显示 0 条选中的先例。

Danıştay 和 AYM 适配器仍使用 mock 适配器。

多来源实时先例管线

实时 Danıştay 适配器、集中式健康法查询扩展模块、按来源诊断信息(sourceSummaries) 以及基于文件的结果缓存。

实时 Danıştay 适配器

LiveDanistayAdapter(src/sources/danistay/liveDanistayAdapter.ts) 的目标地址为 https://karararama.danistay.gov.tr/aramalist。它采用与 Yargıtay 适配器相同的 重试、HTML 全文提取和可用性评估模式。court 设置为 "danistay",文档 ID 以 danistay: 为前缀。

适配器使用集中式查询扩展模块中的 pickHealthLawQuery,而不是维护自己的术语映射。

precedentSources 参数

现在,prepare_doctor_legal_information_pack 和 search_health_precedents 在实时模式下均接受可选的 precedentSources 数组,用于选择要查询的法院:

{
  "question": "aydınlatılmış rıza",
  "sourceMode": "live",
  "precedentSources": ["yargitay", "danistay"]
}

有效值为 "yargitay"、"danistay"、"aym"。如果未指定,默认使用全部三个来源。 AYM 仍使用 mock 适配器。

一个来源无法访问时,其他来源会继续运行。信息包绝不会因单个适配器错误而卡住。

assessmentTone 参数(v0.44.0)

prepare_doctor_legal_information_pack 还接受可选的 assessmentTone 参数:

{
  "question": "hasta hakları nelerdir",
  "sourceMode": "mock",
  "assessmentTone": "grounded-advisory"
}
值行为
"grounded-advisory"(默认)信息包包含 preliminaryAssessment,其中含有基于来源的条件性陈述。每条陈述都带有一个 sourceRef。
"strict"旧行为:仅返回来源列表。不生成评估文本。

preliminaryAssessment 字段包含 summary(概述)和 sentences[](单条评估内容)。每条陈述都包含 text、sourceRef 和 sourceLabel。陈述会使用先例中的实际判决结果/理由以及法规中的原文摘录片段——绝不使用 套话。有关稳定性保证,请参阅 COMPATIBILITY.md。

医疗法律查询扩展

src/health/healthLawQueryExpansion.ts 提供确定性的术语映射,由 Yargıtay 和 Danıştay 适配器共享:

  • riza / onam / aydinlat → "aydınlatılmış rıza"
  • komplikasyon → "komplikasyon tıbbi müdahale"
  • malpraktis → "malpraktis hekim kusur"
  • hekim → "hekimin özen yükümlülüğü"
  • hasta → "hasta hakları"
  • veri / mahrem → "sağlık verisi mahremiyet"
  • kusur → "hizmet kusuru tıbbi müdahale"
  • acil → "acil müdahale hekim yükümlülüğü"

对于已分类的问题,pickHealthLawQuery 会返回优先级最高的映射术语。pickHealthLawQueries 会为多术语搜索返回最多 N 个不重复的术语。

precedentDiagnostics 中的 sourceSummaries

PrecedentSelectionDiagnostics 现在包含 sourceSummaries[],其中提供按来源分类的明细:

{
  "precedentDiagnostics": {
    "query": "aydınlatılmış rıza",
    "selectedPrecedentCount": 1,
    "excludedDecisionCount": 2,
    "sourceSummaries": [
      {
        "source": "yargitay",
        "mode": "live",
        "searched": true,
        "searchResultsCount": 5,
        "candidateCount": 2,
        "selectedCount": 1,
        "excludedCount": 1,
        "unavailableCount": 0,
        "errorCodes": []
      },
      {
        "source": "danistay",
        "mode": "live",
        "searched": false,
        "searchResultsCount": null,
        "candidateCount": 0,
        "selectedCount": 0,
        "excludedCount": 0,
        "unavailableCount": 1,
        "errorCodes": ["source_error"]
      }
    ]
  }
}

selectedPrecedents[] 和 excludedDecisions[] 中的条目现在也包含 source 字段(与 court 的值相同),用于标明生成每项判决的适配器。

基于文件的缓存

PrecedentCache(src/sources/precedentCache.ts)会将实时适配器结果缓存一小时,存储于缓存目录下的 precedents/(默认路径为 ~/.cache/doktor-mcp/precedents/)。缓存文件根据来源、查询和页面大小作为键值。缓存写入失败不会导致致命错误。

smoke:precedents 支持三个缓存标志:

# Önbelleği kullan (varsayılan)
npm run smoke:precedents -- "aydınlatılmış rıza"

# Önbellek okuma ve yazmalarını atla
npm run smoke:precedents -- "aydınlatılmış rıza" --no-cache

# Taze getirmeyi zorla ve önbellek girdisinin üzerine yaz
npm run smoke:precedents -- "aydınlatılmış rıza" --refresh

缓存存储在仓库之外;旧版本使用的 .cache/ 仍保留在 .gitignore 中。

判例来源校准

深入探测分析和标准化器加固。完整校准工作流请参阅 docs/LIVE_SOURCE_CALIBRATION.md。

已验证的端点行为(2026-05-22)
来源状态端点
Yargitayreachable_jsonbedesten.adalet.gov.tr/emsal-karar/searchDocuments - 通过 Bedesten 代理实现的活动集成。
Danistayreachable_jsonkarararama.danistay.gov.tr/aramalist - 活动集成。
Bedestenreachable_jsonbedesten.adalet.gov.tr/emsal-karar/searchDocuments - 活动的统一集成。
AYMsynthetic_only无实时端点。仅使用模拟适配器。
Probe CLI
# HTML/SOAP analizi ve fixture kaydıyla derin probe
npm run probe:precedents -- "aydınlatılmış rıza" -- --source yargitay --save-fixture
npm run probe:precedents -- "hizmet kusuru tıbbi müdahale" -- --source danistay --save-fixture

Probe 输出包括:HTTP 状态、content-type、HTML/SOAP 分析(标题、表单操作、端点提示、正文长度、验证码/登录检测)、calibrationStatus 和 recommendedNextStep。

非 JSON 响应分类

实时适配器收到非 JSON 响应时,DecisionSourceTrace.error 会包含:

代码含义
non_json_response:html_shell_responseHTTP 200 + 小型 HTML SPA 外壳
non_json_response:unexpected_html_response登录页面/大型 HTML
non_json_response:xml_soap_responseSOAP/XML 服务响应
non_json_response:captcha_or_block检测到 CAPTCHA
non_json_response:empty_response空正文
原始 fixture 策略
  • fixtures/raw/ 已添加到 gitignore — 切勿提交原始响应正文。
  • fixtures/live-samples/ 存放经过清理/合成的 fixture — 可以安全提交。
  • 清理后的 fixture 格式请参阅 fixtures/live-samples/README.md。
Pack audit 扩展检查

audit:pack 现在还会检查:

  • sourceSummaries 中不可访问的来源 → 发出包含错误代码的警告
  • 已验证判例中的 decisionSourceTrace.fullTextAvailable === false → 错误
  • 已验证判例中的 decisionSourceTrace.eligibilityStatus !== "precedent_usable" → 错误

完整检查参考请参阅 docs/PACK_AUDIT.md。

生产环境设置

使用 npm 安装

需要 Node.js 20 或更高版本。无需安装软件包即可通过 npx 运行。要添加到 Claude Code:

claude mcp add doktor -- npx -y doktor-mcp

缓存文件会写入用户的缓存目录:如果设置了 DOKTOR_MCP_CACHE_DIR,则写入该目录;否则写入 $XDG_CACHE_HOME/doktor-mcp 或 ~/.cache/doktor-mcp。

来源模式

sourceMode 默认为 "live"(自 0.59.0 起):如果工具调用中未指定 sourceMode, 查询将访问实时官方来源。若要使用测试夹具数据进行试用,请在调用中传入 sourceMode: "mock",或设置环境变量 DOKTOR_MCP_DEFAULT_SOURCE_MODE=mock;此时 响应中会添加 mockDataWarning 字段。

示例:Claude Desktop 配置
{
  "mcpServers": {
    "doktor-mcp": {
      "command": "npx",
      "args": ["-y", "doktor-mcp"]
    }
  }
}
有效值
值含义
"mock"返回测试夹具数据。并非真实法规或裁决。
"live"默认值。查询实时官方来源(mevzuat.gov.tr、Yargıtay、Danıştay)。
"snapshot"使用预先保存的实时来源快照。

如果设置了无效值(例如 DOKTOR_MCP_DEFAULT_SOURCE_MODE=production), 系统会向 stderr 写入警告,并使用默认值 "live"。

注意: DOKTOR_MCP_DEFAULT_SOURCE_MODE 是 DOKTOR_MCP_SOURCE_MODE 的一个 更容易发现的替代变量。两者都会设置 sourceMode;如果同时设置, 则优先处理 DOKTOR_MCP_DEFAULT_SOURCE_MODE。

开发

npm install
npm test
npm run build
npm run smoke -- "Aydinlatilmis riza kaydi eksikse hangi resmi kaynaklar eslesir?"
npm run smoke:legislation -- "kisisel saglik verisi mahremiyet"
npm run smoke:legislation -- "aydınlatılmış rıza"

# Hem Yargıtay hem Danıştay smoke (varsayılan)
npm run smoke:precedents -- "aydınlatılmış rıza"

# Belirli kaynaklar
npm run smoke:precedents -- "hizmet kusuru" --precedentSources yargitay,danistay

# Önbellek kontrolü
npm run smoke:precedents -- "aydınlatılmış rıza" --no-cache
npm run smoke:precedents -- "aydınlatılmış rıza" --refresh

npm run smoke:mcp -- "kişisel sağlık verisi mahremiyet" -- --sourceMode live
npm run smoke:mcp -- "hasta haklari tibbi mudahale" -- --sourceMode live
npm run smoke:mcp -- "riza belgesi" -- --sourceMode mock
npm run dev:mcp

smoke:precedents 会并行查询实时 Yargıtay 和 Danıştay 适配器,将结果缓存,并以 JSON 格式打印每个候选裁决对应的按来源划分的 results,其中包含 sourceTraces 和 eligibilityStatus。如果某个来源无法访问,其结构化的 unavailable 结果会与另一个 来源的输出一同打印。JSON 始终保持可解析。

smoke:mcp 会调用完整的 prepare_doctor_legal_information_pack 处理器。 使用 sourceMode: "live" 时,它会使用实时法规以及实时 Yargıtay + Danıştay 适配器。 可选参数 precedentSources 用于选择要使用的适配器。 AYM 仅支持 mock,在实时模式下处于禁用状态。

执行 npm run build 后,使用以下命令运行已编译的 stdio MCP 服务:

npm run mcp

医生问题 Benchmark 套件

全面的质量评估和回归测试 Benchmark 套件,专注于典型的以医生为中心的法律问题,并 包含实时来源评估指标。

目的
  • 质量衡量:系统评估 15 个独立医疗法律类别中 15-20 个目标问题的表现、法规匹配、先例数量和架构兼容性。
  • 防止回归:强制执行严格的安全限制,例如:在非隐私类套件中不得包含 Kisisel Verilerin Korunmasi Kanunu (KVKK);在拒绝情形下,以医生为中心的职业伦理规则优先于一般患者权利;实时模式下不得回退到 mock 先例。
如何运行

使用 Benchmark runner 脚本运行测试并查看报告输出:

# Tam benchmark'ı mock modda çalıştır (varsayılan)
npm run benchmark:doctor-questions

# Canlı modda çalıştır (canlı mevzuat ve emsalleri sorgular, canlı-kaynak metriklerini raporlar)
npm run benchmark:doctor-questions -- --sourceMode live

# Eşdeğer canlı kısayol
npm run benchmark:doctor-questions:live

# Çalıştırmayı ilk N soruyla sınırla
npm run benchmark:doctor-questions -- --limit 5

# Özel bir rapor dizini belirt (varsayılan exports/doctor-benchmark)
npm run benchmark:doctor-questions -- --out exports/my-custom-report

警告

使用 --sourceMode live 运行 Benchmark 会向总统府法规服务(mevzuat.gov.tr)和高等法院服务(bedesten.adalet.gov.tr 和 karararama.danistay.gov.tr)发送真实 HTTP 请求。为避免这些服务器的速率限制(HTTP 429)或 IP 限制,请确保网络连接稳定,并将请求量控制在合理范围内。

Mock 与实时 Benchmark

Mock 模式是确定性的回归保护机制。当预期的法规、优先级、审计或安全不变量发生回归时,它可能会使命令失败。

实时模式则是评估运行。它会保留相同的安全不变量,但会将来源中断、空结果、速率限制和 sourceUnavailable 条目作为指标和警告报告,而不是自动判定失败。使用不安全先例、出现禁止的 MVP 字段、实时模式下回退到 mock,或出现审计错误,仍会被视为严重回归并导致失败。

基准测试报告和导出文件

运行会在 exports/doctor-benchmark/(位于 gitignore 中)生成可解析的 JSON 和 Markdown 报告:

  • 模拟模式:
    • doctor-benchmark-report.json
    • doctor-benchmark-report.md
  • 实时模式:
    • live-benchmark-report.json
    • live-benchmark-report.md

报告包含:startedAt、completedAt、durationMs、passedRegressionCount、 failedRegressionCount、liveSourceUnavailableCount、审计计数、法规/判例覆盖计数以及逐问题评分。

报告会包含每个选定的已验证判例的实时基准测试质量审计字段: 法院、法庭、裁判日期、案号/裁判编号、访问来源、文档 ID/来源 ID、来源 URL(如有)、 全文可用性、法律理由检测结果、适用性状态/理由、医疗法相关性分数、匹配的术语以及裁判来源链是否存在。报告不会输出裁判全文。

实时模式下回退到模拟模式属于严重回归。AYM 会保持禁用/仅模拟模式,且无法在不提示的情况下提供实时已验证判例。sourceUnavailable、实时搜索结果为空以及临时上游故障会作为质量指标和警告保留,除非它们导致不安全判例或架构/审计违规。

评分

每个问题会获得以下分数:

  • legislationMatchScore:0 到 2 分
  • priorityScore:0 到 2 分
  • precedentSafetyScore:0 到 2 分
  • sourceAvailabilityScore:0 到 2 分
  • auditScore:0 到 2 分
  • forbiddenFieldsScore:0 或 2 分
  • totalScore、maxScore、scorePercent 和 qualityBand

qualityBand:good、acceptable、needs_tuning 或 unsafe。实时来源不可用可能会降低质量,但只有安全违规或审计错误才会使条目变为 unsafe。

已验证判例的评分有意设置得较为严格。选定的已验证判例必须为 precedent_usable,具有已验证全文、已检测到的法律理由,并保留裁判来源链。仅元数据、仅程序性、没有理由、没有全文或通过模拟模式访问的记录,在实时模式下无法获得已验证判例积分。医疗法相关性较弱会限制判例安全积分,并作为调优警告报告,而不会被高总分掩盖。

基准测试会在此审计层之上进行判例相关性调优。它会按问题和来源报告相关性较弱的情况、示例裁判 ID、匹配的主题术语、缺失的预期主题术语、whyWeak 说明以及建议的后续查询术语。它还会区分 goodCleanCount 和 goodWithWarningsCount,并报告医疗法相关性分数的平均值/中位数。

相关性较弱表示裁判通过了严格的判例安全门槛,但裁判文本仅匹配了宽泛的医疗词汇,或者与问题的主题配置文件重合度不高。主题配置文件包括:知情同意、医疗过失/并发症、急救、拒绝治疗、隐私/记录、精神科隐私、暴力/威胁、转诊、私立医院费用纠纷、公职纪律、重症监护以及妊娠急症。实时来源不可用会作为指标/警告保留;unsafe 则仅用于安全违规,例如回退到模拟模式、缺少全文/理由/来源链,或不可用判例混入已验证输出。

性能基准测试命令
npm run benchmark:doctor-questions:performance
# veya limitle:
npm run benchmark:doctor-questions:performance -- --limit 5

基准测试会将全部 15 个法律问题运行两次。冷(cold)运行会访问实时网络,并填充本地文件缓存(.cache/precedents-perf/)。热(warm)运行会立即从缓存重放相同的查询。报告显示:

  • 冷运行与热运行的总耗时及提升百分比
  • 每个来源的冷/热平均耗时(毫秒)、p95、缓存命中数、网络请求数
  • 缓存效果:命中率百分比、缓存提供次数、平均缓存年龄
  • 重试/退避摘要:重试总数、退避耗时、速率限制事件、超时数
  • 最慢的 10 次查询尝试(冷运行和热运行合并)
  • 性能警告(不会阻止操作;硬性失败仍由测试/构建/审计处理)
p50/p95/p99 的解读
值含义
p50查询耗时中位数——一半查询会在该时间内或更短时间内完成
p95第 95 百分位数——尾部延迟;大多数查询耗时更短
p99第 99 百分位数——异常延迟;偶尔出现的慢查询

冷运行 p95 > 60s 表示某个来源较慢(通常是 Yargıtay/Bedesten PDF 获取)。 热运行 p95 > 10s 表示缓存对最慢的查询未能有效发挥作用(可能是 TTL 过期,或适配器内全文获取时缓存未命中)。

缓存集成

在常规实时基准测试和 smoke CLI 运行中,缓存默认处于禁用状态。性能基准测试会注入一个共享的 PrecedentCache(TTL 为 2s,目录为 .cache/precedents-perf/)。缓存会按(source、query、pageSize)组合键存储整个 searchAndNormalize 结果。热运行重放完整无缺——缓存查询不会发起任何网络调用。

.cache/ 位于 gitignore 中。缓存条目不会提交。


版本历史请参阅 CHANGELOG.md。

许可证

本项目根据 GNU Affero 通用公共许可证第 3 版(AGPL-3.0-only)授权;完整文本见 LICENSE 文件。如果您修改本软件并通过网络向他人提供服务,则必须以相同许可证向这些用户提供您修改后的源代码。如何报告安全漏洞,请参阅 SECURITY.md。

版权所有 © 2026 Alpaslan Fatih Sözer

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。