Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020

This commit is contained in:
Public Source Publisher committed 2026-10-01 01:36:21 +02:00
commit cb5be898ea
663 files changed
+82674

No files matched your search

+25
View File
@@ -0,0 +1,25 @@
from .bridge import StdioBridge
from .matrix import FakeVirtualServer, MatrixResult, run_matrix
from .models import (
BootstrapHandle,
ClientConfig,
ClientKind,
ClientRecord,
ClientRegistry,
ClientStatus,
generate_config,
)
__all__ = [
"BootstrapHandle",
"ClientConfig",
"ClientKind",
"ClientRecord",
"ClientRegistry",
"ClientStatus",
"FakeVirtualServer",
"MatrixResult",
"StdioBridge",
"generate_config",
"run_matrix",
]
+80
View File
@@ -0,0 +1,80 @@
"""Minimal JSON-lines stdio bridge; tokens are read only for the call and never emitted."""
from __future__ import annotations
import json
import os
from collections.abc import Callable, Iterable, Iterator, Mapping
from typing import Any, Protocol
class BridgeTransport(Protocol):
def send(
self, request: Mapping[str, Any], *, token: str, endpoint: str
) -> Mapping[str, Any] | None: ...
class StdioBridge:
"""Translate bounded JSON-lines messages to remote MCP without shell or token output."""
ALLOWED_METHODS = frozenset(
{
"initialize",
"notifications/initialized",
"ping",
"tools/list",
"tools/call",
"resources/list",
"resources/templates/list",
"resources/read",
"prompts/list",
"prompts/get",
}
)
def __init__(self, *, endpoint: str, token_env: str | None = None) -> None:
if not endpoint.startswith("https://"):
raise ValueError("stdio bridge endpoints must use HTTPS")
self.endpoint = endpoint
self.token_env = token_env or "ITWORX_MCP_ACCESS_TOKEN"
def forward(
self,
lines: Iterable[str],
transport: BridgeTransport,
*,
environ: Mapping[str, str] | None = None,
token_provider: Callable[[], str] | None = None,
) -> Iterator[str]:
values = environ if environ is not None else os.environ
static_token = values.get(self.token_env)
if not static_token and token_provider is None:
yield _error("authentication_required")
return
for raw in lines:
if len(raw.encode("utf-8")) > 4 * 1024 * 1024:
yield _error("request_too_large")
continue
try:
request = json.loads(raw)
except json.JSONDecodeError:
yield _error("invalid_json")
continue
if not isinstance(request, dict) or request.get("method") not in self.ALLOWED_METHODS:
yield _error("unsupported_method")
continue
try:
token = token_provider() if token_provider is not None else static_token
if not token:
yield _error("authentication_required")
continue
result = transport.send(request, token=token, endpoint=self.endpoint)
if result is not None:
yield json.dumps(dict(result), separators=(",", ":"))
except Exception:
yield _error("upstream_unavailable")
del static_token
def _error(code: str) -> str:
return json.dumps({"error": {"code": code}}, separators=(",", ":"))
+69
View File
@@ -0,0 +1,69 @@
"""Deterministic MCP discovery/invocation matrix for supported client profiles."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from .models import ClientKind
@dataclass(frozen=True)
class MatrixResult:
client_kind: ClientKind
protocol_version: str
connector: str
tool: str
discovered: bool
invoked: bool
detail: str
class FakeVirtualServer:
"""Offline project virtual server used for the client matrix and negative cases."""
def __init__(self) -> None:
self.tools = {
"gitea": "gitea.repository.get",
"knowledge": "knowledge.document.search",
"unraid": "unraid.container.inspect",
}
self.revoked: set[str] = set()
def discover(self, client_key: str, protocol_version: str) -> tuple[str, ...]:
if client_key in self.revoked:
raise PermissionError("client revoked")
if protocol_version not in {"2026-07-28", "2025-11-25"}:
raise ValueError("unsupported protocol version")
return tuple(self.tools.values())
def invoke(
self, client_key: str, tool: str, arguments: dict[str, Any] | None = None
) -> dict[str, Any]:
del arguments
if client_key in self.revoked:
raise PermissionError("client revoked")
if tool not in self.tools.values():
raise LookupError("tool not found")
return {"tool": tool, "ok": True, "truncated": False}
def run_matrix(server: FakeVirtualServer) -> tuple[MatrixResult, ...]:
profiles = (
(ClientKind.NATIVE_2026, "2026-07-28"),
(ClientKind.COMPATIBILITY_2025, "2025-11-25"),
(ClientKind.STDIO_BRIDGE, "2026-07-28"),
(ClientKind.INSPECTOR, "2026-07-28"),
)
results: list[MatrixResult] = []
for kind, revision in profiles:
client_key = kind.value
tools = server.discover(client_key, revision)
for connector, tool in server.tools.items():
invoked = bool(server.invoke(client_key, tool)["ok"])
results.append(
MatrixResult(
kind, revision, connector, tool, tool in tools, invoked, "fixture success"
)
)
return tuple(results)
+235
View File
@@ -0,0 +1,235 @@
"""Typed, secret-free machine-client lifecycle primitives for MCP onboarding."""
from __future__ import annotations
from datetime import UTC, datetime, timedelta
from enum import StrEnum
from threading import RLock
from uuid import UUID, uuid4
from pydantic import BaseModel, ConfigDict, Field
class ClientKind(StrEnum):
NATIVE_2026 = "native-2026"
COMPATIBILITY_2025 = "compatibility-2025"
STDIO_BRIDGE = "stdio-bridge"
INSPECTOR = "inspector"
class ClientStatus(StrEnum):
PENDING = "pending"
ENABLED = "enabled"
DISABLED = "disabled"
REVOKED = "revoked"
class ClientRecord(BaseModel):
model_config = ConfigDict(extra="forbid", frozen=True)
id: UUID
name: str = Field(min_length=1, max_length=128)
project: str = Field(min_length=1, max_length=63, pattern=r"^[a-z0-9][a-z0-9-]*$")
environment: str = Field(min_length=1, max_length=32, pattern=r"^[a-z0-9][a-z0-9-]*$")
kind: ClientKind
status: ClientStatus
credential_reference: str = Field(min_length=1, max_length=256)
created_at: datetime
last_seen_at: datetime | None = None
disabled_at: datetime | None = None
revoked_at: datetime | None = None
class ClientConfig(BaseModel):
"""Generated client configuration. It intentionally contains no token or secret."""
model_config = ConfigDict(extra="forbid", frozen=True, populate_by_name=True)
client_id: UUID = Field(serialization_alias="clientId")
kind: ClientKind
protocol_version: str = Field(serialization_alias="protocolVersion")
endpoint: str
transport: str
scopes: tuple[str, ...]
credential_reference: str = Field(serialization_alias="credentialReference")
environment_variable: str | None = Field(
default=None, serialization_alias="environmentVariable"
)
bridge_command: str | None = Field(default=None, serialization_alias="bridgeCommand")
class BootstrapHandle(BaseModel):
"""A one-time Authentik hand-off reference, never a bearer credential."""
model_config = ConfigDict(extra="forbid", frozen=True, populate_by_name=True)
client_id: UUID
reference: str = Field(min_length=1, max_length=256)
delivery: str = "authentik-service-account"
expires_at: datetime = Field(serialization_alias="expiresAt")
consumed: bool = False
class ClientRegistry:
"""In-memory development registry; production persistence is supplied by the control plane."""
def __init__(self, *, revocation_cache_ttl_seconds: int = 60) -> None:
if not 1 <= revocation_cache_ttl_seconds <= 60:
raise ValueError("revocation cache ceiling is 60 seconds")
self.revocation_cache_ttl_seconds = revocation_cache_ttl_seconds
self._clients: dict[UUID, ClientRecord] = {}
self._bootstrap: dict[str, BootstrapHandle] = {}
self._lock = RLock()
def create(
self,
*,
name: str,
project: str,
environment: str,
kind: ClientKind,
now: datetime | None = None,
) -> ClientRecord:
reference = _aware(now)
client_id = uuid4()
record = ClientRecord(
id=client_id,
name=name,
project=project,
environment=environment,
kind=kind,
status=ClientStatus.ENABLED,
credential_reference=f"authentik://mcp-client/{client_id}",
created_at=reference,
)
with self._lock:
self._clients[client_id] = record
return record
def list(self) -> tuple[ClientRecord, ...]:
with self._lock:
return tuple(self._clients.values())
def get(self, client_id: UUID) -> ClientRecord | None:
with self._lock:
return self._clients.get(client_id)
def disable(self, client_id: UUID, *, now: datetime | None = None) -> ClientRecord:
return self._transition(client_id, ClientStatus.DISABLED, _aware(now))
def revoke(self, client_id: UUID, *, now: datetime | None = None) -> ClientRecord:
return self._transition(client_id, ClientStatus.REVOKED, _aware(now))
def _transition(self, client_id: UUID, status: ClientStatus, now: datetime) -> ClientRecord:
with self._lock:
current = self._clients.get(client_id)
if current is None:
raise KeyError(client_id)
updated = current.model_copy(
update={
"status": status,
"disabled_at": now if status is ClientStatus.DISABLED else current.disabled_at,
"revoked_at": now if status is ClientStatus.REVOKED else current.revoked_at,
}
)
self._clients[client_id] = updated
return updated
def touch(self, client_id: UUID, *, now: datetime | None = None) -> ClientRecord:
reference = _aware(now)
with self._lock:
current = self._clients.get(client_id)
if current is None:
raise KeyError(client_id)
if current.status is not ClientStatus.ENABLED:
raise PermissionError("client is not enabled")
updated = current.model_copy(update={"last_seen_at": reference})
self._clients[client_id] = updated
return updated
def authorize(self, client_id: UUID, *, project: str, environment: str) -> ClientRecord:
record = self.get(client_id)
if record is None or record.status is not ClientStatus.ENABLED:
raise PermissionError("client is disabled or revoked")
if record.project != project or record.environment != environment:
raise PermissionError("client binding does not match endpoint scope")
return record
def issue_bootstrap(
self, client_id: UUID, *, now: datetime | None = None, ttl_seconds: int = 300
) -> BootstrapHandle:
if not 1 <= ttl_seconds <= 900:
raise ValueError("bootstrap TTL must be between 1 and 900 seconds")
if self.get(client_id) is None:
raise KeyError(client_id)
reference = _aware(now)
handle = BootstrapHandle(
client_id=client_id,
reference=f"authentik-bootstrap://{uuid4()}",
expires_at=reference + timedelta(seconds=ttl_seconds),
)
with self._lock:
self._bootstrap[handle.reference] = handle
return handle
def consume_bootstrap(self, reference: str, *, now: datetime | None = None) -> BootstrapHandle:
current = _aware(now)
with self._lock:
handle = self._bootstrap.get(reference)
if handle is None or handle.consumed or handle.expires_at <= current:
raise PermissionError("bootstrap reference is invalid or expired")
consumed = handle.model_copy(update={"consumed": True})
self._bootstrap[reference] = consumed
return consumed
def _aware(value: datetime | None) -> datetime:
result = value or datetime.now(UTC)
if result.tzinfo is None or result.utcoffset() is None:
raise ValueError("timestamps must be timezone-aware")
return result.astimezone(UTC)
def generate_config(record: ClientRecord, *, public_host: str = "mcp.example.com") -> ClientConfig:
endpoint = f"https://{public_host}/mcp/{record.project}/{record.environment}"
if record.kind is ClientKind.NATIVE_2026:
return ClientConfig(
client_id=record.id,
kind=record.kind,
protocol_version="2026-07-28",
endpoint=endpoint,
transport="streamable-http",
scopes=("tools:read",),
credential_reference=record.credential_reference,
)
if record.kind is ClientKind.COMPATIBILITY_2025:
return ClientConfig(
client_id=record.id,
kind=record.kind,
protocol_version="2025-11-25",
endpoint=endpoint,
transport="streamable-http",
scopes=("tools:read",),
credential_reference=record.credential_reference,
)
if record.kind is ClientKind.STDIO_BRIDGE:
return ClientConfig(
client_id=record.id,
kind=record.kind,
protocol_version="2026-07-28",
endpoint=endpoint,
transport="stdio",
scopes=("tools:read",),
credential_reference=record.credential_reference,
environment_variable="ITWORX_MCP_ACCESS_TOKEN",
bridge_command="itworx-mcp-bridge",
)
return ClientConfig(
client_id=record.id,
kind=record.kind,
protocol_version="2026-07-28",
endpoint=f"http://127.0.0.1:18442/mcp/{record.project}/{record.environment}",
transport="streamable-http",
scopes=("tools:read",),
credential_reference=record.credential_reference,
)