Proxy Servers

Use Hyperia as an intermediary or transport bridge for other MCP servers.

New in Hyperia v2.0Hyperia.as_proxy()

A proxy server lets one Hyperia instance stand in front of another MCP server (remote URL, different transport, or even an in‑process Hyperia). The proxy accepts requests from clients, forwards them to the backend, then relays responses—handy for transport conversion, security boundaries, or unified routing.

At a glance

graph TD
    C[Your Client<br>(e.g. Claude Desktop, Stdio)] -->|tools/call| P(Hyperia Proxy)<br/>Stdio
    P -->|tools/call| B(Backend MCP Server)<br/>Streamable‑HTTP or SSE
    B -->|result| P
    P -->|result| C

Why Proxy?

Use Case
Description

Transport Bridging

Expose a remote Streamable‑HTTP or SSE server locally via Stdio so desktop clients work out‑of‑the‑box.

Security Gateway

Keep your production server on a private network; publish only the proxy with auth, rate‑limiting, or logging.

Augmentation Layer

Future: subclass the proxy to cache, rewrite, or watermark responses without touching backend code.

Stable Endpoint

Clients hit one static URI even if the real server location or transport changes later.


Creating a Proxy with Hyperia.as_proxy()

from hyperia import Hyperia, Client

# Easiest: pass any value accepted by Client(...)
proxy = Hyperia.as_proxy(
    "backend_server.py",   # could be URL, config dict, or Hyperia instance
    name="MyProxyServer",
)

# Custom client first
backend = Client("https://api.example.com/mcp/sse")
proxy2 = Hyperia.as_proxy(backend, name="CustomClientProxy")

What happens under the hood

  1. Hyperia spins up a Client to the backend.

  2. It discovers all tools, resources, templates, and prompts.

  3. It auto‑generates local “proxy” counterparts that forward calls.

  4. It returns a fully‑fledged Hyperia server you can run via any transport.

Current proxying covers the major MCP objects. Advanced features (notifications, sampling relay) are roadmap items.


Transport Bridging Example

Convert a remote Streamable‑HTTP endpoint to local Stdio for an IDE:

from hyperia import Hyperia

proxy = Hyperia.as_proxy(
    "https://weather.example.com/mcp",  # backend URL
    name="Weather Bridge",
)

if __name__ == "__main__":
    proxy.run()   # defaults to stdio transport

Your LLM tool (Cursor, Claude Desktop, etc.) can now connect to the proxy via stdio while the proxy talks HTTP under the hood.


In‑Memory Proxying

Wrap an existing Hyperia server to tweak settings without touching backend code.

from hyperia import Hyperia

backend = Hyperia("Original")

@backend.tool()
def ping(): return "pong"

proxy = Hyperia.as_proxy(backend, name="WrapperProxy")

Calls to proxy forward instantly to backend in the same process—useful for adding duplicate‑name handling, CORS, etc.


Configuration‑Based Proxies (v2.3.6+)

Supply an MCPConfig‑style dict:

from hyperia import Hyperia

cfg = {
    "mcpServers": {
        "default": {
            "url": "https://example.com/mcp",
            "transport": "streamable-http",
        }
    }
}
proxy = Hyperia.as_proxy(cfg, name="ConfigProxy")

Composite Proxy (multi‑backend)

cfg = {
    "mcpServers": {
        "weather": {
            "url": "https://weather-api.example.com/mcp",
            "transport": "streamable-http",
        },
        "calendar": {
            "url": "https://calendar-api.example.com/mcp",
            "transport": "streamable-http",
        },
    }
}
proxy = Hyperia.as_proxy(cfg, name="Composite")

Tools/resources are auto‑prefixed (weather_get_forecast, calendar_add_event, etc.).

Spec note MCPConfig is evolving; field names may change as the standard matures.


Internals: HyperiaProxy

Hyperia.as_proxy() builds an instance of HyperiaProxy under the hood. You normally don’t need to touch it, but advanced users can subclass:

from hyperia.proxy import HyperiaProxy

class CachingProxy(HyperiaProxy):
    async def call_tool(self, name, args):
        cache_key = (name, tuple(args.items()))
        if cache_key in self._cache:
            return self._cache[cache_key]
        result = await super().call_tool(name, args)
        self._cache[cache_key] = result
        return result

Limitations & Roadmap

  • Sampling relay: proxies currently forward tools/resources; relaying ctx.sample() calls is under development.

  • Notifications: backend push notifications are not yet surfaced through proxies.

  • Auth & Policy hooks: coming extensions for request rewriting and auth injection.

Last updated