Accueil / Articles

Application WeatherSG MCP : Carte interactive Tools Plus dans ChatGPT et Claude

WeatherSG, une application MCP en TypeScript : contrat de données, Streamable HTTP, déploiement sur Cloud Run et enregistrement d’hôte afin que ChatGPT et Claude affichent une carte météo en direct.

Éditeur : REACTAPP.TOP16 min de lecture3664 mots

Sources: How to Build and Deploy an MCP App

Les applications MCP étendent le Model Context Protocol au-delà des outils qui renvoient du texte : elles peuvent fournir une ressource UI interactive que des hébergeurs comme ChatGPT ou Claude peuvent afficher. Cette démarche guide la création de WeatherSG en TypeScript — contrat de données, récupération des informations météorologiques, outil ordinaire, interface de carte regroupée en une seule ressource HTML, transport HTTP Streamable, déploiement dans Cloud Run via un conteneur, ainsi que l’enregistrement sur les deux hébergeurs.

Qu’est-ce qu’une application MCP ?

Un serveur expose toujours des outils et des ressources ; une application ajoute en outre un front-end que l’hébergeur insère après qu’une appel à outil l’a sélectionné. Le cycle est : prompt → outil → ressource UI → interaction de l’utilisateur → nouvelles appels à outils si nécessaire.

Pourquoi TypeScript ici ?

L’utilisation d’une seule langue pour le serveur et le regroupement de l’UI permet de garder l’unité de déploiement petite. Les types stricts aident à ce que le contrat de données reste cohérent entre les normaliseurs et l’interface de carte.

mkdir weathersg
cd weathersg
npm init -y

npm install \
  @modelcontextprotocol/sdk \
  @modelcontextprotocol/ext-apps \
  express leaflet react react-dom zod

npm install --save-dev \
  @types/express @types/leaflet @types/node \
  @types/react @types/react-dom \
  esbuild supertest tsx typescript vitest

Gardez les secrets dans l’environnement de la plateforme ; ne jamais intégrer les clés API dans le HTML compilé.

{
  "scripts": {
    "build": "npm run build:web && tsc -p tsconfig.json",
    "build:web": "node scripts/build-web.mjs",
    "dev": "npm run build:web && tsx watch src/index.ts",
    "start": "node dist/src/index.js",
    "test": "vitest run",
    "typecheck": "tsc -p tsconfig.json --noEmit"
  },
  "engines": {
    "node": ">=20"
  }
}

Préférez HTTP en flux pour les hôtes qui attendent une URL de session MCP persistante.

weathersg/
  src/
    weather/
      schema.ts
      client.ts
    http-app.ts
    index.ts
    server.ts
  web/
    src/
      main.tsx
      styles.css
  scripts/
    build-web.mjs
  tests/
  Dockerfile
  package.json
  tsconfig.json

Les vérifications d’état des conteneurs doivent cibler l’endpoint MCP, et non seulement une page statique.

import { z } from "zod";

export const weatherLayerSchema = z.enum([
  "all",
  "forecast",
  "rainfall",
]);

const forecastAreaSchema = z.object({
  id: z.string(),
  name: z.string(),
  latitude: z.number(),
  longitude: z.number(),
  condition: z.string(),
  category: z.enum([
    "clear",
    "cloudy",
    "showers",
    "thunderstorms",
    "windy",
    "hazy",
    "unknown",
  ]),
});

const rainfallStationSchema = z.object({
  id: z.string(),
  name: z.string(),
  latitude: z.number(),
  longitude: z.number(),
  rainfallMm: z.number().nonnegative(),
});

export const weatherSnapshotSchema = z.object({
  layer: weatherLayerSchema,
  generatedAt: z.string(),
  forecast: z.object({
    updatedAt: z.string(),
    validFrom: z.string(),
    validTo: z.string(),
    validPeriodText: z.string(),
    areas: z.array(forecastAreaSchema),
  }).nullable(),
  rainfall: z.object({
    observedAt: z.string(),
    readingType: z.string(),
    unit: z.string(),
    stations: z.array(rainfallStationSchema),
  }).nullable(),
  summary: z.object({
    headline: z.string(),
    areasWithRain: z.number().int().nonnegative(),
    reportingRainStations: z.number().int().nonnegative(),
  }),
  warnings: z.array(z.string()),
  sources: z.array(z.object({
    label: z.string(),
    url: z.string().url(),
  })),
});

