Skip to main content
Glama
vltansky

Cursor Conversations MCP Server

get_conversation

Retrieve complete Cursor conversation content including messages, code blocks, file references, and AI summary. Use conversation IDs from list or search results, with summary-only option to conserve context.

Instructions

Retrieves the complete content of a specific Cursor conversation including all messages, code blocks, file references, title, and AI summary. WORKFLOW TIP: Use conversation IDs from list_conversations, search_conversations, or analytics breakdowns (files/languages arrays contain conversation IDs). Use summaryOnly=true to get enhanced summary data without full message content when you need to conserve context.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
conversationIdYesConversation ID from list_conversations, search_conversations, or analytics breakdowns
summaryOnlyNoReturn only enhanced summary data without full message content
outputModeNoOutput format: "json" for formatted JSON (default), "compact-json" for minified JSONjson

Implementation Reference

  • Main handler function that executes the get_conversation tool logic. Connects to Cursor database, fetches conversation by ID, handles both legacy and modern formats, resolves bubble messages if needed, extracts messages, code blocks, file references, title, and AI-generated summary. Supports options like summaryOnly, includeCodeBlocks, resolveBubbles, etc.
    export async function getConversation(input: GetConversationInput): Promise<GetConversationOutput> {
      // Validate input
      const validatedInput = getConversationSchema.parse(input);
    
      // Create database reader
      const dbPath = process.env.CURSOR_DB_PATH || detectCursorDatabasePath();
      const reader = new CursorDatabaseReader({ dbPath });
    
      try {
        // Connect to database
        await reader.connect();
    
        // If summaryOnly is requested, return enhanced summary without full content
        if (validatedInput.summaryOnly) {
          const summary = await reader.getConversationSummary(validatedInput.conversationId, {
            includeTitle: true,
            includeAIGeneratedSummary: true,
            includeFirstMessage: true,
            includeLastMessage: true,
            maxFirstMessageLength: 200,
            maxLastMessageLength: 200
          });
    
          if (!summary) {
            return { conversation: null };
          }
    
          return {
            conversation: {
              composerId: summary.composerId,
              format: summary.format,
              messageCount: summary.messageCount,
              title: summary.title,
              aiGeneratedSummary: summary.aiGeneratedSummary,
              relevantFiles: validatedInput.includeFileReferences ? summary.relevantFiles : undefined,
              attachedFolders: validatedInput.includeFileReferences ? summary.attachedFolders : undefined,
              metadata: validatedInput.includeMetadata ? {
                hasLoaded: true,
                storedSummary: summary.storedSummary,
                storedRichText: summary.storedRichText,
                size: summary.conversationSize
              } : undefined
            }
          };
        }
    
        // Get conversation
        const conversation = await reader.getConversationById(validatedInput.conversationId);
    
        if (!conversation) {
          return { conversation: null };
        }
    
        // Get conversation summary to extract title and AI summary
        const summary = await reader.getConversationSummary(validatedInput.conversationId, {
          includeTitle: true,
          includeAIGeneratedSummary: true
        });
    
        // Determine format
        const format = conversation.hasOwnProperty('_v') ? 'modern' : 'legacy';
    
        // Build response based on format
        if (format === 'legacy') {
          const legacyConv = conversation as any;
          const messages = legacyConv.conversation || [];
    
          // Extract data
          let allCodeBlocks: any[] = [];
          let allRelevantFiles: string[] = [];
          let allAttachedFolders: string[] = [];
    
          const processedMessages = messages.map((msg: any) => {
            if (validatedInput.includeCodeBlocks && msg.suggestedCodeBlocks) {
              allCodeBlocks.push(...msg.suggestedCodeBlocks);
            }
    
            if (validatedInput.includeFileReferences) {
              if (msg.relevantFiles) allRelevantFiles.push(...msg.relevantFiles);
              if (msg.attachedFoldersNew) allAttachedFolders.push(...msg.attachedFoldersNew);
            }
    
            return {
              type: msg.type,
              text: msg.text,
              bubbleId: msg.bubbleId,
              relevantFiles: validatedInput.includeFileReferences ? msg.relevantFiles : undefined,
              attachedFolders: validatedInput.includeFileReferences ? msg.attachedFoldersNew : undefined,
              codeBlocks: validatedInput.includeCodeBlocks ? msg.suggestedCodeBlocks : undefined
            };
          });
    
          allRelevantFiles = Array.from(new Set(allRelevantFiles));
          allAttachedFolders = Array.from(new Set(allAttachedFolders));
    
          return {
            conversation: {
              composerId: legacyConv.composerId,
              format: 'legacy',
              messageCount: messages.length,
              title: summary?.title,
              aiGeneratedSummary: summary?.aiGeneratedSummary,
              messages: processedMessages,
              codeBlocks: validatedInput.includeCodeBlocks ? allCodeBlocks : undefined,
              relevantFiles: validatedInput.includeFileReferences ? allRelevantFiles : undefined,
              attachedFolders: validatedInput.includeFileReferences ? allAttachedFolders : undefined,
              metadata: validatedInput.includeMetadata ? {
                hasLoaded: true,
                storedSummary: legacyConv.storedSummary,
                storedRichText: legacyConv.storedRichText,
                size: JSON.stringify(conversation).length
              } : undefined
            }
          };
        } else {
          const modernConv = conversation as any;
          const headers = modernConv.fullConversationHeadersOnly || [];
    
          if (validatedInput.resolveBubbles) {
            const resolvedMessages = [];
            for (const header of headers.slice(0, 10)) {
              try {
                const bubbleMessage = await reader.getBubbleMessage(modernConv.composerId, header.bubbleId);
                if (bubbleMessage) {
                  resolvedMessages.push({
                    type: header.type,
                    text: bubbleMessage.text,
                    bubbleId: header.bubbleId,
                    relevantFiles: validatedInput.includeFileReferences ? bubbleMessage.relevantFiles : undefined,
                    attachedFolders: validatedInput.includeFileReferences ? bubbleMessage.attachedFoldersNew : undefined,
                    codeBlocks: validatedInput.includeCodeBlocks ? bubbleMessage.suggestedCodeBlocks : undefined
                  });
                }
              } catch (error) {
                console.error(`Failed to resolve bubble ${header.bubbleId}:`, error);
              }
            }
    
            return {
              conversation: {
                composerId: modernConv.composerId,
                format: 'modern',
                messageCount: headers.length,
                title: summary?.title,
                aiGeneratedSummary: summary?.aiGeneratedSummary,
                messages: resolvedMessages,
                metadata: validatedInput.includeMetadata ? {
                  hasLoaded: true,
                  storedSummary: modernConv.storedSummary,
                  storedRichText: modernConv.storedRichText,
                  size: JSON.stringify(conversation).length
                } : undefined
              }
            };
          } else {
            return {
              conversation: {
                composerId: modernConv.composerId,
                format: 'modern',
                messageCount: headers.length,
                title: summary?.title,
                aiGeneratedSummary: summary?.aiGeneratedSummary,
                metadata: validatedInput.includeMetadata ? {
                  hasLoaded: true,
                  storedSummary: modernConv.storedSummary,
                  storedRichText: modernConv.storedRichText,
                  size: JSON.stringify(conversation).length
                } : undefined
              }
            };
          }
        }
    
      } finally {
        // Always close the database connection
        reader.close();
      }
    }
  • Zod input schema defining parameters for the get_conversation tool: conversationId (required), and optional flags for including code blocks, file references, metadata, resolving modern bubble messages, or summary-only mode.
    export const getConversationSchema = z.object({
      conversationId: z.string().min(1),
      includeCodeBlocks: z.boolean().optional().default(true),
      includeFileReferences: z.boolean().optional().default(true),
      includeMetadata: z.boolean().optional().default(false),
      resolveBubbles: z.boolean().optional().default(true),
      summaryOnly: z.boolean().optional().default(false)
    });
  • src/server.ts:142-176 (registration)
    MCP server registration of the 'get_conversation' tool. Defines tool name, description, input schema (slightly extended with outputMode), and handler wrapper that calls the main getConversation function and formats the response.
    server.tool(
      'get_conversation',
      'Retrieves the complete content of a specific Cursor conversation including all messages, code blocks, file references, title, and AI summary. WORKFLOW TIP: Use conversation IDs from list_conversations, search_conversations, or analytics breakdowns (files/languages arrays contain conversation IDs). Use summaryOnly=true to get enhanced summary data without full message content when you need to conserve context.',
      {
        conversationId: z.string().min(1).describe('Conversation ID from list_conversations, search_conversations, or analytics breakdowns'),
        summaryOnly: z.boolean().optional().default(false).describe('Return only enhanced summary data without full message content'),
        outputMode: z.enum(['json', 'compact-json']).optional().default('json').describe('Output format: "json" for formatted JSON (default), "compact-json" for minified JSON')
      },
      async (input) => {
        try {
          const fullInput = {
            ...input,
            includeCodeBlocks: true,
            includeFileReferences: true,
            includeMetadata: false,
            resolveBubbles: true
          };
          const result = await getConversation(fullInput);
    
          return {
            content: [{
              type: 'text',
              text: formatResponse(result, input.outputMode)
            }]
          };
        } catch (error) {
          return {
            content: [{
              type: 'text',
              text: `Error: ${error instanceof Error ? error.message : 'Unknown error occurred'}`
            }]
          };
        }
      }
    );
  • src/server.ts:30-34 (registration)
    Import statement in server.ts that brings in the getConversation handler function from conversation-tools.ts for use in tool registration.
      listConversations,
      getConversation,
      searchConversations,
      getConversationsByProject
    } from './tools/conversation-tools.js';
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes what the tool retrieves (complete content including specific elements) and mentions a performance consideration (summaryOnly to conserve context), but lacks details on permissions, rate limits, error handling, or response structure. It adds some context but is incomplete for a tool with no annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded: the first sentence clearly states the purpose, followed by a workflow tip that adds practical guidance without redundancy. Every sentence earns its place by providing actionable information, with no wasted words or unnecessary elaboration.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (retrieving conversation data with optional filtering), no annotations, and no output schema, the description is mostly complete. It covers the purpose, usage guidelines, and key parameters, but lacks details on behavioral aspects like error handling or response format. It compensates well but has minor gaps in transparency.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds minimal value beyond the schema: it mentions using conversation IDs from specific sources (implied in the schema) and explains the purpose of summaryOnly=true for context conservation, but doesn't provide additional syntax or format details. Baseline 3 is appropriate when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Retrieves') and resource ('complete content of a specific Cursor conversation'), listing concrete components like messages, code blocks, file references, title, and AI summary. It distinguishes from siblings by specifying this tool retrieves full conversation content, unlike list_conversations (which lists IDs) or get_conversation_analytics (which provides analytics).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use this tool: it specifies obtaining conversation IDs from list_conversations, search_conversations, or analytics breakdowns, and includes a 'WORKFLOW TIP' for using summaryOnly=true to conserve context. It implicitly distinguishes from siblings by not suggesting alternatives for retrieving full conversation content.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/vltansky/cursor-conversations-mcp'

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