Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020
This commit is contained in:
commit
cb5be898ea
663 files changed
+82674
No files matched your search
@@ -0,0 +1,153 @@
|
||||
"""Typed, public-safe contracts for the dataplane router."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ipaddress
|
||||
import re
|
||||
from datetime import datetime
|
||||
from typing import Literal, Protocol
|
||||
from urllib.parse import urlparse
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import AnyHttpUrl, BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
|
||||
EnvironmentName = Literal["dev", "test", "staging", "prod"]
|
||||
SUPPORTED_PROTOCOLS = frozenset({"2026-07-28", "2025-11-25"})
|
||||
|
||||
|
||||
class ClientBinding(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid", frozen=True)
|
||||
|
||||
client_id: UUID
|
||||
issuer: str = Field(min_length=1, max_length=2048)
|
||||
subject: str = Field(min_length=1, max_length=512)
|
||||
enabled: bool = False
|
||||
|
||||
|
||||
class AliasRecord(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid", frozen=True)
|
||||
|
||||
project_slug: str = Field(pattern=r"^[a-z0-9][a-z0-9-]{0,62}$")
|
||||
workspace_id: UUID | None = None
|
||||
project_id: UUID | None = None
|
||||
environment: EnvironmentName
|
||||
alias: str
|
||||
upstream_url: AnyHttpUrl
|
||||
enabled: bool = False
|
||||
protocol_revisions: tuple[str, ...] = ("2026-07-28", "2025-11-25")
|
||||
bindings: tuple[ClientBinding, ...] = ()
|
||||
|
||||
@field_validator("alias")
|
||||
@classmethod
|
||||
def validate_alias(cls, value: str) -> str:
|
||||
if len(value) > 128 or not re.fullmatch(
|
||||
r"/mcp/[a-z0-9][a-z0-9-]{0,62}/(?:dev|test|staging|prod)/?", value
|
||||
):
|
||||
raise ValueError("alias must be a stable /mcp path")
|
||||
return value.rstrip("/")
|
||||
|
||||
@field_validator("upstream_url")
|
||||
@classmethod
|
||||
def reject_upstream_userinfo(cls, value: AnyHttpUrl) -> AnyHttpUrl:
|
||||
if value.username is not None or value.password is not None:
|
||||
raise ValueError("upstream URL userinfo is not permitted")
|
||||
internal_contextforge = (
|
||||
value.scheme == "http"
|
||||
and value.host in {"contextforge", "contextforge-control"}
|
||||
and value.port == 4444
|
||||
and (
|
||||
(value.path or "").rstrip("/") == "/mcp"
|
||||
or bool(
|
||||
re.fullmatch(
|
||||
r"/servers/[0-9a-f]{32}/mcp",
|
||||
(value.path or "").rstrip("/"),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
if value.scheme != "https" and not internal_contextforge:
|
||||
raise ValueError("dataplane upstreams must use HTTPS or the fixed internal gateway")
|
||||
hostname = (urlparse(str(value)).hostname or "").casefold()
|
||||
if hostname in {"localhost", "metadata", "metadata.google.internal"}:
|
||||
raise ValueError("dataplane upstream host is not allowed")
|
||||
try:
|
||||
address = ipaddress.ip_address(hostname)
|
||||
except ValueError:
|
||||
address = None
|
||||
if address is not None and (
|
||||
address.is_private
|
||||
or address.is_loopback
|
||||
or address.is_link_local
|
||||
or address.is_reserved
|
||||
or address.is_unspecified
|
||||
or address.is_multicast
|
||||
):
|
||||
raise ValueError("dataplane upstream host is not allowed")
|
||||
return value
|
||||
|
||||
@field_validator("protocol_revisions")
|
||||
@classmethod
|
||||
def validate_protocols(cls, value: tuple[str, ...]) -> tuple[str, ...]:
|
||||
if not value or not set(value).issubset(SUPPORTED_PROTOCOLS):
|
||||
raise ValueError("unsupported MCP protocol revision")
|
||||
return tuple(dict.fromkeys(value))
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_identity(self) -> AliasRecord:
|
||||
if not self.alias.endswith(f"/{self.environment}"):
|
||||
raise ValueError("alias environment does not match the record environment")
|
||||
if len({binding.client_id for binding in self.bindings}) != len(self.bindings):
|
||||
raise ValueError("duplicate client binding")
|
||||
return self
|
||||
|
||||
|
||||
class InvocationMetadata(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid", frozen=True)
|
||||
|
||||
trace_id: str = Field(pattern=r"^[A-Za-z0-9._:-]{1,128}$")
|
||||
project_slug: str
|
||||
environment: EnvironmentName
|
||||
client_id: UUID
|
||||
subject_digest: str = Field(pattern=r"^[0-9a-f]{64}$")
|
||||
method: str = Field(min_length=1, max_length=16)
|
||||
mcp_method: str | None = Field(default=None, max_length=128)
|
||||
mcp_name: str | None = Field(default=None, max_length=256)
|
||||
protocol_revision: str
|
||||
request_bytes: int = Field(ge=0, le=4 * 1024 * 1024)
|
||||
response_status: int = Field(ge=100, le=599)
|
||||
response_bytes: int = Field(ge=0, le=4 * 1024 * 1024)
|
||||
response_content_type: str | None = Field(default=None, max_length=128)
|
||||
jsonrpc_response: bool = False
|
||||
response_id_matches: bool | None = None
|
||||
response_shape: str = Field(default="unknown", pattern=r"^(result|error|unknown)$")
|
||||
duration_ms: int = Field(ge=0, le=120_000)
|
||||
|
||||
|
||||
class RouterSettings(BaseModel):
|
||||
model_config = ConfigDict(extra="forbid", frozen=True)
|
||||
|
||||
max_body_bytes: int = Field(default=4 * 1024 * 1024, ge=1024, le=4 * 1024 * 1024)
|
||||
max_response_bytes: int = Field(default=4 * 1024 * 1024, ge=1024, le=4 * 1024 * 1024)
|
||||
timeout_seconds: float = Field(default=30.0, gt=0, le=30)
|
||||
alias_cache_ttl_seconds: int = Field(default=30, ge=1, le=60)
|
||||
max_upstream_concurrency: int = Field(default=24, ge=1, le=256)
|
||||
upstream_queue_timeout_seconds: float = Field(default=5.0, ge=0.1, le=30)
|
||||
|
||||
|
||||
class PrincipalLike(Protocol):
|
||||
"""Minimal validated principal contract consumed by the dataplane."""
|
||||
|
||||
@property
|
||||
def subject(self) -> str: ...
|
||||
|
||||
@property
|
||||
def issuer(self) -> str: ...
|
||||
|
||||
@property
|
||||
def kind(self) -> object: ...
|
||||
|
||||
@property
|
||||
def client_id(self) -> UUID | None: ...
|
||||
|
||||
@property
|
||||
def expires_at(self) -> datetime: ...
|
||||
Reference in new issue
Block a user