Comment ajouter le protocole de contexte de modèle MCP à Copilot Studio ...

MCP démystifié et exemples :



Nous analyserons le protocole MCP (Model Context Protocol), en expliquant son objectif et comment il permet un échange de données fluide entre votre bot et les systèmes externes.

Microsoft Learn MCP en action: Nous explorerons le MCP Microsoft Learn (https://github.com/microsoftdocs/mcp) et vous montrerons comment l'exploiter pour améliorer les capacités de votre bot.

Démo 1 : La magie du connecteur personnalisé : Suivez-nous pour créer un connecteur personnalisé à l'aide du MCP Microsoft Learn et accéder à des sources de données et services externes.
Dataverse MCP en profondeur : Nous explorerons ensuite le MCP Dataverse (https://learn.microsoft.com/en-us/pow...) et vous montrerons sa puissance d'interaction avec votre environnement Dataverse.

Démo 2 : Opérations CRUD Dataverse : Découvrez le MCP Dataverse en action : nous créons un bot capable de lire, créer et mettre à jour des enregistrements directement dans Dataverse, le tout dans Copilot Studio ! À la fin de cette vidéo, vous maîtriserez parfaitement le MCP et disposerez des compétences pratiques nécessaires pour créer des bots puissants, pilotés par les données, capables de comprendre et de répondre aux besoins de vos utilisateurs.

👍 Aimez, abonnez-vous et activez la cloche de notification pour rester informé des derniers conseils et astuces Copilot Studio !



💬 Dites-moi dans les commentaires quels autres sujets Copilot Studio vous aimeriez que j'aborde ! 🫠 À propos de moi : 👋 Bonjour, je suis Damien Bird, architecte de solutions cloud Power Platform chez Microsoft ☁️ 🧠 Ancien superutilisateur du forum (2021/22) et MVP des applications métier (2022) 🎤 Intervenant lors de conférences en Europe, aux États-Unis et auprès de groupes d'utilisateurs locaux au Royaume-Uni 💡 Passionné par le partage des connaissances, la résolution de problèmes et l'autonomisation de la communauté grâce à Power Platform ! 📚 En savoir plus : 🔗 Blog :
https://DamoBird365.com 🎥 Formation continue vidéo et quiz : https://DamoBird365.com/YouTube 🎓 Rejoignez la communauté : https://DamoBird365.Teachable.com/p/D... 💖 Soutenez la chaîne : https://youtube.com/@DamoBird365/memb... ☕ Offrez-moi un café : https://BuyMeACoffee.com/DamoBird365 💼 LinkedIn :   / damobird365   🐦 Twitter : https://x.com/DamoBird365 🌐 Bluesky : https://bsky.app/profile/DamoBird365.... 📜 Commentaires ou demandes : https://forms.office.com/e/WAV1iF2Wis

POC - Architecture tableau de bord avec MCP pour Cotation Boursière.

 POC - Architecture T2BI-MCP pour Cotation Boursière.

Vue d'ensemble

Ce POC implémente une version simplifiée de l'architecture pour surveiller la cotation d'Apple (AAPL) avec des données gratuites.

Architecture Simplifiée

[Utilisateur] → [Dashboard Grafana] → [Collecteur Python] → [Yahoo Finance (gratuit)]
     ↓                    ↓                    ↓
[Alertes]          [InfluxDB]         [Logs & Métriques]

Composants

1. Collecteur de Données (Simule MCP)

# stock_collector.py
import yfinance as yf
import time
import json
from datetime import datetime
from influxdb import InfluxDBClient
import logging

class StockCollector:
    def __init__(self):
        self.client = InfluxDBClient(host='localhost', port=8086, database='stocks')
        self.setup_logging()
        
    def setup_logging(self):
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('stock_monitoring.log'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)

    def collect_stock_data(self, symbol="AAPL"):
        """Collecte des données boursières - Serveur MCP Performance"""
        try:
            stock = yf.Ticker(symbol)
            info = stock.info
            hist = stock.history(period="1d", interval="1m")
            
            if not hist.empty:
                current_price = hist['Close'].iloc[-1]
                volume = hist['Volume'].iloc[-1]
                
                # Données de gouvernance simulées
                governance_score = self.calculate_governance_score(info)
                risk_level = self.assess_risk_level(current_price, hist)
                
                # Point de données pour InfluxDB
                point = {
                    "measurement": "stock_data",
                    "tags": {
                        "symbol": symbol,
                        "sector": info.get('sector', 'Unknown')
                    },
                    "time": datetime.utcnow(),
                    "fields": {
                        "price": float(current_price),
                        "volume": int(volume),
                        "governance_score": governance_score,
                        "risk_level": risk_level,
                        "market_cap": info.get('marketCap', 0)
                    }
                }
                
                self.client.write_points([point])
                self.logger.info(f"Data collected for {symbol}: ${current_price:.2f}")
                
                return point
                
        except Exception as e:
            self.logger.error(f"Error collecting data for {symbol}: {e}")
            return None

    def calculate_governance_score(self, info):
        """Serveur MCP Gouvernance - Score ESG simplifié"""
        score = 50  # Score de base
        
        # Critères de gouvernance
        if info.get('recommendationKey') == 'buy':
            score += 10
        if info.get('esgScores'):
            score += 20
        if info.get('auditRisk', 10) < 5:
            score += 15
            
        return min(100, score)

    def assess_risk_level(self, current_price, hist):
        """Serveur MCP Sécurité - Évaluation des risques"""
        if len(hist) < 10:
            return 3  # Risque moyen par défaut
            
        volatility = hist['Close'].pct_change().std() * 100
        
        if volatility < 1:
            return 1  # Faible risque
        elif volatility < 3:
            return 2  # Risque modéré
        elif volatility < 5:
            return 3  # Risque élevé
        else:
            return 4  # Très haut risque

if __name__ == "__main__":
    collector = StockCollector()
    
    # Collecte toutes les minutes
    while True:
        collector.collect_stock_data("AAPL")
        time.sleep(60)

2. Configuration Docker Compose

# docker-compose.yml
version: '3.8'
services:
  influxdb:
    image: influxdb:1.8
    container_name: influxdb
    ports:
      - "8086:8086"
    volumes:
      - influxdb_data:/var/lib/influxdb
    environment:
      - INFLUXDB_DB=stocks
      - INFLUXDB_HTTP_AUTH_ENABLED=false

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    depends_on:
      - influxdb

volumes:
  influxdb_data:
  grafana_data:

3. Dashboard Grafana (JSON)

{
  "dashboard": {
    "title": "AAPL Stock Monitoring - T2BI Dashboard",
    "panels": [
      {
        "title": "Prix en Temps Réel",
        "type": "stat",
        "targets": [
          {
            "query": "SELECT last(\"price\") FROM \"stock_data\" WHERE \"symbol\" =~ /^AAPL$/ AND time >= now() - 1h",
            "alias": "Prix AAPL"
          }
        ]
      },
      {
        "title": "Évolution du Prix",
        "type": "graph",
        "targets": [
          {
            "query": "SELECT mean(\"price\") FROM \"stock_data\" WHERE \"symbol\" =~ /^AAPL$/ AND time >= now() - 24h GROUP BY time(5m)",
            "alias": "Prix AAPL"
          }
        ]
      },
      {
        "title": "Score de Gouvernance",
        "type": "gauge",
        "targets": [
          {
            "query": "SELECT last(\"governance_score\") FROM \"stock_data\" WHERE \"symbol\" =~ /^AAPL$/ AND time >= now() - 1h"
          }
        ],
        "fieldConfig": {
          "min": 0,
          "max": 100,
          "thresholds": [
            {"color": "red", "value": 0},
            {"color": "yellow", "value": 50},
            {"color": "green", "value": 80}
          ]
        }
      },
      {
        "title": "Niveau de Risque",
        "type": "stat",
        "targets": [
          {
            "query": "SELECT last(\"risk_level\") FROM \"stock_data\" WHERE \"symbol\" =~ /^AAPL$/ AND time >= now() - 1h"
          }
        ]
      }
    ]
  }
}

4. Système d'Alertes

# alerts.py
class AlertSystem:
    def __init__(self, collector):
        self.collector = collector
        self.thresholds = {
            'price_drop': -5.0,  # Alerte si baisse > 5%
            'high_risk': 4,      # Alerte si risque très élevé
            'low_governance': 40  # Alerte si gouvernance < 40
        }
    
    def check_alerts(self, data):
        alerts = []
        
        # Vérification baisse de prix
        if self.check_price_drop(data):
            alerts.append({
                'type': 'PRICE_DROP',
                'message': f"Baisse significative détectée: {data['fields']['price']:.2f}$",
                'severity': 'HIGH'
            })
        
        # Vérification risque élevé
        if data['fields']['risk_level'] >= self.thresholds['high_risk']:
            alerts.append({
                'type': 'HIGH_RISK',
                'message': f"Niveau de risque élevé: {data['fields']['risk_level']}",
                'severity': 'MEDIUM'
            })
        
        # Vérification gouvernance
        if data['fields']['governance_score'] < self.thresholds['low_governance']:
            alerts.append({
                'type': 'GOVERNANCE',
                'message': f"Score de gouvernance faible: {data['fields']['governance_score']}",
                'severity': 'LOW'
            })
        
        return alerts
    
    def send_alert(self, alert):
        # Simulation envoi d'alerte (email, Slack, etc.)
        print(f"🚨 ALERTE [{alert['severity']}]: {alert['message']}")

Installation et Déploiement

Prérequis

pip install yfinance influxdb pandas numpy

Lancement

# 1. Démarrer les services
docker-compose up -d

# 2. Lancer le collecteur
python stock_collector.py

# 3. Accéder à Grafana
# http://localhost:3000 (admin/admin)

Fonctionnalités du POC

✅ Collecte de Données

  • Prix en temps réel via Yahoo Finance (gratuit)
  • Volume, capitalisation boursière
  • Métriques de gouvernance simulées

✅ Visualisation (T2BI)

  • Dashboard Grafana temps réel
  • Graphiques de tendance
  • Jauges de gouvernance et risque

✅ Gouvernance IA (MCP Simulé)

  • Serveur Gouvernance: Score ESG, audit de conformité
  • Serveur Performance: Métriques financières, utilisation
  • Serveur Sécurité: Évaluation des risques, volatilité

✅ Alertes Automatiques

  • Chute de prix > 5%
  • Risque élevé détecté
  • Score de gouvernance faible

Extensions Possibles

  1. Multi-actions: Ajouter MSFT, GOOGL, TSLA
  2. ML Integration: Prédictions avec scikit-learn
  3. API REST: Interface pour autres applications
  4. Notifications: Email, Slack, Teams
  5. Historique: Stockage long terme avec TimescaleDB

Métriques de Gouvernance IA

  • Transparence: Logs détaillés de toutes les opérations
  • Auditabilité: Traçabilité des décisions d'alerte
  • Conformité: Respect des seuils définis
  • Performance: Latence < 1s pour collecte
  • Sécurité: Gestion des erreurs et données sensibles

Voici un POC simple pour surveiller une cotation boursière (exemple: Apple - AAPL) en utilisant des sources gratuites.

Ce POC implémente votre architecture T2BI-MCP-Grafana de manière simplifiée mais fonctionnelle pour surveiller la cotation d'Apple (AAPL). Voici les points clés :

🎯 Avantages de ce POC

  • Sans API payante : Utilise Yahoo Finance (gratuit)
  • Architecture respectée : T2BI → Grafana → MCP → Sources
  • Gouvernance IA intégrée : 3 serveurs MCP simulés
  • Déploiement rapide : Docker + Python
  • Extensible : Facilement adaptable à d'autres actions

🚀 Démarrage Rapide

  1. Cloner les fichiers du POC
  2. Lancer : docker-compose up -d && python stock_collector.py
  3. Accéder : Dashboard Grafana sur http://localhost:3000

📊 Fonctionnalités Démontrées

  • T2BI : Dashboard temps réel avec KPIs
  • MCP Gouvernance : Score ESG et conformité
  • MCP Performance : Métriques financières
  • MCP Sécurité : Évaluation des risques
  • Alertes : Notifications automatiques


POC - Monitoring Claude avec Fonctions MCP

Architecture Alignée sur T2BI-MCP

[Interface Web] → [Flask Server] → [MCP Servers] → [SQLite DB]
       ↓               ↓              ↓
   [Dashboard]    [API REST]    [Gouvernance IA]
                                [Performance]
                                [Sécurité]

Structure du Projet

claude_mcp_monitor/
├── app.py                    # Serveur Flask principal
├── mcp_servers/
│   ├── governance_server.py  # Serveur MCP Gouvernance
│   ├── performance_server.py # Serveur MCP Performance  
│   └── security_server.py    # Serveur MCP Sécurité
├── data_collector.py         # Collecteur de métriques Claude
├── database.py              # Gestion SQLite
├── templates/
│   └── index.html          # Interface de gouvernance
├── static/
│   ├── style.css          # Styles
│   └── script.js          # JavaScript
└── requirements.txt       # Dépendances

Code Source

1. Serveur Principal (app.py)

from flask import Flask, render_template, jsonify, request
from mcp_servers.governance_server import GovernanceServer
from mcp_servers.performance_server import PerformanceServer
from mcp_servers.security_server import SecurityServer
from data_collector import ClaudeUsageCollector
from database import ClaudeMetricsDB
import threading
import time
from datetime import datetime, timedelta
import json

app = Flask(__name__)

# Initialisation des serveurs MCP
governance_server = GovernanceServer()
performance_server = PerformanceServer()
security_server = SecurityServer()
collector = ClaudeUsageCollector()
db = ClaudeMetricsDB()

# Variables globales
current_metrics = {}
alerts = []
usage_stats = {}

def background_monitoring():
    """Surveillance continue de Claude MCP"""
    while True:
        try:
            # Collecte des métriques via les serveurs MCP
            governance_data = governance_server.get_governance_metrics()
            performance_data = performance_server.get_performance_metrics()
            security_data = security_server.get_security_metrics()
            
            # Fusion des données
            merged_data = {
                'timestamp': datetime.now().isoformat(),
                'governance': governance_data,
                'performance': performance_data,
                'security': security_data
            }
            
            # Sauvegarde
            db.save_metrics(merged_data)
            
            global current_metrics
            current_metrics = merged_data
            
            # Vérification des alertes
            check_mcp_alerts(merged_data)
            
            time.sleep(60)  # Collecte toutes les minutes
            
        except Exception as e:
            print(f"Erreur monitoring MCP: {e}")
            time.sleep(60)

def check_mcp_alerts(data):
    """Système d'alertes pour gouvernance IA"""
    global alerts
    now = datetime.now()
    
    gov = data['governance']
    perf = data['performance']
    sec = data['security']
    
    # Alerte gouvernance - Score éthique faible
    if gov.get('ethics_score', 100) < 70:
        alerts.append({
            'time': now.strftime("%H:%M:%S"),
            'type': 'ÉTHIQUE',
            'message': f"Score éthique faible: {gov['ethics_score']}/100",
            'severity': 'high',
            'server': 'governance'
        })
    
    # Alerte performance - Utilisation excessive
    if perf.get('token_usage_rate', 0) > 80:
        alerts.append({
            'time': now.strftime("%H:%M:%S"),
            'type': 'USAGE',
            'message': f"Utilisation élevée: {perf['token_usage_rate']}%",
            'severity': 'medium',
            'server': 'performance'
        })
    
    # Alerte sécurité - Risque détecté
    if sec.get('risk_level', 1) >= 4:
        alerts.append({
            'time': now.strftime("%H:%M:%S"),
            'type': 'SÉCURITÉ',
            'message': f"Niveau de risque élevé: {sec['risk_level']}/5",
            'severity': 'high',
            'server': 'security'
        })
    
    # Garder seulement les 15 dernières alertes
    alerts = alerts[-15:]

@app.route('/')
def index():
    """Interface de gouvernance IA"""
    return render_template('index.html')

@app.route('/api/current')
def api_current():
    """API - Métriques actuelles"""
    return jsonify(current_metrics)

@app.route('/api/governance')
def api_governance():
    """API - Métriques de gouvernance"""
    return jsonify(governance_server.get_detailed_metrics())

@app.route('/api/performance')
def api_performance():
    """API - Métriques de performance"""
    return jsonify(performance_server.get_detailed_metrics())

@app.route('/api/security')
def api_security():
    """API - Métriques de sécurité"""
    return jsonify(security_server.get_detailed_metrics())

@app.route('/api/alerts')
def api_alerts():
    """API - Alertes actives"""
    return jsonify(alerts)

@app.route('/api/history')
def api_history():
    """API - Historique des métriques"""
    hours = request.args.get('hours', 24, type=int)
    since = datetime.now() - timedelta(hours=hours)
    history = db.get_history_since(since)
    return jsonify(history)

@app.route('/api/compliance')
def api_compliance():
    """API - Rapport de conformité"""
    report = governance_server.generate_compliance_report()
    return jsonify(report)

@app.route('/api/mcp/status')
def api_mcp_status():
    """API - Statut des serveurs MCP"""
    return jsonify({
        'governance': governance_server.health_check(),
        'performance': performance_server.health_check(),
        'security': security_server.health_check()
    })

if __name__ == '__main__':
    # Initialiser la base de données
    db.init_db()
    
    # Démarrer le monitoring en arrière-plan
    monitor_thread = threading.Thread(target=background_monitoring, daemon=True)
    monitor_thread.start()
    
    # Démarrer le serveur web
    app.run(debug=True, host='0.0.0.0', port=5001)

2. Serveur MCP Gouvernance (mcp_servers/governance_server.py)

import random
from datetime import datetime, timedelta
import json

class GovernanceServer:
    """Serveur MCP pour la Gouvernance IA - Conformité, Audit, Éthique"""
    
    def __init__(self):
        self.compliance_rules = {
            'data_privacy': True,
            'bias_detection': True,
            'content_moderation': True,
            'audit_logging': True
        }
        self.ethics_framework = {
            'fairness': 0.95,
            'transparency': 0.90,
            'accountability': 0.88,
            'human_oversight': 0.92
        }
    
    def get_governance_metrics(self):
        """Collecte des métriques de gouvernance"""
        return {
            'ethics_score': self._calculate_ethics_score(),
            'compliance_rate': self._check_compliance_rate(),
            'audit_coverage': self._get_audit_coverage(),
            'bias_score': self._assess_bias_level(),
            'transparency_index': self._calculate_transparency(),
            'human_oversight_rate': random.uniform(85, 98)
        }
    
    def get_detailed_metrics(self):
        """Métriques détaillées de gouvernance"""
        return {
            'compliance_rules': self.compliance_rules,
            'ethics_framework': self.ethics_framework,
            'recent_audits': self._get_recent_audits(),
            'policy_violations': self._get_policy_violations(),
            'training_compliance': random.uniform(90, 100),
            'data_lineage_score': random.uniform(80, 95)
        }
    
    def generate_compliance_report(self):
        """Génère un rapport de conformité"""
        return {
            'report_date': datetime.now().isoformat(),
            'overall_score': self._calculate_ethics_score(),
            'compliance_status': 'CONFORME' if self._check_compliance_rate() > 95 else 'ATTENTION',
            'recommendations': self._get_recommendations(),
            'next_audit_date': (datetime.now() + timedelta(days=30)).isoformat()
        }
    
    def health_check(self):
        """Vérification de santé du serveur MCP"""
        return {
            'status': 'healthy',
            'last_check': datetime.now().isoformat(),
            'active_rules': len(self.compliance_rules),
            'uptime': '99.9%'
        }
    
    def _calculate_ethics_score(self):
        """Calcul du score éthique global"""
        base_score = sum(self.ethics_framework.values()) / len(self.ethics_framework) * 100
        # Simulation de variations
        return max(60, min(100, base_score + random.uniform(-5, 2)))
    
    def _check_compliance_rate(self):
        """Taux de conformité aux règles"""
        active_rules = sum(1 for rule in self.compliance_rules.values() if rule)
        return (active_rules / len(self.compliance_rules)) * 100
    
    def _get_audit_coverage(self):
        """Couverture d'audit"""
        return random.uniform(88, 99)
    
    def _assess_bias_level(self):
        """Évaluation du niveau de biais (score inversé - plus haut = moins de biais)"""
        return random.uniform(75, 95)
    
    def _calculate_transparency(self):
        """Index de transparence"""
        return random.uniform(80, 95)
    
    def _get_recent_audits(self):
        """Audits récents"""
        return [
            {'date': '2025-07-20', 'type': 'Biais', 'status': 'Passé', 'score': 92},
            {'date': '2025-07-15', 'type': 'Conformité', 'status': 'Passé', 'score': 88},
            {'date': '2025-07-10', 'type': 'Sécurité', 'status': 'Attention', 'score': 76}
        ]
    
    def _get_policy_violations(self):
        """Violations de politiques récentes"""
        return random.randint(0, 3)
    
    def _get_recommendations(self):
        """Recommandations d'amélioration"""
        return [
            "Renforcer la formation sur les biais",
            "Augmenter la fréquence des audits",
            "Améliorer la documentation des décisions"
        ]

3. Serveur MCP Performance (mcp_servers/performance_server.py)

import random
from datetime import datetime, timedelta
import psutil
import time

class PerformanceServer:
    """Serveur MCP pour la Performance - Métriques, Utilisation, Coûts"""
    
    def __init__(self):
        self.start_time = time.time()
        self.total_requests = 0
        self.total_tokens = 0
        
    def get_performance_metrics(self):
        """Collecte des métriques de performance"""
        self.total_requests += random.randint(5, 25)
        self.total_tokens += random.randint(1000, 5000)
        
        return {
            'requests_per_minute': random.randint(10, 50),
            'avg_response_time': random.uniform(0.5, 3.0),
            'token_usage_rate': random.uniform(40, 85),
            'success_rate': random.uniform(95, 99.9),
            'error_rate': random.uniform(0.1, 2.0),
            'cost_per_hour': random.uniform(5, 25),
            'cpu_usage': psutil.cpu_percent(),
            'memory_usage': psutil.virtual_memory().percent
        }
    
    def get_detailed_metrics(self):
        """Métriques détaillées de performance"""
        return {
            'total_requests': self.total_requests,
            'total_tokens': self.total_tokens,
            'uptime_hours': (time.time() - self.start_time) / 3600,
            'function_calls': self._get_function_usage(),
            'model_usage': self._get_model_usage(),
            'cost_breakdown': self._get_cost_breakdown(),
            'performance_trends': self._get_performance_trends()
        }
    
    def health_check(self):
        """Vérification de santé du serveur MCP"""
        return {
            'status': 'healthy',
            'last_check': datetime.now().isoformat(),
            'avg_load': psutil.getloadavg()[0] if hasattr(psutil, 'getloadavg') else 0.5,
            'response_time': random.uniform(0.1, 0.5)
        }
    
    def _get_function_usage(self):
        """Utilisation des fonctions MCP"""
        return {
            'web_search': random.randint(50, 200),
            'notion_search': random.randint(20, 80),
            'google_drive': random.randint(10, 50),
            'artifacts': random.randint(30, 120),
            'repl': random.randint(5, 30)
        }
    
    def _get_model_usage(self):
        """Utilisation des modèles"""
        return {
            'claude_sonnet_4': random.uniform(70, 90),
            'function_calls': random.uniform(10, 30)
        }
    
    def _get_cost_breakdown(self):
        """Répartition des coûts"""
        return {
            'input_tokens': random.uniform(30, 50),
            'output_tokens': random.uniform(40, 60),
            'function_calls': random.uniform(10, 30),
            'total_usd': random.uniform(15, 45)
        }
    
    def _get_performance_trends(self):
        """Tendances de performance"""
        return {
            'response_time_trend': 'stable',
            'usage_trend': 'increasing',
            'cost_trend': 'stable',
            'error_trend': 'decreasing'
        }

4. Serveur MCP Sécurité (mcp_servers/security_server.py)

import random
from datetime import datetime, timedelta
import hashlib

class SecurityServer:
    """Serveur MCP pour la Sécurité - Risques, Vulnérabilités, Accès"""
    
    def __init__(self):
        self.security_events = []
        self.access_logs = []
        
    def get_security_metrics(self):
        """Collecte des métriques de sécurité"""
        return {
            'risk_level': random.randint(1, 5),
            'vulnerability_count': random.randint(0, 5),
            'failed_auth_attempts': random.randint(0, 10),
            'data_access_score': random.uniform(85, 98),
            'encryption_coverage': random.uniform(95, 100),
            'privacy_compliance': random.uniform(90, 99),
            'incident_count': random.randint(0, 3)
        }
    
    def get_detailed_metrics(self):
        """Métriques détaillées de sécurité"""
        return {
            'access_patterns': self._analyze_access_patterns(),
            'threat_detection': self._get_threat_analysis(),
            'data_protection': self._get_data_protection_status(),
            'user_permissions': self._get_permission_analysis(),
            'security_events': self._get_recent_security_events(),
            'compliance_checks': self._get_compliance_status()
        }
    
    def health_check(self):
        """Vérification de santé du serveur MCP"""
        return {
            'status': 'secure',
            'last_scan': datetime.now().isoformat(),
            'active_monitors': 12,
            'threat_level': 'low'
        }
    
    def _analyze_access_patterns(self):
        """Analyse des modèles d'accès"""
        return {
            'normal_access': random.uniform(85, 95),
            'suspicious_patterns': random.randint(0, 5),
            'geographic_anomalies': random.randint(0, 2),
            'time_anomalies': random.randint(0, 3)
        }
    
    def _get_threat_analysis(self):
        """Analyse des menaces"""
        return {
            'malware_attempts': random.randint(0, 2),
            'injection_attempts': random.randint(0, 1),
            'data_exfiltration_risk': random.uniform(1, 15),
            'social_engineering_attempts': random.randint(0, 3)
        }
    
    def _get_data_protection_status(self):
        """Statut de protection des données"""
        return {
            'encryption_at_rest': True,
            'encryption_in_transit': True,
            'access_controls': True,
            'data_masking': random.uniform(80, 95),
            'backup_integrity': random.uniform(95, 100)
        }
    
    def _get_permission_analysis(self):
        """Analyse des permissions"""
        return {
            'over_privileged_users': random.randint(0, 5),
            'inactive_accounts': random.randint(0, 10),
            'permission_creep': random.uniform(5, 20),
            'admin_accounts': random.randint(2, 8)
        }
    
    def _get_recent_security_events(self):
        """Événements de sécurité récents"""
        events = []
        for i in range(random.randint(0, 5)):
            events.append({
                'timestamp': (datetime.now() - timedelta(hours=random.randint(1, 48))).isoformat(),
                'type': random.choice(['LOGIN_ANOMALY', 'DATA_ACCESS', 'PERMISSION_CHANGE']),
                'severity': random.choice(['LOW', 'MEDIUM', 'HIGH']),
                'resolved': random.choice([True, False])
            })
        return events
    
    def _get_compliance_status(self):
        """Statut de conformité sécurité"""
        return {
            'gdpr_compliance': random.uniform(85, 98),
            'iso27001_compliance': random.uniform(80, 95),
            'soc2_compliance': random.uniform(88, 96),
            'last_audit': '2025-07-01'
        }

5. Base de Données (database.py)

import sqlite3
from datetime import datetime, timedelta
import json

class ClaudeMetricsDB:
    def __init__(self, db_path="claude_metrics.db"):
        self.db_path = db_path
    
    def init_db(self):
        """Initialise la base de données"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS claude_metrics (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp DATETIME NOT NULL,
                governance_score REAL,
                performance_score REAL,
                security_score REAL,
                metrics_json TEXT
            )
        ''')
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS mcp_events (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                timestamp DATETIME NOT NULL,
                server_type TEXT NOT NULL,
                event_type TEXT NOT NULL,
                severity TEXT,
                details TEXT
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def save_metrics(self, data):
        """Sauvegarde les métriques"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        gov_score = data['governance'].get('ethics_score', 0)
        perf_score = data['performance'].get('success_rate', 0)  
        sec_score = (5 - data['security'].get('risk_level', 3)) * 20  # Convertir en %
        
        cursor.execute('''
            INSERT INTO claude_metrics (timestamp, governance_score, performance_score, security_score, metrics_json)
            VALUES (?, ?, ?, ?, ?)
        ''', (
            data['timestamp'],
            gov_score,
            perf_score,
            sec_score,
            json.dumps(data)
        ))
        
        conn.commit()
        conn.close()
    
    def get_history_since(self, since_date):
        """Récupère l'historique depuis une date"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            SELECT metrics_json FROM claude_metrics 
            WHERE timestamp >= ? 
            ORDER BY timestamp ASC
        ''', (since_date.isoformat(),))
        
        results = []
        for row in cursor.fetchall():
            results.append(json.loads(row[0]))
        
        conn.close()
        return results
    
    def get_average_scores(self, days=7):
        """Scores moyens sur N jours"""
        since = datetime.now() - timedelta(days=days)
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            SELECT AVG(governance_score), AVG(performance_score), AVG(security_score)
            FROM claude_metrics 
            WHERE timestamp >= ?
        ''', (since.isoformat(),))
        
        result = cursor.fetchone()
        conn.close()
        
        return {
            'governance': result[0] or 0,
            'performance': result[1] or 0,
            'security': result[2] or 0
        }

6. Interface Web (templates/index.html)

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Claude MCP Governance Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <div class="container">
        <header>
            <h1>🤖 Claude MCP Governance Dashboard</h1>
            <div class="last-update">Dernière mise à jour: <span id="lastUpdate">-</span></div>
        </header>

        <!-- Statut des serveurs MCP -->
        <div class="mcp-status">
            <div class="mcp-server" id="governanceStatus">
                <h3>🛡️ Gouvernance MCP</h3>
                <div class="status-indicator"></div>
                <div class="server-metrics">
                    <div>Score Éthique: <span id="ethicsScore">-</span></div>
                    <div>Conformité: <span id="complianceRate">-</span></div>
                </div>
            </div>
            
            <div class="mcp-server" id="performanceStatus">
                <h3>⚡ Performance MCP</h3>
                <div class="status-indicator"></div>
                <div class="server-metrics">
                    <div>Utilisation: <span id="tokenUsage">-</span></div>
                    <div>Succès: <span id="successRate">-</span></div>
                </div>
            </div>
            
            <div class="mcp-server" id="securityStatus">
                <h3>🔒 Sécurité MCP</h3>
                <div class="status-indicator"></div>
                <div class="server-metrics">
                    <div>Niveau Risque: <span id="riskLevel">-</span></div>
                    <div>Conformité: <span id="privacyCompliance">-</span></div>
                </div>
            </div>
        </div>

        <!-- Métriques principales -->
        <div class="main-metrics">
            <div class="metric-card">
                <h3>Score de Gouvernance IA</h3>
                <canvas id="governanceGauge"></canvas>
                <div class="metric-value" id="governanceValue">0</div>
            </div>
            
            <div class="metric-card">
                <h3>Performance Globale</h3>
                <canvas id="performanceGauge"></canvas>
                <div class="metric-value" id="performanceValue">0</div>
            </div>
            
            <div class="metric-card">
                <h3>Niveau de Sécurité</h3>
                <canvas id="securityGauge"></canvas>
                <div class="metric-value" id="securityValue">0</div>
            </div>
        </div>

        <!-- Graphiques d'évolution -->
        <div class="charts-section">
            <div class="chart-container">
                <h3>Évolution des Métriques MCP</h3>
                <canvas id="metricsChart"></canvas>
            </div>
        </div>

        <!-- Alertes et conformité -->
        <div class="bottom-section">
            <div class="alerts-section">
                <h3>🚨 Alertes de Gouvernance</h3>
                <div id="alertsList" class="alerts-list">
                    <div class="no-alerts">Aucune alerte</div>
                </div>
            </div>
            
            <div class="compliance-section">
                <h3>📋 Rapport de Conformité</h3>
                <div id="complianceReport" class="compliance-details">
                    <div class="loading">Chargement...</div>
                </div>
            </div>
        </div>
    </div>

    <script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>

7. JavaScript (static/script.js)

let metricsChart;
let governanceGauge, performanceGauge, securityGauge;

// Initialisation
document.addEventListener('DOMContentLoaded', function() {
    initCharts();
    updateDashboard();
    
    // Mise à jour automatique toutes les minutes
    setInterval(updateDashboard, 60000);
});

function initCharts() {
    // Graphique d'évolution des métriques
    const ctx = document.getElementById('metricsChart').getContext('2d');
    metricsChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: [],
            datasets: [
                {
                    label: 'Gouvernance',
                    data: [],
                    borderColor: '#28a745',
                    backgroundColor: 'rgba(40, 167, 69, 0.1)',
                    tension: 0.4
                },
                {
                    label: 'Performance',
                    data: [],
                    borderColor: '#007bff',
                    backgroundColor: 'rgba(0, 123, 255, 0.1)',
                    tension: 0.4
                },
                {
                    label: 'Sécurité',
                    data: [],
                    borderColor: '#dc3545',
                    backgroundColor: 'rgba(220, 53, 69, 0.1)',
                    tension: 0.4
                }
            ]
        },
        options: {
            responsive: true,
            scales: {
                y: {
                    beginAtZero: true,
                    max: 100
                }
            }
        }
    });
    
    // Jauges circulaires
    initGauges();
}

function initGauges() {
    const gaugeOptions = {
        type: 'doughnut',
        options: {
            responsive: true,
            cutout: '70%',
            plugins: {
                legend: {
                    display: false
                }
            }
        }
    };
    
    governanceGauge = new Chart(document.getElementById('governanceGauge'), {
        ...gaugeOptions,
        data: {
            datasets: [{
                data: [0, 100],
                backgroundColor: ['#28a745', '#e9ecef'],
                borderWidth: 0
            }]
        }
    });
    
    performanceGauge = new Chart(document.getElementById('performanceGauge'), {
        ...gaugeOptions,
        data: {
            datasets: [{
                data: [0, 100],
                backgroundColor: ['#007bff', '#e9ecef'],
                borderWidth: 0
            }]
        }
    });
    
    securityGauge = new Chart(document.getElementById('securityGauge'), {
        ...gaugeOptions,
        data: {
            datasets: [{
                data: [0, 100],
                backgroundColor: ['#dc3545', '#e9ecef'],
                borderWidth: 0
            }]
        }
    });
}

async function updateDashboard() {
    try {
        // Métriques actuelles
        const currentResponse = await fetch('/api/current');
        const currentData = await currentResponse.json();
        
        if (currentData.governance) {
            updateMCPStatus(currentData);
            updateGauges(currentData);
        }
        
        // Historique pour le graphique
        const historyResponse = await fetch('/api/history?hours=6');
        const historyData = await historyResponse.json();
        updateMetricsChart(historyData);
        
        // Alertes
        const alertsResponse = await fetch('/api/alerts');
        const alertsData = await alertsResponse.json();
        updateAlerts(alertsData);
        
        // Rapport de conformité
        const complianceResponse = await fetch('/api/compliance');
        const complianceData = await complianceResponse.json();
        updateComplianceReport(complianceData);
        
        // Dernière mise à jour
        document.getElementById('lastUpdate').textContent = new Date().toLocaleTimeString();
        
    } catch (error) {
        console.error('Erreur mise à jour dashboard:', error);
    }
}

function updateMCPStatus(data) {
    const gov = data.governance;
    const perf = data.performance;
    const sec = data.security;
    
    // Gouvernance
    document.getElementById('ethicsScore').textContent = `${gov.ethics_score.toFixed(1)}/100`;
    document.getElementById('complianceRate').textContent = `${gov.compliance_rate.toFixed(1)}%`;
    updateServerStatus('governanceStatus', gov.ethics_score > 70);
    
    // Performance
    document.getElementById('tokenUsage').textContent = `${perf.token_usage_rate.toFixed(1)}%`;
    document.getElementById('successRate').textContent = `${perf.success_rate.toFixed(1)}%`;
    updateServerStatus('performanceStatus', perf.success_rate > 95);
    
    // Sécurité
    document.getElementById('riskLevel').textContent = `${sec.risk_level}/5`;
    document.getElementById('privacyCompliance').textContent = `${sec.privacy_compliance.toFixed(1)}%`;
    updateServerStatus('securityStatus', sec.risk_level < 4);
}

function updateServerStatus(serverId, isHealthy) {
    const server = document.getElementById(serverId);
    const indicator = server.querySelector('.status-indicator');
    
    if (isHealthy) {
        indicator.className = 'status-indicator healthy';
        indicator.textContent = '✓ Opérationnel';
    } else {
        indicator.className = 'status-indicator warning';
        indicator.textContent = '⚠ Attention';
    }
}

function updateGauges(data) {
    const govScore = data.governance.ethics_score;
    const perfScore = data.performance.success_rate;
    const secScore = (5 - data.security.risk_level) * 20; // Convertir en %
    
    // Mise à jour des jauges
    governanceGauge.data.datasets[0].data = [govScore, 100 - govScore];
    governanceGauge.update('none');
    document.getElementById('governanceValue').textContent = `${govScore.toFixed(1)}%`;
    
    performanceGauge.data.datasets[0].data = [perfScore, 100 - perfScore];
    performanceGauge.update('none');
    document.getElementById('performanceValue').textContent = `${perfScore.toFixed(1)}%`;
    
    securityGauge.data.datasets[0].data = [secScore, 100 - secScore];
    securityGauge.update('none');
    document.getElementById('securityValue').textContent = `${secScore.toFixed(1)}%`;
}

function updateMetricsChart(historyData) {
    const labels = [];
    const govData = [];
    const perfData = [];
    const secData = [];
    
    historyData.slice(-20).forEach(item => {
        const time = new Date(item.timestamp).toLocaleTimeString();
        labels.push(time);
        govData.push(item.governance.ethics_score);
        perfData.push(item.performance.success_rate);
        secData.push((5 - item.security.risk_level) * 20);
    });
    
    metricsChart.data.labels = labels;
    metricsChart.data.datasets[0].data = govData;
    metricsChart.data.datasets[1].data = perfData;
    metricsChart.data.datasets[2].data = secData;
    metricsChart.update('none');
}

function updateAlerts(alerts) {
    const alertsList = document.getElementById('alertsList');
    
    if (alerts.length === 0) {
        alertsList.innerHTML = '<div class="no-alerts">Aucune alerte</div>';
        return;
    }
    
    alertsList.innerHTML = alerts.map(alert => `
        <div class="alert ${alert.severity}">
            <div class="alert-header">
                <span class="alert-time">${alert.time}</span>
                <span class="alert-server">${alert.server}</span>
            </div>
            <div class="alert-content">
                <span class="alert-type">${alert.type}</span>
                <span class="alert-message">${alert.message}</span>
            </div>
        </div>
    `).join('');
}

function updateComplianceReport(report) {
    const complianceDiv = document.getElementById('complianceReport');
    
    complianceDiv.innerHTML = `
        <div class="compliance-item">
            <strong>Statut Global:</strong> 
            <span class="status ${report.compliance_status.toLowerCase()}">${report.compliance_status}</span>
        </div>
        <div class="compliance-item">
            <strong>Score Global:</strong> ${report.overall_score.toFixed(1)}/100
        </div>
        <div class="compliance-item">
            <strong>Prochain Audit:</strong> ${new Date(report.next_audit_date).toLocaleDateString()}
        </div>
        <div class="recommendations">
            <strong>Recommandations:</strong>
            <ul>
                ${report.recommendations.map(rec => `<li>${rec}</li>`).join('')}
            </ul>
        </div>
    `;
}

8. Styles CSS (static/style.css)

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    min-height: 100vh;
    color: #333;
}

.container {
    max-width: 1400px;
    margin: 0 auto;
    padding: 20px;
}

header {
    text-align: center;
    color: white;
    margin-bottom: 30px;
}

header h1 {
    font-size: 2.5em;
    margin-bottom: 10px;
}

.last-update {
    opacity: 0.8;
}

/* Statut des serveurs MCP */
.mcp-status {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
}

.mcp-server {
    background: rgba(255, 255, 255, 0.95);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

.mcp-server h3 {
    margin-bottom: 15px;
    font-size: 1.2em;
}

.status-indicator {
    padding: 8px 12px;
    border-radius: 20px;
    font-size: 0.9em;
    font-weight: bold;
    margin-bottom: 15px;
    text-align: center;
}

.status-indicator.healthy {
    background: #d4edda;
    color: #155724;
}

.status-indicator.warning {
    background: #fff3cd;
    color: #856404;
}

.server-metrics div {
    margin: 8px 0;
    font-size: 0.95em;
}

/* Métriques principales */
.main-metrics {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
}

.metric-card {
    background: rgba(255, 255, 255, 0.95);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
    text-align: center;
}

.metric-card h3 {
    margin-bottom: 15px;
    font-size: 1.1em;
}

.metric-card canvas {
    max-width: 120px;
    max-height: 120px;
    margin: 0 auto;
}

.metric-value {
    font-size: 1.5em;
    font-weight: bold;
    margin-top: 10px;
}

/* Graphiques */
.charts-section {
    margin-bottom: 30px;
}

.chart-container {
    background: rgba(255, 255, 255, 0.95);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

.chart-container h3 {
    margin-bottom: 15px;
    text-align: center;
}

/* Section du bas */
.bottom-section {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}

.alerts-section, .compliance-section {
    background: rgba(255, 255, 255, 0.95);
    padding: 20px;
    border-radius: 10px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

.alerts-section h3, .compliance-section h3 {
    margin-bottom: 15px;
}

/* Alertes */
.alert {
    padding: 12px;
    margin-bottom: 10px;
    border-radius: 5px;
    border-left: 4px solid;
}

.alert.high {
    background: #f8d7da;
    border-left-color: #dc3545;
}

.alert.medium {
    background: #fff3cd;
    border-left-color: #ffc107;
}

.alert-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 5px;
    font-size: 0.9em;
}

.alert-time {
    font-weight: bold;
}

.alert-server {
    background: #6c757d;
    color: white;
    padding: 2px 6px;
    border-radius: 3px;
    font-size: 0.8em;
}

.alert-content {
    display: flex;
    gap: 10px;
    align-items: center;
}

.alert-type {
    background: #007bff;
    color: white;
    padding: 2px 8px;
    border-radius: 3px;
    font-size: 0.8em;
    white-space: nowrap;
}

/* Conformité */
.compliance-item {
    margin: 10px 0;
    padding: 8px 0;
    border-bottom: 1px solid #eee;
}

.status.conforme {
    color: #28a745;
    font-weight: bold;
}

.status.attention {
    color: #ffc107;
    font-weight: bold;
}

.recommendations {
    margin-top: 15px;
}

.recommendations ul {
    margin-left: 20px;
    margin-top: 8px;
}

.recommendations li {
    margin: 5px 0;
}

.no-alerts {
    text-align: center;
    color: #999;
    font-style: italic;
    padding: 20px;
}

.loading {
    text-align: center;
    color: #999;
    font-style: italic;
}

/* Responsive */
@media (max-width: 768px) {
    .container {
        padding: 10px;
    }
    
    .mcp-status, .main-metrics {
        grid-template-columns: 1fr;
    }
    
    .bottom-section {
        grid-template-columns: 1fr;
    }
    
    header h1 {
        font-size: 2em;
    }
}

9. Dépendances (requirements.txt)

Flask==2.3.3
psutil==5.9.5

Installation et Lancement

# 1. Créer le projet
mkdir claude_mcp_monitor && cd claude_mcp_monitor

# 2. Créer la structure des dossiers
mkdir mcp_servers templates static

# 3. Installer les dépendances
pip install -r requirements.txt

# 4. Lancer l'application
python app.py

# 5. Accéder au dashboard
# http://localhost:5001

Fonctionnalités de Gouvernance IA

3 Serveurs MCP Complets

  • Gouvernance: Éthique, conformité, audit
  • Performance: Métriques, utilisation, coûts
  • Sécurité: Risques, vulnérabilités, accès

Dashboard de Gouvernance

  • Statut temps réel des serveurs MCP
  • Jauges de performance visuelles
  • Graphiques d'évolution des métriques

Système d'Alertes Intelligent

  • Alertes par catégorie MCP
  • Niveaux de sévérité
  • Notifications temps réel

Rapports de Conformité

  • Score global de gouvernance
  • Recommandations d'amélioration
  • Planification des audits

Métriques Complètes

  • Score éthique et transparence
  • Performance et utilisation
  • Analyse des risques sécuritaire

Pierre Erol GIRAUDY

https://www.erolgiraudy.eu/

https://uga-ia.blogspot.com/

https://www.erolgiraudy.eu/2024/10/mes-15-livres.html

https://and500.blogspot.com/

https://www.ugaia.eu/

Pour Info : Mon livre https://amzn.eu/d/eTuHn56 sur AMAZON

Users Group Artificial Intelligence Andorra (U.G.A.I.A.) : Liste des Certificats PDF Microsoft Learn

Info SharePoint-Teams-Copilot

https://clubsp2013.blogspot.com/p/portfolio-microsoft-learn-pierre-erol.html



Comment ajouter le protocole de contexte de modèle MCP à Copilot Studio ...

MCP démystifié et exemples : https://youtu.be/qjMBkk0R_7s?si=wPc7n9QtUtTHNIOC Nous analyserons le protocole MCP (Model Context Protocol), en...