#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
import { GamExecutor } from './gam-executor.js';
import { allTools } from './tools/index.js';
/**
* GAM MCP Server
* Provides Google Workspace administration capabilities via GAM CLI
*/
async function main() {
// Initialize GAM executor with path from environment or default
const gamPath = process.env['GAM_PATH'] || 'gam';
const gamExecutor = new GamExecutor(gamPath);
// Validate GAM setup before starting
console.log('[MCP] Validating GAM installation...');
const isInstalled = await gamExecutor.checkGamInstallation();
if (!isInstalled) {
console.error('[MCP] GAM is not properly installed or configured');
console.error('[MCP] Please ensure GAM is installed and authenticated');
console.error('[MCP] Run "gam oauth create" to set up authentication');
process.exit(1);
}
console.log('[MCP] GAM installation validated successfully');
// Create MCP server
const server = new Server({
name: 'gam-mcp-server',
version: '1.0.0',
description: 'Google Workspace administration via GAM CLI - MCP Server for Claude'
}, {
capabilities: {
tools: {}
}
});
// Set up tools list handler
server.setRequestHandler(z.object({ method: z.literal('tools/list') }), async () => {
const tools = allTools.map(tool => ({
name: tool.name,
description: tool.description,
inputSchema: tool.inputSchema
}));
return { tools };
});
// Set up tool call handler
server.setRequestHandler(z.object({ method: z.literal('tools/call'), params: z.object({ name: z.string(), arguments: z.any() }) }), async (request) => {
const toolName = request.params.name;
const tool = allTools.find(t => t.name === toolName);
if (!tool) {
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: false,
error: `Unknown tool: ${toolName}`,
data: null
}, null, 2)
}
],
isError: true
};
}
try {
// Validate input parameters
const args = request.params.arguments ?? {};
const validatedParams = tool.inputSchema.parse(args);
// Execute tool handler
const result = await tool.handler(validatedParams);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
}
catch (error) {
console.error(`[MCP] Tool ${toolName} error:`, error);
// Handle validation errors specifically
let errorMessage = 'Unknown error occurred';
if (error instanceof Error) {
errorMessage = error.message;
}
else if (error && typeof error === 'object' && 'issues' in error) {
// Zod validation error
const zodError = error;
errorMessage = `Validation error: ${zodError.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`).join(', ')}`;
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: false,
error: errorMessage,
data: null
}, null, 2)
}
],
isError: true
};
}
});
// Set up error handling
server.onerror = (error) => {
console.error('[MCP] Server error:', error);
};
process.on('SIGINT', () => {
console.log('[MCP] Received SIGINT, shutting down gracefully...');
server.close().then(() => {
console.log('[MCP] Server shutdown complete');
process.exit(0);
});
});
process.on('SIGTERM', () => {
console.log('[MCP] Received SIGTERM, shutting down gracefully...');
server.close().then(() => {
console.log('[MCP] Server shutdown complete');
process.exit(0);
});
});
try {
// Create transport and start server
const transport = new StdioServerTransport();
await server.connect(transport);
console.log('[MCP] GAM MCP Server started successfully');
console.log('[MCP] Available tools:', allTools.map(t => t.name).join(', '));
}
catch (error) {
console.error('[MCP] Failed to start server:', error);
process.exit(1);
}
}
// Start the server
main().catch((error) => {
console.error('[MCP] Failed to start server:', error);
process.exit(1);
});
//# sourceMappingURL=index.js.map