Skip to main content
Glama

Chat Context MCP

by aolshaun
workflows.test.ts9.9 kB
/** * End-to-End Workflow Tests * * These tests simulate real-world usage scenarios */ import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import fs from 'fs'; import path from 'path'; import os from 'os'; import { CursorContext, getCursorDBPath, formatSessionMarkdown, formatSessionPreview } from '../../src/core/index.js'; describe('E2E Workflows', () => { let api: CursorContext; let testMetadataDB: string; beforeAll(async () => { // Use a temporary metadata DB for testing testMetadataDB = path.join(os.tmpdir(), `cursor-context-e2e-${Date.now()}.db`); api = new CursorContext(getCursorDBPath(), testMetadataDB, true); // Sync some sessions for testing await api.syncSessions(15); }); afterAll(() => { if (api) { api.close(); } // Cleanup test database if (fs.existsSync(testMetadataDB)) { fs.unlinkSync(testMetadataDB); } }); describe('Workflow: Organize and Retrieve Sessions', () => { it('should complete full workflow: sync, tag, search, retrieve', async () => { // Step 1: List available sessions const sessions = await api.listSessions({ limit: 5 }); expect(sessions.length).toBeGreaterThan(0); if (sessions.length === 0) return; const testSession = sessions[0]!; // Step 2: Give it a memorable nickname const nickname = `e2e-test-${Date.now()}`; await api.setNickname(testSession.session_id, nickname); // Step 3: Add tags for organization await api.addTag(testSession.session_id, 'test'); await api.addTag(testSession.session_id, 'workflow'); await api.addTag(testSession.session_id, 'e2e'); // Step 4: Search for the session by nickname const searchResults = await api.searchSessions({ query: nickname }); expect(searchResults.length).toBeGreaterThan(0); expect(searchResults.some(s => s.session_id === testSession.session_id)).toBe(true); // Step 5: Retrieve by nickname with full messages const fullSession = await api.getSession(nickname); expect(fullSession.metadata.session_id).toBe(testSession.session_id); expect(fullSession.metadata.nickname).toBe(nickname); expect(fullSession.metadata.tags).toContain('test'); expect(fullSession.metadata.tags).toContain('workflow'); expect(fullSession.metadata.tags).toContain('e2e'); // Step 6: Format the session for display const markdown = formatSessionMarkdown(fullSession, { maxMessages: 3 }); expect(markdown).toContain(nickname); expect(markdown).toContain('# Cursor Session'); const preview = formatSessionPreview(fullSession.metadata); expect(preview).toContain(nickname); }); }); describe('Workflow: Project-Based Organization', () => { it('should organize and filter sessions by project', async () => { // Step 1: Get all projects const projects = api.getProjects(); if (projects.length === 0) { // No projects available, skip test return; } const targetProject = projects[0]!; // Step 2: List all sessions in that project const projectSessions = await api.listSessions({ projectPath: targetProject.path }); expect(projectSessions.length).toBe(targetProject.session_count); expect(projectSessions.every(s => s.project_path === targetProject.path)).toBe(true); // Step 3: Tag all sessions in the project for (const session of projectSessions.slice(0, 3)) { await api.addTag(session.session_id, `project:${targetProject.name}`); } // Step 4: Search within the project const projectSearch = await api.searchSessions({ query: '', projectPath: targetProject.path }); expect(projectSearch.every(s => s.project_path === targetProject.path)).toBe(true); }); }); describe('Workflow: Tag-Based Organization', () => { it('should organize sessions with tags and retrieve by tag', async () => { const sessions = await api.listSessions({ limit: 5 }); if (sessions.length < 3) return; // Step 1: Tag sessions by category await api.addTag(sessions[0]!.session_id, 'feature'); await api.addTag(sessions[1]!.session_id, 'feature'); await api.addTag(sessions[1]!.session_id, 'bugfix'); await api.addTag(sessions[2]!.session_id, 'documentation'); // Step 2: Get all tags const tags = api.getTags(); const featureTag = tags.find(t => t.tag === 'feature'); expect(featureTag).toBeDefined(); expect(featureTag!.count).toBeGreaterThanOrEqual(2); // Step 3: List sessions by tag const featureSessions = await api.listSessions({ tag: 'feature' }); expect(featureSessions.length).toBeGreaterThanOrEqual(2); expect(featureSessions.every(s => s.tags?.includes('feature'))).toBe(true); // Step 4: Search within tagged sessions const taggedSearch = await api.searchSessions({ query: '', taggedOnly: true }); expect(taggedSearch.every(s => s.tags && s.tags.length > 0)).toBe(true); }); }); describe('Workflow: Session Discovery', () => { it('should discover and sync new sessions automatically', async () => { // Step 1: Get current stats const statsBefore = api.getStats(); // Step 2: List sessions to trigger auto-sync const cursorDB = api.getCursorDB(); const allIds = cursorDB.listComposerIds(50); const metadataDB = api.getMetadataDB(); // Find an unsynced session const unsyncedId = allIds.find(id => !metadataDB.getSessionMetadata(id)); if (!unsyncedId) { // All sessions already synced return; } // Step 3: Access the session (should auto-sync) try { const session = await api.getSession(unsyncedId); expect(session.metadata.session_id).toBe(unsyncedId); // Step 4: Verify it's now in metadata DB const metadata = metadataDB.getSessionMetadata(unsyncedId); expect(metadata).toBeDefined(); // Step 5: Stats should reflect the new session const statsAfter = api.getStats(); expect(statsAfter.totalSessionsWithMetadata).toBeGreaterThan(statsBefore.totalSessionsWithMetadata); } catch { // Session might not have valid data, skip } }); }); describe('Workflow: Bulk Operations', () => { it('should handle bulk tagging and organization', async () => { const sessions = await api.listSessions({ limit: 10 }); if (sessions.length < 5) return; // Step 1: Bulk tag sessions const bulkTag = `bulk-${Date.now()}`; for (const session of sessions.slice(0, 5)) { await api.addTag(session.session_id, bulkTag); } // Step 2: Verify all tagged const taggedSessions = await api.listSessions({ tag: bulkTag }); expect(taggedSessions.length).toBe(5); // Step 3: Bulk rename with pattern for (let i = 0; i < 3; i++) { await api.setNickname( sessions[i]!.session_id, `bulk-session-${i + 1}` ); } // Step 4: Search across bulk operations const bulkSearch = await api.searchSessions({ query: 'bulk' }); expect(bulkSearch.length).toBeGreaterThanOrEqual(5); }); }); describe('Workflow: Sorting and Filtering', () => { it('should support complex sorting and filtering', async () => { await api.syncSessions(20); // Step 1: Get newest sessions const newest = await api.listSessions({ sortBy: 'newest', limit: 5 }); expect(newest.length).toBeGreaterThan(0); // Step 2: Get oldest sessions const oldest = await api.listSessions({ sortBy: 'oldest', limit: 5 }); expect(oldest.length).toBeGreaterThan(0); // Step 3: Get sessions with most messages const mostMessages = await api.listSessions({ sortBy: 'most_messages', limit: 5 }); expect(mostMessages.length).toBeGreaterThan(0); // Verify sorting if (mostMessages.length >= 2) { const first = mostMessages[0]!.message_count || 0; const second = mostMessages[1]!.message_count || 0; expect(first).toBeGreaterThanOrEqual(second); } // Step 4: Combine filters const projects = api.getProjects(); if (projects.length > 0) { const filtered = await api.listSessions({ projectPath: projects[0]!.path, sortBy: 'newest', limit: 3 }); expect(filtered.every(s => s.project_path === projects[0]!.path)).toBe(true); } }); }); describe('Workflow: Error Recovery', () => { it('should handle invalid operations gracefully', async () => { // Try to get non-existent session await expect( api.getSession('invalid-session-id-12345') ).rejects.toThrow(); // Try to tag non-existent session await expect( api.addTag('invalid-session-id-12345', 'test') ).rejects.toThrow(); // Try to set nickname for non-existent session await expect( api.setNickname('invalid-session-id-12345', 'test') ).rejects.toThrow(); // Empty search should not throw const emptySearch = await api.searchSessions({ query: 'xyznonexistent123' }); expect(emptySearch).toEqual([]); // List with no results should not throw const noResults = await api.listSessions({ tag: 'nonexistent-tag-xyz' }); expect(noResults).toEqual([]); }); }); });

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/aolshaun/chat-context-mcp'

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