Skip to content

Session Management API

Priority: 🟢 MEDIUM Estimated Time: 6-8 hours Risk Level: LOW Impact: User control over active sessions

← Back to Enhancements


Problem Statement

Users have no visibility into their active MCP sessions and cannot manage them:

  • Cannot list all logged-in devices/sessions
  • Cannot revoke specific sessions (e.g., stolen device)
  • No visibility into session activity
  • Admins cannot view user session status

Use Cases:

  • User wants to see all active sessions
  • User wants to revoke session from lost device
  • Admin needs to audit user sessions
  • Security team investigates suspicious activity

Proposed Solution

Add REST API endpoints for session management:

GET /sessions (authenticated)

List user's active sessions:

json
{
  "sessions": [
    {
      "sessionId": "uuid",
      "createdAt": "2026-01-06T10:00:00Z",
      "lastAccessedAt": "2026-01-06T14:30:00Z",
      "expiresAt": "2026-01-07T10:00:00Z",
      "userAgent": "Claude Desktop 1.0",
      "ipAddress": "192.168.1.100"
    }
  ]
}

DELETE /sessions/:sessionId (authenticated)

Revoke specific session:

bash
curl -X DELETE https://seed.example.com/sessions/abc-123 \
  -H "Authorization: Bearer eyJhbGc..."

# Response
{
  "success": true,
  "message": "Session revoked"
}

Implementation Overview

1. Add Session Metadata

Update SessionMetadata interface to include tracking fields:

typescript
interface SessionMetadata {
  sessionId: string;
  userSub: string;
  createdAt: Date;
  lastAccessedAt: Date;
  expiresAt: Date;
  userAgent?: string;
  ipAddress?: string;
}

2. Create Session Routes

typescript
// src/routes/sessions.ts
import { Router } from "express";
import { requireAuth } from "../middleware/auth.js";

export const sessionsRouter = Router();

// List user's sessions
sessionsRouter.get("/", requireAuth, async (req, res) => {
  const sessions = await sessionStore.getByUser(req.user.sub);
  res.json({ sessions });
});

// Revoke specific session
sessionsRouter.delete("/:sessionId", requireAuth, async (req, res) => {
  const { sessionId } = req.params;

  // Verify session belongs to user
  const session = await sessionStore.get(sessionId);
  if (!session || session.userSub !== req.user.sub) {
    return res.status(404).json({ error: "Session not found" });
  }

  // Remove session
  await removeTransport(sessionId);
  await sessionStore.delete(sessionId);

  res.json({ success: true, message: "Session revoked" });
});

3. Update Session Store

Add getByUser() method to support lookups by user:

typescript
export class RedisSessionStore implements SessionStore {
  async getByUser(userSub: string): Promise<SessionMetadata[]> {
    const pattern = `${this.keyPrefix}*`;
    const keys = await redis.keys(pattern);
    const sessions: SessionMetadata[] = [];

    for (const key of keys) {
      const data = await redis.get(key);
      if (data) {
        const session = JSON.parse(data);
        if (session.userSub === userSub) {
          sessions.push(session);
        }
      }
    }

    return sessions;
  }
}

Acceptance Criteria

  • [ ] GET /sessions endpoint lists user's active sessions
  • [ ] DELETE /sessions/:sessionId revokes specific session
  • [ ] Session metadata includes creation time, last access, user agent, IP
  • [ ] Authorization: users can only manage their own sessions
  • [ ] MCP sessions terminated when revoked via API
  • [ ] Metrics tracked for session management operations
  • [ ] Rate limiting applied to prevent abuse
  • [ ] Unit tests with >90% coverage
  • [ ] Integration tests with real sessions
  • [ ] Documentation with API examples

Estimated Effort

6-8 hours - API endpoints, session store updates, tests, documentation


Released under the MIT License.