export type WeatherSnapshot = z.infer<typeof weatherSnapshotSchema>;

L’enregistrement de l’hôte relève de la configuration — réessayez après chaque modification d’URL ou d’authentification.

async function fetchValidated<T>(
  url: string,
  schema: z.ZodType<T>,
  sourceLabel: string,
): Promise<{ value: T; warning?: string }> {
  const cached = cache.get(url);

  try {
    const response = await fetch(url, {
      headers: { Accept: "application/json" },
      signal: AbortSignal.timeout(8_000),
    });

    if (!response.ok) {
      throw new Error(`Weather service returned HTTP ${response.status}`);
    }
    const value = schema.parse(await response.json());
    cache.set(url, {
      value,
      expiresAt: Date.now() + 60_000,
    });
    return { value };
  } catch (error) {
    if (cached) {
      return {
        value: cached.value as T,
        warning: `${sourceLabel} could not be refreshed`,
      };
    }
    throw error;
  }
}

Considérez cela comme un point de contrôle : les tests de protocole doivent réussir avant toute connexion avec l’hôte de chat.

const [forecastResult, rainfallResult] = await Promise.allSettled([
  fetchValidated(TWO_HOUR_FORECAST_URL, forecastSchema, "Forecast"),
  fetchValidated(RAINFALL_URL, rainfallSchema, "Rainfall"),
]);

Gardez les secrets dans l’environnement de la plateforme ; ne jamais intégrer les clés API dans le HTML compilé.

return weatherSnapshotSchema.parse(snapshot);

Préférez HTTP en flux pour les hôtes qui attendent une URL de session MCP persistante.

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { getSingaporeWeather } from "./weather/client.js";
import {
  weatherLayerSchema,
  weatherSnapshotSchema,
} from "./weather/schema.js";

const server = new McpServer(
  { name: "weathersg", version: "0.1.0" },
  {
    instructions:
      "Use get_singapore_weather for factual weather questions. " +
      "Use show_singapore_weather_map when the user asks to see, " +
      "map, compare, or explore weather across Singapore.",
  },
);

Les vérifications d’état des conteneurs doivent cibler l’endpoint MCP, et non seulement une page statique.

server.registerTool(
  "get_singapore_weather",
  {
    title: "Get Singapore weather",
    description:
      "Get current official two-hour forecasts and five-minute " +
      "rainfall observations across Singapore.",
    inputSchema: {
      layer: weatherLayerSchema.default("all"),
    },
    outputSchema: weatherSnapshotSchema,
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      openWorldHint: false,
    },
  },
  async ({ layer }) => {
    const snapshot = await getSingaporeWeather(layer);
    return {
      structuredContent: snapshot,
      content: [{
        type: "text",
        text: `${snapshot.summary.headline} Snapshot generated at ${snapshot.generatedAt}.`,
      }],
    };
  },
);

L’enregistrement de l’hôte relève de la configuration — réessayez après chaque modification d’URL ou d’authentification.

import {
  registerAppResource,
  registerAppTool,
  RESOURCE_MIME_TYPE,
} from "@modelcontextprotocol/ext-apps/server";

export const WEATHER_APP_URI =
  "ui://weathersg/singapore-weather-map/v1.html";

Considérez ceci comme un point de contrôle : les tests de protocole doivent réussir avant toute connexion entre le chat et l’hôte.

registerAppTool(
  server,
  "show_singapore_weather_map",
  {
    title: "Show Singapore weather map",
    description:
      "Show an interactive map of official forecasts and rainfall " +
      "observations across Singapore.",
    inputSchema: {
      layer: weatherLayerSchema.default("all"),
    },
    outputSchema: weatherSnapshotSchema,
    annotations: {
      readOnlyHint: true,
      destructiveHint: false,
      openWorldHint: false,
    },
    _meta: {
      ui: { resourceUri: WEATHER_APP_URI },
      "openai/toolInvocation/invoking": "Reading Singapore weather…",
      "openai/toolInvocation/invoked": "Singapore weather map ready",
    },
  },
  async ({ layer }) => {
    const snapshot = await getSingaporeWeather(layer);
    return {
      structuredContent: snapshot,
      content: [{
        type: "text",
        text: snapshot.summary.headline,
      }],
    };
  },
);

Gardez les secrets dans l’environnement de la plateforme ; ne jamais intégrer les clés API dans le HTML compilé.

