@digitalsamba/embedded-api-mcp-server
Version:
Digital Samba Embedded API MCP Server - Model Context Protocol server for Digital Samba's Embedded API
242 lines • 11.9 kB
JavaScript
/**
* Export Resources Module
*
* This module provides MCP resources for exporting various types of data from Digital Samba:
* - Communication data (chat messages, Q&A, transcripts)
* - Poll data and results
* - Recording downloads and metadata
*
* Resources in this module are read-only and provide data export capabilities.
*
* @module resources/exports
*/
import { ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
import logger from "../../logger.js";
/**
* Export Resources Class
* Handles MCP resource requests for data exports
*/
export class ExportResources {
constructor(api) {
this.api = api;
}
/**
* Handle export resource requests
*/
async handleResourceRequest(uri) {
try {
logger.info(`Handling export resource request: ${uri}`);
const url = new URL(uri);
// For digitalsamba:// protocol, the host is "exports" and the path starts with the export type
const pathParts = url.pathname.split("/").filter(Boolean);
logger.debug(`Parsed path parts: ${JSON.stringify(pathParts)}`);
if (pathParts.length < 1) {
throw new McpError(ErrorCode.InvalidRequest, "Invalid export resource URI format");
}
const exportType = pathParts[0]; // {exportType}/...
switch (exportType) {
case "communications":
return this.handleCommunicationExport(pathParts, url.searchParams);
case "polls":
return this.handlePollsExport(pathParts, url.searchParams);
case "recordings":
return this.handleRecordingExport(pathParts, url.searchParams);
case "sessions":
return this.handleSessionExport(pathParts, url.searchParams);
default:
throw new McpError(ErrorCode.InvalidRequest, `Unknown export type: ${exportType}`);
}
}
catch (error) {
logger.error(`Error handling export resource request: ${error}`);
if (error instanceof McpError) {
throw error;
}
throw new McpError(ErrorCode.InternalError, `Export resource error: ${error}`);
}
}
/**
* Handle communication data exports (chat, Q&A, transcripts)
*/
async handleCommunicationExport(pathParts, searchParams) {
if (pathParts.length < 3) {
throw new McpError(ErrorCode.InvalidRequest, "Communication export requires: /communications/{roomId}/{type}");
}
const roomId = pathParts[1];
const commType = pathParts[2]; // chat, qa, transcripts
const format = searchParams.get("format") || "json";
const sessionId = searchParams.get("session_id") || undefined;
let exportData;
let description;
switch (commType) {
case "chat":
exportData = await this.api.exportChatMessages(roomId, {
format: format,
session_id: sessionId,
});
description = `Chat messages export for room ${roomId}`;
break;
case "qa":
exportData = await this.api.exportQA(roomId, {
format: format,
session_id: sessionId,
});
description = `Q&A export for room ${roomId}`;
break;
case "transcripts": {
// For transcripts, the session ID is in the path position where room ID would be
const transcriptSessionId = roomId; // Actually the session ID for transcripts
exportData = await this.api.exportTranscripts(transcriptSessionId, {
format: format,
});
description = `Transcript export for session ${transcriptSessionId}`;
break;
}
default:
throw new McpError(ErrorCode.InvalidRequest, `Unknown communication type: ${commType}`);
}
return {
contents: [
{
type: "text",
text: `# ${description}\n\nFormat: ${format.toUpperCase()}\n${sessionId ? `Session: ${sessionId}\n` : ""}\n\`\`\`${format}\n${exportData}\n\`\`\``,
},
],
};
}
/**
* Handle polls data export
*/
async handlePollsExport(pathParts, searchParams) {
if (pathParts.length < 2) {
throw new McpError(ErrorCode.InvalidRequest, "Polls export requires: /polls/{roomId}");
}
const roomId = pathParts[1];
const format = searchParams.get("format") || "json";
const sessionId = searchParams.get("session_id") || undefined;
const exportData = await this.api.exportPolls(roomId, {
format: format,
session_id: sessionId,
});
return {
contents: [
{
type: "text",
text: `# Polls Export for Room ${roomId}\n\nFormat: ${format.toUpperCase()}\n${sessionId ? `Session: ${sessionId}\n` : ""}\n\`\`\`${format}\n${exportData}\n\`\`\``,
},
],
};
}
/**
* Handle recording export/download
*/
async handleRecordingExport(pathParts, _searchParams) {
if (pathParts.length < 2) {
throw new McpError(ErrorCode.InvalidRequest, "Recording export requires: /recordings/{recordingId}");
}
const recordingId = pathParts[1];
try {
// Get recording metadata first
const recording = await this.api.getRecording(recordingId);
return {
contents: [
{
type: "text",
text: `# Recording Export Information\n\n**Recording ID**: ${recordingId}\n**Name**: ${recording.name || "Unnamed"}\n**Status**: ${recording.status}\n**Duration**: ${recording.duration || "Unknown"}\n\n**Download URL**: Use the \`download-recording\` tool to get the download link.\n\n**Metadata**:\n\`\`\`json\n${JSON.stringify(recording, null, 2)}\n\`\`\``,
},
],
};
}
catch {
throw new McpError(ErrorCode.InvalidRequest, `Recording ${recordingId} not found or not accessible`);
}
}
/**
* Handle session data export
*/
async handleSessionExport(pathParts, _searchParams) {
if (pathParts.length < 3) {
throw new McpError(ErrorCode.InvalidRequest, "Session export requires: /sessions/{sessionId}/{type}");
}
const sessionId = pathParts[1];
const exportType = pathParts[2]; // summary, metadata
try {
const session = await this.api.getSessionStatistics(sessionId);
switch (exportType) {
case "summary":
return {
contents: [
{
type: "text",
text: `# Session Summary\n\n**Session ID**: ${sessionId}\n**Room**: ${session.room_description || session.room_id}\n**Started**: ${session.session_start_time}\n**Ended**: ${session.session_end_time || "Ongoing"}\n**Duration**: ${session.session_duration || "Unknown"} minutes\n**Live**: ${session.session_live ? "Yes" : "No"}\n**Participation Minutes**: ${session.participation_minutes}\n\n**Session Data**:\n\`\`\`json\n${JSON.stringify(session, null, 2)}\n\`\`\``,
},
],
};
case "metadata":
return {
contents: [
{
type: "text",
text: `# Session Metadata Export\n\n\`\`\`json\n${JSON.stringify(session, null, 2)}\n\`\`\``,
},
],
};
default:
throw new McpError(ErrorCode.InvalidRequest, `Unknown session export type: ${exportType}`);
}
}
catch {
throw new McpError(ErrorCode.InvalidRequest, `Session ${sessionId} not found or not accessible`);
}
}
}
/**
* Register export resources with the MCP server
*/
export function registerExportResources() {
return [
{
uri: "digitalsamba://exports/communications/{roomId}/chat",
name: "Chat Messages Export",
description: '[Export Data] Export chat messages from a room in formatted text. Use to access: "chat export", "download chat messages", "export room chat", "chat history export", "save chat messages". Requires roomId. Supports format (txt/json) and session_id parameters for specific sessions.',
mimeType: "text/plain",
},
{
uri: "digitalsamba://exports/communications/{roomId}/qa",
name: "Q&A Export",
description: '[Export Data] Export questions and answers from a room. Use to access: "Q&A export", "download questions", "export Q&A data", "question export", "save Q&A session". Requires roomId. Supports format (txt/json) and session_id parameters for filtering to specific sessions.',
mimeType: "text/plain",
},
{
uri: "digitalsamba://exports/communications/{sessionId}/transcripts",
name: "Transcript Export",
description: '[Export Data] Export session transcription data in formatted text. Use to access: "transcript export", "download transcripts", "export transcription", "transcript download", "save meeting transcript". Requires sessionId. Supports format (txt/json) parameter for output formatting.',
mimeType: "text/plain",
},
{
uri: "digitalsamba://exports/polls/{roomId}",
name: "Polls Export",
description: '[Export Data] Export poll questions, options, and results from a room. Use to access: "poll export", "download poll results", "export poll data", "poll results export", "save poll information". Requires roomId. Supports format (txt/json) and session_id parameters.',
mimeType: "text/plain",
},
{
uri: "digitalsamba://exports/recordings/{recordingId}",
name: "Recording Export Info",
description: '[Export Data] Get recording metadata and download information in readable format. Use to access: "recording export info", "recording metadata", "video export details", "recording information", "download recording info". Requires recordingId. Returns formatted recording details and download instructions.',
mimeType: "text/plain",
},
{
uri: "digitalsamba://exports/sessions/{sessionId}/summary",
name: "Session Summary Export",
description: '[Export Data] Export comprehensive session summary with key metrics. Use to access: "session summary export", "meeting report", "session overview", "meeting summary", "export session data". Requires sessionId. Returns formatted summary with participation, duration, and activity data.',
mimeType: "text/plain",
},
{
uri: "digitalsamba://exports/sessions/{sessionId}/metadata",
name: "Session Metadata Export",
description: '[Export Data] Export complete session metadata in JSON format. Use to access: "session metadata export", "full session data", "complete session info", "session raw data", "export session metadata". Requires sessionId. Returns complete technical session data.',
mimeType: "text/plain",
},
];
}
//# sourceMappingURL=index.js.map