<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>AI on Thomas</title>
        <link>https://blog.thomasplantain.fr/categories/ai/</link>
        <description>Recent content in AI on Thomas</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>fr-fr</language>
        <lastBuildDate>Tue, 21 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.thomasplantain.fr/categories/ai/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>MCP pour les nuls - la suite</title>
        <link>https://blog.thomasplantain.fr/post/mcpgtw/</link>
        <pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate>
        
        <guid>https://blog.thomasplantain.fr/post/mcpgtw/</guid>
        <description>&lt;img src="https://blog.thomasplantain.fr/img/mcpgtw/mcp-gateway-gemini.avif" alt="Featured image of post MCP pour les nuls - la suite" /&gt;&lt;blockquote&gt;
&lt;p&gt;Suite du post précédent, je mets en place une gateway pour protéger mon serveur MCP. Le serveur MCP a été déployé sur Azure Container, il est accessible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/mcp-gateway-gemini.avif&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;MCP Gateway&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;mise-en-place-dune-flex-gateway&#34;&gt;Mise en place d&amp;rsquo;une Flex gateway
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Création et enregistrement de ma nouvelle Flex gateway (mcp-gateway)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;J&amp;rsquo;ai créé une image Docker de la flex avec son fichier d&amp;rsquo;enregistrement. L&amp;rsquo;image Docker tourne sur un Azure Container, elle est maintenant visible sur Anypoint (le control plane de MuleSoft).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/new-flex-gtw.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Flex Gateway&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;configuration-de-mon-server-mcp-sur-anypoint&#34;&gt;Configuration de mon server MCP sur Anypoint
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.mulesoft.com/api-manager/latest/create-instance-task-agent-tool&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Documentation officielle de MuleSoft&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ajout de mon serveur MCP (mcp_card)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Aller sur &lt;strong&gt;API Manager&lt;/strong&gt; (Anypoint) et sélectionner &lt;strong&gt;Agent and Tools Instances&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/mcp-server-instance.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;API Manager&#34;
	
	
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;En sélectionnant la Flex Gateway mise en place pour ce projet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/add-mcp1.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Flex Gateway&#34;
	
	
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Maintenant on peut ajouter un &lt;strong&gt;MCP Server&lt;/strong&gt; et on finalise la configuration.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/mcp-config1.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Flex Gateway&#34;
	
	
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le contrat du serveur &lt;strong&gt;mcp_card&lt;/strong&gt; est visible sur le portail API d&amp;rsquo;Anypoint (Exchange).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/exchange-mcp.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Echange&#34;
	
	
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Le serveur mcp_card est théoriquement accessible via la gateway, il faut maintenant ajouter les policies pour le sécuriser.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;policies-pour-mon-serveur-mcp&#34;&gt;Policies pour mon serveur MCP
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://docs.mulesoft.com/gateway/latest/policies-included-mcp-support&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MCP Support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Cette policy est obligatoire pour le bon fonctionnement du serveur MCP.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Client ID Enforcement&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Pour limiter l&amp;rsquo;accès au serveur &lt;strong&gt;mcp_card&lt;/strong&gt; aux applications enregistrées qui ont le duo &lt;strong&gt;client_id/client_secret&lt;/strong&gt; dans leurs Headers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/mcp-clientid.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Echange&#34;
	
	
&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Nous avons donc 2 policies configurées sur notre gateway pour le serveur &lt;strong&gt;mcp_card&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/mcp-policies.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Policies&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;appels-du-serveur-mcp-avec-bruno&#34;&gt;Appels du serveur MCP avec Bruno
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Nous allons tester la connectivité au server &lt;strong&gt;mcp_card&lt;/strong&gt; avec le client API &lt;a class=&#34;link&#34; href=&#34;https://www.usebruno.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;Bruno&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Configuration des Headers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/bruno-headers.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Headers&#34;
	
	
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Appels aux services du serveur &lt;strong&gt;mcp_card&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/call-mcp1.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;card_details&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/call-mcp4.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;transaction_list&#34;
	
	
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Si le &lt;strong&gt;client_secret&lt;/strong&gt; est faux dans les Headers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/call-mcp-failed.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;failed&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;observabilité&#34;&gt;Observabilité
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;L&amp;rsquo;outil de monitoring d&amp;rsquo;Anypoint nous permet au niveau de la configuration du serveur de visualiser les appels. On voit les appels de chaque service et les appels en erreurs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;card_details&lt;/li&gt;
&lt;li&gt;transaction_list&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcpgtw/mcp-metrics.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;metrics&#34;
	
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>MCP pour les nuls</title>
        <link>https://blog.thomasplantain.fr/post/mcp/</link>
        <pubDate>Tue, 24 Mar 2026 00:00:00 +0000</pubDate>
        
        <guid>https://blog.thomasplantain.fr/post/mcp/</guid>
        <description>&lt;img src="https://blog.thomasplantain.fr/img/mcp/mcp_bg.avif" alt="Featured image of post MCP pour les nuls" /&gt;&lt;h2 id=&#34;mcp-kesako-&#34;&gt;MCP Kesako ?
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Protocole de communication entre un agent IA et un service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://modelcontextprotocol.io/docs/getting-started/intro&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;MCP Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le service permet à un agent d&amp;rsquo;avoir accès à des données structurées (format JSON) qui ne sont pas déjà présentes dans son modèle LLM.
Il existe deux protocoles de communication, io et http. Dans mon cas, je souhaite utiliser http, dans l&amp;rsquo;idée de créer un serveur MCP accessible à tous.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcp/mcp-simple-diagram.avif&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;copilot&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;Pour accélérer le développement, je vais utiliser la librairie Python fastMCP :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fastMCP: &lt;a class=&#34;link&#34; href=&#34;https://gofastmcp.com/getting-started/welcome&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://gofastmcp.com/getting-started/welcome&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;prototype-du-service-mcp&#34;&gt;Prototype du service MCP
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Mon cas d&amp;rsquo;utilisation : je veux mettre en place un service qui donne les détails d&amp;rsquo;une carte de crédit si on lui donne le numéro en paramètre, ou la liste des transactions d&amp;rsquo;un compte.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dans ce premier post, je ne vais pas aborder la sécurité ni l&amp;rsquo;observabilité, mais je souhaite en parler bientôt dans un post dédié, notamment via une API Gateway.&lt;/p&gt;
&lt;h3 id=&#34;pour-commencer&#34;&gt;Pour commencer
&lt;/h3&gt;&lt;p&gt;Dans un environnement Python :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install fastmcp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;serveur-mcp-card-details&#34;&gt;Serveur MCP Card Details
&lt;/h3&gt;&lt;p&gt;J&amp;rsquo;ai créé deux services : le détail d&amp;rsquo;une carte et la liste des transactions d&amp;rsquo;un compte, avec des données fictives.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; fastmcp &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; FastMCP
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; starlette.requests &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Request
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; starlette.responses &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; PlainTextResponse
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mcp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; FastMCP(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;My MCP Server&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@mcp.custom_route&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/health&amp;#34;&lt;/span&gt;, methods&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;[&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;])
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;health_check&lt;/span&gt;(request: Request) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; PlainTextResponse:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; PlainTextResponse(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;OK&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;card_details&lt;/span&gt;(card_number: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; dict:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Dummy implementation for demonstration purposes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;card_number&amp;#34;&lt;/span&gt;: card_number,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;card_type&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Visa&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;expiry_date&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;12/25&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cardholder_name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;John Doe&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;transaction_list&lt;/span&gt;(account_id: str) &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; list:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Dummy implementation for demonstration purposes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;transaction_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;txn_001&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;100.0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;completed&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;transaction_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;txn_002&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;50.0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pending&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;transaction_id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;txn_003&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;amount&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;75.0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;currency&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;USD&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed&amp;#34;&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    mcp&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;run(transport&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;, port&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;8000&lt;/span&gt;)    
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pour lancer le serveur qui va écouter sur le port 8000, j&amp;rsquo;exécute :&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python my_server.py
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuration-de-copilot&#34;&gt;Configuration de Copilot
&lt;/h2&gt;&lt;p&gt;Une fois que le serveur MCP tourne dans la console, je configure mon GitHub Copilot pour qu&amp;rsquo;il ajoute le serveur dans sa liste :&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcp/mcp_copilot_config.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;copilot&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;Une fois la configuration faite, on peut voir le serveur et les deux fonctionnalités (&lt;code&gt;card_details&lt;/code&gt; et &lt;code&gt;transaction_list&lt;/code&gt;) :&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcp/mcp_tools.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;tools&#34;
	
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;utilisation-du-service&#34;&gt;Utilisation du service
&lt;/h3&gt;&lt;p&gt;Les deux fonctionnalités sont maintenant accessibles dans le chat de Copilot :
&lt;img src=&#34;https://blog.thomasplantain.fr/img/mcp/mcp_copilot.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;chat&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;prochaines-étapes&#34;&gt;Prochaines étapes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Mettre en place une API Gateway
&lt;ul&gt;
&lt;li&gt;Authentification&lt;/li&gt;
&lt;li&gt;Observabilité&lt;/li&gt;
&lt;li&gt;Limitation, quotas&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>MLOps: Bridging Machine Learning and Operations</title>
        <link>https://blog.thomasplantain.fr/post/mlops/</link>
        <pubDate>Fri, 13 Feb 2026 00:00:00 +0000</pubDate>
        
        <guid>https://blog.thomasplantain.fr/post/mlops/</guid>
        <description>&lt;img src="https://blog.thomasplantain.fr/img/mlops.png" alt="Featured image of post MLOps: Bridging Machine Learning and Operations" /&gt;&lt;h2 id=&#34;what-is-mlops&#34;&gt;What is MLOps?
&lt;/h2&gt;&lt;p&gt;MLOps (Machine Learning Operations) is a set of practices that combines machine learning, DevOps, and data engineering to streamline the development, deployment, and maintenance of machine learning systems in production.&lt;/p&gt;
&lt;p&gt;Think of it as applying software engineering best practices to machine learning workflows—but with additional complexity due to data, model versioning, and continuous retraining requirements.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-mlops-landscape&#34;&gt;The MLOps Landscape
&lt;/h2&gt;&lt;h3 id=&#34;core-pillars&#34;&gt;Core Pillars
&lt;/h3&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;┌─────────────────────────────────────────┐
│          ML Model Development           │
│  (Experimentation, Training, Tuning)    │
└────────────────┬────────────────────────┘
                 │
┌────────────────┴────────────────────────┐
│     Model Validation &amp;amp; Testing          │
│  (Metrics, A/B Testing, Performance)    │
└────────────────┬────────────────────────┘
                 │
┌────────────────┴────────────────────────┐
│      Model Deployment &amp;amp; Serving         │
│  (Containerization, APIs, Scaling)      │
└────────────────┬────────────────────────┘
                 │
┌────────────────┴────────────────────────┐
│   Monitoring, Retraining &amp;amp; Governance   │
│  (Data Drift, Performance, Compliance)  │
└─────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;key-components&#34;&gt;Key Components
&lt;/h2&gt;&lt;h3 id=&#34;1-data-management&#34;&gt;1. &lt;strong&gt;Data Management&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Pipeline&lt;/strong&gt;: Automated extraction, transformation, and loading (ETL)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Versioning&lt;/strong&gt;: Track datasets like code (DVC, Delta Lake)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Quality&lt;/strong&gt;: Validation, schema enforcement, anomaly detection&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature Store&lt;/strong&gt;: Centralized feature management and serving&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;2-model-development&#34;&gt;2. &lt;strong&gt;Model Development&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Experimentation Tracking&lt;/strong&gt;: Log hyperparameters, metrics, artifacts (MLflow, Weights &amp;amp; Biases)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model Registry&lt;/strong&gt;: Version control for trained models&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;: Environment specifications, random seeds, documentation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaboration&lt;/strong&gt;: Shared resources for data scientists and engineers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;3-model-validation&#34;&gt;3. &lt;strong&gt;Model Validation&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unit Testing&lt;/strong&gt;: Data and model logic validation&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration Testing&lt;/strong&gt;: End-to-end pipeline testing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model Evaluation&lt;/strong&gt;: Performance metrics on holdout sets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A/B Testing&lt;/strong&gt;: Compare models in production with real user traffic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fairness &amp;amp; Bias Detection&lt;/strong&gt;: Ensure model equity across demographics&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;4-deployment--serving&#34;&gt;4. &lt;strong&gt;Deployment &amp;amp; Serving&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Containerization&lt;/strong&gt;: Docker for reproducible environments&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Orchestration&lt;/strong&gt;: Kubernetes for managing deployments at scale&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model Serving&lt;/strong&gt;: REST APIs, gRPC, batch inference, real-time serving&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Version Management&lt;/strong&gt;: Blue-green deployments, canary releases, rollback capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;5-monitoring--governance&#34;&gt;5. &lt;strong&gt;Monitoring &amp;amp; Governance&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Performance Monitoring&lt;/strong&gt;: Track model predictions, latency, throughput&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data Drift Detection&lt;/strong&gt;: Alert when input distributions change&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model Decay&lt;/strong&gt;: Monitor accuracy degradation over time&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit Trails&lt;/strong&gt;: Compliance logging for regulated industries&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Optimization&lt;/strong&gt;: Track infrastructure and compute costs&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;mlops-workflow&#34;&gt;MLOps Workflow
&lt;/h2&gt;&lt;h3 id=&#34;from-experimentation-to-production&#34;&gt;From Experimentation to Production
&lt;/h3&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Notebook Experimentation
        ↓
Feature Engineering &amp;amp; Versioning
        ↓
Model Training Pipeline (Automated)
        ↓
Model Validation &amp;amp; Testing
        ↓
Model Registry &amp;amp; Packaging
        ↓
Containerization &amp;amp; Artifact Storage
        ↓
Deployment to Staging Environment
        ↓
A/B Testing &amp;amp; Validation
        ↓
Production Deployment
        ↓
Monitoring &amp;amp; Alerting
        ↓
Retraining Triggers (Data/Model Drift)
        ↓
Loop Back to Training
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;popular-mlops-tools&#34;&gt;Popular MLOps Tools
&lt;/h2&gt;&lt;h3 id=&#34;experiment-tracking--model-management&#34;&gt;Experiment Tracking &amp;amp; Model Management
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MLflow&lt;/strong&gt;: Open-source platform for managing ML lifecycle&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Weights &amp;amp; Biases&lt;/strong&gt;: Cloud-based experiment tracking and hyperparameter optimization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Neptune.ai&lt;/strong&gt;: Lightweight experiment tracking for teams&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;data-management&#34;&gt;Data Management
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DVC&lt;/strong&gt; (Data Version Control): Version control for data and pipelines&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apache Airflow&lt;/strong&gt;: Workflow orchestration and DAG scheduling&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prefect&lt;/strong&gt;: Modern data orchestration platform&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delta Lake&lt;/strong&gt;: ACID transactions for data lakes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;model-serving&#34;&gt;Model Serving
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TensorFlow Serving&lt;/strong&gt;: Specialized serving for TensorFlow models&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Seldon Core&lt;/strong&gt;: Open-source model serving platform on Kubernetes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BentoML&lt;/strong&gt;: Framework for packaging and deploying ML models&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ray Serve&lt;/strong&gt;: Distributed model serving framework&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;monitoring--observability&#34;&gt;Monitoring &amp;amp; Observability
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Datadog&lt;/strong&gt;: Infrastructure and APM monitoring&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prometheus + Grafana&lt;/strong&gt;: Metrics collection and visualization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WhyLabs&lt;/strong&gt;: ML model monitoring and data quality&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arize&lt;/strong&gt;: ML model monitoring and explainability&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;infrastructure--operations&#34;&gt;Infrastructure &amp;amp; Operations
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kubernetes&lt;/strong&gt;: Container orchestration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docker&lt;/strong&gt;: Containerization&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Terraform&lt;/strong&gt;: Infrastructure as Code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jenkins / GitLab CI / GitHub Actions&lt;/strong&gt;: CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;mlops-best-practices&#34;&gt;MLOps Best Practices
&lt;/h2&gt;&lt;h3 id=&#34;development&#34;&gt;Development
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Treat data like code&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Version datasets and transformations&lt;/li&gt;
&lt;li&gt;Automate data pipeline testing&lt;/li&gt;
&lt;li&gt;Document data lineage&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reproducibility First&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lock dependencies (requirements.txt, environment.yml)&lt;/li&gt;
&lt;li&gt;Document model training steps&lt;/li&gt;
&lt;li&gt;Store random seeds and hyperparameters&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Modular Design&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separate feature engineering from model training&lt;/li&gt;
&lt;li&gt;Use configuration files (YAML, JSON) for hyperparameters&lt;/li&gt;
&lt;li&gt;Build reusable components&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;testing&#34;&gt;Testing
&lt;/h3&gt;&lt;ol start=&#34;4&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Comprehensive Testing Strategy&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unit tests for data transformations&lt;/li&gt;
&lt;li&gt;Integration tests for full pipelines&lt;/li&gt;
&lt;li&gt;Model performance tests against baselines&lt;/li&gt;
&lt;li&gt;Test edge cases and adversarial inputs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automated Validation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Schema validation for inputs and outputs&lt;/li&gt;
&lt;li&gt;Range checks for features&lt;/li&gt;
&lt;li&gt;Bias and fairness audits&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;deployment&#34;&gt;Deployment
&lt;/h3&gt;&lt;ol start=&#34;6&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Infrastructure as Code&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Define environments declaratively&lt;/li&gt;
&lt;li&gt;Version control infrastructure changes&lt;/li&gt;
&lt;li&gt;Automate provisioning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Progressive Rollouts&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start with canary deployments (1-5% traffic)&lt;/li&gt;
&lt;li&gt;Monitor metrics closely during rollout&lt;/li&gt;
&lt;li&gt;Have automated rollback mechanisms&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;monitoring&#34;&gt;Monitoring
&lt;/h3&gt;&lt;ol start=&#34;8&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log predictions and features&lt;/li&gt;
&lt;li&gt;Monitor model accuracy in real time&lt;/li&gt;
&lt;li&gt;Track data distributions for drift detection&lt;/li&gt;
&lt;li&gt;Set up alerts for anomalies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Feedback Loops&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Capture true labels as they become available&lt;/li&gt;
&lt;li&gt;Use actuals to retrain models&lt;/li&gt;
&lt;li&gt;Monitor feedback quality&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;organization&#34;&gt;Organization
&lt;/h3&gt;&lt;ol start=&#34;10&#34;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Clear Ownership&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Define roles: data engineer, ML engineer, ML ops engineer&lt;/li&gt;
&lt;li&gt;Establish SLOs (Service Level Objectives) for models&lt;/li&gt;
&lt;li&gt;Document runbooks for common issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Governance &amp;amp; Compliance&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Audit trail for model decisions&lt;/li&gt;
&lt;li&gt;Explainability/interpretability requirements&lt;/li&gt;
&lt;li&gt;Data privacy and regulatory compliance&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;real-world-challenges&#34;&gt;Real-World Challenges
&lt;/h2&gt;&lt;h3 id=&#34;technical-challenges&#34;&gt;Technical Challenges
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data Quality&lt;/strong&gt;: Garbage in, garbage out&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model Complexity&lt;/strong&gt;: Balancing accuracy vs. interpretability vs. latency&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Handling millions of predictions per second&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;: ML experiments are inherently non-deterministic&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;organizational-challenges&#34;&gt;Organizational Challenges
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Silos&lt;/strong&gt;: Data science isolated from engineering&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skills Gap&lt;/strong&gt;: Few engineers understand both ML and infrastructure&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time to Market&lt;/strong&gt;: Experimentation cycles are long&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cost Control&lt;/strong&gt;: Compute resources can quickly become expensive&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;getting-started-with-mlops&#34;&gt;Getting Started with MLOps
&lt;/h2&gt;&lt;h3 id=&#34;level-1-manual-processes&#34;&gt;Level 1: Manual Processes
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Jupyter notebooks for experimentation&lt;/li&gt;
&lt;li&gt;Manual model files and version tracking&lt;/li&gt;
&lt;li&gt;Basic monitoring with logs&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;level-2-automated-pipelines&#34;&gt;Level 2: Automated Pipelines
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Automated training pipelines with cron jobs&lt;/li&gt;
&lt;li&gt;Version control for code and models&lt;/li&gt;
&lt;li&gt;Basic monitoring dashboards&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;level-3-continuous-integration&#34;&gt;Level 3: Continuous Integration
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;Automated testing on code changes&lt;/li&gt;
&lt;li&gt;CI/CD pipelines for model training and deployment&lt;/li&gt;
&lt;li&gt;Experiment tracking and model registries&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;level-4-full-mlops-maturity&#34;&gt;Level 4: Full MLOps Maturity
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;End-to-end automation and orchestration&lt;/li&gt;
&lt;li&gt;Advanced monitoring with drift detection&lt;/li&gt;
&lt;li&gt;Automated retraining triggers&lt;/li&gt;
&lt;li&gt;Multi-model experimentation and A/B testing&lt;/li&gt;
&lt;li&gt;Governance and audit trails&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;MLOps is essential for scaling machine learning from experimentation to reliable, production systems. It bridges the gap between data science innovation and operational stability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MLOps combines ML, DevOps, and data engineering practices&lt;/li&gt;
&lt;li&gt;Success requires automation at every stage&lt;/li&gt;
&lt;li&gt;Monitoring and feedback loops are critical&lt;/li&gt;
&lt;li&gt;Start simple and mature gradually&lt;/li&gt;
&lt;li&gt;Team collaboration and clear processes matter as much as tools&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The goal isn&amp;rsquo;t perfect tooling—it&amp;rsquo;s sustainable, scalable ML systems that deliver business value.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Personal Coding Agent</title>
        <link>https://blog.thomasplantain.fr/post/agent/</link>
        <pubDate>Fri, 30 Jan 2026 00:00:00 +0000</pubDate>
        
        <guid>https://blog.thomasplantain.fr/post/agent/</guid>
        <description>&lt;img src="https://blog.thomasplantain.fr/img/hal/hal12.png" alt="Featured image of post Personal Coding Agent" /&gt;&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/hal/logo.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;HAL9000 tui&#34;
	
	
&gt;&lt;/p&gt;
&lt;h2 id=&#34;hal9000&#34;&gt;HAL9000
&lt;/h2&gt;&lt;h3 id=&#34;introduction&#34;&gt;Introduction
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;HAL9000 is a personal coding agent. It is a powerful tool that can help you write code faster and more efficiently.&lt;/p&gt;
&lt;p&gt;HAL9000 is written in Go and is designed to be easy to use and understand.&lt;/p&gt;
&lt;p&gt;It uses Ollama, an open-source project that provides a simple API for advanced language models.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;features&#34;&gt;Features
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;TUI with lipgloss&lt;/li&gt;
&lt;li&gt;Ollama API integration for advanced language models (Qwen3)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/hal/hal12.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;HAL9000 tui&#34;
	
	
&gt;&lt;/p&gt;
&lt;h4 id=&#34;tools&#34;&gt;Tools
&lt;/h4&gt;&lt;blockquote&gt;
&lt;p&gt;My coding agent should be able to create files, directories, and execute commands.&lt;/p&gt;
&lt;p&gt;I started with &lt;strong&gt;create_file&lt;/strong&gt; tool. I tested with &lt;strong&gt;Bruno&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/hal/ollama-qwen-tools.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;HAL9000 tools&#34;
	
	
&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Kokoro TTS</title>
        <link>https://blog.thomasplantain.fr/post/kokoro/</link>
        <pubDate>Tue, 20 Jan 2026 00:00:00 +0000</pubDate>
        
        <guid>https://blog.thomasplantain.fr/post/kokoro/</guid>
        <description>&lt;img src="https://blog.thomasplantain.fr/img/cover.jpg" alt="Featured image of post Kokoro TTS" /&gt;&lt;h2 id=&#34;text-to-speech&#34;&gt;Text To Speech
&lt;/h2&gt;&lt;blockquote&gt;
&lt;p&gt;Technology that enables text to be converted into speech sounds imitative of the human voice.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;run-locally&#34;&gt;Run locally
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/remsky/Kokoro-FastAPI&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;https://github.com/remsky/Kokoro-FastAPI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker run -p 8880:8880 ghcr.io/remsky/kokoro-fastapi-cpu:latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And you can play with web ui:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;http://localhost:8880/web&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/kokoro/kokoro-webui.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Kokoro web ui&#34;
	
	
&gt;&lt;/p&gt;
&lt;h3 id=&#34;n8n-workflow-with-kokoro&#34;&gt;n8n workflow with Kokoro
&lt;/h3&gt;&lt;blockquote&gt;
&lt;p&gt;I want to hear Qwen answer &amp;#x1f60a;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First I tested kokoro API with Bruno.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/kokoro/bruno-kokoro.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;RBruno&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;And then I added it to a new n8n workflow.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/kokoro/n8n-kokoro.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Kokoro API call&#34;
	
	
&gt;&lt;/p&gt;
&lt;p&gt;I had to remove all special characters.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;https://blog.thomasplantain.fr/img/kokoro/kokoro-api-call.png&#34;
	
	
	
	loading=&#34;lazy&#34;
	
		alt=&#34;Kokoro API call&#34;
	
	
&gt;&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