registerAppResource(
  server,
  "Singapore weather map",
  WEATHER_APP_URI,
  { description: "Interactive map of Singapore weather" },
  async () => ({
    contents: [{
      uri: WEATHER_APP_URI,
      mimeType: RESOURCE_MIME_TYPE,
      text: loadWeatherAppHtml(),
      _meta: {
        ui: {
          prefersBorder: true,
          csp: {
            connectDomains: [],
            resourceDomains: ["https://www.onemap.gov.sg"],
          },
        },
      },
    }],
  }),
);

Préférez HTTP en flux pour les hôtes qui attendent une URL de session MCP persistante.

import { App } from "@modelcontextprotocol/ext-apps";
import { createRoot } from "react-dom/client";

const app = new App(
  { name: "WeatherSG map", version: "0.1.0" },
  {},
  { autoResize: true },
);

function parseSnapshot(value: unknown): WeatherSnapshot | null {
  if (!value || typeof value !== "object") return null;
  const candidate = value as Partial<WeatherSnapshot>;
  if (!candidate.summary || !Array.isArray(candidate.sources)) return null;
  if (!candidate.forecast && !candidate.rainfall) return null;
  return candidate as WeatherSnapshot;
}

app.ontoolresult = (result) => {
  const snapshot = parseSnapshot(result.structuredContent);
  if (snapshot) deliverSnapshot(snapshot);
};

createRoot(document.getElementById("root")!).render(<WeatherApp />);

void app.connect().catch((error) => {
  console.error("Unable to connect to the host", error);
});

Les vérifications de santé du conteneur doivent cibler l’endpoint MCP, et non seulement une page statique.

await build({
  entryPoints: ["web/src/main.tsx"],
  bundle: true,
  minify: true,
  format: "esm",
  platform: "browser",
  write: false,
  outdir: "dist/web-bundle",
});

L’enregistrement de l’hôte relève de la configuration — réessayez après chaque modification d’URL ou d’authentification.

npm run build

Considérez ceci comme un point de contrôle : les tests de protocole doivent réussir avant toute connexion entre le chat et l’hôte.

import { createMcpExpressApp } from
  "@modelcontextprotocol/sdk/server/express.js";
import { StreamableHTTPServerTransport } from
  "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { createWeatherMcpServer } from "./server.js";

const app = createMcpExpressApp();

app.post("/mcp", async (request, response) => {
  response.setHeader("Cache-Control", "no-store");

  const server = createWeatherMcpServer();
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined,
  });

  await server.connect(transport);

  response.on("close", () => {
    void transport.close();
    void server.close();
  });

  await transport.handleRequest(request, response, request.body);
});

Gardez les secrets dans l’environnement de la plateforme ; ne jamais intégrer les clés API dans le HTML compilé.

app.get("/health", (_request, response) => {
  response.json({ status: "ok", service: "weathersg" });
});

app.get("/ready", (_request, response) => {
  const ready = existsSync("dist/web/weather-app.html");
  response.status(ready ? 200 : 503).json({
    status: ready ? "ready" : "not_ready",
  });
});

Préférez HTTP en flux pour les hôtes qui attendent une URL de session MCP persistante.

const port = Number(process.env.PORT ?? 3000);
const app = createWeatherHttpApp();

app.listen(port, "0.0.0.0", () => {
  console.log(`WeatherSG listening on ${port}`);
});

Les vérifications de santé du conteneur doivent cibler l’endpoint MCP, et non seulement une page statique.

npm run dev

L’enregistrement de l’hôte relève de la configuration : réessayez après chaque modification d’URL ou d’authentification.

npx @modelcontextprotocol/inspector@latest

Considérez ceci comme un point de contrôle : les tests de protocole doivent réussir avant toute connexion entre le chat et l’hôte.

git clone https://github.com/modelcontextprotocol/ext-apps.git
cd ext-apps/examples/basic-host
npm install
SERVERS='["http://localhost:3000/mcp"]' npm start

Gardez les secrets dans l’environnement de la plateforme ; ne intégrez jamais de clés API dans le HTML compilé.

npm run typecheck
npm test
npm run build

Préférez HTTP en flux pour les hôtes qui attendent une URL de session MCP persistante.

FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s \
  CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||3000)+'/ready').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
CMD ["node", "dist/src/index.js"]

Les vérifications de santé du conteneur doivent cibler l’endpoint MCP, et non seulement une page statique.

