FrameBridge 0.3.1 community source release

This commit is contained in:
FrameBridge Development committed 2026-10-26 22:09:18 -04:00
commit b23819fff1
1354 files changed
+343716

No files matched your search

@@ -0,0 +1,42 @@
"""Separate loopback-only MCP entry point for the six Fleet READ tools."""
from __future__ import annotations
import os
from mcp.server.fastmcp import FastMCP
from framebridge_node_gateway import discover_nodes, node_read
from framebridge_linux_chatgpt.fleet_hub import FleetHub
from framebridge_linux_chatgpt.fleet_mcp_surface import register_fleet_read_tools
def _server_address() -> tuple[str, int]:
host = os.environ.get("FRAMEBRIDGE_FLEET_HUB_HOST", "127.0.0.1")
if not isinstance(host, str) or host not in ("127.0.0.1", "::1"):
raise ValueError("FLEET_HUB_HOST_INVALID")
try:
port = int(os.environ.get("FRAMEBRIDGE_FLEET_HUB_PORT", "8877"))
except (TypeError, ValueError):
raise ValueError("FLEET_HUB_PORT_INVALID") from None
if not 1024 <= port <= 65535:
raise ValueError("FLEET_HUB_PORT_INVALID")
return host, port
host, port = _server_address()
mcp = FastMCP(
"FrameBridge Fleet Hub",
host=host,
port=port,
streamable_http_path="/mcp",
)
hub = FleetHub(discover_nodes, node_read)
register_fleet_read_tools(mcp, hub)
def main() -> None:
mcp.run(transport="streamable-http")
if __name__ == "__main__":
main()
@@ -0,0 +1 @@
"""FrameBridge Fleet Hub runtime."""
@@ -0,0 +1,42 @@
"""Injected Node Gateway READ boundary; no transport or live gateway imports."""
from __future__ import annotations
from typing import Callable
from .fleet_registry import FleetNode
from .fleet_routing import Operation, ReadRequest, normalize_read_args
class GatewayReadError(ValueError):
"""Fixed local error codes; remote exceptions are never copied."""
class GatewayReadAdapter:
def __init__(self, gateway_node_read: Callable[[str, str, dict], dict]) -> None:
if not callable(gateway_node_read):
raise GatewayReadError("FLEET_GATEWAY_CONFIG_INVALID")
self._gateway_node_read = gateway_node_read
def __call__(self, node: FleetNode, request: ReadRequest) -> dict:
if type(node) is not FleetNode or type(request) is not ReadRequest:
raise GatewayReadError("FLEET_GATEWAY_REQUEST_INVALID")
if request.node_id != node.node_id:
raise GatewayReadError("FLEET_GATEWAY_NODE_MISMATCH")
if request.operation is not Operation.READ or not node.online:
raise GatewayReadError("FLEET_GATEWAY_READ_BLOCKED")
try:
args = normalize_read_args(request.capability, request.args)
except ValueError:
raise GatewayReadError("FLEET_GATEWAY_REQUEST_INVALID") from None
try:
response = self._gateway_node_read(node.alias, request.capability.value, args)
except Exception:
raise GatewayReadError("FLEET_GATEWAY_READ_FAILED") from None
if type(response) is not dict or response.get("ok") is not True:
raise GatewayReadError("FLEET_GATEWAY_READ_FAILED")
for key in ("node", "alias"):
if key in response and (type(response[key]) is not str
or response[key] != node.alias):
raise GatewayReadError("FLEET_GATEWAY_ALIAS_MISMATCH")
# Metadata is payload only. It cannot update identity, routing or policy.
return response
@@ -0,0 +1,65 @@
"""Synchronous, in-memory Fleet READ hub using injected discovery and gateway."""
from __future__ import annotations
from typing import Callable
from .fleet_gateway_adapter import GatewayReadAdapter
from .fleet_registry import FleetNode, FleetRegistry, RegistryError
from .fleet_routing import FleetRequest, FleetRouter, RouteResult
class FleetHubError(ValueError):
"""Sanitized discovery/configuration failure."""
class FleetHub:
def __init__(self, discover_nodes: Callable[[], dict],
gateway_node_read: Callable[[str, str, dict], dict]) -> None:
if not callable(discover_nodes):
raise FleetHubError("FLEET_HUB_CONFIG_INVALID")
self._discover_nodes = discover_nodes
self._adapter = GatewayReadAdapter(gateway_node_read)
registry = FleetRegistry()
self._snapshot = (registry, FleetRouter(registry, self._adapter))
def refresh(self) -> tuple[FleetNode, ...]:
"""Publish only a complete valid registry; failures preserve the old one.
Entries with explicit pairing state must be paired. Legacy entries need
an explicit stable ID too. Missing descriptive metadata stays unknown;
it never supplies identity or readiness. Invalid entries are omitted,
but duplicate IDs/aliases and cross-namespace collisions abort refresh.
"""
try:
discovery = self._discover_nodes()
if (type(discovery) is not dict or discovery.get("ok") is not True
or type(discovery.get("nodes")) is not list):
raise FleetHubError("FLEET_REFRESH_FAILED")
registry = FleetRegistry()
for entry in discovery["nodes"]:
if type(entry) is not dict:
continue
if "pairing_state" in entry and entry["pairing_state"] != "paired":
continue
try:
node = FleetNode(
node_id=entry.get("node_id"), alias=entry.get("alias"),
hostname=entry.get("hostname", "unknown"),
transport=entry.get("transport", "unknown"),
capability_profile=entry.get("capability_profile", "unknown"),
online=entry.get("operational_transport_ready") is True,
)
except RegistryError:
continue
registry.register(node)
router = FleetRouter(registry, self._adapter)
except Exception:
raise FleetHubError("FLEET_REFRESH_FAILED") from None
self._snapshot = (registry, router)
return registry.list_nodes()
def read(self, target: str, capability: str, args: dict | None = None) -> RouteResult:
return self._snapshot[1].route(FleetRequest(target, capability, args=args))
def nodes(self) -> tuple[FleetNode, ...]:
return self._snapshot[0].list_nodes()
@@ -0,0 +1,83 @@
"""Register exactly six READ tools on an injected MCP-compatible registrar."""
from __future__ import annotations
from dataclasses import asdict
import json
from .fleet_hub import FleetHub
from .fleet_routing import RouteResult
_ANNOTATIONS = {
"readOnlyHint": True,
"destructiveHint": False,
"idempotentHint": True,
"openWorldHint": False,
}
def _public_data(value: object) -> object:
"""Copy JSON-only data and omit inert context even in nested gateway payloads."""
if value is None or type(value) in (str, bool, int, float):
return value
if type(value) is list:
return [_public_data(item) for item in value]
if type(value) is dict and all(type(key) is str for key in value):
return {key: _public_data(item) for key, item in value.items()
if key != "context_text"}
raise ValueError("FLEET_RESPONSE_INVALID")
def _serializable(value: dict) -> dict:
# Reject nonfinite numbers as well as custom objects; no repr/str fallback.
return json.loads(json.dumps(_public_data(value), allow_nan=False))
def register_fleet_read_tools(mcp, hub: FleetHub) -> None:
def read(node: str, capability: str, args: dict | None = None) -> dict:
try:
hub.refresh()
except Exception:
return {"ok": False, "error": "FLEET_REFRESH_FAILED"}
try:
result = hub.read(node, capability, args=args)
if type(result) is not RouteResult or result.ok is not True:
return {"ok": False, "error": "FLEET_READ_FAILED"}
return _serializable({"ok": True, "node_id": result.node_id,
"capability": result.capability, "data": result.data})
except Exception:
return {"ok": False, "error": "FLEET_READ_FAILED"}
@mcp.tool(annotations=dict(_ANNOTATIONS))
def framebridge_fleet_nodes() -> dict:
"""Refresh and list Fleet nodes with stable identities and readiness."""
try:
hub.refresh()
return _serializable({"ok": True, "nodes": [asdict(node) for node in hub.nodes()]})
except Exception:
return {"ok": False, "error": "FLEET_NODES_FAILED"}
@mcp.tool(annotations=dict(_ANNOTATIONS))
def framebridge_fleet_node_system_status(node: str) -> dict:
"""Read system status for a Fleet node ID or alias."""
return read(node, "system.status")
@mcp.tool(annotations=dict(_ANNOTATIONS))
def framebridge_fleet_node_hardware_summary(node: str) -> dict:
"""Read hardware summary for a Fleet node ID or alias."""
return read(node, "hardware.summary")
@mcp.tool(annotations=dict(_ANNOTATIONS))
def framebridge_fleet_node_storage_inspect(node: str) -> dict:
"""Inspect storage for a Fleet node ID or alias."""
return read(node, "storage.inspect")
@mcp.tool(annotations=dict(_ANNOTATIONS))
def framebridge_fleet_node_network_inspect(node: str) -> dict:
"""Inspect networking for a Fleet node ID or alias."""
return read(node, "network.inspect")
@mcp.tool(annotations=dict(_ANNOTATIONS))
def framebridge_fleet_node_service_status(node: str, service: str) -> dict:
"""Read status of one validated service for a Fleet node ID or alias."""
return read(node, "service.status", {"service": service})
@@ -0,0 +1,77 @@
"""In-memory Fleet registry. Identity is explicit; no discovery or transport I/O."""
from __future__ import annotations
from dataclasses import dataclass, replace
import re
_IDENTIFIER = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:-]{0,127}")
class RegistryError(ValueError):
"""Stable error code only; never includes supplied metadata."""
def _identifier(value: object) -> bool:
return type(value) is str and _IDENTIFIER.fullmatch(value) is not None
@dataclass(frozen=True)
class FleetNode:
node_id: str
alias: str
hostname: str
transport: str
capability_profile: str
online: bool = False
def __post_init__(self) -> None:
if not _identifier(self.node_id) or not _identifier(self.alias):
raise RegistryError("FLEET_IDENTIFIER_INVALID")
for value in (self.hostname, self.transport, self.capability_profile):
if (type(value) is not str or not value or len(value) > 253
or any(ord(char) < 32 or ord(char) == 127 for char in value)):
raise RegistryError("FLEET_METADATA_INVALID")
if type(self.online) is not bool:
raise RegistryError("FLEET_STATE_INVALID")
class FleetRegistry:
"""Case-sensitive identifiers, sorted by node_id; offline unless specified.
Aliases and IDs share one namespace to prevent ambiguous destination lookup.
Metadata cannot grant capabilities. Instances are for synchronous local use.
"""
def __init__(self) -> None:
self._nodes: dict[str, FleetNode] = {}
self._aliases: dict[str, str] = {}
def register(self, node: FleetNode) -> FleetNode:
if type(node) is not FleetNode:
raise RegistryError("FLEET_NODE_INVALID")
if node.node_id in self._nodes:
raise RegistryError("FLEET_DUPLICATE_NODE_ID")
if node.alias in self._aliases:
raise RegistryError("FLEET_DUPLICATE_ALIAS")
if node.node_id in self._aliases or node.alias in self._nodes:
raise RegistryError("FLEET_IDENTIFIER_COLLISION")
self._nodes[node.node_id] = node
self._aliases[node.alias] = node.node_id
return node
def list_nodes(self) -> tuple[FleetNode, ...]:
return tuple(self._nodes[key] for key in sorted(self._nodes))
def resolve(self, target: str) -> FleetNode:
if not _identifier(target):
raise RegistryError("FLEET_IDENTIFIER_INVALID")
node_id = target if target in self._nodes else self._aliases.get(target)
if node_id is None:
raise RegistryError("FLEET_NODE_NOT_FOUND")
return self._nodes[node_id]
def set_online(self, target: str, online: bool) -> FleetNode:
node = replace(self.resolve(target), online=online)
self._nodes[node.node_id] = node
return node
@@ -0,0 +1,131 @@
"""Typed READ dispatch only. The injected adapter is the sole execution boundary.
No default adapter, shell, SSH, sockets, plan engine, or authority from text.
The embedding application must supply a trusted read-only adapter; this module
does not sandbox arbitrary Python callbacks or authenticate remote callers.
"""
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
import re
from types import MappingProxyType
from typing import Callable, Mapping
from .fleet_registry import FleetNode, FleetRegistry, RegistryError
class Operation(Enum):
READ = "READ"
WRITE = "WRITE"
PLAN = "PLAN"
APPLY = "APPLY"
ROLLBACK = "ROLLBACK"
EXEC = "EXEC"
class ReadCapability(Enum):
SYSTEM_STATUS = "system.status"
HARDWARE_SUMMARY = "hardware.summary"
STORAGE_INSPECT = "storage.inspect"
NETWORK_INSPECT = "network.inspect"
SERVICE_STATUS = "service.status"
READ_ALLOWLIST = frozenset(item.value for item in ReadCapability)
_FORBIDDEN_EXEC = frozenset({"framebridge_exec", "shell", "bash", "exec"})
_SERVICE_NAME = re.compile(r"[A-Za-z0-9_.@:-]{1,128}")
def normalize_read_args(capability: ReadCapability, args: object) -> dict[str, str]:
"""Return a fresh, closed-schema dictionary; never interpret supplied text."""
if type(capability) is not ReadCapability:
raise ValueError("FLEET_ARGS_INVALID")
if args is None:
args = {}
if type(args) not in (dict, MappingProxyType):
raise ValueError("FLEET_ARGS_INVALID")
if capability is ReadCapability.SERVICE_STATUS:
if (set(args) != {"service"} or type(args["service"]) is not str
or _SERVICE_NAME.fullmatch(args["service"]) is None):
raise ValueError("FLEET_ARGS_INVALID")
return {"service": args["service"]}
if args:
raise ValueError("FLEET_ARGS_INVALID")
return {}
@dataclass(frozen=True)
class FleetRequest:
target: str
capability: str
operation: Operation = Operation.READ
context_text: str = "" # Inert text; never forwarded to an adapter.
args: Mapping[str, str] | None = None
def __post_init__(self) -> None:
# Snapshot caller dictionaries before dispatch, including read-only views.
# Invalid inputs remain available for the router's fixed error result.
if type(self.args) in (dict, MappingProxyType):
object.__setattr__(self, "args", MappingProxyType(dict(self.args)))
@dataclass(frozen=True)
class ReadRequest:
node_id: str
capability: ReadCapability
operation: Operation = Operation.READ
args: Mapping[str, str] | None = None
def __post_init__(self) -> None:
object.__setattr__(self, "args", MappingProxyType(
normalize_read_args(self.capability, self.args)))
@dataclass(frozen=True)
class RouteResult:
ok: bool
error: str | None = None
node_id: str | None = None
capability: str | None = None
data: object = None
class FleetRouter:
def __init__(self, registry: FleetRegistry,
adapter: Callable[[FleetNode, ReadRequest], object]) -> None:
if not isinstance(registry, FleetRegistry) or not callable(adapter):
raise ValueError("FLEET_ROUTER_CONFIG_INVALID")
self._registry = registry
self._adapter = adapter
def route(self, request: FleetRequest) -> RouteResult:
if type(request) is not FleetRequest:
return RouteResult(False, "FLEET_REQUEST_INVALID")
# Enum identity deliberately rejects strings and foreign enum values.
if request.operation is not Operation.READ:
return RouteResult(False, "FLEET_OPERATION_BLOCKED")
if type(request.capability) is not str or type(request.context_text) is not str:
return RouteResult(False, "FLEET_REQUEST_INVALID")
if request.capability.strip().casefold() in _FORBIDDEN_EXEC:
return RouteResult(False, "FLEET_EXEC_FORBIDDEN")
if request.capability not in READ_ALLOWLIST:
return RouteResult(False, "FLEET_CAPABILITY_NOT_ALLOWED")
try:
args = normalize_read_args(ReadCapability(request.capability), request.args)
except ValueError:
return RouteResult(False, "FLEET_ARGS_INVALID")
try:
node = self._registry.resolve(request.target)
except RegistryError as exc:
return RouteResult(False, str(exc))
if not node.online:
return RouteResult(False, "FLEET_NODE_OFFLINE", node.node_id)
typed = ReadRequest(node.node_id, ReadCapability(request.capability), args=args)
try:
data = self._adapter(node, typed)
except Exception:
return RouteResult(False, "FLEET_ADAPTER_FAILED", node.node_id,
request.capability)
return RouteResult(True, node_id=node.node_id,
capability=request.capability, data=data)