# yade-mcp - Doramagic AI Context Pack

> 定位：安装前体验与判断资产。它帮助宿主 AI 有一个好的开始，但不代表已经安装、执行或验证目标项目。

## 充分原则

- **充分原则，不是压缩原则**：AI Context Pack 应该充分到让宿主 AI 在开工前理解项目价值、能力边界、使用入口、风险和证据来源；它可以分层组织，但不以最短摘要为目标。
- **压缩策略**：只压缩噪声和重复内容，不压缩会影响判断和开工质量的上下文。

## 给宿主 AI 的使用方式

你正在读取 Doramagic 为 yade-mcp 编译的 AI Context Pack。请把它当作开工前上下文：帮助用户理解适合谁、能做什么、如何开始、哪些必须安装后验证、风险在哪里。不要声称你已经安装、运行或执行了目标项目。

## Claim 消费规则

- **事实来源**：Repo Evidence + Claim/Evidence Graph；Human Wiki 只提供显著性、术语和叙事结构。
- **事实最低状态**：`supported`
- `supported`：可以作为项目事实使用，但回答中必须引用 claim_id 和证据路径。
- `weak`：只能作为低置信度线索，必须要求用户继续核实。
- `inferred`：只能用于风险提示或待确认问题，不能包装成项目事实。
- `unverified`：不得作为事实使用，应明确说证据不足。
- `contradicted`：必须展示冲突来源，不得替用户强行选择一个版本。

## 它最适合谁

- **正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**：README 或插件配置提到多个宿主 AI。 证据：`README.md` Claim：`clm_0002` supported 0.86

## 它能做什么

- **命令行启动或安装流程**（需要安装后验证）：项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 证据：`CONTRIBUTING.md` Claim：`clm_0001` supported 0.86

## 怎么开始

- `git clone https://github.com/yusong652/yade-mcp.git` 证据：`CONTRIBUTING.md` Claim：`clm_0003` supported 0.86

## 继续前判断卡

- **当前建议**：先做权限沙盒试用
- **为什么**：项目存在安装命令、宿主配置或本地写入线索，不建议直接进入主力环境，应先在隔离环境试装。

### 30 秒判断

- **现在怎么做**：先做权限沙盒试用
- **最小安全下一步**：先跑 Prompt Preview；若仍要安装，只在隔离环境试装
- **先别相信**：工具权限边界不能在安装前相信。
- **继续会触碰**：命令执行、宿主 AI 配置、本地环境或项目文件

### 现在可以相信

- **适合人群线索：正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**（supported）：有 supported claim 或项目证据支撑，但仍不等于真实安装效果。 证据：`README.md` Claim：`clm_0002` supported 0.86
- **能力存在：命令行启动或安装流程**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`CONTRIBUTING.md` Claim：`clm_0001` supported 0.86
- **存在 Quick Start / 安装命令线索**（supported）：可以相信项目文档出现过启动或安装入口；不要因此直接在主力环境运行。 证据：`CONTRIBUTING.md` Claim：`clm_0003` supported 0.86

### 现在还不能相信

- **工具权限边界不能在安装前相信。**（unverified）：MCP/tool 类项目通常会触碰文件、网络、浏览器或外部 API，必须真实检查权限和日志。
- **真实输出质量不能在安装前相信。**（unverified）：Prompt Preview 只能展示引导方式，不能证明真实项目中的结果质量。
- **宿主 AI 版本兼容性不能在安装前相信。**（unverified）：Claude、Cursor、Codex、Gemini 等宿主加载规则和版本差异必须在真实环境验证。
- **不会污染现有宿主 AI 行为，不能直接相信。**（inferred）：Skill、plugin、AGENTS/CLAUDE/GEMINI 指令可能改变宿主 AI 的默认行为。 证据：`AGENTS.md`, `CLAUDE.md`
- **可安全回滚不能默认相信。**（unverified）：除非项目明确提供卸载和恢复说明，否则必须先在隔离环境验证。
- **真实安装后是否与用户当前宿主 AI 版本兼容？**（unverified）：兼容性只能通过实际宿主环境验证。
- **项目输出质量是否满足用户具体任务？**（unverified）：安装前预览只能展示流程和边界，不能替代真实评测。
- **安装命令是否需要网络、权限或全局写入？**（unverified）：这影响企业环境和个人环境的安装风险。 证据：`CONTRIBUTING.md`

### 继续会触碰什么

- **命令执行**：包管理器、网络下载、本地插件目录、项目配置或用户主目录。 原因：运行第一条命令就可能产生环境改动；必须先判断是否值得跑。 证据：`CONTRIBUTING.md`
- **宿主 AI 配置**：Claude/Codex/Cursor/Gemini/OpenCode 等宿主的 plugin、Skill 或规则加载配置。 原因：宿主配置会改变 AI 后续工作方式，可能和用户已有规则冲突。 证据：`AGENTS.md`, `CLAUDE.md`
- **本地环境或项目文件**：安装结果、插件缓存、项目配置或本地依赖目录。 原因：安装前无法证明写入范围和回滚方式，需要隔离验证。 证据：`CONTRIBUTING.md`
- **宿主 AI 上下文**：AI Context Pack、Prompt Preview、Skill 路由、风险规则和项目事实。 原因：导入上下文会影响宿主 AI 后续判断，必须避免把未验证项包装成事实。

### 最小安全下一步

- **先跑 Prompt Preview**：用安装前交互式试用判断工作方式是否匹配，不需要授权或改环境。（适用：任何项目都适用，尤其是输出质量未知时。）
- **只在隔离目录或测试账号试装**：避免安装命令污染主力宿主 AI、真实项目或用户主目录。（适用：存在命令执行、插件配置或本地写入线索时。）
- **先备份宿主 AI 配置**：Skill、plugin、规则文件可能改变 Claude/Cursor/Codex 的默认行为。（适用：存在插件 manifest、Skill 或宿主规则入口时。）
- **安装后只验证一个最小任务**：先验证加载、兼容、输出质量和回滚，再决定是否深用。（适用：准备从试用进入真实工作流时。）

