mirror of
https://github.com/hansjone/netx.git
synced 2026-10-17 23:13:26 +08:00
MCP: serve tools from the API process over Streamable HTTP at /mcp
- netx_api/mcp_remote: ops / topology / bizMonitor tools, Bearer auth, per-tool RBAC filtering, ?groups= filter, readOnlyHint and group meta. - Mount the official MCP Streamable HTTP app at /mcp (stateless); AuthAuditMiddleware is pure ASGI and skips /mcp. - Let uvicorn chunk MCP responses; some Windows LSPs rewrite Content-Length replies on */mcp* paths into broken chunked framing. - NETX_MCP_ALLOWED_HOSTS opts into DNS-rebinding checks (off by default so LAN and reverse-proxy hosts work; Bearer is the gate). - Remove the three stdio Python MCP packages; tests moved to /mcp, including real-TCP framing regressions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
918ece86c3
commit
52679a7cfc
150 changed files with 2367 additions and 2812 deletions
87
netx_api/mcp_remote/topology/layout_ops/sides.py
Normal file
87
netx_api/mcp_remote/topology/layout_ops/sides.py
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
"""Atomic op: place side-branch NEs on both sides of spine."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from netx_api.mcp_remote.topology.layout_ops.graph_util import spine_backbone
|
||||
from netx_api.mcp_remote.topology.layout_ops.state import LayoutParams, LayoutState, OpResult
|
||||
|
||||
|
||||
def place_side_branches(
|
||||
state: LayoutState, params: LayoutParams | None = None
|
||||
) -> OpResult:
|
||||
"""X-gain + lane push for non-pinned / off-spine access nodes."""
|
||||
params = params or LayoutParams()
|
||||
st = state.copy()
|
||||
pos = dict(st.positions)
|
||||
if not pos:
|
||||
return OpResult(state=st, moved=set(), op="place_side_branches", note="empty")
|
||||
|
||||
# Amplify X about global center (borrow left/right).
|
||||
xs = [pos[n][0] for n in pos]
|
||||
cx = sum(xs) / len(xs)
|
||||
pos = {n: (cx + (x - cx) * params.x_gain, y) for n, (x, y) in pos.items()}
|
||||
moved = set(pos.keys())
|
||||
|
||||
ens = [n for n in pos if st.layers.get(n) == "access"]
|
||||
if ens:
|
||||
if st.spine:
|
||||
spine = spine_backbone([n for n in ens if n in st.spine], st.adj, st.names)
|
||||
if len(spine) < 2:
|
||||
spine = spine_backbone(ens, st.adj, st.names)
|
||||
else:
|
||||
spine = spine_backbone(ens, st.adj, st.names)
|
||||
spine_set = set(spine)
|
||||
st.spine = spine_set
|
||||
tang: dict[str, tuple[float, float]] = {}
|
||||
for i, n in enumerate(spine):
|
||||
if i + 1 < len(spine):
|
||||
x0, y0 = pos[n]
|
||||
x1, y1 = pos[spine[i + 1]]
|
||||
elif i > 0:
|
||||
x1, y1 = pos[n]
|
||||
x0, y0 = pos[spine[i - 1]]
|
||||
else:
|
||||
tang[n] = (1.0, 0.0)
|
||||
continue
|
||||
dx, dy = x1 - x0, y1 - y0
|
||||
L = math.hypot(dx, dy) or 1.0
|
||||
tang[n] = (dx / L, dy / L)
|
||||
|
||||
for n in ens:
|
||||
if n in spine_set or n in st.pinned:
|
||||
continue
|
||||
sx, sy = pos[n]
|
||||
nearest = min(
|
||||
spine, key=lambda s: math.hypot(pos[s][0] - sx, pos[s][1] - sy)
|
||||
)
|
||||
tx, ty = tang.get(nearest, (1.0, 0.0))
|
||||
nx, ny = -ty, tx
|
||||
px, py = pos[nearest]
|
||||
cross = tx * (sy - py) - ty * (sx - px)
|
||||
sign = 1.0 if cross >= 0 else -1.0
|
||||
cur = math.hypot(sx - px, sy - py)
|
||||
target = max(params.lane, cur)
|
||||
if cur < 1e-6:
|
||||
pos[n] = (px + nx * sign * target, py + ny * sign * target)
|
||||
elif cur < target:
|
||||
sc = target / cur
|
||||
pos[n] = (px + (sx - px) * sc, py + (sy - py) * sc)
|
||||
|
||||
# Pin skeleton after sides placed
|
||||
pin = {
|
||||
n
|
||||
for n in pos
|
||||
if st.layers.get(n) in ("agg", "core") or n in st.spine
|
||||
}
|
||||
st.positions = pos
|
||||
st.pinned = pin
|
||||
st.last_moved = moved - pin
|
||||
return OpResult(
|
||||
state=st,
|
||||
moved=st.last_moved,
|
||||
op="place_side_branches",
|
||||
params={"x_gain": params.x_gain, "lane": params.lane, "pinned_n": len(pin)},
|
||||
note="side lanes from spine; pinned=agg+core+spine",
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue