Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Serveur MCP expérimental fournissant du contexte spatial pour les LLM sur la ba
- [Avec Docker en local](#avec-docker-en-local)
- [Debug de la version locale](#debug-de-la-version-locale)
- [Paramétrage](#paramétrage)
- [Tests](#tests)
- [Fonctionnalités (Tools)](#fonctionnalités-tools)
- [Utiliser des services spatiaux](#utiliser-des-services-spatiaux)
- [Recherche d'informations pour un lieu](#recherche-dinformations-pour-un-lieu)
Expand Down Expand Up @@ -156,16 +157,17 @@ Pour les tests d'intégration et les tests E2E agent, voir [la documentation dé

Pour une utilisation avancée :

| Nom | Description | Valeur par défaut |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" |
| `HTTP_HOST` | Adresse d'écoute en mode HTTP. Utile avec Docker pour exposer le service via `0.0.0.0`. | "127.0.0.1" |
| `HTTP_PORT` | Port d'écoute du MCP | 3000 |
| `HTTP_MCP_ENDPOINT` | Chemin d'exposition du MCP en HTTP | "/mcp" |
| `HTTP_TIMEOUT` | Délai maximal, en secondes, pour les appels HTTP sortants vers les services amont IGN. Au-delà, la requête est interrompue et l'outil renvoie une erreur de timeout structurée. | `15` |
| `GPF_WFS_MINISEARCH_OPTIONS` | Chaîne JSON optionnelle pour ajuster les options MiniSearch utilisées par `gpf_wfs_search_types` (`fields`, `combineWith`, `fuzzy`, `boost.namespace`, `boost.name`, `boost.title`, `boost.description`, `boost.properties`, `boost.enums`, `boost.identifierTokens`). | options par défaut de `@ignfab/gpf-schema-store` |
| `LOG_FORMAT` | Le format d'écriture des logs : "json" ou "simple". | "simple" |
| `LOG_LEVEL` | Le niveau d'écriture des logs : ["error", "info", ou "debug"](https://github.com/winstonjs/winston#logging-levels) | "debug" |
| Nom | Description | Valeur par défaut |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `TRANSPORT_TYPE` | [Transport](https://mcp-framework.com/docs/Transports/transports-overview) permet de choisir entre "stdio" et "http" | "stdio" |
| `HTTP_HOST` | Adresse d'écoute en mode HTTP. Utile avec Docker pour exposer le service via `0.0.0.0`. | "127.0.0.1" |
| `HTTP_PORT` | Port d'écoute du MCP | 3000 |
| `HTTP_MCP_ENDPOINT` | Chemin d'exposition du MCP en HTTP | "/mcp" |
| `HTTP_CORS_ALLOWED_ORIGINS` | Permet la [configuration de allowedOrigins pour protection contre les attaques par DNS rebinding](https://www.mcp-framework.com/docs/transports/http-stream#origin-validation-dns-rebinding-protection). Exemple : `HTTP_CORS_ALLOWED_ORIGINS="http://localhost:3000,https://geollm.beta.ign.fr"` | Aucun (warning) |
| `HTTP_TIMEOUT` | Délai maximal, en secondes, pour les appels HTTP sortants vers les services amont IGN. Au-delà, la requête est interrompue et l'outil renvoie une erreur de timeout structurée. | `15` |
| `GPF_WFS_MINISEARCH_OPTIONS` | Chaîne JSON optionnelle pour ajuster les options MiniSearch utilisées par `gpf_wfs_search_types` (`fields`, `combineWith`, `fuzzy`, `boost.namespace`, `boost.name`, `boost.title`, `boost.description`, `boost.properties`, `boost.enums`, `boost.identifierTokens`). | options par défaut de `@ignfab/gpf-schema-store` |
| `LOG_FORMAT` | Le format d'écriture des logs : "json" ou "simple". | "simple" |
| `LOG_LEVEL` | Le niveau d'écriture des logs : ["error", "info", ou "debug"](https://github.com/winstonjs/winston#logging-levels) | "debug" |

Exemple :

Expand Down
39 changes: 39 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { MCPServer, TransportConfig } from "mcp-framework";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { readFileSync } from "fs";
import logger from "./logger.js";

const __dirname = dirname(fileURLToPath(import.meta.url));

Expand All @@ -11,6 +12,10 @@ function isTransportType(value: string): value is TransportType {
return value === "stdio" || value === "http";
}

/**
* Get the transport type from the environment variable TRANSPORT_TYPE.
* Valid values are "stdio" and "http". If not set, defaults to "stdio".
*/
function getTransportType(): TransportType {
const transportType = process.env.TRANSPORT_TYPE ?? "stdio";

Expand All @@ -21,6 +26,10 @@ function getTransportType(): TransportType {
return transportType;
}

/**
* Get the HTTP port from the environment variable HTTP_PORT.
* The variable should be a decimal integer between 1 and 65535. If not set, defaults to 3000.
*/
function getHttpPort(): number {
const rawPort = process.env.HTTP_PORT?.trim();
const invalidHttpPortMessage = `Invalid HTTP_PORT: ${rawPort}. Expected a decimal integer between 1 and 65535.`;
Expand All @@ -42,6 +51,32 @@ function getHttpPort(): number {
return port;
}

/**
* Get CORS allowed origins from the environment variable HTTP_CORS_ALLOWED_ORIGINS.
* The variable should be a comma-separated list of origins .
*/
function getCorsAllowedOrigins(): undefined|string[] {
if (process.env.HTTP_CORS_ALLOWED_ORIGINS === undefined) {
logger.warn('Security : HTTP_CORS_ALLOWED_ORIGINS is not set. It is recommended to set this variable to prevent DNS rebinding attacks (e.g., HTTP_CORS_ALLOWED_ORIGINS="http://localhost:3000,https://geollm.beta.ign.fr".');
Comment thread
esgn marked this conversation as resolved.
return undefined;
}

const rawOrigins = process.env.HTTP_CORS_ALLOWED_ORIGINS?.trim();

const allowedOrigins = rawOrigins
?.split(",")
.map((origin) => origin.trim())
.filter(Boolean);

if (!allowedOrigins || allowedOrigins.length === 0) {
logger.warn('Security : HTTP_CORS_ALLOWED_ORIGINS is empty. It is recommended to set this variable to prevent DNS rebinding attacks (e.g., HTTP_CORS_ALLOWED_ORIGINS="http://localhost:3000,https://geollm.beta.ign.fr".');
return undefined;
}

return allowedOrigins;
}


function buildTransport(transportType: TransportType): TransportConfig {
// Handle stdio transport configuration
if (transportType === "stdio") {
Expand All @@ -63,12 +98,16 @@ function buildTransport(transportType: TransportType): TransportConfig {
endpoint,
cors: {
allowOrigin: "*",
allowedOrigins: getCorsAllowedOrigins(),
},
host,
},
};
}

/**
* Get the version from package.json for the MCP server metadata.
*/
function getVersion(): string {
const pkgMetadata = JSON.parse(
readFileSync(join(__dirname, "../package.json"), "utf-8")
Expand Down
Loading