Neuron / architecture & delivery plan

Custom tools.
Interfaces they bring with them.

Add MCP Apps support once, then build charts, editors, forms, and other custom tools as ordinary MCP servers. Their interfaces should work in Neuron without adding a React component, tool-name mapping, or private Neuron API for each app.

Proposed · ready for review11 September 2026Source snapshot c69d2863Planning only · no product changes

01 / The product contract

A standard app should be enough

A tool author registers a standard MCP server, links a tool to its HTML resource, and uses the MCP Apps browser SDK inside that HTML. Neuron discovers the interface, renders it beside the tool result, and routes its actions back to the same server.

Acceptance test: connect a second, unrelated MCP App and use it without changing or rebuilding Neuron.

Neuron owns the host

Discovery, transport, rendering, theme, lifecycle, permissions, and conversation integration. Implement these once for every app.

The tool owns its interface

Layout, domain logic, interactive state, tool schemas, and durable application data. React is optional; no Neuron package is required.

Recommended first release: a complete Codex-backed path in web and desktop, using MCP Apps rather than a custom Markdown convention. Additional providers reuse the same host and get explicit capability status. Legacy MCP-UI variants, ChatGPT-only APIs, a marketplace, and migration of Neuron's existing whiteboards are outside this release.

The standard separates the MCP server, host, and embedded view. That is the portability boundary this plan adopts. Official overview

02 / Verified in the checkout

The missing part is the host

What existsWhat it means for this work
MCP timeline outputMessagesTimeline.tsx displays call details as JSON/text. ActivityPayloadProjection.ts reduces results to summarized text. It cannot supply a complete app payload today. Source A
Codex RPC definitionsThe generated client defines mcpServerStatus/list, mcpServer/resource/read, and mcpServer/tool/call. Tool definitions and resource reads retain metadata; direct calls include structured results. No Neuron runtime usage of the latter two was found. Source B
Provider abstractionProviderAdapter has no generic app transport capability. Existing adapters already attach Neuron's own MCP server in provider-specific ways. Source C
Built-in rich UIMarkdown blocks use trusted bundled components, and whiteboards have a dedicated service. Keep those working; neither is a registry for external MCP Apps. Source D
Shared client & typed RPCWeb and desktop can share the host controller through packages/client-runtime, with new Effect Schema contracts and the existing environment RPC path. Source E

Protocol definitions are not a runtime proof. Before building the UI, verify the installed Codex version actually supports these methods, exposes app-only tools to the host, preserves UI metadata, and negotiates MCP Apps with the server. This investigation did not start a provider session or run an app.

03 / Recommended architecture

One host, a narrow provider boundary

Use the official @modelcontextprotocol/ext-apps host bridge for the iframe protocol. Wrap it with Neuron's environment-aware RPC and a small server service that resolves the originating tool invocation. The browser never needs an MCP server credential.

Custom MCP serverStandard tools, HTML resources, app data, and backend operations.
Existing MCP connection, including its authentication and session
Provider transport → Neuron app serviceCatalog, resource reads, direct calls, invocation identity, and durable receipts.
Authenticated Neuron RPC through the owning environment
Shared app controller + chat presentationAppBridge handlers, lazy payload loading, visible status, and conversation actions.
Standard MCP Apps messages through an isolated sandbox proxy
The app's HTML viewTool input/results arrive here. User interactions call the app's server.

Start with the connection Codex already owns

Expose optional catalog/read/call operations behind ProviderAdapter and implement them in CodexSessionRuntime. Always use the mapped provider thread ID. Scope server names to that provider instance and session. Reuse its authenticated MCP connection instead of starting a second connection that may have different session state.

The host bridge can be constructed without a browser-side MCP client and supplied with explicit handlers. Those handlers call Neuron RPC; the server resolves the permitted backend. Keep SDK-specific types at this boundary and use Effect Schema for Neuron contracts. Pin a released SDK and its matching protocol/reference implementation in phase 0. AppBridge API

If a provider cannot expose a complete connection

The fallback is a Neuron-managed MCP gateway, selected per connection. It owns one upstream connection, presents model-visible tools to the provider, and serves UI resource reads and app-visible tools to the host. It records calls before the provider can strip their metadata. This keeps tool authors on standard MCP.

