MCP Eocene After work 2025 - Session pratique de 45 minutes
Du code minimal à une démo multi-tools déployée sur Azure
Cette session vous montre comment créer un serveur Model Context Protocol (MCP) en C#/.NET, l'enrichir avec des tools et resources, puis le déployer en production sur Azure.
Vous repartirez avec :
- ✅ Un serveur MCP .NET fonctionnel
- ✅ Des exemples de tools (API externes) et resources (données locales)
- ✅ Un pipeline de déploiement Azure
- ✅ Les bonnes pratiques de production
Le Model Context Protocol est un protocole standardisé créé par Anthropic pour permettre aux LLMs d'interagir avec des outils et des sources de données de manière uniforme.
- Plugins propriétaires pour chaque plateforme
- APIs custom sans standard
- Réinventer la roue à chaque intégration
- Pas d'interopérabilité entre assistants IA
- ✨ Standard ouvert : un serveur, plusieurs clients
- 🔌 Interopérabilité : fonctionne avec Claude, Azure OpenAI, etc.
- 🔒 Sécurité : MCP Registry pour vérifier les serveurs de confiance
- 🚀 Écosystème : réutilisation des serveurs existants
MCP fait pour l'IA ce que REST a fait pour les APIs web : standardiser l'accès aux données et fonctionnalités.
┌─────────────────┐ ┌──────────────────┐
│ LLM Client │◄────────┤ MCP Server │
│ (Claude, Azure │ MCP │ (.NET/C#) │
│ OpenAI, etc.) │Protocol │ │
└─────────────────┘ └──────────────────┘
│
┌───────────┴───────────┐
│ │
┌───▼────┐ ┌─────▼────┐
│ Tools │ │Resources │
│────────│ │──────────│
│ API │ │ Files │
│ Calls │ │ JSON │
│ Actions│ │ Database │
└────────┘ └──────────┘
-
Tools : Actions que le LLM peut déclencher
- Appeler une API externe (météo, actualités, etc.)
- Exécuter une action métier (créer un ticket, envoyer un email)
- Interagir avec des services Azure
-
Resources : Données exposées au LLM
- Fichiers locaux ou distants
- Bases de données
- Documents d'entreprise
-
Prompts : Templates pré-configurés côté serveur
- Scénarios métier standardisés
- Contexte pré-chargé
- .NET 8.0 SDK ou supérieur
- Visual Studio Code ou Visual Studio 2022
- (Optionnel) Claude Desktop pour les tests locaux
- (Optionnel) Compte Azure pour le déploiement
# Créer un nouveau projet console .NET
dotnet new console -n McpServer
cd McpServer
# Ajouter les packages nécessaires
dotnet add package ModelContextProtocol.NET
dotnet add package Microsoft.Extensions.Hostingusing Microsoft.Extensions.Hosting;
using ModelContextProtocol;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMcpServer(options =>
{
options.ServerInfo = new ServerInfo
{
Name = "demo-mcp-server",
Version = "1.0.0"
};
});
var host = builder.Build();
await host.RunAsync();[McpTool("get_weather", "Récupère la météo pour une ville donnée")]
public class WeatherTool : IMcpTool
{
public async Task<ToolResult> ExecuteAsync(ToolCallRequest request)
{
var city = request.Parameters["city"].ToString();
// Appel API météo (exemple simplifié)
var response = await httpClient.GetAsync($"https://api.openweathermap.org/data/2.5/weather?q={city}");
var weather = await response.Content.ReadAsStringAsync();
return new ToolResult { Content = weather };
}
}// Configurer dans Claude Desktop : ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"demo-server": {
"command": "dotnet",
"args": ["run", "--project", "/path/to/McpServer"]
}
}
}[McpTool("search_news", "Recherche des actualités")]
public class NewsSearchTool : IMcpTool
{
private readonly IHttpClientFactory _httpClientFactory;
public async Task<ToolResult> ExecuteAsync(ToolCallRequest request)
{
var query = request.Parameters["query"].ToString();
var client = _httpClientFactory.CreateClient();
var response = await client.GetAsync(
$"https://newsapi.org/v2/everything?q={query}&apiKey={apiKey}"
);
return new ToolResult
{
Content = await response.Content.ReadAsStringAsync()
};
}
}[McpResource("config://settings", "Configuration de l'application")]
public class ConfigResource : IMcpResource
{
public async Task<ResourceContent> ReadAsync()
{
var json = await File.ReadAllTextAsync("appsettings.json");
return new ResourceContent
{
MimeType = "application/json",
Text = json
};
}
}- Créer
.vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug MCP Server",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/bin/Debug/net8.0/McpServer.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal"
}
]
}- Placer des breakpoints dans vos tools
- Lancer le debugger (F5)
- Tester avec Claude Desktop ou un client MCP test
builder.Services.AddLogging(logging =>
{
logging.AddConsole();
logging.AddDebug();
logging.SetMinimumLevel(LogLevel.Debug);
});Le MCP Inspector est un outil interactif pour tester et debugger votre serveur MCP sans avoir besoin d'un client complet.
# Lancer directement via npx (pas d'installation nécessaire)
npx @modelcontextprotocol/inspector dotnet run --project ./McpServer
# Ou avec des arguments
npx @modelcontextprotocol/inspector dotnet run --project ./McpServer -- --environment DevelopmentInterface web interactive :
- 🔌 Server connection pane : Configure le transport (stdio, SSE, HTTP)
- 📦 Resources tab : Liste et teste vos resources
- 💬 Prompts tab : Teste les prompts avec des arguments custom
- 🛠️ Tools tab : Exécute et teste vos tools avec inputs personnalisés
- 📋 Notifications pane : Visualise les logs et notifications du serveur
Avantages :
- ✅ Pas besoin de Claude Desktop pour tester
- ✅ Interface graphique pour tester chaque tool individuellement
- ✅ Voir les messages JSON-RPC échangés
- ✅ Tester les edge cases et la gestion d'erreurs
- ✅ Vérifier la connexion et la négociation des capabilities
- Lancer l'Inspector avec votre serveur
- Vérifier la connectivité de base
- Faire des changements dans votre code
- Rebuild le serveur
- Reconnecter l'Inspector
- Tester les fonctionnalités modifiées
- Monitorer les messages échangés
- Lancer l'Inspector :
npx @modelcontextprotocol/inspector dotnet run --project ./McpServer - Ouvrir l'interface web (généralement http://localhost:5173)
- Aller dans l'onglet Tools
- Sélectionner
get_weather - Entrer les paramètres :
{ "city": "Namur" } - Cliquer sur Execute
- Voir le résultat et les logs
# Build l'image Docker
docker build -t mcp-server .
# Push vers Azure Container Registry
az acr login --name myregistry
docker tag mcp-server myregistry.azurecr.io/mcp-server:latest
docker push myregistry.azurecr.io/mcp-server:latest
# Déployer sur Container Apps
az containerapp create \
--name mcp-server \
--resource-group MyResourceGroup \
--environment MyEnvironment \
--image myregistry.azurecr.io/mcp-server:latest \
--target-port 8080 \
--ingress external[Function("McpEndpoint")]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "post")] HttpRequestData req)
{
// Gérer les requêtes MCP via HTTP
var mcpRequest = await req.ReadFromJsonAsync<McpRequest>();
var result = await _mcpServer.HandleRequestAsync(mcpRequest);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(result);
return response;
}Pourquoi Durable Functions pour MCP ?
- ✅ Pas de limite de timeout : workflows qui peuvent durer des heures/jours
- ✅ État persistant : conversations et threads maintenus automatiquement
- ✅ Orchestrations déterministes : coordination multi-agents fiable
- ✅ Reprise après échec : l'état survit aux redémarrages
- ✅ Scalabilité : scale to zero avec Flex Consumption Plan
Installation :
dotnet add package Microsoft.Agents.AI.OpenAI --prerelease
dotnet add package Microsoft.Agents.AI.Hosting.AzureFunctions --prerelease
dotnet add package Microsoft.Azure.Functions.Worker --version 2.2.0Code :
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hosting.AzureFunctions;
using Microsoft.Azure.Functions.Worker.Builder;
using Azure.AI.OpenAI;
using Azure.Identity;
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT") ?? "gpt-4";
// Créer un agent MCP avec outils
AIAgent mcpAgent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetChatClient(deploymentName)
.CreateAIAgent(
instructions: "Tu es un assistant utilisant des outils MCP.",
name: "McpDurableAgent"
);
// Ajouter les tools MCP
mcpAgent.Tools.Add(new WeatherTool());
mcpAgent.Tools.Add(new ConfigResourceTool());
// Configurer l'application avec Durable Task Extension
using IHost app = FunctionsApplication
.CreateBuilder(args)
.ConfigureFunctionsWebApplication()
.ConfigureDurableAgents(options =>
options.AddAIAgent(mcpAgent)
)
.Build();
app.Run();Endpoints automatiquement créés :
POST /api/agents/McpDurableAgent/run: Exécuter l'agentGET /api/agents/McpDurableAgent/threads/{threadId}: Récupérer l'historiqueDELETE /api/agents/McpDurableAgent/threads/{threadId}: Supprimer un thread
Utilisation avec threads persistants :
# Première interaction - crée un nouveau thread
curl -X POST https://your-app.azurewebsites.net/api/agents/McpDurableAgent/run \
-H "Content-Type: text/plain" \
-d "Quelle est la météo à Namur ?"
# Réponse inclut le thread ID dans le header x-ms-thread-id
# x-ms-thread-id: @dafx-mcpagent@abc123-def456
# Interaction suivante - continue le même thread avec contexte
curl -X POST "https://your-app.azurewebsites.net/api/agents/McpDurableAgent/run?thread_id=@dafx-mcpagent@abc123-def456" \
-H "Content-Type: text/plain" \
-d "Et demain ?"
# L'agent se souvient du contexte (Namur) grâce à l'état persistantDéploiement :
# Créer une Function App avec Flex Consumption (recommandé)
az functionapp create \
--resource-group mcp-demo-rg \
--name mcp-durable-func \
--storage-account mcpstorage \
--flexconsumption-location westeurope \
--runtime dotnet-isolated \
--runtime-version 8.0
# Déployer
func azure functionapp publish mcp-durable-funcMonitoring : Utilisez le Durable Task Scheduler Dashboard pour visualiser :
- Historique des conversations
- Flux d'orchestration
- État des threads actifs
{
"Authentication": {
"ApiKey": "#{API_KEY}#",
"AllowedOrigins": ["https://claude.ai", "https://myapp.azurewebsites.net"]
},
"RateLimiting": {
"RequestsPerMinute": 60
}
}Le MCP Registry d'Anthropic permet de vérifier les serveurs de confiance :
- ✅ Serveurs vérifiés par la communauté
- ✅ Audits de sécurité
- ✅ Badges de confiance
public async Task<ToolResult> ExecuteAsync(ToolCallRequest request)
{
if (!request.Parameters.ContainsKey("city"))
throw new ArgumentException("Le paramètre 'city' est requis");
var city = request.Parameters["city"].ToString();
if (string.IsNullOrWhiteSpace(city) || city.Length > 100)
throw new ArgumentException("Nom de ville invalide");
// ... suite du code
}try
{
var result = await externalApi.CallAsync();
return new ToolResult { Content = result };
}
catch (HttpRequestException ex)
{
return new ToolResult
{
IsError = true,
Content = $"Erreur API : {ex.Message}"
};
}builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("api", opt =>
{
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(1);
});
});builder.Services.AddApplicationInsightsTelemetry();
// Dans votre tool
_telemetryClient.TrackEvent("ToolExecuted", new Dictionary<string, string>
{
{ "ToolName", "get_weather" },
{ "City", city }
});var client = new AzureOpenAIClient(endpoint, credential);
var agent = await client.CreateAgentAsync(new AgentCreateOptions
{
Model = "gpt-4",
Name = "Assistant Météo",
Tools = new[]
{
new McpToolReference
{
ServerUrl = "https://mcp-server.azurecontainerapps.io",
ToolName = "get_weather"
}
}
});┌──────────────┐
│ Frontend │
│ (React/ │
│ Blazor) │
└──────┬───────┘
│
▼
┌──────────────────┐ ┌─────────────────┐
│ Azure OpenAI │◄──────┤ MCP Server │
│ Agents │ MCP │ (Container Apps)│
└──────────────────┘ └─────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Azure │ │Cosmos │ │Storage │
│APIs │ │DB │ │Account │
└────────┘ └────────┘ └────────┘
builder.Services.AddHealthChecks()
.AddCheck("mcp_server", () => HealthCheckResult.Healthy())
.AddUrlGroup(new Uri("https://api.external.com/health"), "external_api");
app.MapHealthChecks("/health");Exemples de serveurs MCP disponibles dans l'écosystème :
- @modelcontextprotocol/server-filesystem : Accès fichiers
- @modelcontextprotocol/server-github : Intégration GitHub
- @modelcontextprotocol/server-postgres : Base de données PostgreSQL
- @modelcontextprotocol/server-slack : Intégration Slack
- Custom .NET servers : SharePoint, SQL Server, Azure Services
- ModelContextProtocol.NET (hypothétique - adaptez selon le SDK réel)
- Claude Desktop
- MCP Inspector - Outil de test interactif
- MCP Inspector Documentation
- Ce repository : implémentation complète
- MCP Samples
- Introduction & Contexte (5-7 min)
- Démo Live : Création du serveur (15-18 min)
- Déploiement Azure (8-10 min)
- Intégration Production (8-10 min)
- Conclusion & Q&A (3-5 min)
Ce repository est un support de présentation. N'hésitez pas à :
- 🐛 Signaler des bugs ou améliorations
- 💡 Proposer de nouveaux exemples de tools
- 📝 Améliorer la documentation
MIT License - Libre d'utilisation et de modification pour vos propres projets.
Présenté à After work Namur 2025
Contact : adrien.social
Bon développement avec MCP ! 🚀