Overview
Design + scope only (human decision 2026-07-21). Captures the auth model,
tier-2 transport plan, tier-3 hosting sketch, and the Richard/PyAutoMCP
coordination for making the read-only results-inspector MCP server reachable
remotely. No code is written and no network surface is built here. The build
is gated on demonstrated demand + a security-review pass and must never
auto-ship. Follows the passed local-stdio acceptance gate (#17) and the shipped
launcher hardening (#18).
Why design-only now
The prompt gates this as "only pursue once demonstrated demand exists — if it
earns it." Local stdio (tier 1) is shipped and acceptance-passed; there is no
demonstrated demand for remote access yet, and standing up an unauthenticated
file-reading network surface on spec is the wrong risk. Prior-art coordination
with Richard is also a prerequisite. So: design the security + transport now,
build later only if it earns it.
Security model — the core; build this FIRST when built
The read-only tools (list_searches/get_*/fetch_image) resolve arbitrary
absolute directories on the host. Local stdio is safe (only the local user's
client spawns it). A tunneled/hosted server is a remote, **unauthenticated file-read
- directory-enumeration surface** unless all of the following are designed in:
- Authentication before any tool dispatch.
- Tier 2 (personal/prototype): static bearer token —
Authorization: Bearer <secret>
validated by ASGI middleware wrapping the streamable-http app; secret from env
(PYAUTO_MCP_TOKEN), never committed; reject unauthenticated requests with 401
at the transport layer, before MCP dispatch.
- Tier 3 (hosted/shared): OAuth2/OIDC (the MCP HTTP spec supports OAuth) or an
auth gateway; per-user identity; short-lived tokens.
- Path confinement (defense in depth, both tiers). An env allowlist of roots
(PYAUTO_MCP_ALLOWED_ROOTS); every tool Path.resolve()s its directory arg and
rejects anything not under an allowed root — blocks ../ traversal and absolute-path
escape even for an authenticated caller. Tier 3: per-user root scoping.
- Transport hardening. Bind
127.0.0.1; expose only via the tunnel (cloudflared/
ngrok) or a TLS ingress; never bind 0.0.0.0 without auth+TLS; rate-limit; audit-log
every tool call (who / which dir / when) for tier 3.
- Keep the read-only invariant. No writes, no compute/fit tools on a remote surface
(contrast PyAutoMCP below) — the smaller the remote surface, the smaller the risk.
Tier 2 — remote via tunnel (transport plan)
- Add an opt-in run mode to
server.py (both assistants): a CLI/env flag
(PYAUTO_MCP_HTTP=1 / python -m autoassistant.mcp --http) that calls
mcp.run(transport="streamable-http", host="127.0.0.1", port=…) instead of stdio.
Default stays stdio — no accidental network exposure. (Installed mcp FastMCP
supports streamable-http — verified.)
- Wrap the FastMCP ASGI app (
mcp.streamable_http_app()) with the bearer-auth +
path-allowlist middleware before serving.
- cloudflared/ngrok recipe (quick tunnel to test; named tunnel for stability); the
tunnel HTTPS URL is the connector endpoint pasted into claude.ai (custom connector)
/ ChatGPT (developer mode).
- Docs: a
remote section in {af,al}_inspect_results_mcp.md marking the token +
allowlist as mandatory — never run the tunnel without them.
- Effort: medium; MUST pass
security-review before any PR.
Tier 3 — hosted (sketch, gated on demand)
Deploy next to shared collaboration outputs (Euclid sample-scale triage). Auth =
OAuth/OIDC + per-user output scoping; TLS at ingress; audit log; rate limits; async +
aggregator-load caching for scale. Natural consumer: rhayes777/aggregator-agent
(pydantic-ai vision triage of lens-modelling output) — a tier-3 client, not part of
this server. This is "the substance"; do not detail-scope until demand + a hosting
target are chosen.
Coordinate with Richard (rhayes777/PyAutoMCP)
PyAutoMCP (automcp: aggregate/compute/optimisation/visualise/resources/
schema/pydantic_wrapper) is a parallel, broader MCP — it exposes compute +
optimisation (fitting), which our read-only server deliberately does not. Neither has a
remote transport/auth layer today (code search: 0 matches). Decision to make with
Richard before building remote: converge on one server with profiles (a read-only
"inspect" profile = ours + a "compute" profile = his, sharing one transport/auth layer),
or keep two and share only the auth/tunnel recipe. For the read-only remote profile,
drop the optimise/compute surface.
Hard gates
- Build only once demonstrated demand exists.
- MUST run the
security-review skill on the branch before any PR.
- NEVER auto-ship — human-required. The intake classifier mis-sized this small/safe;
it is a network-facing file-read surface.
Original Prompt
Click to expand starting prompt
draft/feature/autofit_assistant/remote_mcp_deployment_tiers.md — build remote-MCP
tiers 2 (tunnel) + 3 (hosted) for the results-inspector server. Scope = transport +
deployment + auth, NOT new tools. human-required + security-review; only pursue once
demonstrated demand exists.
Overview
Design + scope only (human decision 2026-07-21). Captures the auth model,
tier-2 transport plan, tier-3 hosting sketch, and the Richard/PyAutoMCP
coordination for making the read-only results-inspector MCP server reachable
remotely. No code is written and no network surface is built here. The build
is gated on demonstrated demand + a
security-reviewpass and must neverauto-ship. Follows the passed local-stdio acceptance gate (#17) and the shipped
launcher hardening (#18).
Why design-only now
The prompt gates this as "only pursue once demonstrated demand exists — if it
earns it." Local stdio (tier 1) is shipped and acceptance-passed; there is no
demonstrated demand for remote access yet, and standing up an unauthenticated
file-reading network surface on spec is the wrong risk. Prior-art coordination
with Richard is also a prerequisite. So: design the security + transport now,
build later only if it earns it.
Security model — the core; build this FIRST when built
The read-only tools (
list_searches/get_*/fetch_image) resolve arbitraryabsolute directories on the host. Local stdio is safe (only the local user's
client spawns it). A tunneled/hosted server is a remote, **unauthenticated file-read
Authorization: Bearer <secret>validated by ASGI middleware wrapping the streamable-http app; secret from env
(
PYAUTO_MCP_TOKEN), never committed; reject unauthenticated requests with 401at the transport layer, before MCP dispatch.
auth gateway; per-user identity; short-lived tokens.
(
PYAUTO_MCP_ALLOWED_ROOTS); every toolPath.resolve()s itsdirectoryarg andrejects anything not under an allowed root — blocks
../traversal and absolute-pathescape even for an authenticated caller. Tier 3: per-user root scoping.
127.0.0.1; expose only via the tunnel (cloudflared/ngrok) or a TLS ingress; never bind
0.0.0.0without auth+TLS; rate-limit; audit-logevery tool call (who / which dir / when) for tier 3.
(contrast PyAutoMCP below) — the smaller the remote surface, the smaller the risk.
Tier 2 — remote via tunnel (transport plan)
server.py(both assistants): a CLI/env flag(
PYAUTO_MCP_HTTP=1/python -m autoassistant.mcp --http) that callsmcp.run(transport="streamable-http", host="127.0.0.1", port=…)instead of stdio.Default stays stdio — no accidental network exposure. (Installed
mcpFastMCPsupports
streamable-http— verified.)mcp.streamable_http_app()) with the bearer-auth +path-allowlist middleware before serving.
tunnel HTTPS URL is the connector endpoint pasted into claude.ai (custom connector)
/ ChatGPT (developer mode).
remotesection in{af,al}_inspect_results_mcp.mdmarking the token +allowlist as mandatory — never run the tunnel without them.
security-reviewbefore any PR.Tier 3 — hosted (sketch, gated on demand)
Deploy next to shared collaboration outputs (Euclid sample-scale triage). Auth =
OAuth/OIDC + per-user output scoping; TLS at ingress; audit log; rate limits; async +
aggregator-load caching for scale. Natural consumer:
rhayes777/aggregator-agent(pydantic-ai vision triage of lens-modelling output) — a tier-3 client, not part of
this server. This is "the substance"; do not detail-scope until demand + a hosting
target are chosen.
Coordinate with Richard (rhayes777/PyAutoMCP)
PyAutoMCP(automcp:aggregate/compute/optimisation/visualise/resources/schema/pydantic_wrapper) is a parallel, broader MCP — it exposes compute +optimisation (fitting), which our read-only server deliberately does not. Neither has a
remote transport/auth layer today (code search: 0 matches). Decision to make with
Richard before building remote: converge on one server with profiles (a read-only
"inspect" profile = ours + a "compute" profile = his, sharing one transport/auth layer),
or keep two and share only the auth/tunnel recipe. For the read-only remote profile,
drop the optimise/compute surface.
Hard gates
security-reviewskill on the branch before any PR.it is a network-facing file-read surface.
Original Prompt
Click to expand starting prompt
draft/feature/autofit_assistant/remote_mcp_deployment_tiers.md — build remote-MCP
tiers 2 (tunnel) + 3 (hosted) for the results-inspector server. Scope = transport +
deployment + auth, NOT new tools. human-required + security-review; only pursue once
demonstrated demand exists.