Do not build that gateway speculatively alongside a working native path. Phase 0 selects the transport for the first release. If native Codex cannot meet the interoperability contract, the gateway becomes a required dependency. Future providers may use it without changing the renderer. Never run native and gateway execution for the same tool call.

A real sandbox in every connection mode

The web host requires an intermediate sandbox proxy on a different origin. Treat that as a delivery dependency, including for Electron's shared web renderer. Use a self-hosted static sandbox endpoint with no Neuron API credentials; enforce resource CSP and verify the sender window and negotiated message channel. Do not reuse the ordinary HTML file preview as the app host. Sandbox requirements

Phase 0 must prove origin delivery for local use, direct network access, and SSH. Prefer a dedicated sandbox listener whose client-reachable URL is supplied by connection setup; direct HTTPS needs matching TLS/reverse-proxy routing, and SSH needs a forwarded sandbox endpoint. A different port alone does not isolate cookies. The sandbox must ignore credentials and serve no privileged routes. Do not bake localhost into client bundles or require a cloud relay.

04 / What a tool author does

Build the app outside Neuron

  1. Create a standard MCP server. Use a supported stdio or Streamable HTTP configuration through the selected provider. Connection setup is configuration, not an application integration.
  2. Declare the view. Link the tool's metadata to a ui:// resource and return HTML with MIME type text/html;profile=mcp-app. Bundle dependencies or declare required external domains.
  3. Return useful data. Provide a text fallback, structured results for the interface, and private-to-the-view result metadata where appropriate. No special tool names are required.
  4. Implement interactions using the standard App SDK. Receive tool results and call server tools for refresh, save, or other actions. Store durable domain state on the app's server.
  5. Connect and test. Ask the agent to invoke the tool. Neuron opens its generic app card. Update the app resource during development and reload the view without rebuilding Neuron.
{
  "name": "inspect_inventory",
  "_meta": {
    "ui": {
      "resourceUri": "ui://inventory/editor.html",
      "visibility": ["model", "app"]
    }
  }
}

Illustrative metadata fragment, not a complete tool definition. A companion save tool may use visibility: ["app"]. The official authoring quickstart supplies the server/resource/view pattern; the implementation should deliver a small standalone example with no Neuron imports.

First-release setup uses the provider's existing server configuration. Add an MCP Apps section under Settings → Integrations for availability, enabled state, and reload/status. A provider-independent server installer and secret manager are separate work unless the gateway is required.

05 / The initial support contract

Interactive, with explicit limits

Only advertise capabilities whose behavior is implemented. Use negotiated SDK capability fields; unsupported methods return protocol errors. Do not claim compatibility merely because an iframe loads.

CapabilityProposed first-release behavior
Discovery & renderRead tool metadata, resolve its resource on the same connection, validate MIME type, and handle HTML in text or base64 resource content. Honor resource metadata. Use standard metadata helpers, including only the legacy alias supported by the pinned SDK.
Initialization & resultsWait for the initialized signal before delivering input and results. Handle success, tool error, cancellation, and teardown. Complete arguments are required; partial input streaming can follow later.
Tool & resource actionsProxy calls and reads through the originating server connection. Enforce model/app tool visibility. Return complete results to the requesting view; a refresh must not start an agent turn.
Theme & sizeSend standard theme tokens, locale, timezone, container dimensions, and host context updates. Respect requested size within the chat layout. Support inline and fullscreen, with a clear return to inline.
Conversation messagesHandle ui/message through a visible, thread-scoped confirmation before starting a user turn. Preserve an existing composer draft. Report acceptance only after dispatch succeeds; decline or cancellation must not masquerade as delivery.
Model contextHandle ui/update-model-context as bounded, replaceable context attached to the app instance. Include the latest version in the next user turn, never silently restart the agent. Show that context is attached and allow clearing it.
Links & logsOpen supported external links through the existing client opener. Keep app logs in local diagnostics with payload redaction and size limits.
Permissions & approvalsApply resource CSP and granted permissions. Preserve backend tool authorization; a click is not blanket permission. Bind pending approvals to their app operation, including when no agent turn is active.
Deferred capabilitiesPicture-in-picture, sampling, generalized elicitation forms, resource subscriptions, file download extensions, and camera/microphone/geolocation access. If an app requires one, show the limitation instead of broad compatibility claims.