### 退出方式

- **保留安装前状态**：记录原始宿主配置和项目状态，后续才能判断是否可恢复。
- **准备移除宿主 plugin / Skill / 规则入口**：如果试装后行为异常，可以把宿主 AI 恢复到试装前状态。
- **记录安装命令和写入路径**：没有明确卸载说明时，至少要知道哪些目录或配置需要手动清理。
- **如果没有回滚路径，不进入主力环境**：不可回滚是继续前阻断项，不应靠信任或运气继续。

## 哪些只能预览

- 解释项目适合谁和能做什么
- 基于项目文档演示典型对话流程
- 帮助用户判断是否值得安装或继续研究

## 哪些必须安装后验证

- 真实安装 Skill、插件或 CLI
- 执行脚本、修改本地文件或访问外部服务
- 验证真实输出质量、性能和兼容性

## 边界与风险判断卡

- **把安装前预览误认为真实运行**：用户可能高估项目已经完成的配置、权限和兼容性验证。 处理方式：明确区分 prompt_preview_can_do 与 runtime_required。 Claim：`clm_0004` inferred 0.45
- **命令执行会修改本地环境**：安装命令可能写入用户主目录、宿主插件目录或项目配置。 处理方式：先在隔离环境或测试账号中运行。 证据：`CONTRIBUTING.md` Claim：`clm_0005` supported 0.86
- **待确认**：真实安装后是否与用户当前宿主 AI 版本兼容？。原因：兼容性只能通过实际宿主环境验证。
- **待确认**：项目输出质量是否满足用户具体任务？。原因：安装前预览只能展示流程和边界，不能替代真实评测。
- **待确认**：安装命令是否需要网络、权限或全局写入？。原因：这影响企业环境和个人环境的安装风险。

## 开工前工作上下文

### 加载顺序

- 先读取 how_to_use.host_ai_instruction，建立安装前判断资产的边界。
- 读取 claim_graph_summary，确认事实来自 Claim/Evidence Graph，而不是 Human Wiki 叙事。
- 再读取 intended_users、capabilities 和 quick_start_candidates，判断用户是否匹配。
- 需要执行具体任务时，优先查 role_skill_index，再查 evidence_index。
- 遇到真实安装、文件修改、网络访问、性能或兼容性问题时，转入 risk_card 和 boundaries.runtime_required。

### 任务路由

- **命令行启动或安装流程**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`CONTRIBUTING.md` Claim：`clm_0001` supported 0.86

### 上下文规模

- 文件总数：508
- 重要文件覆盖：40/508
- 证据索引条目：76
- 角色 / Skill 条目：14

### 证据不足时的处理

- **missing_evidence**：说明证据不足，要求用户提供目标文件、README 段落或安装后验证记录；不要补全事实。
- **out_of_scope_request**：说明该任务超出当前 AI Context Pack 证据范围，并建议用户先查看 Human Manual 或真实安装后验证。
- **runtime_request**：给出安装前检查清单和命令来源，但不要替用户执行命令或声称已执行。
- **source_conflict**：同时展示冲突来源，标记为待核实，不要强行选择一个版本。

## Prompt Recipes

### 适配判断

- 目标：判断这个项目是否适合用户当前任务。
- 预期输出：适配结论、关键理由、证据引用、安装前可预览内容、必须安装后验证内容、下一步建议。

```text
请基于 yade-mcp 的 AI Context Pack，先问我 3 个必要问题，然后判断它是否适合我的任务。回答必须包含：适合谁、能做什么、不能做什么、是否值得安装、证据来自哪里。所有项目事实必须引用 evidence_refs、source_paths 或 claim_id。
```

### 安装前体验

- 目标：让用户在安装前感受核心工作流，同时避免把预览包装成真实能力或营销承诺。
- 预期输出：一段带边界标签的体验剧本、安装后验证清单和谨慎建议；不含真实运行承诺或强营销表述。

```text
请把 yade-mcp 当作安装前体验资产，而不是已安装工具或真实运行环境。

请严格输出四段：
1. 先问我 3 个必要问题。
2. 给出一段“体验剧本”：用 [安装前可预览]、[必须安装后验证]、[证据不足] 三种标签展示它可能如何引导工作流。
3. 给出安装后验证清单：列出哪些能力只有真实安装、真实宿主加载、真实项目运行后才能确认。
4. 给出谨慎建议：只能说“值得继续研究/试装”“先补充信息后再判断”或“不建议继续”，不得替项目背书。

硬性边界：
- 不要声称已经安装、运行、执行测试、修改文件或产生真实结果。
- 不要写“自动适配”“确保通过”“完美适配”“强烈建议安装”等承诺性表达。
- 如果描述安装后的工作方式，必须使用“如果安装成功且宿主正确加载 Skill，它可能会……”这种条件句。
- 体验剧本只能写成“示例台词/假设流程”：使用“可能会询问/可能会建议/可能会展示”，不要写“已写入、已生成、已通过、正在运行、正在生成”。
- Prompt Preview 不负责给安装命令；如用户准备试装，只能提示先阅读 Quick Start 和 Risk Card，并在隔离环境验证。
- 所有项目事实必须来自 supported claim、evidence_refs 或 source_paths；inferred/unverified 只能作风险或待确认项。

```

### 角色 / Skill 选择

- 目标：从项目里的角色或 Skill 中挑选最匹配的资产。
- 预期输出：候选角色或 Skill 列表，每项包含适用场景、证据路径、风险边界和是否需要安装后验证。

```text
请读取 role_skill_index，根据我的目标任务推荐 3-5 个最相关的角色或 Skill。每个推荐都要说明适用场景、可能输出、风险边界和 evidence_refs。
```

### 风险预检

- 目标：安装或引入前识别环境、权限、规则冲突和质量风险。
- 预期输出：环境、权限、依赖、许可、宿主冲突、质量风险和未知项的检查清单。

```text
请基于 risk_card、boundaries 和 quick_start_candidates，给我一份安装前风险预检清单。不要替我执行命令，只说明我应该检查什么、为什么检查、失败会有什么影响。
```

