feat(mcp): add project knowledge search
CI / test (pull_request) Canceled after 0s

Complete the Project Context MCP MVP with the second read-only tool,
search_project_knowledge, so an agent can go from an issue's requirement
to the project documents that explain it, with citable evidence.

Retrieval reuses what Cowork already owns instead of adding a vector DB,
an embedding pipeline, or a new RAG framework:
- core/projects.py already defines a project's knowledge as the files at
  its workspace root, so that folder is the entire corpus. Isolation is
  structural, not a filter applied after the fact.
- core/doc_extract.py already extracts docx/pptx/xlsx/pdf/text, so the
  provider inherits format support and duplicates none of it.

Security properties:
- Read-only. The workspace root resolves from the identity, never from
  the request; project_id only verifies scope and is never routing
  authority. Symlinks escaping the workspace are dropped.
- Policy runs before provider resolution; target and access resolution
  are separate seams so a pilot local root can become an on-behalf-of
  served backend without changing the tool or the provider.
- Bounded output per detail mode with cursor pagination; no unlimited
  mode. Backend failures map to safe errors that leak no internals.

score is honest term coverage, not a fabricated similarity; the upgrade
path is documented on _score_chunk.

Adds tests/test_project_context_knowledge.py (40 tests) and
tests/test_project_context_e2e.py, which proves the two tools compose:
issue -> requirement -> related knowledge -> evidence.
This commit is contained in:
thanhnv
2026-09-04 10:46:41 +09:00
parent fecbe7cb25
commit e0ab653a61
4 changed files with 1398 additions and 5 deletions
+15
View File
@@ -54,9 +54,24 @@ COWORK_MCP_PROJECT=<project> \
GITEA_BASE_URL=<https://gitea.example> \
GITEA_TOKEN=<service-account-token> \
PROJECT_CONTEXT_REPO_MAP='{"<org>/<customer>/<project>":"<owner>/<repo>"}' \
PROJECT_CONTEXT_KNOWLEDGE_ROOT=<path chứa 1 thư mục con cho mỗi project> \
python -m cowork_local.mcp_servers.project_context_server
```
Target map ưu tiên key đủ `org_unit/customer/project`; key `project` chỉ là legacy fallback cho pilot
env cũ. Không commit giá trị môi trường hoặc credential. Cowork kết nối bằng stdio với command Python
và args `-m cowork_local.mcp_servers.project_context_server`.
## Knowledge search (`search_project_knowledge`)
Corpus là workspace của chính project: `PROJECT_CONTEXT_KNOWLEDGE_ROOT/<identity.project>` — cùng
định nghĩa "knowledge" mà `core/projects.py` đã dùng (file ở workspace root), và tái sử dụng
`core/doc_extract.py` để đọc docx/pptx/xlsx/pdf/text. Không thêm vector DB, embedding pipeline hay
RAG framework mới.
- Thư mục được resolve từ **identity**, không bao giờ từ `project_id` trong request; `project_id`
chỉ dùng để verify scope. Symlink trỏ ra ngoài workspace bị loại.
- `score` là term-coverage (lexical), không phải similarity giả. Upgrade path: thay riêng
`_score_chunk` bằng semantic ranker khi corpus đủ lớn.
- Bound theo `detail`: `summary` 3 kết quả / 200 ký tự, `standard` 5 / 600, `full` 10 / 1200.
`top_k` chỉ thu hẹp, không nới rộng. Không có unlimited mode.