Method names and lifecycle follow the MCP Apps specification. The specific UX and release limits above are Neuron proposals. Network permissions use resource-level _meta.ui.csp; declaring a domain does not itself solve CORS. Stable custom app origins remain a documented compatibility limit until implemented. CSP and CORS guide

06 / State that survives a chat session

Retain results; don't replay work

Introduce a durable generic app record tied to an environment, project, thread, provider instance, server connection, and original tool invocation. Keep its small descriptor in the thread projection; load the full payload only when the card opens. Avoid sending every app's HTML and structured data in every thread snapshot.

Data boundaryProposed responsibility
Durable app recordStable app/invocation IDs, server identity, original arguments, result reference, resource URI, resource hash, and lifecycle status. Retain full UI payload before timeline summarization, including view-only metadata. Keep it out of model context unless intentionally selected.
Resource storageSnapshot HTML plus relevant CSP/permission metadata on first load, with a content hash. Scope caches to environment, connection, and authorization identity. Explicit development reload fetches a new version; do not silently run new code against an old result.
Transient viewIframe, bridge requests, focus, and unsaved client-only input. Unmount with teardown. App authors save durable edits through their server; iframe memory is not durable state.
App operationsRecord UI-initiated calls with their own request ID, source app, status, and receipt. Correlate any provider echo so one action appears once. Retry transport delivery with the same ID; never blindly retry an uncertain mutation.
Conversation contextStore the latest explicit context update per app under an agreed size limit and revision. Clear it on user request or app removal. Send it through the existing turn-start path, separately from view-only metadata.

Use event sourcing for durable changes. Commands record app operations and lifecycle changes; queue-backed workers execute provider I/O and emit receipts. Pure deciders and projectors stay free of network calls. Read-only resource fetches belong in the app service. Define the minimum schema migration needed for references and retained payloads; keep HTML out of activity JSON.

Available→Loading→Interactive→Suspended / closed→Reopened

Reopening or scrolling a card into view must never repeat the original tool call. Resume from saved input and result. Historical cards open paused, with no automatic server actions until the user resumes the app. An unavailable server leaves the text result readable and reports that interactions are disconnected.

Closing a view releases its bridge; disabling a server blocks new actions immediately. Clear app context independently of closing the card, with a visible indicator for retained context. Thread deletion removes its app records and unreferenced resources. Reconnecting one client must not revive a revoked app session or rerun another client's action.

Document that app side effects, like other external MCP tool effects, are outside Neuron's Git checkpoint restore. Shared app state and concurrent edit conflicts belong to the app server. Neuron prevents duplicate delivery of a known request; it cannot promise exactly-once external effects after an ambiguous upstream failure.

07 / Every supported surface

Tool portability and provider coverage are separate

ProviderDecision and evidence
CodexFirst implementation target. Generated catalog/read/call methods exist. Runtime support, visibility filtering, approval behavior, and post-turn calls must pass phase 0 before enabling Apps.
ClaudeOwn-tool MCP injection is present. No generic app read/call contract is currently exposed by Neuron. Initially show ordinary tool output; add native transport if proven complete, otherwise use the managed gateway.
CursorACP session creation passes MCP servers. That alone does not provide an app host transport. Initially text-only; qualify a native path or gateway using the same conformance fixture.
GrokMCP server injection exists. Initially text-only; use the same transport qualification and shared renderer.
OpenCodeNeuron adds its MCP server for locally managed OpenCode instances. External instances skip that attachment today. Initially text-only; do not assume a gateway can be installed on an external server.
AntigravityACP session configuration includes MCP servers. Initially text-only until a complete transport is qualified. Reuse the generic host when enabled.

These are implementation targets, not claims that each provider lacks native MCP Apps features. Only Neuron's current adapter boundary was inspected. A provider badge should distinguish supported, unavailable, and incompatible runtime versions.

