mcp-memory-libsql
by spences10
Verified
- src
- tools
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import logger from '../utils/logger.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool
} from "@modelcontextprotocol/sdk/types.js";
// Get docker hash from environment
const DOCKER_HASH = process.env.DOCKER_HASH || 'unknown';
// Import tool definitions and registry
import { allTools } from './definitions.js';
import { ToolRegistry } from '../modules/tools/registry.js';
// Import handlers
import {
handleListWorkspaceAccounts,
handleAuthenticateWorkspaceAccount,
handleRemoveWorkspaceAccount
} from './account-handlers.js';
import {
handleSearchWorkspaceEmails,
handleSendWorkspaceEmail,
handleGetWorkspaceGmailSettings,
handleManageWorkspaceDraft,
handleManageWorkspaceLabel,
handleManageWorkspaceLabelAssignment,
handleManageWorkspaceLabelFilter,
handleManageWorkspaceAttachment
} from './gmail-handlers.js';
import {
handleListWorkspaceCalendarEvents,
handleGetWorkspaceCalendarEvent,
handleManageWorkspaceCalendarEvent,
handleCreateWorkspaceCalendarEvent,
handleDeleteWorkspaceCalendarEvent
} from './calendar-handlers.js';
import {
handleListDriveFiles,
handleSearchDriveFiles,
handleUploadDriveFile,
handleDownloadDriveFile,
handleCreateDriveFolder,
handleUpdateDrivePermissions,
handleDeleteDriveFile
} from './drive-handlers.js';
// Import error types
import { AccountError } from '../modules/accounts/types.js';
import { GmailError } from '../modules/gmail/types.js';
import { CalendarError } from '../modules/calendar/types.js';
// Import service initializer
import { initializeAllServices } from '../utils/service-initializer.js';
// Import types and type guards
import {
CalendarEventParams,
SendEmailArgs,
AuthenticateAccountArgs,
ManageDraftParams,
ManageAttachmentParams
} from './types.js';
import {
ManageLabelParams,
ManageLabelAssignmentParams,
ManageLabelFilterParams
} from '../modules/gmail/services/label.js';
import {
assertBaseToolArguments,
assertCalendarEventParams,
assertEmailEventIdArgs,
assertSendEmailArgs,
assertManageDraftParams,
assertManageLabelParams,
assertManageLabelAssignmentParams,
assertManageLabelFilterParams,
assertDriveFileListArgs,
assertDriveSearchArgs,
assertDriveUploadArgs,
assertDriveDownloadArgs,
assertDriveFolderArgs,
assertDrivePermissionArgs,
assertDriveDeleteArgs,
assertManageAttachmentParams
} from './type-guards.js';
export class GSuiteServer {
private server: Server;
private toolRegistry: ToolRegistry;
constructor() {
this.toolRegistry = new ToolRegistry(allTools);
this.server = new Server(
{
name: "Google Workspace MCP Server",
version: "0.1.0"
},
{
capabilities: {
tools: {
list: true,
call: true
}
}
}
);
this.setupRequestHandlers();
}
private setupRequestHandlers(): void {
// Tools are registered through the ToolRegistry which serves as a single source of truth
// for both tool discovery (ListToolsRequestSchema) and execution (CallToolRequestSchema).
// Tools only need to be defined once in allTools and the registry handles making them
// available to both handlers.
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
// Get tools with categories organized
const categories = this.toolRegistry.getCategories();
const toolsByCategory: { [key: string]: Tool[] } = {};
for (const category of categories) {
// Convert ToolMetadata to Tool (strip out category and aliases for SDK compatibility)
toolsByCategory[category.name] = category.tools.map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema
}));
}
return {
tools: allTools.map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema
})),
_meta: {
categories: toolsByCategory,
aliases: Object.fromEntries(
allTools.flatMap(tool =>
(tool.aliases || []).map(alias => [alias, tool.name])
)
)
}
};
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
try {
const args = request.params.arguments || {};
const toolName = request.params.name;
// Look up the tool using the registry
const tool = this.toolRegistry.getTool(toolName);
if (!tool) {
// Generate helpful error message with suggestions
const errorMessage = this.toolRegistry.formatErrorWithSuggestions(toolName);
throw new Error(errorMessage);
}
let result;
// Use the canonical tool name for the switch
switch (tool.name) {
// Account Management
case 'list_workspace_accounts':
result = await handleListWorkspaceAccounts();
break;
case 'authenticate_workspace_account':
result = await handleAuthenticateWorkspaceAccount(args as AuthenticateAccountArgs);
break;
case 'remove_workspace_account':
assertBaseToolArguments(args);
result = await handleRemoveWorkspaceAccount(args);
break;
// Gmail Operations
case 'search_workspace_emails':
assertBaseToolArguments(args);
result = await handleSearchWorkspaceEmails(args);
break;
case 'send_workspace_email':
assertSendEmailArgs(args);
result = await handleSendWorkspaceEmail(args as SendEmailArgs);
break;
case 'get_workspace_gmail_settings':
assertBaseToolArguments(args);
result = await handleGetWorkspaceGmailSettings(args);
break;
case 'manage_workspace_draft':
assertManageDraftParams(args);
result = await handleManageWorkspaceDraft(args as ManageDraftParams);
break;
case 'manage_workspace_attachment':
assertManageAttachmentParams(args);
result = await handleManageWorkspaceAttachment(args as ManageAttachmentParams);
break;
// Calendar Operations
case 'list_workspace_calendar_events':
assertCalendarEventParams(args);
result = await handleListWorkspaceCalendarEvents(args as CalendarEventParams);
break;
case 'get_workspace_calendar_event':
assertEmailEventIdArgs(args);
result = await handleGetWorkspaceCalendarEvent(args);
break;
case 'manage_workspace_calendar_event':
assertBaseToolArguments(args);
result = await handleManageWorkspaceCalendarEvent(args);
break;
case 'create_workspace_calendar_event':
assertBaseToolArguments(args);
result = await handleCreateWorkspaceCalendarEvent(args);
break;
case 'delete_workspace_calendar_event':
assertEmailEventIdArgs(args);
result = await handleDeleteWorkspaceCalendarEvent(args);
break;
// Label Management
case 'manage_workspace_label':
assertManageLabelParams(args);
result = await handleManageWorkspaceLabel(args as unknown as ManageLabelParams);
break;
case 'manage_workspace_label_assignment':
assertManageLabelAssignmentParams(args);
result = await handleManageWorkspaceLabelAssignment(args as unknown as ManageLabelAssignmentParams);
break;
case 'manage_workspace_label_filter':
assertManageLabelFilterParams(args);
result = await handleManageWorkspaceLabelFilter(args as unknown as ManageLabelFilterParams);
break;
// Drive Operations
case 'list_drive_files':
assertDriveFileListArgs(args);
result = await handleListDriveFiles(args);
break;
case 'search_drive_files':
assertDriveSearchArgs(args);
result = await handleSearchDriveFiles(args);
break;
case 'upload_drive_file':
assertDriveUploadArgs(args);
result = await handleUploadDriveFile(args);
break;
case 'download_drive_file':
assertDriveDownloadArgs(args);
result = await handleDownloadDriveFile(args);
break;
case 'create_drive_folder':
assertDriveFolderArgs(args);
result = await handleCreateDriveFolder(args);
break;
case 'update_drive_permissions':
assertDrivePermissionArgs(args);
result = await handleUpdateDrivePermissions(args);
break;
case 'delete_drive_file':
assertDriveDeleteArgs(args);
result = await handleDeleteDriveFile(args);
break;
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
// Wrap result in McpToolResponse format
return {
content: [{
type: 'text',
text: JSON.stringify(result, null, 2)
}],
_meta: {}
};
} catch (error) {
const response = this.formatErrorResponse(error);
return {
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
isError: true,
_meta: {}
};
}
});
}
private formatErrorResponse(error: unknown) {
if (error instanceof AccountError || error instanceof GmailError || error instanceof CalendarError) {
const details = error instanceof GmailError ? error.details :
error instanceof AccountError ? error.resolution :
error instanceof CalendarError ? error.message :
'Please try again or contact support if the issue persists';
return {
status: 'error',
error: error.message,
resolution: details
};
}
return {
status: 'error',
error: error instanceof Error ? error.message : 'Unknown error occurred',
resolution: 'Please try again or contact support if the issue persists'
};
}
async run(): Promise<void> {
try {
// Initialize server
logger.info(`google-workspace-mcp v0.9.0 (docker: ${DOCKER_HASH})`);
// Initialize all services
await initializeAllServices();
// Set up error handler
this.server.onerror = (error) => console.error('MCP Error:', error);
// Connect transport
const transport = new StdioServerTransport();
await this.server.connect(transport);
logger.info('Google Workspace MCP server running on stdio');
} catch (error) {
logger.error('Fatal server error:', error);
throw error;
}
}
}