Files
rengine/mcp/context.py
T
Yogesh OjhaandClaude Fable 5.1 0a69f3201c copy: state the fact, delete the explanation
Repo-wide sweep of every user-facing string: frontend components, routes,
config and stores; API details and route docs; shared definitions and
models; stage config help; report prose; MCP, toolbox, interest and
connector text; notification and worker messages.

Descriptions that explained, reassured, justified or restated their title
are deleted. Confirm dialogs name what is removed and stop. Failed actions
read "<Noun> not <verbed>", successes "<Noun> <verbed>". No reader address,
no product-as-subject, no em-dashes or parentheticals in prose.

Mirrors updated on both sides: EPSS band help, compare refusal reasons,
interest labels. Four tests asserting on old wording follow the new text.
The rules are condensed into CLAUDE.md under Writing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SK5o8xR96cbSnAfjYSTPSe
2026-09-12 11:35:07 +05:30

51 lines
1.5 KiB
Python

"""Everything a tool is given: a session, who is asking, and what they may do."""
from __future__ import annotations
import uuid
from dataclasses import dataclass, field
from typing import TYPE_CHECKING
from mcp.capabilities import Capability
from mcp.errors import CapabilityError, ScopeError
if TYPE_CHECKING:
from sqlalchemy.ext.asyncio import AsyncSession
@dataclass(frozen=True)
class TokenIdentity:
id: uuid.UUID
name: str
project_id: uuid.UUID | None
capabilities: frozenset[str]
issued_by: uuid.UUID | None = None
def allows(self, capability: str) -> bool:
return capability in self.capabilities
@dataclass
class ToolContext:
session: AsyncSession
token: TokenIdentity
ui_base_url: str
client: str = "unknown"
extras: dict = field(default_factory=dict)
def require(self, capability: str | Capability) -> None:
value = str(capability)
if not self.token.allows(value):
msg = f"This token lacks the {value} capability."
raise CapabilityError(msg)
def scoped_projects(self) -> list[uuid.UUID] | None:
"""None means every project."""
return None if self.token.project_id is None else [self.token.project_id]
def check_project(self, project_id: uuid.UUID) -> uuid.UUID:
if self.token.project_id is not None and project_id != self.token.project_id:
msg = "The project is outside this token's scope."
raise ScopeError(msg)
return project_id