diff --git a/README.md b/README.md
index a358b4c..09b25f4 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,7 @@ Table of Contents:
| **[Terraform NGINX hello world](containers/terraform-nginx-hello-world/README.md)**
A minimal example running the base NGINX image in a serverless container deployed with Terraform. | N/A | [Terraform] |
| **[Triggers with Terraform](containers/terraform-triggers/README.md)**
Configuring two SQS triggers, used to trigger two containers, one public, one private. | N/A | [Terraform] |
| **[gRPC HTTP2 in Go](containers/grpc-http2-go/README.md)**
A Go gRPC Container using http2 | Go/Protobuf | [CLI] |
+| **[Remote MCP Server](containers/mcp-go-server/README.md)**
A Go-based Model Context Protocol server exposing tools over HTTP on Serverless Containers. | Go | [Terraform]-[CLI] |
| **[Rust hello world](containers/rust-hello-world)**
A simple Rust hello world Container | Rust | [CLI] |
| **[.NET C#](containers/csharp-hello-world)**
A .NET C# Container hello world | C# .NET | [CLI] |
| **[Ruby Hello World](containers/ruby-hello-world/)**
A simple Ruby Hello world Container | Ruby | [CLI] |
diff --git a/containers/mcp-go-server/.env.example b/containers/mcp-go-server/.env.example
new file mode 100644
index 0000000..e4b184c
--- /dev/null
+++ b/containers/mcp-go-server/.env.example
@@ -0,0 +1,9 @@
+# Scaleway credentials (IAM API key) - never commit real values
+SCW_ACCESS_KEY=SCWXXXXXXXXXXXXXXXXX
+SCW_SECRET_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+
+# Optional: Scaleway project ID (uses default project if omitted)
+# SCW_DEFAULT_PROJECT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+
+# Value returned by the get_app_name MCP tool
+SCW_APPLICATION_NAME=my-mcp-server
diff --git a/containers/mcp-go-server/.gitignore b/containers/mcp-go-server/.gitignore
new file mode 100644
index 0000000..3a95676
--- /dev/null
+++ b/containers/mcp-go-server/.gitignore
@@ -0,0 +1,16 @@
+# Terraform
+.terraform/
+terraform.tfstate*
+*.tfvars
+*.tfplan
+
+# Serverless Framework / OSLS
+.serverless/
+node_modules/
+
+# Go build artifacts
+mcp-server
+*.exe
+
+# Local env files
+.env
diff --git a/containers/mcp-go-server/Dockerfile b/containers/mcp-go-server/Dockerfile
new file mode 100644
index 0000000..67a8ec0
--- /dev/null
+++ b/containers/mcp-go-server/Dockerfile
@@ -0,0 +1,31 @@
+# syntax=docker/dockerfile:1
+
+# Step 1: Build binary using modern Go toolchain
+FROM golang:1.27-alpine AS builder
+
+WORKDIR /app
+
+COPY go.mod go.sum ./
+
+RUN go mod download
+
+COPY main.go .
+
+RUN CGO_ENABLED=0 GOOS=linux go build \
+ -trimpath \
+ -ldflags="-w -s" \
+ -o mcp-server main.go
+
+# Step 2: Minimal non-root distroless runtime (~5MB final image)
+FROM gcr.io/distroless/static-debian13:nonroot
+
+WORKDIR /
+
+COPY --from=builder /app/mcp-server /mcp-server
+
+EXPOSE 8080
+ENV PORT=8080
+
+USER nonroot:nonroot
+
+ENTRYPOINT ["/mcp-server"]
diff --git a/containers/mcp-go-server/README.md b/containers/mcp-go-server/README.md
new file mode 100644
index 0000000..3355dee
--- /dev/null
+++ b/containers/mcp-go-server/README.md
@@ -0,0 +1,155 @@
+# Deploying Remote MCP Servers on Scaleway Serverless Containers
+
+A lightweight Go implementation of the **Model Context Protocol (MCP)** deployed as a Scaleway Serverless Container, enabling AI agents (like OpenCode, Claude, and Cursor) to securely invoke tools over HTTP.
+
+The server is built on the official [MCP Go SDK](https://github.com/modelcontextprotocol/go-sdk) (`github.com/modelcontextprotocol/go-sdk/mcp`), which handles the JSON-RPC protocol lifecycle, tool schemas/validation, and the Streamable HTTP transport.
+
+The server exposes three tools:
+
+| Tool | Description |
+| :--- | :--- |
+| `get_server_time` | Returns the current UTC time from the container. |
+| `echo` | Echoes back the input message. |
+| `get_app_name` | Returns the `SCW_APPLICATION_NAME` environment variable. |
+
+---
+
+## Why Serverless Fits the Model Context Protocol
+
+The Model Context Protocol (MCP) standardizes how LLMs interact with external tools and data sources. Hosting MCP servers on serverless platforms like Scaleway Serverless Containers offers key operational advantages:
+
+| Advantage | Why It Matters for MCP |
+| :--- | :--- |
+| **Scale-to-Zero Cost** | AI agents invoke tools in intermittent bursts. Serverless ensures you pay only for active execution time, eliminating costs when idle. |
+| **Stateless Architecture** | Remote MCP uses HTTP/SSE transports where requests carry their own execution context. Serverless containers scale horizontally without sticky sessions. |
+| **Sandbox Security** | Tool execution happens inside isolated, microVM-level container sandboxes, protecting infrastructure from unexpected agent actions. |
+| **Zero Maintenance** | Automated OS patching, SSL termination, and horizontal scaling are handled entirely by the cloud provider. |
+
+### Why Scaleway Serverless Containers?
+
+- **Native Container Support:** Run any Docker image (Go, Rust, Python, Node.js) with zero runtime restrictions.
+- **Built-in Private Access Control:** Native API Gateway enforcement of `X-Auth-Token` blocks unauthorized traffic before it hits your container — saving compute costs.
+- **European Sovereignty & GDPR:** Full data processing compliance in European regions (Paris, Amsterdam, Warsaw).
+- **Automated TLS & Custom Domains:** Out-of-the-box HTTPS endpoint provisioning with support for custom domain mapping.
+
+---
+
+## Technical Architecture & Transports
+
+Local MCP servers communicate over standard input/output (`stdio`). Remote serverless MCP deployments require network-based transports over HTTP:
+
+- **Streamable HTTP / SSE:** The MCP server exposes a `/mcp` endpoint accepting POST requests for JSON-RPC 2.0 tool execution and streaming responses back over Server-Sent Events (SSE). This transport is provided by the SDK's `mcp.StreamableHTTPHandler` (deployed in `Stateless` mode, ideal for scale-to-zero containers).
+- **Isolated Routing:** This example uses Go's `http.NewServeMux` (Go 1.22+ method routing) rather than the global default router, preventing route hijacking and allowing clean middleware integration.
+
+A `/health` endpoint is also exposed for container health checks.
+
+---
+
+## Prerequisites
+
+- [Terraform](https://www.terraform.io/downloads) `>= 1.5`
+- [Scaleway CLI (`scw`)](https://github.com/scaleway/scaleway-cli) (latest)
+- [Docker](https://docs.docker.com/get-docker/) (for building and pushing the image)
+- [Go](https://go.dev/dl/) `>= 1.22` (only needed for local development/testing)
+- A Scaleway account with an [IAM API key](https://www.scaleway.com/en/docs/identity-and-access-management/iam/how-to/create-api-keys/)
+
+---
+
+## Environment Variables
+
+Copy `.env.example` to `.env` and fill in your values:
+
+| Variable | Required | Description |
+| :--- | :--- | :--- |
+| `SCW_ACCESS_KEY` | Yes | Scaleway IAM access key. |
+| `SCW_SECRET_KEY` | Yes | Scaleway IAM secret key. |
+| `SCW_DEFAULT_PROJECT_ID` | No | Target project ID. Uses your default project if omitted. |
+
+```bash
+cp .env.example .env
+# Edit .env with your real values
+```
+
+---
+
+## Deployment
+
+This example offers two deployment methods. **Choose one.**
+
+### Option 1: Terraform
+
+The `main.tf` file provisions the registry namespace, builds and pushes the Docker image, and creates/deployes the container.
+
+```bash
+# Export your Scaleway credentials (or set them in a .env file sourced beforehand)
+export SCW_ACCESS_KEY="SCWXXXXXXXXXXXXXXXXX"
+export SCW_SECRET_KEY="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+
+terraform init
+terraform apply
+```
+
+When prompted, type `yes` to confirm. The apply output will print the container URL, the MCP endpoint, and the health endpoint.
+
+### Option 2: Scaleway CLI (`deploy.sh`)
+
+The `deploy.sh` script builds the Docker image, pushes it, and creates/deployes the container using only `scw` commands.
+
+```bash
+export SCW_SECRET_KEY="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+
+chmod +x deploy.sh
+./deploy.sh
+```
+
+The script prints the container URL, MCP endpoint, and health endpoint on success.
+
+---
+
+## Connecting Clients (e.g. OpenCode)
+
+Add the deployed remote endpoint to your client configuration (such as `opencode.json` or `~/.config/opencode/opencode.json`). Pass your Scaleway IAM secret key via the `X-Auth-Token` header:
+
+```json
+{
+ "$schema": "https://opencode.ai/config.json",
+ "mcp": {
+ "scaleway-tools": {
+ "type": "remote",
+ "url": "https://..functions.fnc.fr-par.scw.cloud/mcp",
+ "headers": {
+ "X-Auth-Token": "YOUR_SCALEWAY_IAM_SECRET_KEY"
+ }
+ }
+ }
+}
+```
+
+---
+
+## Cleanup
+
+### Terraform
+
+```bash
+terraform destroy
+```
+
+### Scaleway CLI
+
+The deletion commands are commented out at the bottom of `deploy.sh`. Uncomment and run them, or execute directly:
+
+```bash
+scw container container delete region=fr-par
+scw container namespace delete region=fr-par
+# Optionally, remove the pushed image from the registry:
+scw registry namespace delete region=fr-par
+```
+
+---
+
+## Production Best Practices
+
+- **Cold Start Optimization:** Keep container images ultra-minimal (e.g., Go/Rust static binaries inside `distroless` or `alpine`) to ensure cold boots remain under 1 second. For latency-critical agents, set `min_scale = 1`.
+- **Database Connection Management:** When connecting tools to databases (like PostgreSQL), use HTTP-based query clients or a connection pooler (e.g., PgBouncer) to prevent connection exhaustion during rapid container scaling.
+- **Least-Privilege Tool Execution:** Restrict database user roles to read-only permissions and sanitize all inputs inside tool implementations to prevent SQL injection or accidental data manipulation.
diff --git a/containers/mcp-go-server/deploy.sh b/containers/mcp-go-server/deploy.sh
new file mode 100755
index 0000000..bc22872
--- /dev/null
+++ b/containers/mcp-go-server/deploy.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# =============================================================================
+# Scaleway CLI deployment script for the mcp-go-server container example.
+# Builds the Docker image, pushes it to the Scaleway Container Registry, then
+# creates/deployes a Serverless Container exposing the MCP server.
+# =============================================================================
+
+# --- Configuration -----------------------------------------------------------
+NAMESPACE_NAME="mcp-go-server-ns"
+CONTAINER_NAME="mcp-go-server"
+IMAGE_NAME="mcp-server"
+IMAGE_TAG="latest"
+PORT=8080
+MIN_SCALE=0
+MAX_SCALE=5
+PRIVACY="private"
+REGION="fr-par"
+REGISTRY="rg.${REGION}.scw.cloud"
+
+# --- Pre-flight checks -------------------------------------------------------
+if ! command -v scw >/dev/null 2>&1; then
+ echo "Error: Scaleway CLI ('scw') is not installed or not in PATH."
+ echo "Install it from: https://github.com/scaleway/scaleway-cli"
+ exit 1
+fi
+
+if ! command -v docker >/dev/null 2>&1; then
+ echo "Error: 'docker' is required but was not found in PATH."
+ exit 1
+fi
+
+if ! command -v jq >/dev/null 2>&1; then
+ echo "Error: 'jq' is required but was not found in PATH."
+ exit 1
+fi
+
+if [[ -z "${SCW_SECRET_KEY:-}" ]]; then
+ echo "Error: SCW_SECRET_KEY environment variable is not set."
+ echo "Export your Scaleway IAM secret key before running this script."
+ exit 1
+fi
+
+# Use a per-run unique registry namespace name to avoid collisions.
+# Scaleway registry namespace names must be unique per region.
+REGISTRY_NAMESPACE="mcp-go-server-$(date +%s | tail -c 5)"
+
+# --- Docker registry login ---------------------------------------------------
+echo "Logging in to Scaleway Container Registry..."
+echo "${SCW_SECRET_KEY}" | docker login "${REGISTRY}" -u nologin --password-stdin
+
+# --- Registry namespace ------------------------------------------------------
+# The registry namespace must exist before the image can be pushed.
+echo "Ensuring the registry namespace '${REGISTRY_NAMESPACE}' exists..."
+REGISTRY_NAMESPACE_ID="$(scw registry namespace list \
+ region="${REGION}" \
+ name="${REGISTRY_NAMESPACE}" \
+ -o json | jq -r '.[0].id // empty')"
+
+if [[ -z "${REGISTRY_NAMESPACE_ID}" ]]; then
+ echo "Creating registry namespace '${REGISTRY_NAMESPACE}'..."
+ REGISTRY_NAMESPACE_ID="$(scw registry namespace create \
+ region="${REGION}" \
+ name="${REGISTRY_NAMESPACE}" \
+ -o json | jq -r '.id')"
+fi
+
+# --- Build and push the image ------------------------------------------------
+FULL_IMAGE="${REGISTRY}/${REGISTRY_NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG}"
+
+echo "Building Docker image: ${FULL_IMAGE}"
+docker build -t "${FULL_IMAGE}" .
+
+echo "Pushing Docker image..."
+docker push "${FULL_IMAGE}"
+
+# --- Container namespace -----------------------------------------------------
+NAMESPACE_ID="$(scw container namespace list \
+ region="${REGION}" \
+ name="${NAMESPACE_NAME}" \
+ -o json | jq -r '.[0].id // empty')"
+
+if [[ -z "${NAMESPACE_ID}" ]]; then
+ echo "Creating container namespace '${NAMESPACE_NAME}'..."
+ NAMESPACE_ID="$(scw container namespace create \
+ region="${REGION}" \
+ name="${NAMESPACE_NAME}" \
+ --wait \
+ -o json | jq -r '.id')"
+else
+ echo "Reusing existing namespace '${NAMESPACE_NAME}' (${NAMESPACE_ID})."
+fi
+
+# --- Container ---------------------------------------------------------------
+echo "Creating container '${CONTAINER_NAME}'..."
+CONTAINER_ID="$(scw container container create \
+ region="${REGION}" \
+ namespace-id="${NAMESPACE_ID}" \
+ name="${CONTAINER_NAME}" \
+ image="${FULL_IMAGE}" \
+ port="${PORT}" \
+ min-scale="${MIN_SCALE}" \
+ max-scale="${MAX_SCALE}" \
+ privacy="${PRIVACY}" \
+ --wait \
+ -o json | jq -r '.id')"
+
+# --- Output ------------------------------------------------------------------
+DOMAIN="$(scw container container get \
+ region="${REGION}" \
+ "${CONTAINER_ID}" \
+ -o json | jq -r '.public_endpoint')"
+
+echo ""
+echo "Container URL: ${DOMAIN}"
+echo "MCP endpoint: ${DOMAIN}/mcp"
+echo "Health endpoint: ${DOMAIN}/health"
+
+# =============================================================================
+# Cleanup / Remove
+# -----------------------------------------------------------------------------
+# To delete the container and namespace created above, uncomment and run:
+#
+# scw container container delete region="${REGION}" "${CONTAINER_ID}"
+# scw container namespace delete region="${REGION}" "${NAMESPACE_ID}"
+#
+# To also remove the pushed Docker image from the registry:
+#
+# scw registry namespace delete region="${REGION}" "${REGISTRY_NAMESPACE_ID}"
+# =============================================================================
diff --git a/containers/mcp-go-server/go.mod b/containers/mcp-go-server/go.mod
new file mode 100644
index 0000000..178f3ab
--- /dev/null
+++ b/containers/mcp-go-server/go.mod
@@ -0,0 +1,16 @@
+module github.com/scaleway/serverless-examples/containers/mcp-go-server
+
+go 1.27.0
+
+require github.com/modelcontextprotocol/go-sdk v1.7.0
+
+require (
+ github.com/google/jsonschema-go v0.4.3 // indirect
+ github.com/segmentio/asm v1.1.3 // indirect
+ github.com/segmentio/encoding v0.5.4 // indirect
+ github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
+ golang.org/x/oauth2 v0.35.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ golang.org/x/sys v0.41.0 // indirect
+ golang.org/x/time v0.15.0 // indirect
+)
diff --git a/containers/mcp-go-server/go.sum b/containers/mcp-go-server/go.sum
new file mode 100644
index 0000000..f93aba1
--- /dev/null
+++ b/containers/mcp-go-server/go.sum
@@ -0,0 +1,24 @@
+github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
+github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
+github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
+github.com/modelcontextprotocol/go-sdk v1.7.0 h1:yqjY2dsbKAC0LSuWZVBMrHgiG8ukXv6NRo0JiALay44=
+github.com/modelcontextprotocol/go-sdk v1.7.0/go.mod h1:dL7u98E/zjJTGzEq+j30jQ8K2k1mb6LeAH4inEcSGts=
+github.com/segmentio/asm v1.1.3 h1:WM03sfUOENvvKexOLp+pCqgb/WDjsi7EK8gIsICtzhc=
+github.com/segmentio/asm v1.1.3/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
+github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
+github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
+github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
+github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
+golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
+golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
+golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
+golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
+golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
diff --git a/containers/mcp-go-server/main.go b/containers/mcp-go-server/main.go
new file mode 100644
index 0000000..fef933c
--- /dev/null
+++ b/containers/mcp-go-server/main.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+ "context"
+ "log/slog"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/modelcontextprotocol/go-sdk/mcp"
+)
+
+type echoArgs struct {
+ Message string `json:"message" jsonschema:"The string to echo back"`
+}
+
+func main() {
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = "8080"
+ }
+
+ server := mcp.NewServer(&mcp.Implementation{
+ Name: "scaleway-test-mcp",
+ Version: "1.1.0",
+ }, nil)
+
+ mcp.AddTool(server, &mcp.Tool{
+ Name: "get_server_time",
+ Description: "Returns current UTC time from the Scaleway container",
+ }, func(_ context.Context, req *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: "Scaleway Container UTC Time: " + time.Now().UTC().Format(time.RFC3339),
+ }},
+ }, nil, nil
+ })
+
+ mcp.AddTool(server, &mcp.Tool{
+ Name: "echo",
+ Description: "Echoes back the input message",
+ }, func(_ context.Context, req *mcp.CallToolRequest, in echoArgs) (*mcp.CallToolResult, any, error) {
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: "Echo from Scaleway: " + in.Message,
+ }},
+ }, nil, nil
+ })
+
+ mcp.AddTool(server, &mcp.Tool{
+ Name: "get_app_name",
+ Description: "Returns the SCW_APPLICATION_NAME environment variable from the container",
+ }, func(_ context.Context, _ *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
+ appName := os.Getenv("SCW_APPLICATION_NAME")
+ if appName == "" {
+ appName = "[NOT_SET]"
+ }
+
+ return &mcp.CallToolResult{
+ Content: []mcp.Content{&mcp.TextContent{
+ Text: "SCW_APPLICATION_NAME: " + appName,
+ }},
+ }, nil, nil
+ })
+
+ mux := http.NewServeMux()
+
+ mux.HandleFunc("GET /health", handleHealth)
+ mux.Handle("/mcp", mcp.NewStreamableHTTPHandler(func(_ *http.Request) *mcp.Server {
+ return server
+ }, &mcp.StreamableHTTPOptions{
+ Stateless: true,
+ DisableLocalhostProtection: true, // auth is enforced upstream by the Scaleway platform
+ }))
+
+ slog.Info("Starting MCP server", "port", port)
+
+ httpServer := &http.Server{
+ Addr: ":" + port,
+ ReadHeaderTimeout: 10 * time.Second,
+ Handler: mux,
+ }
+
+ err := httpServer.ListenAndServe()
+ if err != nil {
+ slog.Error("Server crashed", "error", err)
+ os.Exit(1)
+ }
+}
+
+func handleHealth(w http.ResponseWriter, _ *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write([]byte("OK"))
+}
diff --git a/containers/mcp-go-server/main.tf b/containers/mcp-go-server/main.tf
new file mode 100644
index 0000000..ae51686
--- /dev/null
+++ b/containers/mcp-go-server/main.tf
@@ -0,0 +1,114 @@
+###############################################################################
+# Terraform configuration for the mcp-go-server Serverless Container example.
+#
+# Deploys a lightweight Go-based MCP (Model Context Protocol) server on Scaleway
+# Serverless Containers. The Docker image is built locally and pushed to the
+# Scaleway Container Registry, then referenced by the container.
+###############################################################################
+
+terraform {
+ required_version = ">= 1.5"
+
+ required_providers {
+ scaleway = {
+ source = "scaleway/scaleway"
+ version = "~> 2.0"
+ }
+ random = {
+ source = "hashicorp/random"
+ version = "~> 3.0"
+ }
+ }
+}
+
+# Credentials (SCW_ACCESS_KEY, SCW_SECRET_KEY) and the target project
+# (SCW_DEFAULT_PROJECT_ID) are read from the environment by the provider.
+provider "scaleway" {
+ region = "fr-par"
+}
+
+locals {
+ name_prefix = "mcp-go-server"
+ tags = ["serverless-examples", "mcp", "go", "terraform"]
+ image_name = "mcp-server"
+ image_tag = "latest"
+ container_port = 8080
+ min_scale = 0
+ max_scale = 5
+}
+
+# Scaleway registry namespace names are unique per-region,
+# so we add a short random suffix to avoid name collisions.
+resource "random_string" "registry_suffix" {
+ length = 4
+ lower = true
+ upper = false
+ numeric = true
+ special = false
+}
+
+resource "scaleway_registry_namespace" "main" {
+ name = "${local.name_prefix}-registry-${random_string.registry_suffix.result}"
+}
+
+resource "scaleway_container_namespace" "main" {
+ name = "${local.name_prefix}-ns"
+ description = "Namespace for the MCP Go server example"
+ tags = local.tags
+}
+
+# Build and push the Docker image to the Scaleway Container Registry.
+# Note: in a production CI/CD pipeline, you would typically build and push the
+# image outside of Terraform. This null_resource keeps the example self-contained.
+resource "null_resource" "build_and_push" {
+ depends_on = [scaleway_registry_namespace.main]
+
+ triggers = {
+ image_tag = timestamp() # Force rebuild on every apply
+ }
+
+ provisioner "local-exec" {
+ command = <<-EOT
+ set -euo pipefail
+ # $${...} is escaped so the shell expands SCW_SECRET_KEY from the
+ # environment at apply time (Terraform otherwise treats it as a reference).
+ docker login "${scaleway_registry_namespace.main.endpoint}" -u nologin -p "$${SCW_SECRET_KEY}"
+ docker build --platform linux/amd64 -t "${scaleway_registry_namespace.main.endpoint}/${local.image_name}:${local.image_tag}" .
+ docker push "${scaleway_registry_namespace.main.endpoint}/${local.image_name}:${local.image_tag}"
+ EOT
+ }
+}
+
+resource "scaleway_container" "main" {
+ depends_on = [null_resource.build_and_push]
+
+ name = local.name_prefix
+ namespace_id = scaleway_container_namespace.main.id
+ registry_image = "${scaleway_registry_namespace.main.endpoint}/${local.image_name}:${local.image_tag}"
+ port = local.container_port
+ tags = local.tags
+
+ cpu_limit = 1000
+ memory_limit_bytes = 1024 * 1024 * 1024 # 1 GiB
+ min_scale = local.min_scale
+ max_scale = local.max_scale
+
+ # WARN: Set privacy = "private" to enforces IAM token authentication via the API Gateway,
+ # so only callers with a valid X-Auth-Token header reach the container.
+ privacy = "public"
+}
+
+output "container_domain" {
+ description = "Public HTTPS endpoint of the deployed MCP server."
+ value = scaleway_container.main.public_endpoint
+}
+
+output "mcp_endpoint" {
+ description = "Full URL of the /mcp JSON-RPC endpoint."
+ value = "${scaleway_container.main.public_endpoint}/mcp"
+}
+
+output "health_endpoint" {
+ description = "Health check endpoint."
+ value = "${scaleway_container.main.public_endpoint}/health"
+}