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
51 changes: 51 additions & 0 deletions examples/server-deployment/docker/deploy/caddy/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{$DOMAIN} {
tls {
issuer acme {
disable_tlsalpn_challenge # force HTTP-01 on port 80
# ca https://acme-staging-v02.api.letsencrypt.org/directory # optional during testing
}
}

encode gzip

@mcp {
path /mcp /mcp/ /mcp/*
}
handle @mcp {
# Ensure trailing slash for /mcp -> /mcp/
uri path_regexp ^/mcp$ /mcp/
reverse_proxy http://mcp:8001 {
# SSE/MCP streaming configuration
flush_interval -1
header_up X-Real-IP {remote_host}
# Disable buffering for SSE
@sse {
header Accept *text/event-stream*
}
}
}

# Serve favicon and icon files with proper caching
handle /favicon.ico {
root * /srv/site
header Cache-Control "public, max-age=86400, immutable"
header Content-Type "image/x-icon"
file_server
}
handle /favicon.png {
root * /srv/site
header Cache-Control "public, max-age=86400, immutable"
header Content-Type "image/png"
file_server
}
handle /site.webmanifest {
root * /srv/site
header Cache-Control "public, max-age=3600"
header Content-Type "application/manifest+json"
file_server
}
handle {
root * /srv/site
file_server
}
}
56 changes: 56 additions & 0 deletions examples/server-deployment/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
networks:
internal:
driver: bridge

volumes:
caddy_data:
caddy_config:

services:
mcp:
# Option A: build from this repo's Dockerfile (assumes you are working from the repo's examples/server-deployment/docker directory)
build:
context: ../../../
dockerfile: Dockerfile
# Option B: if you publish an image, replace with:
# image: ghcr.io/teradata/teradata-mcp-server:latest
container_name: teradata-mcp
env_file: .env
expose:
- "8001" # only visible inside the compose network
command:
- teradata-mcp-server
- --mcp_transport
- streamable-http
- --mcp_host
- 0.0.0.0
- --mcp_port
- "8001"
healthcheck:
test: ["CMD", "python", "-c", "import socket; s = socket.socket(); s.settimeout(5); s.connect(('127.0.0.1', 8001)); s.close()"]
interval: 15s
timeout: 5s
retries: 10
start_period: 10s
networks:
- internal

caddy:
image: caddy:2
container_name: caddy
depends_on:
mcp:
condition: service_healthy
environment:
# Set this to your DuckDNS (or real) domain, e.g. teradata-mcp.duckdns.org
- DOMAIN=${DOMAIN}
ports:
- "80:80"
- "443:443"
volumes:
- ./deploy/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data # certs / ACME storage
- caddy_config:/config
- ./site:/srv/site:ro # optional favicon/landing page
networks:
- internal
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions examples/server-deployment/docker/site/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<title>Teradata MCP Server</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="apple-touch-icon" href="/favicon.png" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="manifest" href="/site.webmanifest" />
<meta property="og:image" content="/favicon.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:title" content="Teradata MCP Server" />
<meta property="og:description" content="Teradata MCP Server - Secure AI Database Access" />
</head>
<body style="font-family:sans-serif;text-align:center;margin-top:10%;">
<img src="/favicon.png" width="96" alt="Teradata">
<h2>Teradata MCP Server is running</h2>
<p>Secure endpoint: <b>/mcp/</b></p>
<p>
⚙️ Need to configure your client? See the
<a href="https://github.com/Teradata/teradata-mcp-server/tree/main/docs#-client-guide" target="_blank">
MCP Client Guide
</a>.
</p>
</body>
</html>
14 changes: 14 additions & 0 deletions examples/server-deployment/docker/site/site.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "Teradata MCP Server",
"short_name": "Teradata MCP",
"icons": [
{
"src": "/favicon.png",
"sizes": "192x192",
"type": "image/png"
}
],
"theme_color": "#FF6200",
"background_color": "#ffffff",
"display": "standalone"
}
153 changes: 153 additions & 0 deletions examples/server-deployment/quickstart-docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Quickstart — Docker Compose (MCP + Caddy HTTPS)

This guide shows how to run the **Teradata MCP server** behind **Caddy** with automatic **HTTPS (Let’s Encrypt)** using **Docker Compose**. It keeps port **8001** private and exposes only **80/443**.

---

## 0) Prerequisites

- Docker + Docker Compose plugin installed.
- An EC2 instance or host with public IPv4.
- A DNS record pointing to your host (e.g. `teradata-mcp.duckdns.org → <public IP>`).
*(you can use a free dynamic DNS service such as DuckDNS for testing...)*
- Security Group / firewall allows inbound **TCP 80** and **TCP 443** (keep **22** for SSH).

---

## 1) Folder layout

Copy the [docker](examples/server-deployment/docker) directory outside this code directory and move into it this is the structure:

```
examples/server-deployment/docker/
├─ docker-compose.yml
├─ .env
├─ Dockerfile
├─ deploy/
│ └─ caddy/
│ └─ Caddyfile
└─ site/
├─ favicon.ico # optional
├─ favicon.png # optional
└─ index.html # optional landing page
```

Eg.
```bash
#If you haven't, clone this repo
git clone https://github.com/<your-org>/teradata-mcp-server.git

cp -R teradata-mcp-server/examples/server-deployment/docker teradata-mcp-service
cp teradata-mcp-server/Dockerfile teradata-mcp-service
cd teradata-mcp-service
```


---

## 2) `.env` — runtime configuration

Update the `.env` file with your database connection string for `DATABASE_URI` and domain name for `DOMAIN`:

```dotenv
# --- MCP server (FastMCP) ---
DATABASE_URI=teradata://USER:PASS@HOST:1025/DEFAULT_DB_SCHEMA # <-- Update here
MCP_TRANSPORT=streamable-http
MCP_HOST=0.0.0.0
MCP_PORT=8001

# --- Caddy / HTTPS ---
# Set this to the DNS name that points at your server
DOMAIN=teradata-mcp.duckdns.org # <-- Update here
```

> Keep secrets out of command history by using `.env`. For all supported vars, see **docs/server_guide/CONFIGURATION.md**.

---

## 3) (Optional) landing page / favicon

Add files under `examples/server-deployment/docker/site/` if you want a root page or custom icon:

- Update `favicon.ico` and `favicon.png` with your preferred icon
- Update `index.html` (minimal example)

---

## 4) Start the stack

From your directory:

```bash
docker compose up -d --build
docker compose ps
```

First-time HTTPS may take ~30–90 seconds. Watch Caddy:

```bash
docker compose logs -f caddy
```

---

## 7) Verify

```bash
# Expect 200/401/405 from the app (not HTML)
curl -i https://${DOMAIN}/mcp/

# Inside the network (debug): curl from caddy to mcp
docker compose exec caddy sh -lc 'wget -qO- http://mcp:8001/mcp/ | head'
```

If you added a landing page: visit `https://${DOMAIN}/`.

---

## 8) Use with Claude Desktop

With HTTPS you **do not** need `--allow-http`:

```json
{
"mcpServers": {
"teradata_mcp_remote_https": {
"command": "npx",
"args": ["mcp-remote", "https://YOUR_DOMAIN/mcp/"]
}
}
}
```

Add headers if you enforce auth at the app or proxy (e.g., `--header "Authorization: Basic ${AUTH_TOKEN}"`).

---

## 9) Operations

```bash
# Update/recreate
docker compose pull && docker compose up -d --build

# Logs
docker compose logs -f mcp
docker compose logs -f caddy

# Stop
docker compose down
```

---

## 10) Troubleshooting

- **TLS errors right after deploy** → DNS propagation or first ACME run; retry in a minute and check `docker compose logs -f caddy`.
- **HTML/404 served at `/mcp/`** → ensure the `@mcp` matcher appears *before* the static handlers in `Caddyfile`.
- **80/443 blocked** → open in Security Group / firewall; confirm public IPv4 resolves for `${DOMAIN}`.
- **Icon still shows DuckDNS duck** → Claude may brand by base domain (`duckdns.org`). Use your own domain to fully customize.

---

**That’s it.** You now have a clean, HTTPS-protected MCP server via Docker Compose with Caddy.
-----