Skip to main content

Profiles & Tool Routing

A profile is a named bundle of installed MCP servers, owned by a user, exposed as one streamable-HTTP MCP endpoint with its own bearer token (design decision #11):

/mcp/p/<slug>

Instead of configuring every MCP client with every server, you point each client (Claude Code, Cursor, ...) at one profile endpoint and manage the server bundle centrally — in the dashboard or via the REST API.

The model

PropertyDetail
Slug^[a-z0-9][a-z0-9-]{1,62}$, unique, forms the endpoint path
Name1–128 characters, display only
OwnerThe creating user; admins can see and manage all profiles
ServersReplace-all list; every name must be an installed server
Tokengig_-prefixed bearer token, plaintext shown exactly once

Profiles are per-user, but credentials are shared across a user's profiles: when the egress proxy resolves a sandbox's identity to a profile, the credential lookup uses the profile owner's user ID — one stored key serves all of that user's profiles. See egress proxy and vault.

Connecting a client

Create a profile (dashboard or POST /api/profiles), copy the token from the one-time reveal, then:

claude mcp add --transport http my-profile http://localhost:8080/mcp/p/<slug> \
--header "Authorization: Bearer gig_..."

Authentication is per-request: the gateway hashes the presented bearer token and looks up (slug, token hash) in the database on every request. A rotated or deleted token is rejected immediately. Streamable HTTP uses POST, GET, and DELETE on the same URL, so the route is method-agnostic.

The legacy aggregated endpoint (/mcp, authenticated by GIG_BEARER_TOKEN) still works alongside profile endpoints — see authentication.

Runtime lifecycle: lazy spawn per profile

Profile runtimes are lazy. Nothing runs until the first authorized request hits /mcp/p/<slug>; the gateway then:

  1. Loads the profile's server bundle.
  2. Spawns one sandboxed instance of each server with the tenant set to the profile ID — shared code/image, never shared process (design decision #5). Each sandbox gets its own network namespace and /30, so the egress proxy can attribute every outbound call to (server, user, profile).
  3. Builds an aggregator over the spawned backends and caches the runtime; later requests reuse it.

Concurrent cold-start requests for the same profile coalesce into a single spawn; a slow spawn of one profile never blocks warm requests to another. If a spawn fails the error is not cached — the next request retries.

:::note Known limitation Idle reaping is not implemented yet: once spawned, a profile's sandboxes stay up until invalidated or the gateway shuts down. The sandbox count is bounded by profiles × servers. :::

Invalidation

Editing a profile's bundle or deleting the profile invalidates its runtime: the sandboxes are torn down and the next request respawns the bundle lazily. In-flight requests against a torn-down runtime fail with a transport error and must reconnect (re-auth + respawn) — invalidation is a rare, operator-triggered event, not a hot path.

Token rotation does not invalidate the runtime. New requests must present the new token (per-request check), but an already-established MCP stream continues until the client disconnects. Hard revocation is a bundle edit or profile deletion.

If a server is uninstalled but still referenced by a profile, the spawn skips it with a log line rather than failing the whole profile — the profile stays usable with its remaining servers.

Tool routing

The gateway aggregates every backend's tools into one MCP server, re-exposing each tool as:

<server>_<tool>

For example, the bundled echo server's echo tool appears as echo_echo. Because _ is the namespace separator, backend names must not contain _, and duplicate backend names are rejected.

Default tool subsets

Registry manifests mark each tool default: true/false. When a profile spawns a manifest-installed server, only the default: true tools are exposed — installs surface a curated subset rather than everything the server offers. Servers without a manifest (the legacy GIG_ECHO_BIN fallback) expose all tools.

A per-profile meta-tools mode (search/load tools on demand) is designed as an opt-in flag but is not implemented yet.

Managing profiles via the API

All endpoints require a control-plane session (see authentication); non-owners get 404 for foreign profiles unless they are admins.

OperationEndpointNotes
ListGET /api/profilesOwn profiles; admins see all
CreatePOST /api/profiles {name, slug}Response includes the token plaintext once
DetailGET /api/profiles/{id}Includes endpoint and servers; never the token
RenamePATCH /api/profiles/{id} {name}
Set bundlePUT /api/profiles/{id}/servers {servers: []}Replace-all; unknown names are 400; invalidates the runtime
Rotate tokenPOST /api/profiles/{id}/tokenNew plaintext returned once; runtime not invalidated
DeleteDELETE /api/profiles/{id}Cascades the bundle and tears down the runtime

Every mutation writes an audit event (profile_create, profile_rename, profile_servers, profile_token_rotate, profile_delete), visible in the dashboard audit page.