### 宿主 AI 开工指令

- 目标：把项目上下文转成一次对话开始前的宿主 AI 指令。
- 预期输出：一段边界明确、证据引用明确、适合复制给宿主 AI 的开工前指令。

```text
请基于 yade-mcp 的 AI Context Pack，生成一段我可以粘贴给宿主 AI 的开工前指令。这段指令必须遵守 not_runtime=true，不能声称项目已经安装、运行或产生真实结果。
```

## 角色 / Skill 索引

- 共索引 14 个角色 / Skill / 项目文档条目。

- **yade-mcp**（project_doc）：English https://github.com/yusong652/yade-mcp/blob/master/README.md 简体中文 https://github.com/yusong652/yade-mcp/blob/master/README.zh-CN.md 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.md`
- **yade-mcp-bridge**（project_doc）：! PyPI https://img.shields.io/pypi/v/yade-mcp-bridge https://pypi.org/project/yade-mcp-bridge/ 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`yade-mcp-bridge/README.md`
- **Drained triaxial test — agent-produced**（project_doc）：Drained triaxial test — agent-produced 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`showcase/triaxial/README.md`
- **AGENTS.md**（project_doc）：yade-mcp is an MCP server that connects AI agents to YADE open-source DEM engine . Two packages live in this monorepo: 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`AGENTS.md`
- **CLAUDE.md**（project_doc）：yade-mcp is an MCP server that connects AI agents to YADE open-source DEM engine . Two packages live in this monorepo: 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CLAUDE.md`
- **yade-mcp Bootstrap Claude Code**（project_doc）：Use this profile when the client is Claude Code. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap-claude.md`
- **yade-mcp Bootstrap Codex**（project_doc）：Use this profile when the client is OpenAI Codex CLI/IDE. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap-codex.md`
- **yade-mcp Bootstrap GitHub Copilot CLI**（project_doc）：yade-mcp Bootstrap GitHub Copilot CLI 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap-copilot.md`
- **yade-mcp Bootstrap Gemini CLI**（project_doc）：Use this profile when the client is Gemini CLI. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap-gemini.md`
- **yade-mcp Bootstrap OpenCode**（project_doc）：Use this profile when the client is OpenCode. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap-opencode.md`
- **yade-mcp Agent Bootstrap Guide**（project_doc）：Use this guide when an agent needs to set up yade-mcp execution end-to-end on a Linux machine. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap.md`
- **Contributing**（project_doc）：To run the bridge from source inside YADE: 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CONTRIBUTING.md`
- **yade-mcp Bootstrap toyoura-nagisa**（project_doc）：Use this profile when the client is toyoura-nagisa. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/agentic/yade-mcp-bootstrap-toyoura-nagisa.md`
- **yade-mcp**（project_doc）：English https://github.com/yusong652/yade-mcp/blob/master/README.md 简体中文 https://github.com/yusong652/yade-mcp/blob/master/README.zh-CN.md 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.zh-CN.md`

## 证据索引

- 共索引 76 条证据。

