fix: harden MCP endpoint after code review
Critical: the MCP SDK auto-enables DNS-rebinding protection when its host parameter is left at the 127.0.0.1 default, hard-coding a loopback-only Host allow-list. Every remote client (the only deployment this feature targets) was refused with HTTP 421 before auth or the tool ran. Now driven by a new MCP_ALLOWED_HOSTS setting, with '*' as an explicit, logged opt-out. Also bounds query/top_k to match AskRequest (top_k is amplified 4x downstream, so an unbounded value was a resource-exhaustion vector), decodes the Authorization header as latin-1 per the ASGI spec instead of raising a 500 on malformed bytes, and returns WWW-Authenticate on 401 per RFC 7235. Moves the psycopg2 import guard into backend/tests/conftest.py: duplicated across four test modules, it only worked because of alphabetical collection order, and any earlier-sorting package would have reintroduced a live connection attempt against the production database. Registers the mcp module in the authoritative backend architecture doc. 84 backend tests pass. Verified against a live server: allowed remote Host returns a valid initialize result, unknown Host returns 421, missing token returns 401 with WWW-Authenticate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -206,6 +206,7 @@
|
||||
```text
|
||||
backend/app/
|
||||
api/
|
||||
mcp/
|
||||
application/
|
||||
documents/
|
||||
knowledge/
|
||||
@@ -314,6 +315,25 @@ backend/app/
|
||||
- `backend/app/shared/bootstrap.py` 是现阶段的 composition root,负责把端口实现、基础设施适配器和 application service 连接起来。
|
||||
- 后续如果新增 wiring 入口,应继续保持在同一类装配边界内,不要把依赖装配拆回各个路由或 service 构造函数中。
|
||||
|
||||
### 4.6 `mcp`
|
||||
|
||||
职责:
|
||||
|
||||
- 以 Model Context Protocol 对外暴露平台已有能力
|
||||
- MCP tool 注册与入参 schema 绑定
|
||||
- MCP 专用鉴权(复用现有 JWT)与 Streamable HTTP 子 ASGI 应用装配
|
||||
|
||||
非职责:
|
||||
|
||||
- 不实现任何新的检索、问答或业务编排逻辑
|
||||
- 不直接访问 Milvus、MinIO、LLM SDK
|
||||
|
||||
说明:
|
||||
|
||||
- `mcp` 与 `api` 是并列的两个 transport 适配层:`api` 面向 HTTP REST 客户端,`mcp` 面向 MCP 客户端(Claude Desktop、IDE 等)。二者共用同一套 application service。
|
||||
- 它独立成顶层模块而不是放进 `api/routes/`,因为 MCP 使用装饰器式 tool 注册和自带的子 ASGI 应用,与 `APIRouter` 是不同的传输机制。
|
||||
- 当前实现见 `backend/app/mcp/server.py`,只暴露 `search_regulations` 一个 tool,内部直接调用 `get_agent_conversation_service()`。
|
||||
|
||||
## 5. Module Responsibilities
|
||||
|
||||
### 5.1 `api`
|
||||
@@ -637,6 +657,7 @@ infrastructure -> external systems
|
||||
具体规则如下:
|
||||
|
||||
- `api` 可以依赖 `application` 和 API 自己的 request/response models
|
||||
- `mcp` 与 `api` 同级,只能依赖 `application` 和 composition root,不能依赖 `infrastructure` 或反过来被 `application` 依赖
|
||||
- `application` 只能依赖 `domain`、端口接口,以及通过 composition root 注入进来的实现实例
|
||||
- `domain` 不能依赖 `api` 或 `infrastructure`
|
||||
- `infrastructure` 可以依赖 `domain` 定义的端口和数据模型,但不能反向驱动 application 逻辑
|
||||
|
||||
Reference in New Issue
Block a user