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:
hadron_list_apps— enumerate accessible Apps.hadron_set_active_app— pin one for the session.
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.
hadron_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:
- Exactly one accessible App. Returns the single-row list plus a
helpful tail noting that
hadron_set_active_appisn'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.AppMemberrow 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.
hadron_set_active_app¶
Pin a Hadron App as the active scope for the rest of the MCP session.
Subsequent App-scoped tool calls (hadron_list_memories, hadron_find_nodes,
hadron_create_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:
- Canonical URN — preferred form. Either bare
(
acme-corp:mealplan) or prefixed (hrn:app:acme-corp:mealplan). Matched againstApp.urndirectly; lookup includes the lifecycle filter (soft-deleted / soft-uninstalled Apps are reported asapp_unavailable). - Short form — App display name, case-insensitive, with
surrounding whitespace trimmed. Matched against the caller's
accessible Apps' display names (the same set
hadron_list_appsreturns). If exactly one matches, resolved. If two or more match (e.g. two orgs both have an App namedJuno), 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 hadron_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 hadron_list_apps to see your current accessible set. |
On any error, the previously-active selection (if any) is unchanged
— a failed hadron_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 (
hadron_list_memories,hadron_find_nodes,hadron_list_nodes,hadron_get_next_node, and all URN-input tools likehadron_get_node,hadron_update_node,hadron_create_node, etc.) — work without an active App. When no App is selected,hadron_list_memoriesreturns 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:
hadron_start_session,hadron_end_session, allhadron_chat_*tools, and anyhadron_run_actionwhose 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 hadron_list_apps or hadron_set_active_app, OR sent a directory-aware initialize parameter) but no active App is set. The message names hadron_list_apps + hadron_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.
Related¶
- Install Hadron in Claude Desktop — the how-to that uses these tools.
- Add Hadron to Claude Code (OAuth)
— the OAuth flow and
hdr_user_*credential these tools assume. - URN composition — the URN shape
App.urntakes.