Skip to main content
Glama
SESSION_IDENTIFICATION.mdโ€ข8.57 kB
# Team Identification via SessionId ## The Elegant Solution The **sessionId already uniquely identifies which team is requesting permission**. ## Core Insight **Only autonomous spawned agents (toTeam) ever call the `permissions__approve` tool.** The user at the console (fromTeam) has a keyboard - they approve permissions interactively. They will NEVER call `mcp__iris__permissions__approve`. ## The Chain of Sessions Let's trace a realistic scenario: ``` 1. Console user (jenova) runs claude โ†’ The user is there to approve claude 2. Console claude wakes team-alpha โ†’ Creates session: claude->team-alpha (sessionId: 123) โ†’ team-alpha gets MCP config: http://localhost:1615/mcp/123 3. team-alpha needs permission to sudo rm -rf / โ†’ Calls permissions__approve via /mcp/123 โ†’ We KNOW this is team-alpha (toTeam from session 123) โ†’ Why? Console claude would never call this endpoint! 4. team-alpha wakes team-beta โ†’ Creates session: team-alpha->team-beta (sessionId: 456) โ†’ team-beta gets MCP config: http://localhost:1615/mcp/456 โ†’ User is notified of request approval via dashboard or other 5. team-beta needs permission (because alpha said to sudo rm -rf /) โ†’ Calls permissions__approve via /mcp/456 โ†’ We KNOW this is team-beta (toTeam from session 456) โ†’ Why? team-alpha would use /mcp/123 for its own perms! โ†’ User is notified of request approval via dashboard or other 6. team-beta wakes team-gamma โ†’ Creates session: team-beta->team-gamma (sessionId: 789) โ†’ team-gamma gets MCP config: http://localhost:1615/mcp/789 7. team-gamma needs permission to sudo kill -9 <team-alpha-pid> โ†’ Calls permissions__approve via /mcp/789 โ†’ We KNOW this is team-gamma (toTeam from session 789) ``` ## The Pattern ``` Session Creation: fromTeam -> toTeam (sessionId: X) โ””โ”€> toTeam gets MCP config with /mcp/X Permission Request: Request arrives at /mcp/X โ””โ”€> ALWAYS from toTeam (the spawned agent) โ””โ”€> NEVER from fromTeam (they have interactive approval) ``` ## Why This Works 1. **SessionId = Unique Session**: Each Claude session has a unique ID 2. **Session = Team Pair**: SessionId maps to fromTeam->toTeam relationship 3. **Only Agents Need Permission**: Only the spawned agent (toTeam) calls permissions__approve 4. **MCP Config Per Session**: Each spawned agent gets unique /mcp/:sessionId URL 5. **Natural Routing**: Request URL tells us exactly which team is asking ## Implementation ### Route Pattern ``` /mcp/:sessionId ``` Not `/mcp/:teamId` or `/mcp/:uuid` - just the sessionId we already have! ### Lookup Strategy ```typescript // Permission request arrives at /mcp/abc-123 const sessionId = req.params.sessionId; // "abc-123" // Look up session in ProcessPool const process = processPool.getProcessBySessionId(sessionId); // Get team context const requestingTeam = process.toTeam; // This is who's asking! const teamConfig = configManager.getTeam(requestingTeam); // Check permission config switch (teamConfig.grantPermission) { case 'yes': return { behavior: 'allow' }; case 'no': return { behavior: 'deny' }; case 'ask': /* show dashboard popup */ case 'forward': /* send to Slack/webhook */ } ``` ### MCP Config Injection **CRITICAL UPDATE (2025-10-23): Session-Specific Server Naming** To avoid conflicts with global `~/.claude.json` MCP configurations, session-specific MCP configs now use a **unique server name** per session: ```typescript // Session-specific server name prevents conflicts with global "iris" config const serverName = `iris-${sessionId}`; const mcpConfig = { mcpServers: { [serverName]: { // e.g., "iris-abc-123-def-456" type: "http", url: `http://localhost:1615/mcp/${this.sessionId}` } } }; ``` **Why This Matters:** Without unique naming, local teams had **two simultaneous connections** to iris-mcp: 1. Global connection via `~/.claude.json` (server name: `"iris"`) - **NO session context** 2. Session-specific connection via `--mcp-config` (server name: `"iris"`) - **HAS session context** When Claude called tools, it used the global connection by default, causing `permissions__approve` to fail with "No session context" errors. **The Fix:** By naming the session-specific server `iris-${sessionId}`, we create separate namespaces: - Regular tools use global `mcp__iris__*` (no session needed) - Permission tool uses session-specific `mcp__iris-${sessionId}__permissions__approve` (has session context) **Implementation:** **ClaudeCommandBuilder** (`src/utils/command-builder.ts:199-224`): ```typescript static buildMcpConfig(irisConfig: IrisConfig, sessionId: string): McpConfig { const mcpUrl = `${protocol}://localhost:${mcpPort}/mcp/${sessionId}`; // Use session-specific server name to avoid global config conflicts const serverName = `iris-${sessionId}`; return { mcpServers: { [serverName]: { type: "http", url: mcpUrl, }, }, }; } ``` **Permission Tool Flag** (`src/utils/command-builder.ts:128-154`): ```typescript // Match the session-specific server name const permissionTool = `mcp__iris-${sessionId}__permissions__approve`; if (grantPermission === "yes" || grantPermission === "ask") { args.push("--permission-prompt-tool", permissionTool); } ``` **Benefits:** - โœ… No naming conflicts between global and session configs - โœ… Permission tool gets session context via dedicated connection - โœ… Regular tools continue using global connection (efficient) - โœ… No need for `--strict-mcp-config` flag - โœ… Works for both local and remote teams ## What We Don't Need - โŒ `mcp-team-registry.ts` - Delete it! - โŒ UUID generation - Use sessionId! - โŒ registerTeam() / unregisterTeam() - ProcessPool already manages! - โŒ Dependency injection of registry - Use ProcessPool! - โŒ Path mapping - Direct sessionId lookup! ## Benefits 1. **Simpler**: One less abstraction layer 2. **Faster**: Direct ProcessPool lookup (already in-memory) 3. **Consistent**: SessionId is already the source of truth 4. **Natural**: Leverages existing session lifecycle management 5. **Obvious**: The URL itself tells you which session is asking ## Security Note The sessionId is a UUID, so it's unguessable. Even if an attacker knew the endpoint pattern, they can't forge permission requests for other teams without knowing their sessionId. ## Edge Cases **Q: What if a session terminates but requests still arrive?** A: ProcessPool lookup returns null โ†’ return 404 "Session not found" **Q: What if the same team is spawned multiple times?** A: Each spawn gets a unique sessionId โ†’ separate /mcp/:sessionId endpoints โ†’ no collision **Q: What about session resumption (--resume)?** A: Same sessionId = same team context = same permissions โ†’ works perfectly ## Summary **The sessionId is the team identifier.** When a permission request arrives at `/mcp/:sessionId`, we look up that session in the ProcessPool to find the `toTeam` (the agent requesting permission). The `toTeam` is ALWAYS the one asking for permission because only autonomous agents call `permissions__approve` - users have keyboards. This is beautiful, simple, and requires no additional infrastructure beyond what we already have. --- ## Changelog ### 2025-10-23: Session-Specific Server Naming **Problem Discovered:** Local teams experienced "No session context" errors when calling `permissions__approve`. **Root Cause:** MCP server name collision - Global `~/.claude.json` config: server name `"iris"` - Session-specific `--mcp-config`: server name `"iris"` (same!) - Claude defaulted to global connection โ†’ no session context in URL **Solution Implemented:** Unique server names per session - Global config remains: `"iris"` โ†’ tools use `mcp__iris__*` - Session configs now use: `"iris-${sessionId}"` โ†’ permission tool uses `mcp__iris-${sessionId}__permissions__approve` **Files Modified:** - `src/utils/command-builder.ts:199-224` - buildMcpConfig() generates unique server name - `src/utils/command-builder.ts:128-154` - Permission tool flag matches session-specific name **Result:** - โœ… Dual-connection architecture works perfectly - โœ… Regular tools use efficient global connection - โœ… Permission tool gets session context via dedicated connection - โœ… No conflicts, no "No session context" errors **Credit:** Human insight identified that only `permissions__approve` requires session context, enabling this elegant namespace-based solution instead of heavy-handed `--strict-mcp-config` approach.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jenova-marie/iris-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server