File size: 6,850 Bytes
ca4d83b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""FastMCP server aureon-public. stdio by default, streamable HTTP optional."""

from __future__ import annotations

import argparse
import json
import logging
import os
import sys

from mcp.server.fastmcp import FastMCP

from aureon_public import body, layers, surfaces, tools
from aureon_public.guard_loader import PINNED_COMMIT, apply_space_guard, aureon_source
from aureon_public.text import SERVER_PLAIN

SERVER_INSTRUCTIONS = (
    f"{SERVER_PLAIN} "
    "This server is read-only. It does not place orders, read keys, start circulation, "
    "self-code, self-repair, or write the repository or state/."
)


def refuse_sweep_environment() -> None:
    """AUREON_PUBLIC_SWEEP is not a server mode. Setting it must not start the server."""

    if os.environ.get("AUREON_PUBLIC_SWEEP"):
        raise SystemExit("AUREON_PUBLIC_SWEEP must not be set. The server will not start.")


def enforce_public_pin(source: dict[str, str] | None = None) -> None:
    """Refuse to start when public hosting requires the pinned commit.

    AUREON_PUBLIC_REQUIRE_PIN=1 is unset for local runs. Those runs still
    report aureon_source. Public hosting must set the variable.
    """

    if os.environ.get("AUREON_PUBLIC_REQUIRE_PIN") != "1":
        return
    current = aureon_source() if source is None else source
    if current.get("kind") == "pinned" and current.get("commit") == PINNED_COMMIT:
        return
    raise SystemExit(
        "AUREON_PUBLIC_REQUIRE_PIN=1 requires aureon_source kind pinned "
        f"at {PINNED_COMMIT}. This process would use {current}."
    )


def build_server(host: str = "127.0.0.1", port: int = 8077) -> FastMCP:
    """Register the milestone-1 tools, resources, and prompts."""

    refuse_sweep_environment()
    apply_space_guard()
    source = aureon_source()
    instructions = (
        f"{SERVER_INSTRUCTIONS} "
        f"aureon_source={json.dumps(source, sort_keys=True)}"
    )
    server = FastMCP(
        "aureon-public",
        instructions=instructions,
        host=host,
        port=port,
        streamable_http_path="/mcp",
        # JSON responses and no session. GET /mcp is not a long-lived event
        # stream. The HTTP guard answers that GET with 405 so it cannot hold
        # an in-flight call slot.
        json_response=True,
        stateless_http=True,
    )
    for fn in (
        tools.hnc_reality_step,
        tools.hnc_canonical_read,
        tools.hnc_blend_read,
        tools.lambda_engine_step,
        tools.auris_nodes,
        tools.auris_coherence,
        tools.qgita_analyze,
        tools.organism_replay_read,
        tools.organism_catalog,
        *layers.public_layer_tools(),
        body.body_call,
        body.body_surface,
        body.body_depth,
        body.body_registry,
    ):
        server.tool()(fn)
    server.resource("aureon://packages", mime_type="application/json")(layers.packages_resource)
    server.resource(
        "aureon://hnc/harmonic-reality/defaults",
        mime_type="application/json",
    )(surfaces.harmonic_reality_defaults)
    server.resource(
        "aureon://hnc/lambda-engine/defaults",
        mime_type="application/json",
    )(surfaces.lambda_engine_defaults)
    server.resource(
        "aureon://hnc/params/code-defaults",
        mime_type="application/json",
    )(surfaces.hnc_params_code_defaults)
    server.resource(
        "aureon://auris/nodes",
        mime_type="application/json",
        description=surfaces.auris_nodes_resource.__doc__,
    )(surfaces.auris_nodes_resource)
    server.resource("aureon://organism/seats", mime_type="application/json")(surfaces.organism_seats_resource)
    server.resource("aureon://organism/nodes", mime_type="application/json")(surfaces.organism_nodes_resource)
    server.resource("aureon://organism/systems", mime_type="application/json")(surfaces.organism_systems_resource)
    server.resource("aureon://body/depth", mime_type="application/json")(body.body_depth)
    server.resource("aureon://body/registry", mime_type="application/json")(body.body_registry)
    server.resource("aureon://holds", mime_type="application/json")(surfaces.holds_resource)
    server.resource("aureon://replay/brain", mime_type="application/json")(surfaces.replay_brain_resource)
    server.resource("aureon://replay/qgita", mime_type="application/json")(surfaces.replay_qgita_resource)
    server.resource("aureon://replay/organism", mime_type="application/json")(surfaces.replay_organism_resource)
    server.resource(
        "aureon://replay/auris",
        mime_type="application/json",
        description=surfaces.replay_auris_resource.__doc__,
    )(surfaces.replay_auris_resource)
    for fn in (
        surfaces.explain_two_lambda_implementations,
        surfaces.explain_auris_four_meanings,
        surfaces.explain_qgita_adapter,
        surfaces.explain_organism_replay,
    ):
        server.prompt()(fn)
    return server


def streamable_http_config(app: object, host: str, port: int):
    """Uvicorn config that does not rewrite the client from forwarded headers.

    Uvicorn's default ``proxy_headers`` trusts ``X-Forwarded-For`` from
    127.0.0.1 and replaces ``scope["client"]`` before this process's middleware
    runs. ``proxy_headers=False`` and an empty ``forwarded_allow_ips`` leave
    that header for ``http_guard`` only.
    """

    import uvicorn

    return uvicorn.Config(
        app,
        host=host,
        port=port,
        log_level="warning",
        proxy_headers=False,
        forwarded_allow_ips="",
    )


def serve_streamable_http(server: FastMCP, host: str, port: int) -> None:
    """Listen with the bearer check and the rate, size, and timeout limits."""

    import uvicorn

    from aureon_public.http_guard import PublicHttpMiddleware, load_http_limits

    app = PublicHttpMiddleware(server.streamable_http_app(), load_http_limits())
    uvicorn.Server(streamable_http_config(app, host, port)).run()


def main(argv: list[str] | None = None) -> None:
    """stdio, or streamable HTTP when --transport streamable-http is set."""

    logging.basicConfig(stream=sys.stderr, level=logging.WARNING)
    parser = argparse.ArgumentParser(prog="aureon-public")
    parser.add_argument("--transport", choices=("stdio", "streamable-http"), default="stdio")
    parser.add_argument("--host", default="127.0.0.1")
    parser.add_argument("--port", type=int, default=8077)
    args = parser.parse_args(argv)
    refuse_sweep_environment()
    apply_space_guard()
    enforce_public_pin()
    if args.transport == "stdio":
        build_server().run(transport="stdio")
        return
    from aureon_public.http_guard import resolve_http_bind

    host = resolve_http_bind(args.host)
    server = build_server(host=host, port=args.port)
    serve_streamable_http(server, host, args.port)


if __name__ == "__main__":
    main()