docker build -t weathersg .
docker run --rm -p 3000:3000 weathersg

L’enregistrement de l’hôte relève de la configuration : réessayez après chaque modification d’URL ou d’authentification.

gcloud auth login
gcloud config set project YOUR_PROJECT_ID
gcloud services enable \
  run.googleapis.com \
  cloudbuild.googleapis.com \
  artifactregistry.googleapis.com

Considérez ceci comme un point de contrôle : les tests de protocole doivent réussir avant toute connexion entre le chat et l’hôte.

gcloud run deploy weathersg \
  --source . \
  --region asia-southeast1 \
  --allow-unauthenticated \
  --set-env-vars PUBLISHER_NAME=WeatherSG

Gardez les secrets dans l’environnement de la plateforme ; ne intégrez jamais de clés API dans le HTML compilé.

https://YOUR_SERVICE_HOST/mcp

Préférez HTTP en flux pour les hôtes qui attendent une URL de session MCP persistante.

curl -fsS https://YOUR_SERVICE_HOST/health
curl -fsS https://YOUR_SERVICE_HOST/ready

Les vérifications de santé du conteneur doivent cibler l’endpoint MCP, et non seulement une page statique.

Is it raining anywhere in Singapore right now?

Show me the Singapore weather map.

Now show only rainfall stations.

L’enregistrement de l’hôte relève de la configuration : réessayez après toute modification d’URL ou d’autorisation.

https://YOUR_SERVICE_HOST/mcp

Considérez cela comme un point de contrôle : les tests de protocole doivent réussir avant toute connexion entre le chat et l’hôte.

Test avant l’interface de chat

Utilisez des outils et des ressources avec un inspecteur MCP ou un client scripté. Les hôtes de chat amplifient les échecs ; un protocole fonctionnel localement économise des heures de travail.

Déploiement et enregistrement

Envoyez le conteneur sur Cloud Run (ou un équivalent), puis orientez les connecteurs ChatGPT et Claude vers l’URL MCP publique accompagnée des en-têtes d’autorisation requis. Vérifiez à nouveau l’interaction avec la carte après la fin du chiffrement TLS.

Conclusion

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas dupliquer la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas dupliquer la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas dupliquer la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/clair ne doivent pas modifier la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/clair ne doivent pas modifier la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas modifier la logique de récupération des données.

Enregistrez les identifiants de récupération avec les tours de conversation afin d’en faciliter le tri ultérieur.

Reconstruisez les index à un rythme correspondant au taux de changement des sources.

Refusez les demandes lorsque les segments principaux semblent faibles.

Versonnez les contrats API à côté des identifiants d’incorporation.

Séparez les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas modifier la logique de récupération des données.

Enregistrez les identifiants de récupération avec les tours de conversation afin d’en faciliter le tri ultérieur.

Reconstruisez les index à un rythme correspondant au taux de changement des sources.

Refusez les demandes lorsque les segments principaux semblent faibles.

Versonnez les contrats API à côté des identifiants d’incorporation.

Séparez les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas modifier la logique de récupération des données.

Enregistrez les identifiants de récupération avec les tours de conversation afin d’en faciliter le tri ultérieur.

Reconstruisez les index à un rythme correspondant au taux de changement des sources.

Refusez les demandes lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas dupliquer la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas dupliquer la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/claire ne doivent pas dupliquer la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/clair ne doivent pas modifier la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/clair ne doivent pas modifier la logique de récupération.

Enregistrer les identifiants de récupération avec les tours de conversation pour un tri ultérieur.

Reconstruire les index à un rythme correspondant au taux de changement des sources.

Refuser lorsque les segments principaux semblent faibles.

Versionner les contrats API à côté des identifiants d’embedder.

Séparer les gestionnaires HTTP des services purs pour les tests unitaires.

Les thèmes d’interface sombre/clair ne doivent pas modifier la logique de récupération des données.

Enregistrez les identifiants des journaux avec les tours de conversation afin d’en faciliter le tri ultérieur.

Récréez les index à un rythme correspondant au taux de modification des sources.

Refusez d’appliquer les modifications lorsque les segments principaux semblent faibles.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de référence, les responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs responsables et les notes de réversion à côté des modifications d’ingestion et de déploiement.

Gardez les fichiers de configuration, leurs propriétaires ainsi que les notes de réversion à côté des modifications d’ingestion et de déploiement.