> Documentation index: [/llms.txt](/llms.txt). Every page as one file: [/llms-full.txt](/llms-full.txt).

# Example: a findings inbox for agents

Example: a findings inbox for agents [#example-a-findings-inbox-for-agents]

Build **Risk Radar**, an app with its own database that agents report findings into, then connect an agent, a second app and an outside job to it. Every step uses one of the paths in [Connect agents and apps](overview).

```text
Risk Scout (agent) ──MCP──▶ Risk Radar (app) ──runs as the viewer──▶ default agent (triage)
Ops Wallboard (app) ──MCP via the platform──▶ Risk Radar
External job ──signed webhook──▶ Risk Radar
```

1\. Build the app [#1-build-the-app]

In a new App Builder chat:

```text
Build me an app called "Risk Radar": an inbox of security findings that AI agents report
into and my team triages. It owns its data in SQLite: findings(id, external_id unique,
title, severity critical|high|medium|low, source, summary, url, status new|triaged|resolved,
triage_note, created_at).
Routes: GET /api/findings and GET /api/stats; PATCH /api/findings/{id} to set status;
POST /api/findings/{id}/triage, which asks the default platform agent for a 2-3 sentence
triage note with AloAgentsClient and the request's app identity, saves it and sets
status=triaged.
Webhook POST /api/hooks/findings following Standard Webhooks, reading webhook_id,
webhook_timestamp and webhook_signature from the query string, secret RADAR_WEBHOOK_SECRET,
401 on a bad signature or a timestamp more than 5 minutes off, idempotent on webhook_id.
MCP server at /mcp with the official mcp SDK (FastMCP, stateless_http=True,
json_response=True), tools report_finding(title, severity, summary, url) and
list_findings(status=None); accept the token from the `token` query parameter, compared in
constant time with RADAR_MCP_TOKEN; construct FastMCP with
TransportSecuritySettings(enable_dns_rebinding_protection=False). Read secrets at request
time from os.environ, falling back to /home/user/.alo/app_env.json.
UI: a dark dashboard with severity counters, a findings table, a detail panel with a
"Triage with Alo" button, refreshing every 10 seconds. No demo data.
```

2\. Make it reachable [#2-make-it-reachable]

1. In the app's settings, add the secrets `RADAR_MCP_TOKEN` and `RADAR_WEBHOOK_SECRET`.
2. Set its visibility to **Public**.
3. Add an MCP connection named `Risk Radar (app)` with URL `https://<app_id>.<apps domain>/mcp/mcp?token=…`. The platform lists its two tools.

3\. Create an agent that reports into it [#3-create-an-agent-that-reports-into-it]

In an Agent Builder chat:

```text
Create and publish a workspace agent called "Risk Scout". On each run it researches new
critical or high security issues from the last 7 days for Python/FastAPI, Next.js,
PostgreSQL and Keycloak with web search. It uses the MCP connection "Risk Radar (app)":
first list_findings to skip anything already reported, then report_finding for each new
item, at most 5 per run. Attach that connection to the agent.
```

Then, in a chat with Risk Scout: `Report a high finding into Risk Radar: "Keycloak admin console reachable from the internet on staging". Check list_findings first.` The row appears in Risk Radar on its next refresh.

4\. Triage from the app [#4-triage-from-the-app]

Open a finding in Risk Radar and click **Triage with Alo**. The app's backend runs the default agent as you; the note is saved on the finding and its status becomes `triaged`. A visitor who is not signed in cannot run it.

5\. Read it from a second app [#5-read-it-from-a-second-app]

In a new App Builder chat:

```text
Build "Ops Wallboard": a dark wallboard that shows Risk Radar's findings. Read them
through the MCP connection "Risk Radar (app)" with list_findings, as the person viewing
the wallboard. Add a "Report incident" form whose backend calls report_finding on the same
connection. Refresh every 15 seconds. No demo data.
```

An incident reported on the wallboard appears in Risk Radar.

6\. Post from an outside job [#6-post-from-an-outside-job]

Sign and send an event as in [Send events to an app](webhooks-into-apps). Sending the same `webhook_id` again creates no second row; a wrong signature gets `401`.

What each step used [#what-each-step-used]

| Step | Path                           | Page                                         |
| ---- | ------------------------------ | -------------------------------------------- |
| 3    | Agent → app over MCP           | [Let an agent use an app](agent-uses-app)    |
| 4    | App → agent, as the viewer     | [Call an agent from an app](app-calls-agent) |
| 5    | App → app through the platform | [Connect two apps](app-to-app)               |
| 6    | Outside system → app           | [Send events to an app](webhooks-into-apps)  |
