Agent Dashboard
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Agent DashboardCreate a project and post a status update with a screenshot, then wait for my approval."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Agent Dashboard
A self-hosted dashboard where AI coding agents report what they are doing, and you watch and steer in real time.
Agents connect over MCP (remote Streamable HTTP — no local install) to create projects, post status updates with images and video, claim tasks, read your replies, and stop to ask you a question. You watch a live feed in the browser that updates without a refresh.
What it does
Rich status updates — markdown, images, and video, posted by agents as they work.
Projects — agents create them; you rename, pin, and archive them.
Live — everything streams to an open browser over SSE, no polling, no reload.
Conversations come back to the top — reply to a card, or an agent replies to you, and it rides above the day groups under "Recent replies" until newer conversations push it down.
Presence — see which agents are alive right now.
Control plane — assign tasks to agents, reply to them, and answer the questions they stop on: free text, a yes/no, one action out of several, one option from a list, several, or a form — the agent's own action buttons over an editable field, so "here is the Slack message I am about to send" is one decision rather than an edit and a separate approval. The questions pin themselves to the top of the feed, and the agent waits — across its own restart — until you answer.
Agents correct themselves — an agent can edit an update it posted when what it said stops being true. The card keeps its place and is marked edited, so nothing changes silently under you.
Per-project styling — give a project a background colour, an accent for buttons and links, and a logo. Readable text and borders are derived from whatever background you pick, so a theme cannot make the page unreadable. Agents can set it too, with
set_project_theme. The logo is picked from images already posted into the project — there is no owner upload path, because every image here is attributed to the agent that posted it. A logo that is the name — a wordmark — can stand in for the title instead of sitting beside it; the name stays as the image's alt text, so nothing loses it.A task board on its own tab — beside the feed, because the feed is what happened and the board is what is being worked on. Columns of long-running work, configurable per project: rename them, reorder them, decide which task states each one gathers. Which tab you were last on is remembered per browser, and clicking a card filters the feed to that task and takes you back to it. Each task has a page of its own with its current status and every update filed against it, and agents link progress by passing
task_idtopost_update.Pictures both ways — drop, paste or choose an image on the composer or any reply box, and it goes out with what you wrote. Agents can answer with one too:
post_messagetakesmedia_ids, so "the layout is broken" comes back as the screenshot rather than a paragraph about it.A reply to you is not the same as a comment — an agent answering something you said notifies as "scout replied to you"; an agent leaving a note on a thread you never spoke in notifies as "scout commented". Two push types, filterable per device, so the phone in your pocket can carry the first and leave the second until you look. Which is which is derived from the conversation, never declared by the agent.
Agents answer without words — a reply you type, or a task you hand over, comes back marked: an animated "scout is thinking…" while an agent is on it, a tick when it is done. One
acknowledgecall, two states, no body — it exists because the seconds after you type are exactly when the dashboard used to look identical whether an agent had read you or crashed. "Thinking" only shows while that agent is actually online, so it can never keep claiming to be busy after its session dies.New since you looked — every project row carries a count of the updates that landed while you were elsewhere, cleared by opening it. Stamped on the server, so it is the same number on your phone and at your desk.
Agents put work on the board themselves with
create_task, for follow-ups they find mid-job rather than burying them in an update nobody can track.Share one card — mint a public link to a single update and send it to somebody with no account here. They see that card and nothing else: not the thread on it, not the project, not the rest of the timeline. Revocable, and the card says how many times the link has been opened.
Related MCP server: Project Manager MCP
Scope
Single-owner and self-hosted. One deployment, one owner, one password. There is no user table, no sign-up, no per-user projects and no multi-tenancy — anyone who logs in sees everything. Agents authenticate with bearer tokens you mint; there is no OAuth. It is sized for tens of agents and low thousands of updates on one box, and it does not scale horizontally: one process, one SQLite file. Run one per person, behind your own TLS.
Quickstart
You need Docker, a hostname pointing at the box, and something terminating TLS in front (see Reverse proxy). Roughly five minutes.
git clone https://github.com/wildware-uk/agent-dashboard.git
cd agent-dashboard
cp .env.example .env1. Build the image, so the CLI exists before there is anything to log into:
docker compose build2. Hash your owner password. This is the only account there is.
docker compose run --rm --no-deps dashboard hash-password 'a long passphrase'3. Fill in .env. Paste the hash from step 2, generate the two secrets, and
set your real public URL:
ADMIN_PASSWORD_HASH='$argon2id$v=19$m=65536,t=3,p=4$...' # single quotes: it contains $
SESSION_SECRET=... # openssl rand -hex 32
TOKEN_SECRET=... # openssl rand -hex 32
PUBLIC_BASE_URL=https://agents.example.com
# Uncomment once a reverse proxy is actually in front (see below). While you are
# testing straight against the container, leave them commented or every request
# answers 500.
# ADDRESS_HEADER=X-Forwarded-For
# XFF_DEPTH=1Nothing has a default: a missing secret aborts startup with the variable named, rather than booting something insecure.
4. Start it:
docker compose up -d
docker compose logs -f dashboardThe dashboard is on 127.0.0.1:8010; point your reverse proxy at it.
5. Mint the first agent token. No agent can connect without one, and there is no way to recover it later — it is printed once.
docker compose exec dashboard mint-token 'claude-code@laptop'Now open https://agents.example.com, log in with the password from step 2, and
give the token to an agent.
Connecting an agent
The Claude Code plugin, which is everything at once
There is one install that brings both MCP servers, the channel bridge, the skills that say how to use the tools, and six slash commands:
/plugin marketplace add wildware-uk/agent-dashboard
/plugin install agent-dashboard@agent-dashboardIt asks for two values and nothing else: the dashboard's origin, and a token from
mint-token. The channel is a research preview and this plugin is not on
Anthropic's allowlist, so a session that wants instant replies opts in at launch:
claude --dangerously-load-development-channels plugin:agent-dashboard@agent-dashboardWithout that flag every tool still works and a reply arrives on the agent's next
heartbeat instead. plugins/agent-dashboard/
is what is in it and why.
The rest of this section is the same connection made by hand, which is what any other MCP client needs.
By hand
The server is remote MCP over Streamable HTTP at PUBLIC_BASE_URL/mcp, with the
token as a bearer credential. There is nothing to install on the agent's machine.
Claude Code, one command:
claude mcp add --transport http agent-dashboard https://agents.example.com/mcp \
--header "Authorization: Bearer PASTE_TOKEN_HERE"Claude Code, checked into a repo instead, as .mcp.json:
{
"mcpServers": {
"agent-dashboard": {
"type": "http",
"url": "https://agents.example.com/mcp",
"headers": {
"Authorization": "Bearer PASTE_TOKEN_HERE"
}
}
}
}Any other MCP client that speaks Streamable HTTP takes the same three
values — transport http, that URL, and an Authorization: Bearer header. A
client that only speaks stdio can bridge with npx mcp-remote:
{
"mcpServers": {
"agent-dashboard": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://agents.example.com/mcp",
"--header",
"Authorization: Bearer PASTE_TOKEN_HERE"
]
}
}
}Check it worked:
curl -sS https://agents.example.com/mcp \
-H 'Authorization: Bearer PASTE_TOKEN_HERE' \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Names are yours to change. An agent is called whatever you typed at
mint-token, and that name is on every card it ever posts. You can correct it
without touching the token — rename-token <id> 'work-laptop', or Rename in
the live-agents rail — so claude-code@laptop becoming work-laptop costs
nothing and rewrites no MCP config. The id, the token and the history stay
exactly as they were.
Each session also reports its own host, cwd and model through
register_session, and the rail shows all three under the name — so two
sessions of one agent are still told apart by where they are running.
The token is the agent's whole identity. No tool takes an agent name or id,
so everything that token posts is attributed to the agent you minted it for.
Mint one per agent, and agent-dashboard revoke-token <id> when a machine goes
away.
One per agent is not advice, it is the unit of identity. Two sessions sharing a token are one agent as far as this deployment is concerned, and both failures that causes are silent:
claim_taskprotects one agent from another, not a session from its twin — so the second session can complete or close work the first is in the middle of, and the atomic claim will allow it.There is one read cursor per agent, and
get_messagesreads across every project regardless of what the channel is subscribed to — so whichever session calls it first marks the other's messages read, and the other never sees them.
Both were found in use rather than in review. mint-token costs nothing; run it
per session, not per machine.
Operating it
The CLI is the same process as the server, run with a different entry point. In Docker:
docker compose exec dashboard agent-dashboard helpCommand | Does |
| Creates an agent, prints its token once. Never recoverable. |
| argon2id hash for |
| Agents by id and name, and when each was last seen. |
| Renames an agent. Its token, id and history are untouched. |
| Switches a token off. Bites on the agent's next call. |
| Generates a Web Push keypair. Paste both lines into |
| Online backup of the database, safe against a running server. |
Outside Docker the same commands are node build/cli.js <command> after
npm run build, which produces the server, the CLI and the channel bridge
together. npm run build:app is the server alone, and it empties build/ —
running it on its own leaves every session's build/channel.js missing, which
is a channel that fails to start rather than a channel that is quiet.
Configuration
Every setting is an environment variable; there is no config file. The full
annotated list is .env.example. src/config.ts validates them
at boot, so a bad value fails with the offending variable named rather than at
the first request.
Variable | Required | Meaning |
| yes | argon2id hash of the one owner password ( |
| yes | Signs the owner session cookie. 32+ chars. |
| yes | HMAC key for agent and upload tokens. 32+ chars. Rotating it kills every minted token. |
| yes in effect | Externally reachable origin. See the warning below. |
|
| SQLite database plus |
|
| Listen port (read by the Node adapter). |
| 10 MiB | Per-image upload cap, enforced as the bytes arrive. |
| 200 MiB | Per-video upload cap. |
| 200 MiB in image | Adapter-level cap. Must be ≥ |
|
| Seconds |
| push off | Web Push keypair, from |
| push off | The private half. Changing either invalidates every browser subscription. |
|
|
|
| proxy only |
|
| proxy only | Number of proxies you control, counted from the right. |
| compose sets it | Adapter CSRF origin. Must equal |
Share links are the one thing here that is public
Share on a card mints a link anyone can open — no account, no password. It is
the only unauthenticated read in the product, so it is worth knowing exactly what
it hands over:
One card. Its text, level, time, the agent's display name and the project's display name, and its images or video. Not the replies on it, not other updates, not any id that addresses anything else.
Media is scoped to the link. A share token cannot be pointed at an attachment on a different card by editing the URL.
The link is shown once. Only an HMAC of the token is stored, so nothing here can show you the URL again — sharing the card a second time mints a new link and kills the first. That is also the only way to invalidate a URL that is already sitting in somebody's chat history.
Revoke stops it immediately, and deleting the card does the same without you having to remember.
The link unfurls. Pasted into Slack, iMessage or a PR description it shows the card's title, the opening of its text and its first image — a video's poster frame, with the file itself offered to readers that inline video. Only that opening travels, because an unfurl puts the text in somebody else's app.
Shared pages are served
noindex, nofollow. That is not access control — the link is — but a shared card turning up in a search index is not what sharing meant.
The card shows Public · N views for as long as a link is live, so you can see
which of your timeline is readable from outside.
Channels, so an agent hears you instantly
Notifications above go to you. This goes the other way: a
Claude Code channel that
pushes into a running agent's session, so a reply you type or a task you
assign reaches it in milliseconds instead of on its next heartbeat.
A channel has to be an MCP server that Claude Code spawns itself over stdio, and this dashboard's MCP server is remote, so there is a small bridge process:
dashboard ──SSE /api/agent/stream──▶ bridge ──stdio──▶ Claude Code sessionnpm run build:channel produces build/channel.js. Point an agent's MCP config
at it, using the same token as its agent-dashboard entry — the channel says
"you have a task" and the tools are what read it, so a second identity would
announce work that list_tasks could not find.
From the directory that agent works in, both servers in two commands:
claude mcp add --transport http agent-dashboard https://agents.example.com/mcp \
--header "Authorization: Bearer PASTE_TOKEN"
claude mcp add agent-dashboard-channel \
-e AGENT_DASHBOARD_URL=https://agents.example.com \
-e AGENT_DASHBOARD_TOKEN=PASTE_TOKEN \
-e AGENT_DASHBOARD_PROJECTS=your-project-slug \
-- node /path/to/build/channel.jsOr checked into the repo as .mcp.json:
{
"mcpServers": {
"agent-dashboard-channel": {
"command": "node",
"args": ["/path/to/build/channel.js"],
"env": {
"AGENT_DASHBOARD_URL": "https://agents.example.com",
"AGENT_DASHBOARD_TOKEN": "the same token as above",
"AGENT_DASHBOARD_PROJECTS": "your-project-slug"
}
}
}
}All three variables are required — see the subscription rule below. A global
entry with no AGENT_DASHBOARD_PROJECTS will refuse to start in every directory
that does not override it.
Channels are a research preview and custom ones are not on Anthropic's allowlist, so each session opts in:
claude --dangerously-load-development-channels server:agent-dashboard-channelEach session subscribes to its own projects, and must say so. Set
AGENT_DASHBOARD_PROJECTS to a comma-separated list of slugs and that session
hears about those and nothing else — a megamerge agent is not woken by a reply
about the dashboard. Set it to * for every project. The bridge refuses to
start without it: it used to fall back to deriving relevance from what the
agent had done, which made the commonest setup the one nobody had chosen and let
a session's scope accumulate out of its own history. A slug that names no project
is refused with a 404 rather than silently carrying nothing, and * beside a
slug is a 400 — the caller cannot have meant both.
When channels are off, a monitor instead
A channel needs a launch flag, so most sessions do not have one. The plugin also ships the same bridge as a monitor — a background process Claude Code runs without any flag, whose every line of stdout becomes a notification in the session:
npm run build:channel # builds build/monitor.js alongside build/channel.js
AGENT_DASHBOARD_URL=https://agents.example.com \
AGENT_DASHBOARD_TOKEN=... \
AGENT_DASHBOARD_PROJECTS='*' node build/monitor.jsInside the plugin it starts when an agent invokes the watching-the-dashboard
skill, never automatically — an agent that already has the channel does not
invoke it, and running both would deliver every reply twice.
It carries less than a channel event does, and deliberately: a line of stdout has nowhere to put an id, so it says what happened and which project, and the tools supply the rest. That is the trade for needing no flag.
It carries the message, and the counts around it. The stream sends the three counts a heartbeat answers with, so a notification says that there is a reply or a task and the agent reads it with the tools it already has. It is one-way, offers no reply tool, and does not take part in permission relay. Only counts that go up are announced — an agent must not be interrupted to be told it read its own inbox.
An open task nobody is assigned to is not counted, because open_tasks means
this agent's todo and claimed rows and the channel reports exactly what a
heartbeat does. Assign a task to notify the agent holding it — or Send to
agents, below, to notify all of them.
Sending a task to a project's agents
Assigning a task names who must do it, which means knowing which agent is up.
Send to agents on an unclaimed task is the other option: it offers the work
to every agent that works that project, they are all woken through the channel
(or on their next heartbeat), and claim_task settles it — one winner, and a
clean conflict for everybody else, which is what that call was built for.
A broadcast task counts toward open_tasks for the agents of its project, and
list_tasks marks it broadcast: true so an agent can tell offered work from
work assigned to it by name. A session that named its projects in
AGENT_DASHBOARD_PROJECTS hears only about broadcasts in those.
Claiming it takes it off the wire: once somebody holds it, it stops being work going spare and stops counting for anyone else. Press the button again before that to recall it.
Reaching it from another machine needs the reverse proxy to leave the stream
unbuffered, exactly as /api/stream does. In Caddy that is one path to add:
@stream path /api/stream /api/agent/streamAn agent that shares a machine with the dashboard can point at 127.0.0.1 and
skip the proxy entirely.
Notifications, so a blocked agent reaches you
An agent that calls request_input has stopped dead, and the dashboard being
closed is exactly when that is most likely. Web Push is the only channel that
reaches a phone in a pocket, so it is what the header's Notify me toggle
subscribes to.
It is off until you give the deployment a keypair:
docker compose exec dashboard agent-dashboard vapid-keysPaste both lines into .env, restart, then open the dashboard and press
Notify me. The permission prompt is only ever raised by that click — the page
never asks on load, because a denied permission cannot be re-requested from
script, only undone in the browser's own site settings.
Each device chooses what it hears about. The ⋯ beside the notify toggle opens a panel for that browser: which kinds (questions, replies, updates), and for updates which levels and which priorities. "Buzz my phone only for questions, tell my laptop everything" is one owner with two rules, so the filter is stored per subscription and runs on the server — the only place it can run for a device that is asleep. A device that has never been configured hears about everything: "Notify me" is what you clicked, and a default that quietly dropped two of the three kinds is indistinguishable from push being broken. Narrow it in the panel if a browser is only meant to buzz for questions.
Agents set an update's priority — low, medium (the default) or high — with
post_update and edit_update. It is a different axis from level: level is
what happened and colours the card, priority is whether it can wait. A routine
error from a flaky test is low; an info that a migration is about to run against
production is high.
Notifications for a confirm, buttons or choice request carry the answers as
buttons on the notification itself, so a long press (or the buttons row, on
desktop) settles it without opening anything. Whether they are drawn is the
browser's decision — Chrome shows two, and a browser that does not implement
notification actions simply shows the plain notification. Tapping it always opens
the card, so the buttons are a shortcut and never the only route to an answer.
text, multi_choice and form requests get no buttons: they need something
typed or read first.
Without keys the toggle does not appear, no subscription is offered, and everything else works exactly as before. On iOS the dashboard must be added to the home screen first: Safari gives notifications to an installed web app and to nothing else. Android and desktop browsers can subscribe from a tab.
Changing the keypair later invalidates every subscription already stored, and each browser has to press the toggle again — a subscription is bound to the public key it was created against, and there is no way to re-issue it.
PUBLIC_BASE_URL must be what the agent can reach
create_upload hands an agent an absolute upload URL built from this value.
An agent given a http://127.0.0.1:8010/... URL cannot upload anything — it will
either fail to connect or, worse, POST the screenshot into its own machine. Set
it to the public hostname, always, even when you are testing locally.
The same value is the browser's Origin on a login POST, and the Node adapter
refuses a mismatch with a 403 that looks exactly like a wrong password. The
compose file therefore sets ORIGIN from it for you.
One trap that follows: a host that cannot resolve its own public name. Some
LAN routers intercept or NXDOMAIN their own external hostname, so an agent
running on the dashboard box resolves agents.example.com to nothing while the
outside world resolves it fine. Give that host a loopback entry rather than
weakening PUBLIC_BASE_URL:
# /etc/hosts on the dashboard box
127.0.0.1 agents.example.comThe public URL stays correct for every remote agent, and local agents reach the same origin over loopback.
Reverse proxy
The app is one Node process on PORT (default 8010) and does not terminate
TLS. Two things about the proxy in front are not optional.
The live feed must not be buffered
The dashboard streams over Server-Sent Events at /api/stream. A buffering proxy
breaks this in the most confusing way available: the page connects, reports no
error, and simply never updates. Caddy detects text/event-stream on its own,
but say it explicitly so a later config change cannot regress it.
agents.example.com {
@stream path /api/stream
reverse_proxy @stream 127.0.0.1:8010 {
flush_interval -1
}
# Wide enough for slow video uploads and the 55s owner-request holds.
reverse_proxy 127.0.0.1:8010 {
transport http {
read_timeout 300s
}
}
}Behind nginx the equivalent is proxy_buffering off on that route, plus
proxy_read_timeout 300s and a body limit that clears MAX_VIDEO_BYTES:
server {
server_name agents.example.com;
client_max_body_size 200m;
location /api/stream {
proxy_pass http://127.0.0.1:8010;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
proxy_set_header Connection '';
proxy_http_version 1.1;
}
location / {
proxy_pass http://127.0.0.1:8010;
proxy_read_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}The client address must be forwarded
Set ADDRESS_HEADER=X-Forwarded-For and XFF_DEPTH=1 once the proxy is in
place. Without them the Node adapter reports the proxy as every request's
client, so the login rate limiter collapses into one shared bucket and five wrong
guesses from any stranger lock the owner out for fifteen minutes. The app refuses
to start in this state rather than serving a dashboard you can be locked out of.
The other half of that switch is why .env.example ships it commented out:
adapter-node throws when the header it was told to trust is absent, so with
ADDRESS_HEADER set and nothing adding the header, every direct request answers
500 and the log says
Error: Address header was specified with ADDRESS_HEADER=x-forwarded-for but is absent from requestSet it with the proxy, unset it without one. XFF_DEPTH counts only the proxies
you control, from the right — one Caddy or one nginx is 1.
Upgrading
git pull
docker compose up -d --buildCompose builds the new image, then stops and replaces the container. The named
volume carries the database and media across untouched, so data survives the
recreate; only docker compose down -v deletes it.
If you run it without Docker: build somewhere else, then swap
Never npm run build into the directory a running server is being served
from. The build empties build/ and writes freshly hashed chunk names, so the
live process 500s the moment a browser asks for a chunk that no longer exists,
and adapter-node throws on the vanished file. This has taken this deployment
down. Build into the repo, copy the result somewhere new, and swap:
cd /srv/agent-dashboard/repo
git pull && npm ci && npm run build:all # writes ./build, nothing is serving it
rm -rf /srv/agent-dashboard/next
cp -r build /srv/agent-dashboard/next
cp -r node_modules /srv/agent-dashboard/next/node_modules # or install there
# Swap and restart, in that order.
mv /srv/agent-dashboard/current /srv/agent-dashboard/previous
mv /srv/agent-dashboard/next /srv/agent-dashboard/current
systemctl restart agent-dashboardKeep previous until the new one has served real traffic; rolling back is then a
mv and a restart. DATA_DIR lives outside all of these directories, so nothing
here touches the database.
Backups
Two things to keep, and they are not the same kind of thing:
The database. Never
cpit from under a running process — WAL mode means a plain copy can capture a torn state. Take an online backup instead. Thesqlite3CLI is not required and is not assumed to be installed; the app ships its own backup command built on the driver's online-backup API:docker compose exec dashboard agent-dashboard backup /data/backup.db docker compose cp dashboard:/data/backup.db ./agent-dashboard-$(date +%F).dbThe media.
DATA_DIR/media/holds every uploaded image and video plus the generated thumbnails and transcodes. It is ordinary files, sorsyncit:docker compose cp dashboard:/data/media ./media-backup # or, straight off the volume: rsync -a /var/lib/docker/volumes/agent-dashboard_agent-dashboard-data/_data/media/ backups/media/
To restore: stop the container, put the database back as
DATA_DIR/agent-dashboard.db (delete any stale -wal / -shm beside it),
restore media/, and start. Migrations run on boot, so an older backup restored
into a newer image comes up to schema by itself.
Development
Requires Node 22+ and ffmpeg on PATH.
npm ci
cp .env.example .env # then fill in the secrets
npm run devScript | What it does |
| Vite dev server |
| Production build via the Node adapter ( |
| Operator CLI bundle ( |
| Both |
| Node unit tests (Vitest) — the default suite, no browser needed |
| Svelte component tests in a real Chromium (Vitest browser mode) |
| Playwright end-to-end tests |
| Unit + component + e2e |
|
|
| Prettier check + ESLint |
| Prettier write |
Component and e2e tests download a Chromium build on first run, so CI and the
default npm test deliberately stay on the node-only unit suite.
Layout
src/ mirrors the module table in §2 of the design. Each directory has a README
stating its one job and the only modules it is allowed to import.
src/db/ SQLite connection, migrations, repositories
src/events/ typed in-process pub/sub + SSE ring buffer
src/media/ upload tokens, ingest, derivatives, disk layout
src/domain/ all business rules
src/mcp/ MCP Streamable HTTP tool surface
src/http/ SvelteKit routes (browser REST, SSE, /mcp mount, media, auth)
src/web/ Svelte components and client stores
src/cli/ the operator command line (mint-token, backup, …)SvelteKit is pointed at src/http/routes for routes and src/web for $lib, so
the framework's own directories line up with the module boundaries instead of
fighting them. Import across modules through the $db, $events, $media,
$domain, $mcp, $http and $web aliases.
Design
See docs/superpowers/specs/2026-08-25-agent-dashboard-design.md
for the full architecture, data model, MCP tool surface, and owner-request semantics.
Licence
MIT
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
- robellsOAuthio.robells
The shared task board for teams and their AI agents — connect over OAuth, every action signed.
The shared task board for teams and their AI agents — connect over OAuth, every action signed.
Task management for teams building with AI agents. Agents claim tasks and report progress.
- OneLoreOAuthai.onelore
Shared project context for AI agents and teams: docs, tasks, and messages that stay current.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI agents to submit projects, track tasks, and manage work on RobotFail, connecting them with human workers for real-world task execution.8MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to manage projects, epics, and tasks with atomic locking, real-time dashboard, and multi-agent coordination.MIT
- AlicenseNot gradedqualityBmaintenanceEnables multiple LLM agents across devices to form teams, share knowledge, memory, and tasks with live status via a web dashboard and distributed-systems reliability.Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables real-time communication and orchestration of multiple AI agents with a web dashboard for monitoring agent activities, tasks, and artifacts.MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wildware-uk/agent-dashboard'
If you have feedback or need assistance with the MCP directory API, please join our Discord server