Entry points and reverse actions

Chat cards open/close and retry rendering. Settings enables/disables Apps and shows connection status. Command palette and any keybinding use those same actions. Fullscreen returns to the original card with focus restored.

Clients and environments

Web and desktop share the controller and UI. Sandbox frames get no Electron preload or IPC. Every request targets the card's environment, including direct network, SSH, multiple open windows, and multiple devices.

08 / Dependency order

Prove the boundary, then build the experience

Owners below name implementation roles, not assigned people. Each phase ends with evidence needed by the next. No product implementation or provider configuration changes are authorized by this planning document.

0

Prove transport and sandbox feasibility

Owner: provider/runtime maintainer. Build a disposable standard MCP App fixture outside the worktree, with a model-visible launch tool, an app-only action, a model-only tool, and a stateful server session. Pin the SDK release. Check capability negotiation, catalog metadata, resource reads, full results, app-only access, approval/cancel behavior, and tool calls after the agent turn ends. Determine the actual supported runtime version.

Choose and test a reachable sandbox origin for each connection mode. Verify the native path does not leak app-only tools to the agent or drop view-only metadata. If it fails, select the managed gateway and scope its catalog filtering, session ownership, authentication, and invocation correlation before continuing.

Exit: recorded pass/fail evidence, one selected transport, a protocol/version support statement, and an origin strategy. No assumption that generated schemas prove runtime support.

1

Add the generic service and durable contract

Owner: backend/contracts maintainer. Add optional provider app transport, typed RPC, authorization, app records, payload retention, and operation receipts. Read the repository's Effect guidance before implementation. Extract result payloads before activity projection; attach a generic descriptor rather than a tool-specific marker.

Exit: focused tests prove correct environment/session routing, visibility enforcement, lossless permitted UI payload delivery, duplicate handling, disconnect behavior, and replay without repeating calls.

2

Render one app through the shared host

Owner: client/runtime maintainer. Add the generic app card and AppBridge controller, isolated sandbox delivery, lazy resource loading, input/result/error handling, theme, resize, fullscreen, and teardown. Keep the current text result accessible.

Exit: an official example renders through the real provider connection. The same host bundle works in web and desktop. Closing, reopening, theme changes, and failed resources preserve the conversation.

3

Complete interactions and conversation feedback

Owner: full-stack maintainer. Route app tool calls and resource reads through the selected transport. Add scoped approvals, visible message confirmation, bounded model-context updates, settings, and developer resource reload. Persist operation outcomes without manufacturing agent turns.

Exit: a standalone inventory editor can refresh and save through its app-only tool, then send selected context to the agent. Reload and two-client scenarios do not repeat writes.

4

Prove portability and release the supported slice

Owner: integrating maintainer. Connect an unrelated app written against the same standard. Run the targeted acceptance matrix and, once explicitly authorized, one integrated real-client pass. Ship a reusable external example plus concise setup/limitations guidance. Record unsupported provider states visibly.

Exit: two unrelated apps work with zero app-specific Neuron changes; all claimed client/connection modes pass. Then enable Codex Apps by default for compatible runtimes, with a setting to return to ordinary tool output.

Later provider work: qualify one adapter at a time against the same fixture. Implement a managed gateway only when it is needed for a selected provider. General server management, OAuth setup, legacy APIs, and additional display modes get separate scope.

09 / What must be demonstrated

Test interoperability, not component wiring

  1. Unmodified external apps. Run an official SDK example and a separate custom app with different UI and data. Neither imports Neuron code or appears in a host registry.
  2. Real action round trip. Change data in a view and observe the server's persisted state. App-only tools stay absent from the agent catalog; model-only tools reject UI calls.
  3. Complete payload handling. Preserve nested structured results, resource metadata, and view-only result metadata even when text output is summarized. Test the size boundary with a clear fallback; never silently truncate a UI payload into invalid data.
  4. Session continuity. The original call and UI actions reach the same logical server session. Reopen after turn completion, reconnect after a server restart, and inspect history with the server unavailable.
  5. Safe recovery. Test initial errors, denial, cancellation, late provider notifications, lost responses, repeated click delivery, resource changes, and two concurrent clients. Uncertain mutations require reconciliation, not an automatic retry.
  6. Conversation semantics. Context updates replace the previous app context and enter the next turn only. Confirmed messages target the right thread and preserve drafts. Clearing context and disabling Apps take effect immediately.
  7. Client and origin matrix. Verify web and Electron over local, direct network, and SSH connections. Include narrow layouts, keyboard focus, fullscreen exit, inaccessible app content, and the text fallback.
  8. Isolation and performance. A test app cannot access the host DOM, session data, Electron IPC, or another app's server. Enforce CSP and request bounds. Long transcripts do not mount every iframe or continuously repaint idle apps.

