Server Config
Combine multiple Hyperia servers into a single application via importing (static) or mounting (dynamic).
New in Hyperia v2.2 — modular composition APIs
As your project grows you may split tools, resources, or prompts into logical modules—e.g. WeatherServer
, DBServer
, CalendarServer
. Hyperia lets you stitch those modules together in two ways:
Importing
await main.import_server(prefix, sub)
One‑time copy (static)
Not reflected
Bundle finalised components into a monolith
Mounting
main.mount(prefix, sub, as_proxy=False)
Live delegation (dynamic)
Instantly reflected
Runtime composition, microservices style
You can also mount proxy servers created with Hyperia.as_proxy()
, which is handy for remote or multi‑transport backends.
1. Importing (Static)
Copies every component from subserver into main with a prefix to avoid collisions.
import asyncio
from hyperia import Hyperia
# --- Sub‑server ---
weather = Hyperia("Weather")
@weather.tool()
def forecast(city: str):
return {"city": city, "forecast": "Sunny"}
@weather.resource("data://cities/supported")
def cities():
return ["London", "Paris", "Tokyo"]
# --- Main server ---
main = Hyperia("MainApp")
async def setup():
await main.import_server("weather", weather)
if __name__ == "__main__":
asyncio.run(setup())
main.run()
Resulting IDs:
Tool →
weather_forecast
Resource →
data://weather/cities/supported
Internals
Tools/prompts get name
prefix_
+ original.Resources/templates rewrite URI path as
protocol://prefix/...
(default path prefix format).One‑time copy—later edits to
weather
are not propagated.
2. Mounting (Dynamic)
Creates a live link; requests are routed to the subserver at runtime.
from hyperia import Hyperia, Client
import asyncio
dynamic = Hyperia("Dyn")
@dynamic.tool()
def first():
return "One"
main = Hyperia("MainLive")
main.mount("dyn", dynamic) # direct mount
@dynamic.tool()
def later():
return "Two" # appears automatically in main
async def demo():
async with Client(main) as c:
print(await c.call_tool("dyn_later")) # → "Two"
if __name__ == "__main__":
asyncio.run(demo())
Direct vs Proxy Mount
Direct (default)
False
No client lifecycle on subserver; method calls in‑process
Simple composition, same Python process
Proxy
True
Full client connect/disconnect on subserver; communication via in‑mem Client transport
Need lifespan hooks, auth, or you’re mounting a proxy instance
Note: If the sub‑server defines a custom lifespan handler, Hyperia automatically switches to proxy mounting.
main.mount("api", api_server, as_proxy=True) # force proxy mode
Mounting a server returned by Hyperia.as_proxy()
always uses proxy mode.
Resource Prefix Formats (v2.4+)
Path (default)
resource://weather/data/info
Prefix inserted after protocol; avoids URI‑scheme issues.
Protocol (legacy)
weather+resource://data/info
Earlier default (<2.4); underscores not allowed in schemes.
Configure:
import hyperia
hyperia.settings.settings.resource_prefix_format = "protocol" # global
srv = Hyperia("Legacy", resource_prefix_format="protocol") # per‑server
Env var: HYPERIA_RESOURCE_PREFIX_FORMAT=protocol
.
Interaction with Proxies
remote = Hyperia.as_proxy("https://api.example.com/mcp")
main.mount("remote", remote) # proxy mount, live
Tools become remote_<name>
, resources resource://remote/...
etc.
Summary
Import = freeze‑dry a subserver into the main app.
Mount = route requests live, with optional proxy lifecycle.
Prefix collisions controlled via
on_duplicate_*
settings discussed earlier.
Last updated