- **yade-mcp**（documentation）：English https://github.com/yusong652/yade-mcp/blob/master/README.md 简体中文 https://github.com/yusong652/yade-mcp/blob/master/README.zh-CN.md 证据：`README.md`
- **yade-mcp-bridge**（documentation）：! PyPI https://img.shields.io/pypi/v/yade-mcp-bridge https://pypi.org/project/yade-mcp-bridge/ 证据：`yade-mcp-bridge/README.md`
- **Drained triaxial test — agent-produced**（documentation）：Drained triaxial test — agent-produced 证据：`showcase/triaxial/README.md`
- **AGENTS.md**（documentation）：yade-mcp is an MCP server that connects AI agents to YADE open-source DEM engine . Two packages live in this monorepo: 证据：`AGENTS.md`
- **CLAUDE.md**（documentation）：yade-mcp is an MCP server that connects AI agents to YADE open-source DEM engine . Two packages live in this monorepo: 证据：`CLAUDE.md`
- **yade-mcp Bootstrap Claude Code**（documentation）：Use this profile when the client is Claude Code. 证据：`docs/agentic/yade-mcp-bootstrap-claude.md`
- **yade-mcp Bootstrap Codex**（documentation）：Use this profile when the client is OpenAI Codex CLI/IDE. 证据：`docs/agentic/yade-mcp-bootstrap-codex.md`
- **yade-mcp Bootstrap GitHub Copilot CLI**（documentation）：yade-mcp Bootstrap GitHub Copilot CLI 证据：`docs/agentic/yade-mcp-bootstrap-copilot.md`
- **yade-mcp Bootstrap Gemini CLI**（documentation）：Use this profile when the client is Gemini CLI. 证据：`docs/agentic/yade-mcp-bootstrap-gemini.md`
- **yade-mcp Bootstrap OpenCode**（documentation）：Use this profile when the client is OpenCode. 证据：`docs/agentic/yade-mcp-bootstrap-opencode.md`
- **yade-mcp Agent Bootstrap Guide**（documentation）：Use this guide when an agent needs to set up yade-mcp execution end-to-end on a Linux machine. 证据：`docs/agentic/yade-mcp-bootstrap.md`
- **Contributing**（documentation）：To run the bridge from source inside YADE: 证据：`CONTRIBUTING.md`
- **License**（source_file）：Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files the "Software" , to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 证据：`LICENSE`
- **yade-mcp Bootstrap toyoura-nagisa**（documentation）：Use this profile when the client is toyoura-nagisa. 证据：`docs/agentic/yade-mcp-bootstrap-toyoura-nagisa.md`
- **Mpibodycontainer**（structured_config）：{ "name": "MPIBodyContainer", "category": "engines", "parent": "", "description": "a dummy container to serialize and send.", "attributes": { "name": "bContainer", "type": "vector ", "default": "", "description": "a dummy body container to serialize" } , "methods": { "name": "clearContainer", "description": "clear bodies in the container" }, { "name": "getCount", "description": "get container count" }, { "name": "insertBody", "description": "insert a body by id in this container" }, { "name": "insertBodyListPy", "description": "inset a list of bodies by ids " } } 证据：`src/yade_mcp/knowledge/resources/python_api_docs/misc/MPIBodyContainer.json`
- **Bodycontainer**（structured_config）：{ "name": "BodyContainer", "category": "bodies", "parent": "instance", "description": "Container for all bodies, accessed as O.bodies.", "methods": { "name": "append", "args": { "name": "arg2", "type": "Body" } , "returns": "int", "description": "append BodyContainer arg1, Body arg2 - int : Append one Body instance, return its id. append BodyContainer arg1, object arg2 - object : Append list of Body instance, return list of" }, { "name": "appendClumped", "args": { "name": "arg2", "type": "object" }, { "name": "discretization", "type": "int", "default": "0" } , "returns": "tuple", "description": "Append given list of bodies as a clump rigid aggregate ; returns a tuple of clumpId, memberId1,m… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/runtime/BodyContainer.json`
- **Filegenerator**（structured_config）：{ "name": "FileGenerator", "category": "engines", "parent": "Serializable", "description": "Base class for scene generators, preprocessors.", "attributes": , "methods": { "name": "generate", "args": { "name": "out", "type": "str" } , "returns": "None", "description": "Generate scene, save to given file" }, { "name": "load", "args": , "returns": "None", "description": "Generate scene, save to temporary file and load immediately" }, { "name": "dict", "args": , "returns": "dict", "description": "Return dictionary of attributes.", "inherited from": "Serializable" }, { "name": "updateAttrs", "args": { "name": "arg2", "type": "dict" } , "returns": "None", "description": "Update object attributes… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/runtime/FileGenerator.json`
- **Interactioncontainer**（structured_config）：{ "name": "InteractionContainer", "category": "bodies", "parent": "instance", "description": "Access to interactions of simulation, by using \n\n . id's of both Bodies of the interactions, e.g. O.interactions 23,65 \n . iteraction over the whole container::\n\n\tfor i in O.interactions: print i.id1,i.id2\n\n.. note::\n\tIteration silently skips interactions that are virtual...", "attributes": { "name": "serializeSorted", "type": "auto", "default": "", "description": "" } , "methods": { "name": "has", "args": { "name": "id1", "type": "int" }, { "name": "id2", "type": "int" }, { "name": "onlyReal", "type": "bool", "default": "False" } , "returns": "bool", "description": "Tell if a pair of ids… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/runtime/InteractionContainer.json`
- **Materialcontainer**（structured_config）：{ "name": "MaterialContainer", "category": "engines", "parent": "instance", "description": "Container for Materials . A material can be accessed using \n\n . numerical index in range 0,len cont , like cont 2 ; \n . textual label that was given to the material, like cont 'steel' . This entails traversing all materials and should not be used frequently.", "attributes": , "methods": { "name": "append", "args": { "name": "arg2", "type": "Material" } , "returns": "int", "description": "Add new shared Material; changes its id and return it. append MaterialContainer arg1, object arg2 - object : Append list of Material instances, return list of ids." }, { "name": "index", "args": { "name": "arg2",… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/runtime/MaterialContainer.json`
- **Simpleshear**（structured_config）：{ "name": "SimpleShear", "category": "engines", "parent": "FileGenerator", "description": "Preprocessor for a simple shear box model. The packing initially conforms a gas-like, very loose, state see utils.makeCloud function , but importing some existing packing from a text file can be also performed after little change in the source code. In its current state, the preprocessor carries out an oedometric compression, until a value of normal stress equal to 2 MPa and a stable mechanical state . Others Engines such as KinemCNDEngine, KinemCNSEngine and KinemCNLEngine, could be used to apply resp. constant normal displacement, constant normal rigidity and constant normal stress paths using such… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/runtime/SimpleShear.json`
- **Triaxialtest**（structured_config）：{ "name": "TriaxialTest", "category": "engines", "parent": "FileGenerator", "description": "Create a scene for triaxal test.\n\n Introduction \n\tYade includes tools to simulate triaxial tests on particles assemblies. This pre-processor and variants like e.g. CapillaryTriaxialTest illustrate how to use them. It generates a scene which will - by default - go through the following steps :\n\n\t generate random loose packings in a parallelepiped.\n\t compress the packing isotropicaly, either squeezing the packing between moving rigid boxes or expanding the particles while boxes are fixed depending on flag internalCompaction . The confining pressure in this stage is defined via sigmaIsoCompacti… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/runtime/TriaxialTest.json`
- **Init**（source_file）：version = "0.6.0" 证据：`src/yade_mcp/__init__.py`
- **Init**（source_file）：all = "BridgeResponseTooLargeError", "get bridge client", "close bridge client" 证据：`src/yade_mcp/bridge/__init__.py`
- **Context**（source_file）：logger = logging.getLogger "yade-mcp.context" async def fetch bridge context - dict str, Any None ⋮---- context: dict str, Any = {} ⋮---- client = await get bridge client response = await client.consume console history data = response.get "data" or {} entries = data.get "entries", ⋮---- def with context func: Callable ..., Awaitable dict str, Any - Callable ..., Awaitable dict str, Any ⋮---- @functools.wraps func async def wrapper args: Any, kwargs: Any - dict str, Any ⋮---- envelope = await func args, kwargs ⋮---- error = envelope.get "error" ⋮---- context = await fetch bridge context ⋮---- def format entry entry: dict str, Any - dict str, Any ⋮---- formatted: dict str, Any = {"input": ent… 证据：`src/yade_mcp/bridge/context.py`
- **Init**（source_file）：all = "APISearch" 证据：`src/yade_mcp/knowledge/search/__init__.py`
- **Server**（source_file）：mcp = FastMCP logger = logging.getLogger "yade-mcp.server" ⋮---- def main - None ⋮---- parser = argparse.ArgumentParser ⋮---- args = parser.parse args ⋮---- level = getattr logging, args.log level.upper ⋮---- uvicorn level = level if level <= logging.INFO else logging.CRITICAL ⋮---- run kwargs: dict str, Any = { 证据：`src/yade_mcp/server.py`
- **Init**（source_file）：all = 证据：`src/yade_mcp/tools/__init__.py`
- **Self class as the first entry, so the browse response is "here is the**（source_file）：def register mcp: FastMCP - None ⋮---- normalized = path or "" .strip resolved = APILoader.resolve path normalized level = resolved "level" ⋮---- details = { ⋮---- async def browse root - dict str, Any ⋮---- """List every top-level category.""" categories = APILoader.list categories entries = {"entry type": "category", cat} for cat in categories ⋮---- async def browse tree node category: str, tree path: list str - dict str, Any ⋮---- contents = APILoader.list node contents category, tree path ⋮---- display path = category + "." + ".".join tree path if tree path else "" entries: list dict str, Any = Self class as the first entry, so the browse response is "here is the node itself, and here i… 证据：`src/yade_mcp/tools/browse_api.py`
- **Check Task Status**（source_file）：def lifecycle status response: dict str, Any - str ⋮---- data = response.get "data" or {} ⋮---- def register mcp: FastMCP - None ⋮---- client = await get bridge client terminal states = {"completed", "failed", "interrupted", "not found"} ⋮---- response = await client.check task status is terminal = ⋮---- bridge error = response.get "error" or {} ⋮---- normalized status = normalize status lifecycle status response bridge output = data.get "output" or "" output text = bridge output if bridge output else " no output " pagination = data.get "pagination" or { result: dict str, Any = { 证据：`src/yade_mcp/tools/check_task_status.py`
- **Execute Code**（source_file）：def register mcp: FastMCP - None ⋮---- client = await get bridge client response = await client.execute code ⋮---- bridge data = response.get "data" or {} bridge error = response.get "error" or {} bridge details = bridge error.get "details" or {} ok = response.get "ok" ⋮---- ok = response.get "status" == "success" ⋮---- result data: dict str, Any = { ⋮---- code = bridge error.get "code", "execution error" message = bridge error.get "message" or response.get "message", "" ⋮---- partial output = bridge data.get "output" 证据：`src/yade_mcp/tools/execute_code.py`
- **Execute Task**（source_file）：def register mcp: FastMCP - None ⋮---- client = await get bridge client ⋮---- task id = uuid.uuid4 .hex :6 ⋮---- response = await client.execute task ⋮---- bridge error = response.get "error" or {} ok = response.get "ok" ⋮---- ok = response.get "status" == "pending" 证据：`src/yade_mcp/tools/execute_task.py`
- **Surface the bridge's cancellation metadata to the agent.**（source_file）：def register mcp: FastMCP - None ⋮---- @mcp.tool @with context async def yade interrupt task task id: TaskId - dict str, Any ⋮---- client = await get bridge client response = await client.interrupt task task id ⋮---- bridge error = response.get "error" or {} bridge data = response.get "data" or {} ok = response.get "ok" ⋮---- ok = response.get "status" == "success" ⋮---- payload: dict str, Any = { Surface the bridge's cancellation metadata to the agent. 证据：`src/yade_mcp/tools/interrupt_task.py`
- **List Tasks**（source_file）：def register mcp: FastMCP - None ⋮---- client = await get bridge client response = await client.list tasks ⋮---- ok = response.get "ok" ⋮---- ok = response.get "status" == "success" ⋮---- bridge error = response.get "error" or {} ⋮---- tasks = response.get "data" or pagination = response.get "pagination" or {} total count = pagination.get "total count", len tasks normalized tasks: list dict str, Any = ⋮---- normalized task = { 证据：`src/yade_mcp/tools/list_tasks.py`
- **Query Api**（source_file）：def register mcp: FastMCP - None ⋮---- matches = APISearch.search query, top k=limit payload = build docs data 证据：`src/yade_mcp/tools/query_api.py`
- **Init**（source_file）：version = "0.7.0" all = "start" 证据：`yade-mcp-bridge/src/yade_mcp_bridge/__init__.py`
- **Init**（source_file）：all = "ConsoleCapture", "ConsoleHistory" 证据：`yade-mcp-bridge/src/yade_mcp_bridge/console/__init__.py`
- **History**（source_file）：logger = logging.getLogger "MCP-Bridge" HISTORY FILENAME = os.path.join DATA DIR, "console history.jsonl" CURSOR FILENAME = os.path.join DATA DIR, "console cursor.json" DEFAULT MAX ENTRIES = 500 class ConsoleHistory ⋮---- def init self, max entries=DEFAULT MAX ENTRIES, path=None def add self, input text, output="", result=None, success=True ⋮---- """Record a console entry and return it. input text is the code the user typed, output the captured stdout, result the expression result if any , and success whether execution succeeded. """ entry = { ⋮---- def consume self, limit=20 ⋮---- entries = e for e in self. entries if e "id" self. last delivered id ⋮---- entries = entries -limit: ⋮---- def… 证据：`yade-mcp-bridge/src/yade_mcp_bridge/console/history.py`
- **Init**（source_file）：all = 证据：`yade-mcp-bridge/src/yade_mcp_bridge/execution/__init__.py`
- **Init**（source_file）：all = 证据：`yade-mcp-bridge/src/yade_mcp_bridge/handlers/__init__.py`
- **Context**（source_file）：class ServerContext ⋮---- def init self, task manager, script runner, code runner, executor, runtime mode, console history=None 证据：`yade-mcp-bridge/src/yade_mcp_bridge/handlers/context.py`
- **Tasks**（source_file）：logger = logging.getLogger "MCP-Bridge" DEFAULT LIMIT = 64 def handle execute task ctx, data ⋮---- request id = data.get "request id", "unknown" ⋮---- description = data.get "description", "" result = ctx.script runner.run script path, description, task id=task id ⋮---- def handle check task status ctx, data ⋮---- skip newest = data.get "skip newest", 0 limit = data.get "limit", DEFAULT LIMIT filter text = data.get "filter text" result = ctx.task manager.get task status ⋮---- def handle list tasks ctx, data ⋮---- offset = data.get "offset", 0 limit = data.get "limit" ⋮---- limit = DEFAULT LIMIT result = ctx.task manager.list all tasks offset=offset, limit=limit ⋮---- def handle interrupt ta… 证据：`yade-mcp-bridge/src/yade_mcp_bridge/handlers/tasks.py`
- **Init**（source_file）：all = 证据：`yade-mcp-bridge/src/yade_mcp_bridge/runtime/__init__.py`
- **Detect tamper before restoring so the user sees why their**（source_file）：INTERRUPT CHECK PERIOD = 1 def install pyrunner logger ⋮---- interrupt triggered = {"value": False} def mcp pyrunner tick def ensure tick in main ⋮---- main mod = sys.modules.get " main " ⋮---- pyrunner config = { PYRUNNER COMMAND = " mcp pyrunner tick yade-mcp-bridge: DO NOT MODIFY" def make pyrunner def find our pyrunner def normalize pyrunner ⋮---- expected period = pyrunner config "period" existing = find our pyrunner ⋮---- Detect tamper before restoring so the user sees why their interrupt might have been delayed on the previous run. actual period = getattr existing, "iterPeriod", expected period actual dead = getattr existing, "dead", False ⋮---- If we're not at index 0, move there. N… 证据：`yade-mcp-bridge/src/yade_mcp_bridge/runtime/pyrunner.py`
- **Init**（source_file）：all = 证据：`yade-mcp-bridge/src/yade_mcp_bridge/tasks/__init__.py`
- **Init**（source_file）：all = 证据：`yade-mcp-bridge/src/yade_mcp_bridge/transport/__init__.py`
- **-- Lifecycle ----------------------------------------------------------**（source_file）：logger = logging.getLogger "MCP-Bridge" SSE KEEPALIVE S = 15.0 SSE QUEUE MAXSIZE = 256 def json bytes obj class ThreadingHTTPServer socketserver.ThreadingMixIn, http.server.HTTPServer ⋮---- daemon threads = True allow reuse address = True class BridgeRequestHandler http.server.BaseHTTPRequestHandler ⋮---- protocol version = "HTTP/1.1" def log message self, fmt, args ⋮---- @property def bridge self def write json self, status, payload bytes def read body self ⋮---- length = int self.headers.get "Content-Length", 0 ⋮---- length = 0 ⋮---- def do POST self ⋮---- command = self.path.split "?", 1 0 .strip "/" raw = self. read body handler = self. bridge.handlers.get command ⋮---- data = json.load… 证据：`yade-mcp-bridge/src/yade_mcp_bridge/transport/server.py`
- **Init**（source_file）：all = 证据：`yade-mcp-bridge/src/yade_mcp_bridge/utils/__init__.py`
- **Response**（source_file）：class TaskDataBuilder ⋮---- def init self, task id, task type, script path, description def with status self, status def with timing self, start time, end time=None, elapsed time=None def with output self, output def with pagination self, pagination def with result self, result def with error self, error def build self def ok body data=None ⋮---- body = {"ok": True} ⋮---- def error body code, message, , details=None, data=None ⋮---- error = {"code": code, "message": message} ⋮---- body = {"ok": False, "error": error} ⋮---- def ok response response type, request id, data=None def error response response type, request id, code, message, , details=None, data=None 证据：`yade-mcp-bridge/src/yade_mcp_bridge/utils/response.py`
- **yade-mcp**（documentation）：English https://github.com/yusong652/yade-mcp/blob/master/README.md 简体中文 https://github.com/yusong652/yade-mcp/blob/master/README.zh-CN.md 证据：`README.zh-CN.md`
- **Glama**（structured_config）：{ "$schema": "https://glama.ai/mcp/schemas/server.json", "maintainers": "yusong652" } 证据：`glama.json`
- **Server**（structured_config）：{ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.yusong652/yade-mcp", "title": "YADE MCP Server", "description": "MCP server for YADE — open-source DEM engine. Browse API docs, run simulations, manage tasks.", "repository": { "url": "https://github.com/yusong652/yade-mcp", "source": "github" }, "version": "0.1.5", "packages": { "registryType": "pypi", "identifier": "yade-mcp", "version": "0.1.5", "transport": { "type": "stdio" } } } 证据：`server.json`
- **Body**（structured_config）：{ "name": "Body", "category": "bodies", "parent": "Serializable", "description": "A simulation body with shape, material, state, and bound.", "attributes": { "name": "id", "type": "Body::id t", "default": "Body::ID NONE", "description": "Unique id of this body.", "read only": true }, { "name": "groupMask", "type": "mask t", "default": "1", "description": "Bitmask for interaction detection purposes: it is required that two bodies have at least one bit in common in their groupMask for their interaction to be possible from the" }, { "name": "flags", "type": "int", "default": "FLAG BOUNDED", "description": "Bits of various body-related flags. Do not access directly . In c++, use isDynamic/setDy… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/body/Body.json`
- **Cell**（structured_config）：{ "name": "Cell", "category": "bodies", "parent": "Serializable", "description": "Parameters of periodic boundary conditions . Only applies if O.isPeriodic==True.", "attributes": { "name": "trsf", "type": "Matrix3", "default": "Matrix3 1,0,0, 0,1,0, 0,0,1 ", "description": "Current transformation matrix of the cell $ mat{F}$ giving current Cell vector $d vec{x}$ from its reference state $d vec{X}$ as per $d vec{x} = mat{F} d vec{X}$. Obtained from time integration of velGrad$ times mat{F}$ as detailed in the documentation during the prologue of a YADE iteration before the O.engines loop . auto-updated ", "read only": true }, { "name": "refHSize", "type": "Matrix3", "default": "Matrix3.Ident… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/body/Cell.json`
- **Energytracker**（structured_config）：{ "name": "EnergyTracker", "category": "bodies", "parent": "Serializable", "description": "Storage for tracing energies. Only to be used if O.trackEnergy is True.", "attributes": { "name": "energies", "type": "OpenMPArrayAccumulator ", "default": "", "description": "Energy values, in linear array" } , "methods": { "name": "clear", "args": , "returns": "None", "description": "Clear all stored values." }, { "name": "keys", "args": , "returns": "list", "description": "Return defined energies." }, { "name": "items", "args": , "returns": "list", "description": "Return contents as list of name,value tuples." }, { "name": "total", "args": , "returns": "float", "description": "Return sum of all ene… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/body/EnergyTracker.json`
- **Interaction**（structured_config）：{ "name": "Interaction", "category": "bodies", "parent": "Serializable", "description": "Interaction between pair of bodies.", "attributes": { "name": "id1", "type": "Body::id t", "default": "0", "description": "Id of the first body in this interaction.", "read only": true }, { "name": "id2", "type": "Body::id t", "default": "0", "description": "Id of the second body in this interaction.", "read only": true }, { "name": "iterMadeReal", "type": "int", "default": "-1", "description": "Step number at which the interaction was fully in the sense of geom and phys created. Should be touched only by" }, { "name": "geom", "type": "IGeom", "default": "None", "description": "Geometry part of the inte… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/body/Interaction.json`
- **Matchmaker**（structured_config）：{ "name": "MatchMaker", "category": "bodies", "parent": "Serializable", "description": "Class matching pair of ids to return pre-defined for a pair of ids defined in matches or derived value computed using algo of a scalar parameter. It can be called id1 , id2 , val1=NaN , val2=NaN in both python and c++. \n\n.. note:: There is a...", "attributes": { "name": "matches", "type": "list Vector3 ", "default": " ", "description": "Array of id1,id2,value items; queries matching id1 + id2 or id2 + id1 will return value", "read only": true }, { "name": "algo", "type": "str", "default": "\"avg\"", "description": "Algorithm used to compute value when no match for ids is found. Possible values are 'avg… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/body/MatchMaker.json`
- **Aabb**（structured_config）：{ "name": "Aabb", "category": "bodies", "parent": "Bound", "description": "Axis-aligned bounding box, for use with InsertionSortCollider. This class is quasi-redundant since min,max are already contained in Bound itself. That might change at some point, though. ", "attributes": { "name": "lastUpdateIter", "type": "int", "default": "0", "description": "record iteration of last reference position update auto-updated ", "read only": true, "inherited from": "Bound" }, { "name": "refPos", "type": "Vector3", "default": "Vector3r NaN,NaN,NaN ", "description": "Reference position, updated at current body position each time the bound dispatcher update bounds auto-updated ", "read only": true, "inher… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/bound/Aabb.json`
- **Bound**（structured_config）：{ "name": "Bound", "category": "bodies", "parent": "Serializable", "description": "Object bounding part of space taken by associated body; might be larger, used to optimalize collision detection", "attributes": { "name": "lastUpdateIter", "type": "int", "default": "0", "description": "record iteration of last reference position update auto-updated ", "read only": true }, { "name": "refPos", "type": "Vector3", "default": "Vector3r NaN,NaN,NaN ", "description": "Reference position, updated at current body position each time the bound dispatcher update bounds auto-updated ", "read only": true }, { "name": "sweepLength", "type": "float", "default": "0", "description": "The length used to increa… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/bound/Bound.json`
- **Axialgravityengine**（structured_config）：{ "name": "AxialGravityEngine", "category": "engines", "parent": "FieldApplier", "description": "Apply acceleration independent of distance directed towards an axis.", "attributes": { "name": "axisPoint", "type": "Vector3", "default": " 0, 0, 0 ", "description": "Point through which the axis is passing." }, { "name": "axisDirection", "type": "Vector3", "default": "Vector3r::UnitX ", "description": "direction of the gravity axis will be normalized automatically " }, { "name": "acceleration", "type": "float", "default": "0", "description": "Acceleration magnitude kgms\u207b\u00b2 " }, { "name": "mask", "type": "int", "default": "0", "description": "If mask defined, only bodies with correspond… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/engine/AxialGravityEngine.json`
- **Bicyclepedalengine**（structured_config）：{ "name": "BicyclePedalEngine", "category": "engines", "parent": "KinematicEngine", "description": "Engine applying the linear motion of bicycle pedal e.g. moving points around the axis without rotation", "attributes": { "name": "angularVelocity", "type": "float", "default": "0", "description": "Angular velocity. rad/s " }, { "name": "rotationAxis", "type": "Vector3", "default": "Vector3r::UnitX ", "description": "Axis of rotation direction ; will be normalized automatically." }, { "name": "radius", "type": "float", "default": "-1.0", "description": "Rotation radius. m " }, { "name": "fi", "type": "float", "default": "Mathr::PI/2.0", "description": "Initial phase radians " }, { "name": "ids… 证据：`src/yade_mcp/knowledge/resources/python_api_docs/engine/BicyclePedalEngine.json`
- 其余 16 条证据见 `AI_CONTEXT_PACK.json` 或 `EVIDENCE_INDEX.json`。

## 宿主 AI 必须遵守的规则

- **把本资产当作开工前上下文，而不是运行环境。**：AI Context Pack 只包含证据化项目理解，不包含目标项目的可执行状态。 证据：`README.md`, `yade-mcp-bridge/README.md`, `showcase/triaxial/README.md`
- **回答用户时区分可预览内容与必须安装后才能验证的内容。**：安装前体验的消费者价值来自降低误装和误判，而不是伪装成真实运行。 证据：`README.md`, `yade-mcp-bridge/README.md`, `showcase/triaxial/README.md`

## 用户开工前应该回答的问题

- 你准备在哪个宿主 AI 或本地环境中使用它？
- 你只是想先体验工作流，还是准备真实安装？
- 你最在意的是安装成本、输出质量、还是和现有规则的冲突？

## 验收标准

- 所有能力声明都能回指到 evidence_refs 中的文件路径。
- AI_CONTEXT_PACK.md 没有把预览包装成真实运行。
- 用户能在 3 分钟内看懂适合谁、能做什么、如何开始和风险边界。

---

## Doramagic Context Augmentation

下面内容用于强化 Repomix/AI Context Pack 主体。Human Manual 只提供阅读骨架；踩坑日志会被转成宿主 AI 必须遵守的工作约束。

## Human Manual 骨架

使用规则：这里只是项目阅读路线和显著性信号，不是事实权威。具体事实仍必须回到 repo evidence / Claim Graph。

宿主 AI 硬性规则：
- 不得把页标题、章节顺序、摘要或 importance 当作项目事实证据。
- 解释 Human Manual 骨架时，必须明确说它只是阅读路线/显著性信号。
- 能力、安装、兼容性、运行状态和风险判断必须引用 repo evidence、source path 或 Claim Graph。

- **概览与系统架构**：importance `high`
  - source_paths: README.md, README.zh-CN.md, src/yade_mcp/__init__.py, src/yade_mcp/server.py, src/yade_mcp/config.py
- **MCP Server、工具与知识库**：importance `high`
  - source_paths: src/yade_mcp/tools/__init__.py, src/yade_mcp/tools/browse_api.py, src/yade_mcp/tools/query_api.py, src/yade_mcp/tools/execute_code.py, src/yade_mcp/tools/execute_task.py
- **Bridge 运行时、执行与任务生命周期**：importance `high`
  - source_paths: yade-mcp-bridge/src/yade_mcp_bridge/transport/server.py, yade-mcp-bridge/src/yade_mcp_bridge/handlers/__init__.py, yade-mcp-bridge/src/yade_mcp_bridge/handlers/code.py, yade-mcp-bridge/src/yade_mcp_bridge/handlers/tasks.py, yade-mcp-bridge/src/yade_mcp_bridge/handlers/console.py
- **部署、运维与 Showcase 示例**：importance `medium`
  - source_paths: docs/agentic/yade-mcp-bootstrap.md, docs/agentic/yade-mcp-bootstrap-claude.md, docs/agentic/yade-mcp-bootstrap-codex.md, docs/agentic/yade-mcp-bootstrap-copilot.md, docs/agentic/yade-mcp-bootstrap-gemini.md

## Repo Inspection Evidence / 源码检查证据

- repo_clone_verified: true
- repo_inspection_verified: true
- repo_commit: `49f04604fc39c14d14e3e94943d3b368025462db`
- inspected_files: `Dockerfile`, `README.md`, `pyproject.toml`, `uv.lock`, `docs/agentic/yade-mcp-bootstrap-claude.md`, `docs/agentic/yade-mcp-bootstrap-codex.md`, `docs/agentic/yade-mcp-bootstrap-copilot.md`, `docs/agentic/yade-mcp-bootstrap-gemini.md`, `docs/agentic/yade-mcp-bootstrap-opencode.md`, `docs/agentic/yade-mcp-bootstrap-toyoura-nagisa.md`, `docs/agentic/yade-mcp-bootstrap.md`, `src/yade_mcp/__init__.py`, `src/yade_mcp/bridge/__init__.py`, `src/yade_mcp/bridge/client.py`, `src/yade_mcp/bridge/context.py`, `src/yade_mcp/config.py`, `src/yade_mcp/contracts.py`, `src/yade_mcp/formatting.py`, `src/yade_mcp/knowledge/__init__.py`, `src/yade_mcp/knowledge/loader.py`

宿主 AI 硬性规则：
- 没有 repo_clone_verified=true 时，不得声称已经读过源码。
- 没有 repo_inspection_verified=true 时，不得把 README/docs/package 文件判断写成事实。
- 没有 quick_start_verified=true 时，不得声称 Quick Start 已跑通。

## Doramagic Pitfall Constraints / 踩坑约束

这些规则来自 Doramagic 发现、验证或编译过程中的项目专属坑点。宿主 AI 必须把它们当作工作约束，而不是普通说明文字。

### Constraint 1: 可能修改宿主 AI 配置

- Trigger: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- Host AI rule: 列出会写入的配置文件、目录和卸载/回滚步骤。
- Why it matters: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- Evidence: capability.host_targets | https://github.com/yusong652/yade-mcp | host_targets=mcp_host, claude, claude_code, gemini_cli, codex
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。

### Constraint 2: 能力判断依赖假设

- Trigger: README/documentation is current enough for a first validation pass.
- Host AI rule: 将假设转成下游验证清单。
- Why it matters: 假设不成立时，用户拿不到承诺的能力。
- Evidence: capability.assumptions | https://github.com/yusong652/yade-mcp | README/documentation is current enough for a first validation pass.
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。

### Constraint 3: 维护活跃度未知

- Trigger: 未记录 last_activity_observed。
- Host AI rule: 补 GitHub 最近 commit、release、issue/PR 响应信号。
- Why it matters: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- Evidence: evidence.maintainer_signals | https://github.com/yusong652/yade-mcp | last_activity_observed missing
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。

- Trigger: no_demo
- Evidence: downstream_validation.risk_items | https://github.com/yusong652/yade-mcp | no_demo; severity=medium
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。

### Constraint 5: 存在评分风险

- Trigger: no_demo
- Why it matters: 风险会影响是否适合普通用户安装。
- Evidence: risks.scoring_risks | https://github.com/yusong652/yade-mcp | no_demo; severity=medium
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。

### Constraint 6: issue/PR 响应质量未知

- Trigger: issue_or_pr_quality=unknown。
- Host AI rule: 抽样最近 issue/PR，判断是否长期无人处理。
- Why it matters: 用户无法判断遇到问题后是否有人维护。
- Evidence: evidence.maintainer_signals | https://github.com/yusong652/yade-mcp | issue_or_pr_quality=unknown
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。

### Constraint 7: 发布节奏不明确

- Trigger: release_recency=unknown。
- Host AI rule: 确认最近 release/tag 和 README 安装命令是否一致。
- Why it matters: 安装命令和文档可能落后于代码，用户踩坑概率升高。
- Evidence: evidence.maintainer_signals | https://github.com/yusong652/yade-mcp | release_recency=unknown
- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。