Run focused backend tests, affected lint/type checks, and receipt-based async tests. Avoid repo-wide checks and sleep-based synchronization. Browser and desktop checks are a future implementation gate requiring explicit permission; this plan itself receives static verification only.

Documentation and rollout

Add a concise user guide for connecting an app, using its interface, and handling unsupported capabilities. Keep the portable author example outside Neuron-specific UI code. Add one short internal decision record only for the chosen transport, sandbox origin, and replay constraints that cross components. Keep this plan outside the repository.

Roll out behind an Apps setting, qualified by runtime capabilities. Disabling it tears down active frames and blocks new UI calls while preserving text history. Do not auto-execute old cards when the feature is first enabled.

10 / Decisions and evidence

Defaults are clear; technical unknowns have gates

DecisionStatus
Standard MCP AppsRecommended. One host implementation, portable external servers, no per-tool renderer.
Codex firstPlanning assumption. It offers the clearest checked-in RPC path. Wider initial provider coverage would expand the first release.
Native connection firstConditional recommendation. Phase 0 must prove complete metadata, capability negotiation, visibility, and action support. Use the gateway if it cannot.
Sandbox endpointEngineering decision before phase 1. Establish reachable isolated origins and packaging for all claimed modes. Never ship a localhost-only workaround as network support.
Version and payload limitsEngineering decision in phase 0/1. Pin compatible released SDK/runtime versions and document concrete HTML, result, context, and request limits from fixture measurements.
General server managerDeferred unless gateway is required. Existing provider configuration is sufficient for initial tool authoring. It must not become a demand to write Neuron-specific tool code.

Repository evidence

Source paths are relative to the Neuron checkout at the revision above. They are listed for implementation navigation; this public document does not require access to a hosted repository.

  1. A · Rendering and projection.apps/web/src/components/chat/MessagesTimeline.tsx:3084apps/server/src/orchestration/ActivityPayloadProjection.ts:240Existing MCP expansion and result summarization; generic app payload retention must precede this boundary.
  2. B · Codex protocol and runtime.packages/effect-codex-app-server/src/_generated/meta.gen.ts:67packages/effect-codex-app-server/src/_generated/schema.gen.ts:39094packages/effect-codex-app-server/src/_generated/schema.gen.ts:39170apps/server/src/provider/Layers/CodexSessionRuntime.ts:2065Read/call schema availability and existing limited elicitation handling. Generated files are evidence, not manual edit targets.
  3. C · Provider boundary and connection attachment.apps/server/src/provider/Services/ProviderAdapter.tsapps/server/src/mcp/McpProviderSession.tsapps/server/src/provider/Layers/{Codex,Claude,Cursor,Grok,OpenCode,Antigravity}Adapter.tsapps/server/src/mcp/McpSessionRegistry.tsExisting own-tool attachment is useful transport evidence, not a generic external app service.
  4. D · Existing UI ownership.apps/web/src/blocks/registry.tsdocs/internals/blocks.mdapps/web/src/components/settings/IntegrationsSettings.tsxTrusted block registration and the current integrations settings entry point.
  5. E · Shared RPC and server composition.packages/contracts/src/rpc.tspackages/client-runtime/src/rpc/client.tsapps/server/src/auth/RpcAuthorization.tsapps/server/src/server.tsUse these boundaries for new typed app operations and environment authorization.

Public implementation references

References checked 11 September 2026. Official documentation and repository main can move independently; phase 0 pins a consistent released SDK and protocol baseline rather than mixing examples across versions.