Skip to content

MCP App selection

When a Hadron account is a member of 2 or more Apps, MCP sessions that authenticate as the user (OAuth hdr_user_… tokens) must choose which App is the active scope for the session. Two MCP tools handle this:

Both tools are always present in tools/list for any authenticated MCP session, regardless of whether the caller has 0, 1, or many Apps. For single-App callers they're effectively no-ops (Hadron's single-App default already resolves the App at session open). For multi-App callers they're how you select.

App-Key callers (server-to-server, hdr_app_… tokens) carry their App identity in the credential itself and don't need these tools. The tools return helpful messages in that case rather than silently doing nothing.

h-list-apps

Enumerate the Hadron Apps the caller can access. Callable any time the MCP session is authenticated, including before any selection has been made.

Parameters

None.

Return shape

A bulleted Markdown list, one App per line:

3 accessible apps:

- **hrn:app:acme-corp::mealplan** — Acme Mealplan (role: owner)
- **hrn:app:mentor-co::juno** — Mentor Co Juno (role: principal)
- **hrn:app:client-co::juno** — Client Co Juno (role: principal)

Order is deterministic — App.createdAt ascending. Each row shows the App's canonical URN, display name, and the caller's AppMember.role on it.

Special cases

  • No accessible Apps. Returns:
    No accessible apps. Ask an App owner to add you, or visit the
    Hadron portal to create one.
    
  • Exactly one accessible App. Returns the single-row list plus a helpful tail noting that h-set-active-app isn't required (the App is the implicit default).
  • App-Key caller. Returns the single App the key is scoped to, labeled (via App Key).

Filtering

Apps are filtered to active membership only:

  • App.deletedAt IS NULL — soft-deleted Apps are hidden.
  • App.uninstalledAt IS NULL — soft-uninstalled Apps are hidden.
  • AppMember row must exist for the caller (no orphaned access).

A user who was once a member but had their AppMember row removed will not see that App in the list.

h-set-active-app

Pin a Hadron App as the active scope for the rest of the MCP session. Subsequent App-scoped tool calls (h-list-memories, h-find-nodes, h-add-node, etc.) resolve to this App until the session ends or the tool is called again with a different identifier.

Parameters

Name Type Required Description
app string yes Canonical App URN (e.g. hrn:app:acme-corp::mealplan) or a display name that matches exactly one accessible App. Trimmed; case-insensitive on the short-form path.

Identifier resolution

The tool accepts two forms:

  1. Canonical URN — preferred form. Either bare (acme-corp:mealplan) or prefixed (hrn:app:acme-corp::mealplan). Matched against App.urn directly; lookup includes the lifecycle filter (soft-deleted / soft-uninstalled Apps are reported as app_unavailable).
  2. Short form — App display name, case-insensitive, with surrounding whitespace trimmed. Matched against the caller's accessible Apps' display names (the same set h-list-apps returns). If exactly one matches, resolved. If two or more match (e.g. two orgs both have an App named Juno), returns the typed error [app_identifier_ambiguous] with the URN candidates so the caller can disambiguate.

The matcher does not do slug-style normalization (no lowercase-and-dash). Pass the URN if your input has unusual punctuation or whitespace.

Behavior on success

  • Writes the selection into the in-memory per-session map keyed by the MCP transport sessionId.
  • Returns a success message naming the URN + display name.
  • A subsequent invocation replaces the selection atomically — the next App-scoped tool call sees the new App.

The selection lifecycle is per-session: when the MCP transport closes (Claude Desktop disconnects the connector, the session is DELETEd, the server restarts), the selection is cleared. A new session starts unselected.

Error envelopes

All errors are returned as MCP tool-error envelopes ({ isError: true, content: [{ type: 'text', text: '[<code>] …' }] }) — not as HTTP errors. The [<code>] prefix carries the machine-readable code.

Code When Recovery
app_identifier_ambiguous Short form matches 2+ accessible Apps. Retry with the URN form. The error message lists the matching URN candidates.
app_not_found URN or short form matches zero accessible Apps. Use h-list-apps to see available Apps. May indicate the user isn't an AppMember of the named App.
app_unavailable The matched App is soft-deleted or soft-uninstalled. Ask the App owner to reinstall, or pick a different App.
app_member_revoked Caller's AppMember row was removed (rare race; mostly surfaces in mid-session revocation handling for App-scoped tool calls, not at selection time). Use h-list-apps to see your current accessible set.

On any error, the previously-active selection (if any) is unchanged — a failed h-set-active-app call doesn't clear what you already had.

Tool error vocabulary (for strict-list tools after the new regimes)

Per spec 026 D-2026-05-21-003, tools split into two classes:

  • Advisory tools (h-list-memories, h-find-nodes, h-list-nodes, h-read-next-node, and all URN-input tools like h-read-node, h-update-node, h-add-node, etc.) — work without an active App. When no App is selected, h-list-memories returns the un-narrowed set across every accessible App; URN-input tools use the URN's embedded App identity. App identity is a focusing concern, not access control (constitution Article V — Zero-Trust Apps).
  • Strict tools — a narrow set that genuinely needs App context to function and has no per-resource URN to fall back on: h-start-session, h-end-session, all h-chat-* tools, and any h-run-action whose action declares App-scope. These return a tool error when no App is active.

When a strict tool runs without an active selection, the server returns one of these tool errors:

Code When
no_active_app The session has already engaged with the selection surface (called h-list-apps or h-set-active-app, OR sent a directory-aware initialize parameter) but no active App is set. The message names h-list-apps + h-set-active-app as the recovery path.
multiple_apps_resolved FR-016 fall-through. The session has NOT engaged with the new selection surface (legacy client behavior). Carries the literal multiple_apps_resolved token in the [<code>] prefix verbatim so production-log greps continue to match (SC-003 adoption signal). The message text starts with User has more than one Hadron App; this MCP client does not support App selection. Recovery is the same as no_active_app.

The split exists so production-log telemetry can distinguish "un-engaged client" (FR-016 fall-through) from "engaged client but caller skipped selection" (new code). Both surfaces are valid recovery paths.