Skip to main content
Glama

Chat Context MCP

by aolshaun
tools.ts7.99 kB
/** * MCP Tool Handlers * * Implementation of each MCP tool using the core library */ import { CursorContext, formatSessionMarkdown, formatSessionJSON } from '../core/index.js'; /** * List sessions */ export async function handleListSessions(api: CursorContext, args: any) { const sessions = await api.listSessions({ limit: args.limit || 20, projectPath: args.project, tag: args.tag, taggedOnly: args.taggedOnly || false, sortBy: args.sort || 'newest', source: (args.source || 'all') as 'cursor' | 'claude' | 'all', }); // Format as readable text const lines = sessions.map((s, i) => { const nickname = s.nickname || s.session_id; const project = s.project_name || 'no project'; const msgs = s.message_count || 0; const tags = s.tags && s.tags.length > 0 ? s.tags.join(', ') : 'no tags'; const date = s.created_at ? formatDate(s.created_at) : 'unknown'; return `${i + 1}. ${nickname} | ${project} | ${msgs} msgs | ${tags} | ${date}`; }); const result = sessions.length > 0 ? `Found ${sessions.length} session(s):\n\n${lines.join('\n')}` : 'No sessions found matching criteria.'; return { content: [ { type: 'text', text: result, }, ], }; } /** * Search sessions */ export async function handleSearchSessions(api: CursorContext, args: any) { if (!args.query) { throw new Error('query is required'); } const results = await api.searchSessions({ query: args.query, projectPath: args.project, taggedOnly: args.taggedOnly || false, limit: args.limit || 10, }); if (results.length === 0) { return { content: [ { type: 'text', text: `No sessions found matching "${args.query}".`, }, ], }; } // Format results const lines = results.map((s, i) => { const nickname = s.nickname || s.session_id.substring(0, 8) + '...'; const project = s.project_name || 'no project'; const preview = s.first_message_preview ? s.first_message_preview.substring(0, 80) + '...' : 'no preview'; const tags = s.tags && s.tags.length > 0 ? ` [${s.tags.join(', ')}]` : ''; return `${i + 1}. **${nickname}** (${project})${tags}\n ID: ${s.session_id}\n Preview: "${preview}"`; }); const result = `Found ${results.length} session(s) matching "${args.query}":\n\n${lines.join('\n\n')}`; return { content: [ { type: 'text', text: result, }, ], }; } /** * Get session by ID or nickname */ export async function handleGetSession(api: CursorContext, args: any) { if (!args.idOrNickname) { throw new Error('idOrNickname is required'); } const session = await api.getSession(args.idOrNickname, { parseOptions: { maxContentLength: 100000, }, }); // Limit messages if requested if (args.maxMessages && session.messages.length > args.maxMessages) { session.messages = session.messages.slice(0, args.maxMessages); } // Format based on requested format const format = args.format || 'markdown'; const content = format === 'json' ? formatSessionJSON(session) : formatSessionMarkdown(session, { maxMessages: args.maxMessages }); return { content: [ { type: 'text', text: content, }, ], }; } /** * Nickname current session */ export async function handleNicknameCurrentSession(_api: CursorContext, args: any) { if (!args.nickname) { throw new Error('nickname is required'); } // This tool just records the nickname in the tool call params // The actual nickname will be applied when this session is synced // The workspace extractor will find this tool call and extract the nickname return { content: [ { type: 'text', text: `✓ Nickname "${args.nickname}" will be applied to this session when it is synced to the database.`, }, ], }; } /** * Set nickname for session */ export async function handleSetNickname(api: CursorContext, args: any) { if (!args.sessionId || !args.nickname) { throw new Error('sessionId and nickname are required'); } await api.setNickname(args.sessionId, args.nickname); return { content: [ { type: 'text', text: `✓ Nickname "${args.nickname}" set for session ${args.sessionId.substring(0, 8)}...`, }, ], }; } /** * Add tag(s) to session */ export async function handleAddTag(api: CursorContext, args: any) { if (!args.sessionId || !args.tags) { throw new Error('sessionId and tags are required'); } const tags = Array.isArray(args.tags) ? args.tags : [args.tags]; for (const tag of tags) { await api.addTag(args.sessionId, tag); } return { content: [ { type: 'text', text: `✓ Added ${tags.length} tag(s) to session: ${tags.join(', ')}`, }, ], }; } /** * Remove tag(s) from session */ export async function handleRemoveTag(api: CursorContext, args: any) { if (!args.sessionId || !args.tags) { throw new Error('sessionId and tags are required'); } const tags = Array.isArray(args.tags) ? args.tags : [args.tags]; for (const tag of tags) { await api.removeTag(args.sessionId, tag); } return { content: [ { type: 'text', text: `✓ Removed ${tags.length} tag(s) from session`, }, ], }; } /** * List all tags */ export async function handleListTags(api: CursorContext) { const tags = api.getTags(); if (tags.length === 0) { return { content: [ { type: 'text', text: 'No tags found.', }, ], }; } const lines = tags.map((t, i) => `${i + 1}. ${t.tag} (${t.count} session${t.count !== 1 ? 's' : ''})`); return { content: [ { type: 'text', text: `Available tags:\n\n${lines.join('\n')}`, }, ], }; } /** * List all projects */ export async function handleListProjects(api: CursorContext) { const projects = api.getProjects(); if (projects.length === 0) { return { content: [ { type: 'text', text: 'No projects found.', }, ], }; } const lines = projects.map((p, i) => { const name = p.name || 'unknown'; return `${i + 1}. **${name}** (${p.session_count} session${p.session_count !== 1 ? 's' : ''})\n Path: ${p.path}`; }); return { content: [ { type: 'text', text: `Projects:\n\n${lines.join('\n\n')}`, }, ], }; } /** * Sync sessions from Cursor DB and/or Claude Code to Metadata DB */ export async function handleSyncSessions(api: CursorContext, args: any) { const limit = args.limit || undefined; // undefined = sync all const source = (args.source || 'all') as 'cursor' | 'claude' | 'all'; const sourceLabel = source === 'all' ? 'Cursor and Claude Code' : source === 'cursor' ? 'Cursor' : 'Claude Code'; const synced = await api.syncSessions(limit, source); const stats = api.getStats(); return { content: [ { type: 'text', text: `✅ Synced ${synced} session(s) from ${sourceLabel} 📊 Current Stats: Total sessions in Cursor: ${stats.totalSessionsInCursor || 0} Total sessions with metadata: ${stats.totalSessionsWithMetadata || 0} Sessions with projects: ${stats.sessionsWithProjects || 0} Total projects: ${stats.totalProjects || 0} Total tags: ${stats.totalTags || 0}`, }, ], }; } /** * Helper to format dates */ function formatDate(timestamp: number): string { const daysAgo = Math.floor((Date.now() - timestamp) / (1000 * 60 * 60 * 24)); if (daysAgo === 0) return 'today'; if (daysAgo === 1) return 'yesterday'; if (daysAgo < 7) return `${daysAgo}d ago`; if (daysAgo < 30) return `${Math.floor(daysAgo / 7)}w ago`; if (daysAgo < 365) return `${Math.floor(daysAgo / 30)}mo ago`; return `${Math.floor(daysAgo / 365)}y ago`; }

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