@dalcontak/blogger-mcp-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@dalcontak/blogger-mcp-server",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "description": "MCP Server for Blogger API",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "start": "node dist/index.js",
11
+ "dev": "ts-node src/index.ts",
12
+ "test": "jest --forceExit",
13
+ "lint": "eslint src/**/*.ts"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "blogger",
18
+ "api",
19
+ "claude",
20
+ "ai"
21
+ ],
22
+ "author": "",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@modelcontextprotocol/sdk": "^1.8.0",
26
+ "express": "^4.21.0",
27
+ "googleapis": "^171.4.0",
28
+ "socket.io": "^4.7.2",
29
+ "zod": "^3.22.4"
30
+ },
31
+ "devDependencies": {
32
+ "@types/express": "^5.0.1",
33
+ "@types/jest": "^30.0.0",
34
+ "@types/node": "^20.11.0",
35
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
36
+ "@typescript-eslint/parser": "^6.19.0",
37
+ "eslint": "^8.56.0",
38
+ "jest": "^30.2.0",
39
+ "ts-jest": "^29.4.6",
40
+ "ts-node": "^10.9.2",
41
+ "typescript": "^5.3.3"
42
+ }
43
+ }
@@ -0,0 +1,201 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Blogger MCP Server - Tableau de bord</title>
7
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
8
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
9
+ <link rel="stylesheet" href="styles.css">
10
+ </head>
11
+ <body>
12
+ <div class="container-fluid">
13
+ <div class="row">
14
+ <!-- Sidebar -->
15
+ <div class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
16
+ <div class="position-sticky pt-3">
17
+ <div class="text-center mb-4">
18
+ <h5 class="text-white">Blogger MCP Server</h5>
19
+ <p class="text-muted">Tableau de bord</p>
20
+ </div>
21
+ <ul class="nav flex-column">
22
+ <li class="nav-item">
23
+ <a class="nav-link active" href="#dashboard">
24
+ <i class="bi bi-speedometer2 me-2"></i>
25
+ Tableau de bord
26
+ </a>
27
+ </li>
28
+ <li class="nav-item">
29
+ <a class="nav-link" href="#connections">
30
+ <i class="bi bi-people me-2"></i>
31
+ Connexions
32
+ </a>
33
+ </li>
34
+ <li class="nav-item">
35
+ <a class="nav-link" href="#tools">
36
+ <i class="bi bi-tools me-2"></i>
37
+ Outils
38
+ </a>
39
+ </li>
40
+ <li class="nav-item">
41
+ <a class="nav-link" href="#logs">
42
+ <i class="bi bi-journal-text me-2"></i>
43
+ Journaux
44
+ </a>
45
+ </li>
46
+ <li class="nav-item">
47
+ <a class="nav-link" href="#settings">
48
+ <i class="bi bi-gear me-2"></i>
49
+ Paramètres
50
+ </a>
51
+ </li>
52
+ </ul>
53
+ </div>
54
+ </div>
55
+
56
+ <!-- Main content -->
57
+ <main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
58
+ <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
59
+ <h1 class="h2">Tableau de bord</h1>
60
+ <div class="btn-toolbar mb-2 mb-md-0">
61
+ <div class="btn-group me-2">
62
+ <button type="button" id="restart-server" class="btn btn-sm btn-outline-secondary">
63
+ <i class="bi bi-arrow-repeat me-1"></i>
64
+ Redémarrer
65
+ </button>
66
+ <button type="button" id="refresh-data" class="btn btn-sm btn-outline-secondary">
67
+ <i class="bi bi-arrow-clockwise me-1"></i>
68
+ Actualiser
69
+ </button>
70
+ </div>
71
+ </div>
72
+ </div>
73
+
74
+ <!-- Status Cards -->
75
+ <div class="row mb-4">
76
+ <div class="col-md-3">
77
+ <div class="card">
78
+ <div class="card-body">
79
+ <h5 class="card-title">Statut</h5>
80
+ <p class="card-text status-badge">
81
+ <span id="server-status" class="badge bg-success">En ligne</span>
82
+ </p>
83
+ <p class="card-text">Mode: <span id="server-mode">HTTP</span></p>
84
+ <p class="card-text">Démarré: <span id="server-uptime">--</span></p>
85
+ </div>
86
+ </div>
87
+ </div>
88
+ <div class="col-md-3">
89
+ <div class="card">
90
+ <div class="card-body">
91
+ <h5 class="card-title">Connexions</h5>
92
+ <h2 class="card-text" id="connection-count">0</h2>
93
+ <p class="card-text">Clients connectés</p>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ <div class="col-md-3">
98
+ <div class="card">
99
+ <div class="card-body">
100
+ <h5 class="card-title">Requêtes</h5>
101
+ <h2 class="card-text" id="request-count">0</h2>
102
+ <p class="card-text">Total des requêtes</p>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ <div class="col-md-3">
107
+ <div class="card">
108
+ <div class="card-body">
109
+ <h5 class="card-title">Taux de succès</h5>
110
+ <h2 class="card-text" id="success-rate">0%</h2>
111
+ <p class="card-text">Requêtes réussies</p>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+
117
+ <!-- Connections Section -->
118
+ <div class="row mb-4" id="connections">
119
+ <div class="col-12">
120
+ <div class="card">
121
+ <div class="card-header">
122
+ <h5>Connexions actives</h5>
123
+ </div>
124
+ <div class="card-body">
125
+ <div class="table-responsive">
126
+ <table class="table table-striped table-sm">
127
+ <thead>
128
+ <tr>
129
+ <th>ID</th>
130
+ <th>IP</th>
131
+ <th>Connecté à</th>
132
+ <th>Dernière activité</th>
133
+ <th>Requêtes</th>
134
+ <th>Actions</th>
135
+ </tr>
136
+ </thead>
137
+ <tbody id="connections-table">
138
+ <!-- Connections will be populated here -->
139
+ </tbody>
140
+ </table>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </div>
146
+
147
+ <!-- Tools Usage Section -->
148
+ <div class="row mb-4" id="tools">
149
+ <div class="col-md-6">
150
+ <div class="card">
151
+ <div class="card-header">
152
+ <h5>Utilisation des outils</h5>
153
+ </div>
154
+ <div class="card-body">
155
+ <canvas id="tools-chart"></canvas>
156
+ </div>
157
+ </div>
158
+ </div>
159
+ <div class="col-md-6">
160
+ <div class="card">
161
+ <div class="card-header">
162
+ <h5>Outils disponibles</h5>
163
+ </div>
164
+ <div class="card-body">
165
+ <ul class="list-group" id="tools-list">
166
+ <!-- Tools will be populated here -->
167
+ </ul>
168
+ </div>
169
+ </div>
170
+ </div>
171
+ </div>
172
+
173
+ <!-- Logs Section -->
174
+ <div class="row mb-4" id="logs">
175
+ <div class="col-12">
176
+ <div class="card">
177
+ <div class="card-header d-flex justify-content-between align-items-center">
178
+ <h5>Journaux récents</h5>
179
+ <button class="btn btn-sm btn-outline-secondary" id="clear-logs">
180
+ <i class="bi bi-trash me-1"></i>
181
+ Effacer
182
+ </button>
183
+ </div>
184
+ <div class="card-body">
185
+ <div class="logs-container">
186
+ <pre id="logs-content" class="logs-pre">Aucun journal disponible</pre>
187
+ </div>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ </main>
193
+ </div>
194
+ </div>
195
+
196
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
197
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
198
+ <script src="/socket.io/socket.io.js"></script>
199
+ <script src="main.js"></script>
200
+ </body>
201
+ </html>
package/public/main.js ADDED
@@ -0,0 +1,271 @@
1
+ // Script principal pour l'interface utilisateur du serveur MCP Blogger
2
+
3
+ // Connexion Socket.IO
4
+ const socket = io();
5
+
6
+ // Éléments DOM
7
+ const serverStatus = document.getElementById('server-status');
8
+ const serverMode = document.getElementById('server-mode');
9
+ const serverUptime = document.getElementById('server-uptime');
10
+ const connectionCount = document.getElementById('connection-count');
11
+ const requestCount = document.getElementById('request-count');
12
+ const successRate = document.getElementById('success-rate');
13
+ const connectionsTable = document.getElementById('connections-table');
14
+ const toolsList = document.getElementById('tools-list');
15
+ const logsContent = document.getElementById('logs-content');
16
+
17
+ // Boutons
18
+ const restartServerBtn = document.getElementById('restart-server');
19
+ const refreshDataBtn = document.getElementById('refresh-data');
20
+ const clearLogsBtn = document.getElementById('clear-logs');
21
+
22
+ // Graphique d'utilisation des outils
23
+ let toolsChart;
24
+
25
+ // Initialisation
26
+ document.addEventListener('DOMContentLoaded', () => {
27
+ initToolsChart();
28
+ setupEventListeners();
29
+ });
30
+
31
+ // Initialiser le graphique d'utilisation des outils
32
+ function initToolsChart() {
33
+ const ctx = document.getElementById('tools-chart').getContext('2d');
34
+ toolsChart = new Chart(ctx, {
35
+ type: 'bar',
36
+ data: {
37
+ labels: [],
38
+ datasets: [{
39
+ label: 'Nombre d\'appels',
40
+ data: [],
41
+ backgroundColor: 'rgba(52, 152, 219, 0.7)',
42
+ borderColor: 'rgba(52, 152, 219, 1)',
43
+ borderWidth: 1
44
+ }]
45
+ },
46
+ options: {
47
+ responsive: true,
48
+ maintainAspectRatio: false,
49
+ scales: {
50
+ y: {
51
+ beginAtZero: true,
52
+ ticks: {
53
+ precision: 0
54
+ }
55
+ }
56
+ }
57
+ }
58
+ });
59
+ }
60
+
61
+ // Configurer les écouteurs d'événements
62
+ function setupEventListeners() {
63
+ // Événements Socket.IO
64
+ socket.on('status', updateStatus);
65
+ socket.on('connections', updateConnections);
66
+ socket.on('stats', updateStats);
67
+ socket.on('logs', appendLog);
68
+
69
+ // Événements de boutons
70
+ restartServerBtn.addEventListener('click', restartServer);
71
+ refreshDataBtn.addEventListener('click', refreshData);
72
+ clearLogsBtn.addEventListener('click', clearLogs);
73
+
74
+ // Navigation
75
+ document.querySelectorAll('.nav-link').forEach(link => {
76
+ link.addEventListener('click', (e) => {
77
+ e.preventDefault();
78
+ const targetId = e.target.getAttribute('href').substring(1);
79
+ document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
80
+ e.target.classList.add('active');
81
+
82
+ // Implémentation simple de navigation, à améliorer si nécessaire
83
+ if (targetId === 'dashboard') {
84
+ window.scrollTo(0, 0);
85
+ } else {
86
+ const targetElement = document.getElementById(targetId);
87
+ if (targetElement) {
88
+ targetElement.scrollIntoView({ behavior: 'smooth' });
89
+ }
90
+ }
91
+ });
92
+ });
93
+ }
94
+
95
+ // Mettre à jour l'affichage du statut
96
+ function updateStatus(status) {
97
+ // Mettre à jour le badge de statut
98
+ serverStatus.textContent = status.running ? 'En ligne' : 'Hors ligne';
99
+ serverStatus.className = `badge ${status.running ? 'bg-success' : 'bg-danger'}`;
100
+
101
+ // Mettre à jour le mode
102
+ serverMode.textContent = status.mode;
103
+
104
+ // Mettre à jour le temps de fonctionnement
105
+ if (status.startTime) {
106
+ const startTime = new Date(status.startTime);
107
+ serverUptime.textContent = formatDateTime(startTime);
108
+ } else {
109
+ serverUptime.textContent = '--';
110
+ }
111
+
112
+ // Mettre à jour la liste des outils
113
+ updateToolsList(status.tools);
114
+
115
+ // Ajouter une animation pour indiquer la mise à jour
116
+ highlightElement(serverStatus.parentElement.parentElement);
117
+ }
118
+
119
+ // Mettre à jour l'affichage des connexions
120
+ function updateConnections(connections) {
121
+ // Mettre à jour le compteur
122
+ connectionCount.textContent = connections.length;
123
+ highlightElement(connectionCount);
124
+
125
+ // Vider et reconstruire le tableau
126
+ connectionsTable.innerHTML = '';
127
+
128
+ if (connections.length === 0) {
129
+ const row = document.createElement('tr');
130
+ row.innerHTML = '<td colspan="6" class="text-center">Aucune connexion active</td>';
131
+ connectionsTable.appendChild(row);
132
+ } else {
133
+ connections.forEach(conn => {
134
+ const row = document.createElement('tr');
135
+
136
+ const connectedAt = new Date(conn.connectedAt);
137
+ const lastActivity = new Date(conn.lastActivity);
138
+
139
+ row.innerHTML = `
140
+ <td>${conn.id}</td>
141
+ <td>${conn.ip || 'N/A'}</td>
142
+ <td>${formatDateTime(connectedAt)}</td>
143
+ <td>${formatDateTime(lastActivity)}</td>
144
+ <td>${conn.requestCount}</td>
145
+ <td>
146
+ <button class="btn btn-sm btn-danger disconnect-btn" data-id="${conn.id}">
147
+ <i class="bi bi-x-circle"></i> Déconnecter
148
+ </button>
149
+ </td>
150
+ `;
151
+ connectionsTable.appendChild(row);
152
+ });
153
+
154
+ // Ajouter des écouteurs pour les boutons de déconnexion
155
+ document.querySelectorAll('.disconnect-btn').forEach(btn => {
156
+ btn.addEventListener('click', () => {
157
+ const clientId = btn.getAttribute('data-id');
158
+ disconnectClient(clientId);
159
+ });
160
+ });
161
+ }
162
+ }
163
+
164
+ // Mettre à jour les statistiques
165
+ function updateStats(stats) {
166
+ // Mettre à jour le compteur de requêtes
167
+ requestCount.textContent = stats.totalRequests;
168
+ highlightElement(requestCount);
169
+
170
+ // Calculer et mettre à jour le taux de succès
171
+ const rate = stats.totalRequests > 0
172
+ ? Math.round((stats.successfulRequests / stats.totalRequests) * 100)
173
+ : 0;
174
+ successRate.textContent = `${rate}%`;
175
+ highlightElement(successRate);
176
+
177
+ // Mettre à jour le graphique d'utilisation des outils
178
+ updateToolsChart(stats.toolUsage);
179
+ }
180
+
181
+ // Mettre à jour le graphique d'utilisation des outils
182
+ function updateToolsChart(toolUsage) {
183
+ const tools = Object.keys(toolUsage);
184
+ const counts = tools.map(tool => toolUsage[tool]);
185
+
186
+ toolsChart.data.labels = tools;
187
+ toolsChart.data.datasets[0].data = counts;
188
+ toolsChart.update();
189
+ }
190
+
191
+ // Mettre à jour la liste des outils disponibles
192
+ function updateToolsList(tools) {
193
+ toolsList.innerHTML = '';
194
+
195
+ if (tools.length === 0) {
196
+ const item = document.createElement('li');
197
+ item.className = 'list-group-item text-center';
198
+ item.textContent = 'Aucun outil disponible';
199
+ toolsList.appendChild(item);
200
+ } else {
201
+ tools.forEach(tool => {
202
+ const item = document.createElement('li');
203
+ item.className = 'list-group-item';
204
+ item.innerHTML = `
205
+ <div>
206
+ <span class="tool-name">${tool}</span>
207
+ </div>
208
+ <span class="badge bg-primary">MCP</span>
209
+ `;
210
+ toolsList.appendChild(item);
211
+ });
212
+ }
213
+ }
214
+
215
+ // Ajouter un message aux journaux
216
+ function appendLog(message) {
217
+ const timestamp = new Date().toLocaleTimeString();
218
+ const logEntry = `[${timestamp}] ${message}\n`;
219
+
220
+ if (logsContent.textContent === 'Aucun journal disponible') {
221
+ logsContent.textContent = logEntry;
222
+ } else {
223
+ logsContent.textContent += logEntry;
224
+ }
225
+
226
+ // Faire défiler vers le bas pour voir les derniers journaux
227
+ logsContent.scrollTop = logsContent.scrollHeight;
228
+ }
229
+
230
+ // Actions
231
+ function restartServer() {
232
+ if (confirm('Êtes-vous sûr de vouloir redémarrer le serveur ?')) {
233
+ socket.emit('restart-server');
234
+ appendLog('Demande de redémarrage du serveur envoyée.');
235
+ }
236
+ }
237
+
238
+ function refreshData() {
239
+ socket.emit('refresh-data');
240
+ appendLog('Actualisation des données demandée.');
241
+ }
242
+
243
+ function clearLogs() {
244
+ logsContent.textContent = 'Aucun journal disponible';
245
+ }
246
+
247
+ function disconnectClient(clientId) {
248
+ if (confirm(`Êtes-vous sûr de vouloir déconnecter le client ${clientId} ?`)) {
249
+ socket.emit('disconnect-client', clientId);
250
+ appendLog(`Demande de déconnexion du client ${clientId} envoyée.`);
251
+ }
252
+ }
253
+
254
+ // Utilitaires
255
+ function formatDateTime(date) {
256
+ return new Intl.DateTimeFormat('fr-FR', {
257
+ day: '2-digit',
258
+ month: '2-digit',
259
+ year: 'numeric',
260
+ hour: '2-digit',
261
+ minute: '2-digit',
262
+ second: '2-digit'
263
+ }).format(date);
264
+ }
265
+
266
+ function highlightElement(element) {
267
+ element.classList.add('highlight');
268
+ setTimeout(() => {
269
+ element.classList.remove('highlight');
270
+ }, 1500);
271
+ }
@@ -0,0 +1,155 @@
1
+ /* Styles pour le tableau de bord du serveur MCP Blogger */
2
+
3
+ /* Variables */
4
+ :root {
5
+ --primary-color: #3498db;
6
+ --secondary-color: #2c3e50;
7
+ --success-color: #2ecc71;
8
+ --warning-color: #f39c12;
9
+ --danger-color: #e74c3c;
10
+ --light-color: #ecf0f1;
11
+ --dark-color: #2c3e50;
12
+ --sidebar-width: 250px;
13
+ }
14
+
15
+ /* Styles généraux */
16
+ body {
17
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
18
+ background-color: #f8f9fa;
19
+ }
20
+
21
+ /* Sidebar */
22
+ .sidebar {
23
+ position: fixed;
24
+ top: 0;
25
+ bottom: 0;
26
+ left: 0;
27
+ z-index: 100;
28
+ padding: 48px 0 0;
29
+ box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
30
+ width: var(--sidebar-width);
31
+ }
32
+
33
+ .sidebar .nav-link {
34
+ color: #ced4da;
35
+ padding: .75rem 1rem;
36
+ margin-bottom: .25rem;
37
+ border-radius: .25rem;
38
+ transition: all 0.3s;
39
+ }
40
+
41
+ .sidebar .nav-link:hover {
42
+ color: #fff;
43
+ background-color: rgba(255, 255, 255, 0.1);
44
+ }
45
+
46
+ .sidebar .nav-link.active {
47
+ color: #fff;
48
+ background-color: var(--primary-color);
49
+ }
50
+
51
+ /* Main content */
52
+ main {
53
+ padding-top: 1.5rem;
54
+ }
55
+
56
+ /* Cards */
57
+ .card {
58
+ border-radius: 10px;
59
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
60
+ margin-bottom: 1.5rem;
61
+ transition: transform 0.3s;
62
+ }
63
+
64
+ .card:hover {
65
+ transform: translateY(-5px);
66
+ }
67
+
68
+ .card-title {
69
+ font-size: 1rem;
70
+ font-weight: 600;
71
+ color: var(--secondary-color);
72
+ }
73
+
74
+ .card-text {
75
+ font-size: 0.9rem;
76
+ }
77
+
78
+ .card h2 {
79
+ font-size: 2.5rem;
80
+ font-weight: 700;
81
+ margin-bottom: 0.5rem;
82
+ color: var(--primary-color);
83
+ }
84
+
85
+ /* Status badge */
86
+ .status-badge {
87
+ font-size: 1.2rem;
88
+ }
89
+
90
+ /* Tables */
91
+ .table {
92
+ font-size: 0.9rem;
93
+ }
94
+
95
+ .table th {
96
+ font-weight: 600;
97
+ color: var(--secondary-color);
98
+ }
99
+
100
+ /* Logs */
101
+ .logs-container {
102
+ background-color: #2c3e50;
103
+ border-radius: 5px;
104
+ padding: 10px;
105
+ max-height: 300px;
106
+ overflow-y: auto;
107
+ }
108
+
109
+ .logs-pre {
110
+ color: #ecf0f1;
111
+ font-family: 'Courier New', Courier, monospace;
112
+ font-size: 0.85rem;
113
+ white-space: pre-wrap;
114
+ margin: 0;
115
+ }
116
+
117
+ /* Tools list */
118
+ .list-group-item {
119
+ display: flex;
120
+ justify-content: space-between;
121
+ align-items: center;
122
+ padding: 0.5rem 1rem;
123
+ }
124
+
125
+ .tool-name {
126
+ font-weight: 600;
127
+ }
128
+
129
+ .tool-description {
130
+ font-size: 0.8rem;
131
+ color: #6c757d;
132
+ }
133
+
134
+ /* Responsive adjustments */
135
+ @media (max-width: 767.98px) {
136
+ .sidebar {
137
+ position: static;
138
+ width: 100%;
139
+ padding-top: 0;
140
+ }
141
+
142
+ main {
143
+ margin-left: 0 !important;
144
+ }
145
+ }
146
+
147
+ /* Animation for data updates */
148
+ @keyframes highlight {
149
+ 0% { background-color: rgba(52, 152, 219, 0.3); }
150
+ 100% { background-color: transparent; }
151
+ }
152
+
153
+ .highlight {
154
+ animation: highlight 1.5s ease-out;
155
+ }