# Hono

> The page's route in Hono, for Node.js, Bun, Deno or Cloudflare Workers: AG-UI runs go on to MorphScreen with your key and the events stream back.

```sh
npm install hono @hono/node-server
```

Hono returns web `Response` objects, so MorphScreen's stream goes back to the page as it is, with no piping.

```js
// The page's route in Hono: each AG-UI run goes on to MorphScreen with your
// key, and the events stream straight back. Shown on Node.js; on Bun, Deno or
// Cloudflare Workers, export the app instead of calling serve.
import { serve } from "@hono/node-server";
import { Hono } from "hono";

const API = process.env.MORPHSCREEN_API ?? "https://api.morphscreen.com/v1";
const MODEL = process.env.MODEL ?? "deepseek/deepseek-v4.1-flash";

const app = new Hono();

app.post("/api/agent", async (c) => {
  const run = await c.req.json();
  run.forwardedProps = { ...run.forwardedProps, model: MODEL };
  const upstream = await fetch(`${API}/ui`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "X-MorphScreen-Key": process.env.MORPHSCREEN_KEY },
    body: JSON.stringify(run),
    // The reader leaving stops the call too.
    signal: c.req.raw.signal,
  });
  return new Response(upstream.body, { status: upstream.status, headers: { "Content-Type": upstream.headers.get("content-type") ?? "text/event-stream" } });
});

serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000) });
```

## Other runtimes

The route is the same everywhere; only the start and where the key comes from change:

- **Bun and Deno:** drop `serve` and `export default app`.
- **Cloudflare Workers:** `export default app`, and read the key from the binding, `c.env.MORPHSCREEN_KEY`, since Workers have no `process.env`. Put it in with `wrangler secret put MORPHSCREEN_KEY`.

## A chat UI of your own

For your own chat UI, add a second route that sends `{ model, stream: true, messages }` to `/v1/chat/completions` and returns `upstream.body` the same way. The [Express page](/docs/integrations/express) has both routes side by side.

We run this file in CI on Node.js against a recorded answer: a page with `connectAgent` draws the answer through it.
