Skip to main content
Glama
systempromptio

SystemPrompt Coding Agent

Official
resource-handlers.ts10.9 kB
/** * @fileoverview MCP Resource handlers for agent status and task resources * @module handlers/resource-handlers * * @remarks * This module provides handlers for MCP resource operations including: * - Listing available resources (static and dynamic) * - Reading resource contents (tasks, logs, status) * - Handling resource templates for dynamic URIs * * @example * ```typescript * import { handleListResources, handleResourceCall } from './handlers/resource-handlers'; * * // List all resources * const { resources } = await handleListResources(); * * // Read a specific task * const result = await handleResourceCall({ * params: { uri: 'task://123' } * }); * ``` */ import type { ListResourcesResult, ReadResourceRequest, ReadResourceResult, Resource, } from "@modelcontextprotocol/sdk/types.js"; import { RESOURCES } from "../constants/resources.js"; import { TaskStore } from "../services/task-store.js"; import { logger } from "../utils/logger.js"; import { matchResourceTemplate } from "./resource-templates-handler.js"; import { type TaskResourceContent, type TaskSession, type TaskMetadata } from "../types/resources/task-resource.js"; import { enhanceTask } from "../utils/task-helpers.js"; /** * Lists all available MCP resources including static and dynamic task resources * * @returns List of available resources with metadata * @throws {Error} If resource listing fails * * @example * ```typescript * const { resources } = await handleListResources(); * console.log(`Available resources: ${resources.length}`); * ``` */ export async function handleListResources(): Promise<ListResourcesResult> { try { const resources: Resource[] = [...RESOURCES]; const taskStore = TaskStore.getInstance(); const tasks = await taskStore.getTasks(); tasks.forEach((task) => { resources.push({ uri: `task://${task.id}`, name: `Task: ${task.description}`, mimeType: "application/json", description: `${task.description} (Status: ${task.status})`, }); }); logger.debug( `📚 Listing ${resources.length} resources (${RESOURCES.length} static, ${tasks.length} tasks)`, ); return { resources }; } catch (error) { throw new Error(`Failed to list resources: ${error}`); } } /** * Handles MCP resource read requests for various resource types * * @param request - The resource read request with URI * @param _extra - Additional context (unused) * @returns Resource content in appropriate format * @throws {Error} If resource is not found or read fails * * @remarks * Supports multiple resource URI patterns: * - `agent://status` - Agent status and capabilities * - `task://list` - List of all tasks * - `task://[id]` - Individual task details * - `task://[id]/logs` - Task logs * - `task://[id]/result` - Task result * - Various template-based resources * * @example * ```typescript * const result = await handleResourceCall({ * params: { uri: 'agent://status' } * }); * const status = JSON.parse(result.contents[0].text); * ``` */ export async function handleResourceCall( request: ReadResourceRequest, _extra?: unknown, ): Promise<ReadResourceResult> { try { const { uri } = request.params; const taskStore = TaskStore.getInstance(); if (uri === "agent://status") { const tasks = await taskStore.getTasks(); const activeTasks = tasks.filter((t) => t.status === "in_progress"); return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify( { status: "ready", version: "0.01", capabilities: ["claude", "gemini", "task-management"], activeTaskCount: activeTasks.length, totalTaskCount: tasks.length, }, null, 2, ), }, ], }; } if (uri === "task://list" || uri === "agent://tasks") { const tasks = await taskStore.getTasks(); return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify( { count: tasks.length, tasks: tasks.map((task) => ({ id: task.id, description: task.description, status: task.status, created_at: task.created_at, updated_at: task.updated_at, })), }, null, 2, ), }, ], }; } if (uri.startsWith("task://")) { const taskId = uri.replace("task://", ""); const task = await taskStore.getTask(taskId); if (!task) { throw new Error(`Task not found: ${taskId}`); } // Enhance the task to parse stringified JSON and extract metrics const enhancedTask = enhanceTask(task); const { AgentManager } = await import("../services/agent-manager/index.js"); const agentManager = AgentManager.getInstance(); const sessions = agentManager.getAllSessions(); const taskSession = sessions.find(s => s.taskId === taskId); let session: TaskSession | undefined; if (taskSession) { session = { id: taskSession.id, type: taskSession.type, status: taskSession.status }; } // Get metadata from enhanced task const metadata: TaskMetadata | undefined = enhancedTask.claudeMetrics ? { duration_ms: enhancedTask.claudeMetrics.duration, cost_usd: enhancedTask.claudeMetrics.cost, tokens: { input: enhancedTask.claudeMetrics.usage.inputTokens, output: enhancedTask.claudeMetrics.usage.outputTokens, cached: enhancedTask.claudeMetrics.usage.cacheCreationTokens + enhancedTask.claudeMetrics.usage.cacheReadTokens } } : undefined; // Create resource content with parsed result const processResource: TaskResourceContent & { logs?: typeof enhancedTask.logs; tool_invocations?: typeof enhancedTask.toolInvocations; tool_usage_summary?: typeof enhancedTask.toolUsageSummary; files_affected?: typeof enhancedTask.filesAffected; commands_executed?: typeof enhancedTask.commandsExecuted; } = { id: enhancedTask.id, description: enhancedTask.description, tool: enhancedTask.tool, status: enhancedTask.status, created_at: enhancedTask.created_at, updated_at: enhancedTask.updated_at, session, result: enhancedTask.result, // This is now properly parsed error: enhancedTask.error, metadata, log_count: enhancedTask.logs.length, // Include full enhanced data logs: enhancedTask.logs, tool_invocations: enhancedTask.toolInvocations, tool_usage_summary: enhancedTask.toolUsageSummary, files_affected: enhancedTask.filesAffected, commands_executed: enhancedTask.commandsExecuted }; return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify(processResource, null, 2), }, ], }; } if (uri === "agent://sessions") { return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify( { sessions: [], count: 0, }, null, 2, ), }, ], }; } const templateMatch = matchResourceTemplate(uri); if (templateMatch) { const { template, params } = templateMatch; logger.debug(`📋 Matched resource template: ${template.name}`, params); if (uri.match(/^task:\/\/[^\/]+\/logs$/)) { const taskId = params.taskId; const task = await taskStore.getTask(taskId); if (!task) { throw new Error(`Task not found: ${taskId}`); } return { contents: [ { uri: request.params.uri, mimeType: "text/plain", text: task.logs.join("\n") || "No logs available", }, ], }; } if (uri.match(/^task:\/\/[^\/]+\/result$/)) { const taskId = params.taskId; const task = await taskStore.getTask(taskId); if (!task) { throw new Error(`Task not found: ${taskId}`); } return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify(task.result || { message: "No result available" }, null, 2), }, ], }; } if (uri.match(/^session:\/\/[^\/]+\/[^\/]+$/)) { const { sessionType, sessionId } = params; return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify( { type: sessionType, id: sessionId, status: "placeholder", message: "Session details not yet implemented", }, null, 2, ), }, ], }; } if (uri.match(/^project:\/\/[^\/]+\/status$/)) { const { projectPath } = params; const tasks = await taskStore.getTasks(); const projectTasks: typeof tasks = []; return { contents: [ { uri: request.params.uri, mimeType: "application/json", text: JSON.stringify( { project: projectPath, taskCount: projectTasks.length, activeTasks: projectTasks.filter((t) => t.status === "in_progress").length, completedTasks: projectTasks.filter((t) => t.status === "completed").length, status: "active", }, null, 2, ), }, ], }; } if (uri.match(/^log:\/\/[^\/]+\/[^\/]+$/)) { const { logType, date } = params; return { contents: [ { uri: request.params.uri, mimeType: "text/plain", text: `Logs for ${logType} on ${date}\n\nLog retrieval not yet implemented.`, }, ], }; } } throw new Error(`Unknown resource: ${uri}`); } catch (error) { throw new Error(`Failed to read resource: ${error}`); } }

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/systempromptio/systemprompt-code-orchestrator'

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