What a Dashboard is
A dashboard is a curated set of MCP Apps that admins assign to people or teams. After sign-in, it appears under Dashboard in each member’s desktop sidebar. Each tile is an MCP App from one of the organization’s Connectors. OpenWork renders the tile as real, interactive UI; what a member does inside it is not sent to the model. When the feature is enabled for the organization, Dashboards appear in the OpenWork Cloud admin sidebar under Manage → Dashboards.Create and share a dashboard (admin)
1
Connect the MCP server
In OpenWork Cloud, open Connectors, click Add connector, paste the Server URL (for example,
https://mcp.example.com/mcp), and choose Authentication and Account mode: Individual accounts or Org account. Use Test tools to confirm the server responds. Only connectors that expose at least one MCP App can be added to a dashboard.2
Create the dashboard
Open Dashboards, click New dashboard, enter a Name such as
Support overview, then click Create dashboard.3
Add apps
Click Add app, pick an MCP, choose one of its Apps, and click Add. MCPs without Apps are hidden. If the app’s tool requires input, fill Launch input (JSON). Reorder or remove apps from the list.
4
Decide how each app runs
Apps run on request by default: the member clicks Run. Turn on Run automatically to run an app on dashboard load and refresh. This also applies to tools that modify data, so enable it only for apps you trust.
5
Share it
In Access, turn on Everyone in the organization, or leave it off and add specific people and teams. Members see the dashboard the next time they open OpenWork.
What members see
The desktop sidebar shows Dashboard, with one section per assigned dashboard labeled Managed by your organization. Tiles have one of these badges:- Organization auto-run
- Run on request
- Run once to enable
Build an MCP App widget
MCP Apps are a standard extension of MCP (io.modelcontextprotocol/ui). An app is an ordinary MCP server with a tool that points to a UI resource and that resource served as HTML. OpenWork supports the subset below, not every optional feature of the specification. Apps must check the host’s advertised capabilities. The ext-apps repository provides the SDK and examples.
Supported host protocol
The shared chat and dashboard renderer uses the stable 2026-01-26 protocol withext-apps 1.7.5:
- After initialization, the host sends complete
ui/notifications/tool-inputarguments beforeui/notifications/tool-result. Result delivery retainscontent,structuredContent,_meta, and the optionalisErrorflag, including explicitfalse. - Writable Apps advertise
serverToolsandopenLinks. Tool calls retain the originating endpoint, workspace, session, engine (when supplied), and live launch lease through approval and dispatch. Link requests require an active writable view, use the host’s HTTP(S)-only opener, and report failures. - Only
inlinedisplay is available. Validui/request-display-moderequests return the currentinlinemode, including requests for fullscreen or picture-in-picture; they do not change the layout. - Size notifications adjust the inline height within host limits. Unmount retains the existing bounded
ui/resource-teardownhandshake and bridge close. - Message/context writes, View-provided tools, and resource proxy requests are not supported by this renderer. Unsupported requests receive protocol errors, not successful empty responses. There is no full progress or cancellation forwarding.
Closing or replacing a view disables its pending actions and releases its owned lease. Dashboard endpoint removal also retires that endpoint’s lease. A restored cached view cannot reuse the previous lease, and the server revalidates launch ownership before dispatching tools.
Chat views mount from completed, preserved results; dashboard tiles render successful or saved results. A cancelled in-flight launch therefore has no mounted recipient for
ui/notifications/tool-cancelled. Cancelling another operation or unmounting an already completed result does not invent a cancellation notification. Early mounting and streaming launch input are not implemented. Dashboard launch failures retain the existing error or saved-result presentation rather than mounting an actionable failed launch.
Provider data and gateway additions
ProviderstructuredContent is left unchanged, including fields named serverTools or schemaGuidance. OpenWork gateway additions use reserved _meta keys: openwork/mcpApp for the launch binding, openwork/serverTools for gateway tool names, and openwork/schemaGuidance for advisory schema warnings. Apps should read gateway tool names from result._meta["openwork/serverTools"], not from provider structuredContent.serverTools.
Schema guidance is also appended as a separate text content block under openwork/schemaGuidance so the model can use it without seeing private result _meta. Warnings do not invalidate a provider success or justify repeating a successful call. Gateway-generated error payloads may still include schemaGuidance; those payloads are not provider structured data.
Requirements OpenWork checks
- The tool’s
_meta.ui.resourceUriis a string starting withui://. - If
_meta.ui.visibilityis set, it includes"app". resources/readfor that URI returns exactly one content item withmimeTypetext/html;profile=mcp-app, at most 768 KiB.- Optional
_meta.ui.cspon the resource supportsconnectDomains,resourceDomains,frameDomains, andbaseUriDomains: HTTPS origins only, up to 16 each.permissionsanddomainare not supported; OpenWork rejects a resource containing either. - The server is reachable over HTTP(S) as a remote Streamable HTTP MCP server. Local stdio servers cannot be dashboard apps.
- Mark read-only tools with
annotations: { readOnlyHint: true }. Tools without it, or withdestructiveHint: true, are treated as modifying data and run only on request unless an admin enables auto-run. - The dashboard picker uses
title, orannotations.title, as the tile name. It shows a Launch input field wheninputSchema.requiredis non-empty.
Example: a Team budget widget
Install@modelcontextprotocol/sdk, @modelcontextprotocol/ext-apps, and express, then create these two files.
1
Create the MCP server
server.ts
2
Create the view
Bundle this file with Vite so it resolves the package import, or serve the import through an ESM CDN.
view.html
3
Add it to OpenWork
Run the server on a public HTTPS URL, or use a tunnel for testing, then follow the admin steps above. You can test it in chat first: ask the agent to call
get_budget, and the tile renders inline.Tips
- Keep the resource self-contained. If it loads remote assets, declare their origins in
_meta.ui.csp. - Return shared result data in
structuredContentand readable fallback text incontent. Treat both as model-visible; put view-only data in result_meta. - One tool can drive one view. Ship several tools for several widgets.