Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4de366cde7 |
@@ -21,13 +21,12 @@ cần đổi, mở một PR nhỏ riêng và để cả ba người rebase sau k
|
|||||||
|
|
||||||
## Bắt đầu trong 5 phút
|
## Bắt đầu trong 5 phút
|
||||||
|
|
||||||
1. Chạy `python --version` và xác nhận Python 3.11+ như baseline trong `requirements.txt`.
|
1. Tạo branch từ commit template chứa tài liệu này sau khi PR template merge.
|
||||||
2. Tạo branch từ commit template chứa tài liệu này sau khi PR template merge.
|
2. Đọc input/output model trong module tool được giao; không thêm field riêng của Gitea/Jira/Redmine.
|
||||||
3. Đọc input/output model trong module tool được giao; không thêm field riêng của Gitea/Jira/Redmine.
|
3. Implement provider read-only trong module `providers/<tool>.py`; credential chỉ lấy sau policy ALLOW.
|
||||||
4. Implement provider read-only trong module `providers/<tool>.py`; credential chỉ lấy sau policy ALLOW.
|
4. Thêm test happy, invalid, not-found, timeout, DENIED với `resolver.calls == 0`, output sai schema,
|
||||||
5. Thêm test happy, invalid, not-found, timeout, DENIED với `resolver.calls == 0`, output sai schema,
|
|
||||||
truncation/cursor và source mở được có `revision`.
|
truncation/cursor và source mở được có `revision`.
|
||||||
6. Chạy:
|
5. Chạy:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python -m pytest tests/test_project_context_mcp_template.py tests/test_project_context_<tool>.py -q
|
python -m pytest tests/test_project_context_mcp_template.py tests/test_project_context_<tool>.py -q
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
@@ -13,18 +12,6 @@ from .providers.change import build_provider as build_change_provider
|
|||||||
from .providers.issue import build_provider as build_issue_provider
|
from .providers.issue import build_provider as build_issue_provider
|
||||||
from .providers.knowledge import build_provider as build_knowledge_provider
|
from .providers.knowledge import build_provider as build_knowledge_provider
|
||||||
|
|
||||||
MINIMUM_PYTHON = (3, 11)
|
|
||||||
|
|
||||||
|
|
||||||
def require_supported_python(version_info: tuple[int, ...] | None = None) -> None:
|
|
||||||
"""Fail with an actionable message before the MCP server starts."""
|
|
||||||
current = version_info or tuple(sys.version_info[:3])
|
|
||||||
if current[:2] < MINIMUM_PYTHON:
|
|
||||||
raise RuntimeError(
|
|
||||||
"Project Context MCP requires Python 3.11 or newer; "
|
|
||||||
f"current runtime is {current[0]}.{current[1]}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class ProjectScopePolicy:
|
class ProjectScopePolicy:
|
||||||
@@ -59,7 +46,6 @@ def _required_environment(name: str) -> str:
|
|||||||
|
|
||||||
def default_runtime() -> ProjectContextRuntime:
|
def default_runtime() -> ProjectContextRuntime:
|
||||||
"""Build immutable runtime state; missing identity configuration fails at boot."""
|
"""Build immutable runtime state; missing identity configuration fails at boot."""
|
||||||
require_supported_python()
|
|
||||||
identity = IdentityContext(
|
identity = IdentityContext(
|
||||||
actor_id=_required_environment("COWORK_MCP_ACTOR_ID"),
|
actor_id=_required_environment("COWORK_MCP_ACTOR_ID"),
|
||||||
org_unit=_required_environment("COWORK_MCP_ORG_UNIT"),
|
org_unit=_required_environment("COWORK_MCP_ORG_UNIT"),
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from .foundation import (
|
|||||||
error_result,
|
error_result,
|
||||||
)
|
)
|
||||||
from .registry import TOOLS_BY_NAME, tool_declarations
|
from .registry import TOOLS_BY_NAME, tool_declarations
|
||||||
from .runtime import default_runtime, require_supported_python
|
from .runtime import default_runtime
|
||||||
|
|
||||||
|
|
||||||
def dispatch(
|
def dispatch(
|
||||||
@@ -102,7 +102,6 @@ def build_server(runtime: Optional[ProjectContextRuntime] = None):
|
|||||||
from mcp import types
|
from mcp import types
|
||||||
from mcp.server.lowlevel import Server
|
from mcp.server.lowlevel import Server
|
||||||
|
|
||||||
require_supported_python()
|
|
||||||
app_runtime = runtime or default_runtime()
|
app_runtime = runtime or default_runtime()
|
||||||
app = Server("project_context")
|
app = Server("project_context")
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ from cowork_local.mcp_servers.project_context.registry import (
|
|||||||
TOOL_NAMES,
|
TOOL_NAMES,
|
||||||
tool_declarations,
|
tool_declarations,
|
||||||
)
|
)
|
||||||
from cowork_local.mcp_servers.project_context.runtime import require_supported_python
|
|
||||||
from cowork_local.mcp_servers.project_context.server import dispatch
|
from cowork_local.mcp_servers.project_context.server import dispatch
|
||||||
from mcp import types
|
from mcp import types
|
||||||
|
|
||||||
@@ -96,11 +95,6 @@ def test_template_exposes_exactly_three_provider_neutral_tools() -> None:
|
|||||||
assert all(types.Tool(**item).name in EXPECTED_TOOLS for item in declarations)
|
assert all(types.Tool(**item).name in EXPECTED_TOOLS for item in declarations)
|
||||||
|
|
||||||
|
|
||||||
def test_runtime_fails_fast_below_python_311() -> None:
|
|
||||||
with pytest.raises(RuntimeError, match="requires Python 3.11"):
|
|
||||||
require_supported_python((3, 9, 0))
|
|
||||||
|
|
||||||
|
|
||||||
def test_denied_request_never_resolves_credentials_or_calls_provider(
|
def test_denied_request_never_resolves_credentials_or_calls_provider(
|
||||||
identity: IdentityContext,
|
identity: IdentityContext,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user