206 lines
6.1 KiB
TypeScript
206 lines
6.1 KiB
TypeScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
import {
|
|
CallToolRequestSchema,
|
|
ListToolsRequestSchema,
|
|
ListResourcesRequestSchema,
|
|
ReadResourceRequestSchema,
|
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
import { BrevoApiClient } from './types/api-client.js';
|
|
import { createContactsTools } from './tools/contacts-tools.js';
|
|
import { createCampaignsTools } from './tools/campaigns-tools.js';
|
|
import { createTransactionalTools } from './tools/transactional-tools.js';
|
|
import { createListsTools } from './tools/lists-tools.js';
|
|
import { createSendersTools } from './tools/senders-tools.js';
|
|
import { createTemplatesTools } from './tools/templates-tools.js';
|
|
import { createAutomationsTools } from './tools/automations-tools.js';
|
|
import { createSmsTools } from './tools/sms-tools.js';
|
|
import { createDealsTools } from './tools/deals-tools.js';
|
|
import { createWebhooksTools } from './tools/webhooks-tools.js';
|
|
import { contactDashboardApp } from './apps/contact-dashboard.js';
|
|
import { contactDetailApp } from './apps/contact-detail.js';
|
|
import { contactGridApp } from './apps/contact-grid.js';
|
|
import { campaignDashboardApp } from './apps/campaign-dashboard.js';
|
|
import { campaignBuilderApp } from './apps/campaign-builder.js';
|
|
import { automationDashboardApp } from './apps/automation-dashboard.js';
|
|
import { dealPipelineApp } from './apps/deal-pipeline.js';
|
|
import { transactionalMonitorApp } from './apps/transactional-monitor.js';
|
|
import { templateGalleryApp } from './apps/template-gallery.js';
|
|
import { smsDashboardApp } from './apps/sms-dashboard.js';
|
|
import { listManagerApp } from './apps/list-manager.js';
|
|
import { reportDashboardApp } from './apps/report-dashboard.js';
|
|
import { webhookManagerApp } from './apps/webhook-manager.js';
|
|
import { importWizardApp } from './apps/import-wizard.js';
|
|
|
|
export class BrevoServer {
|
|
private server: Server;
|
|
private client: BrevoApiClient;
|
|
private tools: any[];
|
|
private apps: any[];
|
|
|
|
constructor(apiKey: string) {
|
|
this.server = new Server(
|
|
{
|
|
name: 'brevo-server',
|
|
version: '1.0.0',
|
|
},
|
|
{
|
|
capabilities: {
|
|
tools: {},
|
|
resources: {},
|
|
},
|
|
}
|
|
);
|
|
|
|
this.client = new BrevoApiClient({ apiKey });
|
|
|
|
// Initialize all tools
|
|
this.tools = [
|
|
...createContactsTools(this.client),
|
|
...createCampaignsTools(this.client),
|
|
...createTransactionalTools(this.client),
|
|
...createListsTools(this.client),
|
|
...createSendersTools(this.client),
|
|
...createTemplatesTools(this.client),
|
|
...createAutomationsTools(this.client),
|
|
...createSmsTools(this.client),
|
|
...createDealsTools(this.client),
|
|
...createWebhooksTools(this.client),
|
|
];
|
|
|
|
// Initialize all apps
|
|
this.apps = [
|
|
contactDashboardApp(),
|
|
contactDetailApp(),
|
|
contactGridApp(),
|
|
campaignDashboardApp(),
|
|
campaignBuilderApp(),
|
|
automationDashboardApp(),
|
|
dealPipelineApp(),
|
|
transactionalMonitorApp(),
|
|
templateGalleryApp(),
|
|
smsDashboardApp(),
|
|
listManagerApp(),
|
|
reportDashboardApp(),
|
|
webhookManagerApp(),
|
|
importWizardApp(),
|
|
];
|
|
|
|
this.setupHandlers();
|
|
}
|
|
|
|
private setupHandlers() {
|
|
// List available tools
|
|
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
return {
|
|
tools: this.tools.map(tool => ({
|
|
name: tool.name,
|
|
description: tool.description,
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: tool.inputSchema.shape,
|
|
required: Object.keys(tool.inputSchema.shape).filter(
|
|
key => !tool.inputSchema.shape[key].isOptional()
|
|
),
|
|
},
|
|
})),
|
|
};
|
|
});
|
|
|
|
// Execute tool
|
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const tool = this.tools.find(t => t.name === request.params.name);
|
|
if (!tool) {
|
|
throw new Error(`Tool not found: ${request.params.name}`);
|
|
}
|
|
|
|
try {
|
|
const result = await tool.execute(request.params.arguments || {});
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(result, null, 2),
|
|
},
|
|
],
|
|
};
|
|
} catch (error: any) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: `Error: ${error.message}`,
|
|
},
|
|
],
|
|
isError: true,
|
|
};
|
|
}
|
|
});
|
|
|
|
// List resources (MCP apps)
|
|
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
return {
|
|
resources: this.apps.map(app => ({
|
|
uri: `brevo://app/${app.name}`,
|
|
name: app.name,
|
|
description: app.description,
|
|
mimeType: 'text/html',
|
|
})),
|
|
};
|
|
});
|
|
|
|
// Read resource (render app UI)
|
|
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
const appName = request.params.uri.replace('brevo://app/', '');
|
|
const app = this.apps.find(a => a.name === appName);
|
|
|
|
if (!app) {
|
|
throw new Error(`App not found: ${appName}`);
|
|
}
|
|
|
|
const html = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>${app.ui.title}</title>
|
|
<style>
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
line-height: 1.6;
|
|
color: #333;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background: #f5f5f5;
|
|
}
|
|
h1, h2, h3, h4 { color: #2c3e50; }
|
|
${app.ui.style}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
${app.ui.content}
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
return {
|
|
contents: [
|
|
{
|
|
uri: request.params.uri,
|
|
mimeType: 'text/html',
|
|
text: html,
|
|
},
|
|
],
|
|
};
|
|
});
|
|
}
|
|
|
|
async run() {
|
|
const transport = new StdioServerTransport();
|
|
await this.server.connect(transport);
|
|
console.error('Brevo MCP Server running on stdio');
|
|
}
|
|
}
|