get_project_context
Before starting work, retrieve a condensed project context snapshot: recent sessions, favorites, and stats to load memory.
Instructions
Get a condensed context snapshot for the current project. Call this at the START of every session to load project memory: recent sessions, favorited sessions, and project stats. This is your primary memory tool — use it before doing any work.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectId | No | Project ID (defaults to current project) | |
| detail | No | Detail level for token budgeting: "minimal" (~500 tokens), "standard" (~1500 tokens, default), "full" (~3000+ tokens) | standard |
Implementation Reference
- server/src/mcp/tools.js:34-152 (registration)Tool registration via server.tool() call with name 'get_project_context', description, Zod schema (projectId, detail params), and handler function.
// ─── get_project_context ──────────────────────────────────────── server.tool( 'get_project_context', 'Get a condensed context snapshot for the current project. Call this at the START of every session to load project memory: recent sessions, favorited sessions, and project stats. This is your primary memory tool — use it before doing any work.', { projectId: z.string().optional().describe('Project ID (defaults to current project)'), detail: z.enum(['minimal', 'standard', 'full']).default('standard').optional().describe('Detail level for token budgeting: "minimal" (~500 tokens), "standard" (~1500 tokens, default), "full" (~3000+ tokens)'), }, async ({ projectId, detail = 'standard' }) => { try { const { fileScanner, metadataService, memoryService, sessionParser, currentProjectId } = await getServices() const { project, projectId: resolvedId } = await resolveProject(fileScanner, projectId, currentProjectId) const sessions = await fileScanner.scanSessions(project.path) sessions.sort((a, b) => new Date(b.lastUpdatedAt) - new Date(a.lastUpdatedAt)) // ── minimal: just project stats + session titles ── if (detail === 'minimal') { const titles = sessions.slice(0, 5).map(s => s.title || s.sessionId) const memStats = await memoryService.getStats(resolvedId) return { content: [{ type: 'text', text: JSON.stringify({ project: project.name, sessions: sessions.length, lastActivity: sessions[0]?.lastUpdatedAt || null, recentTitles: titles, storedMemories: memStats.total, }), }], } } // ── standard + full: recent sessions with metadata ── const sessionCount = detail === 'full' ? 10 : 5 const recentSessions = await Promise.all( sessions.slice(0, sessionCount).map(async (s) => { const meta = await metadataService.getMetadata(resolvedId, s.sessionId) let topicHint = null if (detail === 'full') { try { const parsed = await sessionParser.parseSession(s.filePath) const firstUser = parsed.messages.find(m => m.role === 'user') if (firstUser) { const content = typeof firstUser.content === 'string' ? firstUser.content : JSON.stringify(firstUser.content) topicHint = content.slice(0, 200).replace(/\n/g, ' ') } } catch { /* skip parse errors */ } } return { sessionId: s.sessionId, title: meta?.customTitle || s.title || s.sessionId, messageCount: s.messageCount, lastUpdated: s.lastUpdatedAt, isFavorited: meta?.isFavorited || false, tags: meta?.tags || [], ...(topicHint ? { topicHint } : {}), } }) ) // Get favorited sessions const allMeta = await Promise.all( sessions.map(async (s) => { const meta = await metadataService.getMetadata(resolvedId, s.sessionId) return meta?.isFavorited ? { sessionId: s.sessionId, title: meta?.customTitle || s.title || s.sessionId, tags: meta?.tags || [], notes: meta?.notes || null, } : null }) ) const favorites = allMeta.filter(Boolean) // Get stored memories (high-priority ones for context) const highPriorityMemories = await memoryService.recall({ projectId: resolvedId, limit: detail === 'full' ? 20 : 10, }) // Filter to priority >= 7 for standard, all for full const memories = detail === 'full' ? highPriorityMemories : highPriorityMemories.filter(m => m.priority >= 7) const memStats = await memoryService.getStats(resolvedId) const context = { project: { id: resolvedId, name: project.name, totalSessions: sessions.length, lastActivity: sessions[0]?.lastUpdatedAt || null, }, recentSessions, favoritedSessions: favorites.slice(0, 10), memories: memories.length > 0 ? memories : undefined, memoryStats: memStats, summary: `Project "${project.name}" has ${sessions.length} sessions, ${memStats.total} stored memories. Last activity: ${sessions[0]?.lastUpdatedAt || 'unknown'}. ${favorites.length} favorited sessions.`, } return { content: [{ type: 'text', text: JSON.stringify(context, null, 2), }], } } catch (error) { return { content: [{ type: 'text', text: `Error getting project context: ${error.message}` }], isError: true, } } } ) - server/src/mcp/tools.js:42-151 (handler)Main handler function: resolves project, scans sessions, returns context based on detail level (minimal/standard/full) with session metadata, favorites, and stored memories.
async ({ projectId, detail = 'standard' }) => { try { const { fileScanner, metadataService, memoryService, sessionParser, currentProjectId } = await getServices() const { project, projectId: resolvedId } = await resolveProject(fileScanner, projectId, currentProjectId) const sessions = await fileScanner.scanSessions(project.path) sessions.sort((a, b) => new Date(b.lastUpdatedAt) - new Date(a.lastUpdatedAt)) // ── minimal: just project stats + session titles ── if (detail === 'minimal') { const titles = sessions.slice(0, 5).map(s => s.title || s.sessionId) const memStats = await memoryService.getStats(resolvedId) return { content: [{ type: 'text', text: JSON.stringify({ project: project.name, sessions: sessions.length, lastActivity: sessions[0]?.lastUpdatedAt || null, recentTitles: titles, storedMemories: memStats.total, }), }], } } // ── standard + full: recent sessions with metadata ── const sessionCount = detail === 'full' ? 10 : 5 const recentSessions = await Promise.all( sessions.slice(0, sessionCount).map(async (s) => { const meta = await metadataService.getMetadata(resolvedId, s.sessionId) let topicHint = null if (detail === 'full') { try { const parsed = await sessionParser.parseSession(s.filePath) const firstUser = parsed.messages.find(m => m.role === 'user') if (firstUser) { const content = typeof firstUser.content === 'string' ? firstUser.content : JSON.stringify(firstUser.content) topicHint = content.slice(0, 200).replace(/\n/g, ' ') } } catch { /* skip parse errors */ } } return { sessionId: s.sessionId, title: meta?.customTitle || s.title || s.sessionId, messageCount: s.messageCount, lastUpdated: s.lastUpdatedAt, isFavorited: meta?.isFavorited || false, tags: meta?.tags || [], ...(topicHint ? { topicHint } : {}), } }) ) // Get favorited sessions const allMeta = await Promise.all( sessions.map(async (s) => { const meta = await metadataService.getMetadata(resolvedId, s.sessionId) return meta?.isFavorited ? { sessionId: s.sessionId, title: meta?.customTitle || s.title || s.sessionId, tags: meta?.tags || [], notes: meta?.notes || null, } : null }) ) const favorites = allMeta.filter(Boolean) // Get stored memories (high-priority ones for context) const highPriorityMemories = await memoryService.recall({ projectId: resolvedId, limit: detail === 'full' ? 20 : 10, }) // Filter to priority >= 7 for standard, all for full const memories = detail === 'full' ? highPriorityMemories : highPriorityMemories.filter(m => m.priority >= 7) const memStats = await memoryService.getStats(resolvedId) const context = { project: { id: resolvedId, name: project.name, totalSessions: sessions.length, lastActivity: sessions[0]?.lastUpdatedAt || null, }, recentSessions, favoritedSessions: favorites.slice(0, 10), memories: memories.length > 0 ? memories : undefined, memoryStats: memStats, summary: `Project "${project.name}" has ${sessions.length} sessions, ${memStats.total} stored memories. Last activity: ${sessions[0]?.lastUpdatedAt || 'unknown'}. ${favorites.length} favorited sessions.`, } return { content: [{ type: 'text', text: JSON.stringify(context, null, 2), }], } } catch (error) { return { content: [{ type: 'text', text: `Error getting project context: ${error.message}` }], isError: true, } } } - server/src/mcp/tools.js:38-41 (schema)Input schema using Zod: projectId (optional string) and detail (enum: minimal/standard/full, default standard).
{ projectId: z.string().optional().describe('Project ID (defaults to current project)'), detail: z.enum(['minimal', 'standard', 'full']).default('standard').optional().describe('Detail level for token budgeting: "minimal" (~500 tokens), "standard" (~1500 tokens, default), "full" (~3000+ tokens)'), }, - server/src/mcp/tools.js:7-26 (helper)resolveProject helper function used to find project by ID or partial match, with fallback to current project.
async function resolveProject(fileScanner, projectId, currentProjectId) { const targetId = projectId || currentProjectId const projects = await fileScanner.scanProjects() const project = projects.find(p => p.id === targetId) if (!project) { // Try partial match (user might pass just the short name) const partial = projects.find(p => p.name === targetId || p.id.endsWith(`-${targetId}`) ) if (partial) return { project: partial, projectId: partial.id } const available = projects.slice(0, 10).map(p => ` ${p.id} (${p.name})`).join('\n') throw new Error( `Project not found: "${targetId}"\n\nAvailable projects:\n${available}${projects.length > 10 ? `\n ... and ${projects.length - 10} more` : ''}` ) } return { project, projectId: targetId } } - server/src/mcp/index.js:85-85 (helper)System instructions recommending get_project_context as first call at session start to load project memory.
'- At session start: call get_project_context to load project memory (focus, recent work, conventions)',