Session Management API
Priority: 🟢 MEDIUM Estimated Time: 6-8 hours Risk Level: LOW Impact: User control over active sessions
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
Related Enhancements
- Session IP Binding - Session fingerprinting
- Token Revocation - Token invalidation
- Audit Logging - Log session management events