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:

Method
Call
Behaviour
Updates
Use‑case

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

Mode
as_proxy flag
Lifecycle
When to use

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+)

Format
Example
Notes

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