Skip to content

Commit 0076ed5

Browse files
tomkosmnickscamara
andauthored
Fastmcp (#97)
* fastmcp * fix ci * fix * specify host * wip * fix host for cloud * wip * wip * wip * remove log * fix * wip * ready * fix sse? * Update package.json * Update package.json * Nick: * Update index.ts * Update package.json * Nick: * Nick: tool descriptions * Nick: * Update ci.yml --------- Co-authored-by: Nicolas <nicolascamara29@gmail.com>
1 parent a4c3911 commit 0076ed5

File tree

15 files changed

+2091
-8998
lines changed

15 files changed

+2091
-8998
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,4 @@ jobs:
2323
run: npm ci
2424

2525
- name: Build
26-
run: npm run build
27-
28-
- name: Lint
29-
run: npm run lint
26+
run: npm run build
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Deploy Images to GHCR staging
2+
3+
env:
4+
DOTNET_VERSION: '6.0.x'
5+
6+
on:
7+
push:
8+
branches:
9+
- staging
10+
- fastmcp
11+
workflow_dispatch:
12+
13+
14+
jobs:
15+
push-image:
16+
runs-on: ubuntu-latest
17+
steps:
18+
19+
- name: 'Checkout GitHub Action'
20+
uses: actions/checkout@main
21+
22+
- name: 'Login to GitHub Container Registry'
23+
uses: docker/login-action@v1
24+
with:
25+
registry: ghcr.io
26+
username: ${{ github.actor }}
27+
password: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: 'Set up Docker Buildx'
30+
uses: docker/setup-buildx-action@v1
31+
32+
- name: 'Build Service Image'
33+
uses: docker/build-push-action@v2
34+
with:
35+
context: .
36+
file: ./Dockerfile.service
37+
push: true
38+
tags: ghcr.io/firecrawl/firecrawl-mcp-server-alpha:latest
39+
cache-from: type=registry,ref=ghcr.io/firecrawl/firecrawl-mcp-server-alpha:latest
40+
cache-to: type=inline

.github/workflows/image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
uses: docker/build-push-action@v2
3131
with:
3232
context: .
33-
file: ./Dockerfile
33+
file: ./Dockerfile.service
3434
push: true
3535
tags: ghcr.io/firecrawl/firecrawl-mcp-server:latest
3636
cache-from: type=registry,ref=ghcr.io/firecrawl/firecrawl-mcp-server:latest

Dockerfile.service

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1-
FROM node:22-slim
1+
## Service image: Node (FastMCP) + NGINX sidecar in one container
22

3+
# 1) Build stage
4+
FROM node:22-alpine AS builder
35
WORKDIR /app
46

5-
COPY package.json package-lock.json* ./
7+
COPY package*.json ./
8+
# Ensure dev dependencies (typescript, etc.) are installed for build, but skip scripts to avoid running
9+
# the package "prepare" script before the source code is copied.
10+
RUN npm ci --include=dev --ignore-scripts
611

7-
8-
COPY tsconfig.json ./
9-
COPY src ./src
12+
COPY . .
1013
RUN npm run build
1114

12-
ENV CLOUD_SERVICE=true
13-
ENV PORT=3000
1415

15-
# Expose the port
16-
EXPOSE 3000
16+
# 2) Runtime stage (Node + NGINX)
17+
FROM node:22-alpine AS runner
18+
WORKDIR /app
19+
20+
RUN apk add --no-cache nginx bash curl
21+
22+
# Copy built app and install prod deps only
23+
COPY --from=builder /app/dist ./dist
24+
COPY package*.json ./
25+
RUN npm ci --omit=dev --ignore-scripts
26+
27+
# NGINX config and entrypoint
28+
COPY docker/nginx.conf /etc/nginx/nginx.conf
29+
COPY docker/entrypoint.sh /entrypoint.sh
30+
RUN chmod +x /entrypoint.sh
31+
32+
ENV PORT=3000
33+
EXPOSE 8080
1734

18-
# Run the server
19-
CMD ["node", "dist/index.js"]
35+
CMD ["/entrypoint.sh"]

docker/entrypoint.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env sh
2+
set -e
3+
4+
# Start Node app in background
5+
node dist/index.js &
6+
APP_PID=$!
7+
8+
# Start NGINX in foreground
9+
nginx -g 'daemon off;'
10+
11+
wait $APP_PID
12+
13+

docker/nginx.conf

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
events {}
2+
http {
3+
upstream app { server 127.0.0.1:3000; }
4+
gzip off;
5+
6+
server {
7+
listen 8080;
8+
9+
# Alias common typo/variant: /{apiKey}/v1|v2/see -> /sse
10+
location ~ ^/(?<apikey>[^/]+)/v(?:1|2)/see$ {
11+
proxy_set_header X-Firecrawl-API-Key $apikey;
12+
proxy_set_header Host $host;
13+
14+
proxy_buffering off;
15+
proxy_read_timeout 620s;
16+
proxy_send_timeout 620s;
17+
18+
rewrite ^/.*/see$ /sse break;
19+
proxy_pass http://app;
20+
}
21+
22+
# Legacy with API key and version: /{apiKey}/v1|v2/{rest}
23+
location ~ ^/(?<apikey>[^/]+)/v(?:1|2)/(.*)$ {
24+
proxy_set_header X-Firecrawl-API-Key $apikey;
25+
proxy_set_header Host $host;
26+
27+
proxy_buffering off;
28+
proxy_read_timeout 620s;
29+
proxy_send_timeout 620s;
30+
31+
rewrite ^/[^/]+/v(?:1|2)/(.*)$ /$1 break;
32+
proxy_pass http://app;
33+
}
34+
35+
# Legacy: /{apiKey}/{rest}
36+
location ~ ^/(?<apikey>[^/]+)/(.*)$ {
37+
proxy_set_header X-Firecrawl-API-Key $apikey;
38+
proxy_set_header Host $host;
39+
40+
proxy_buffering off;
41+
proxy_read_timeout 620s;
42+
proxy_send_timeout 620s;
43+
44+
rewrite ^/[^/]+/(.*)$ /$1 break;
45+
proxy_pass http://app;
46+
}
47+
48+
# Header-based with version alias: /v1|v2/see -> /sse
49+
location ~ ^/v(?:1|2)/see$ {
50+
proxy_buffering off;
51+
proxy_read_timeout 620s;
52+
proxy_send_timeout 620s;
53+
proxy_set_header Host $host;
54+
proxy_set_header X-Forwarded-For $remote_addr;
55+
proxy_set_header X-Forwarded-Proto $scheme;
56+
rewrite ^/v(?:1|2)/see$ /sse break;
57+
proxy_pass http://app;
58+
}
59+
60+
# Header-based with version: /v1|v2/{rest}
61+
location ~ ^/v(?:1|2)/(.*)$ {
62+
proxy_buffering off;
63+
proxy_read_timeout 620s;
64+
proxy_send_timeout 620s;
65+
proxy_set_header Host $host;
66+
proxy_set_header X-Forwarded-For $remote_addr;
67+
proxy_set_header X-Forwarded-Proto $scheme;
68+
rewrite ^/v(?:1|2)/(.*)$ /$1 break;
69+
proxy_pass http://app;
70+
}
71+
72+
# Direct header-based paths
73+
location /mcp {
74+
proxy_buffering off;
75+
proxy_read_timeout 620s;
76+
proxy_send_timeout 620s;
77+
proxy_pass http://app/mcp;
78+
proxy_set_header Host $host;
79+
proxy_set_header X-Forwarded-For $remote_addr;
80+
proxy_set_header X-Forwarded-Proto $scheme;
81+
}
82+
83+
location /messages {
84+
proxy_http_version 1.1;
85+
proxy_request_buffering off;
86+
proxy_buffering off;
87+
chunked_transfer_encoding off;
88+
proxy_read_timeout 620s;
89+
proxy_send_timeout 620s;
90+
proxy_set_header Connection "";
91+
proxy_set_header Host $host;
92+
proxy_set_header X-Forwarded-For $remote_addr;
93+
proxy_set_header X-Forwarded-Proto $scheme;
94+
proxy_pass http://app/messages;
95+
}
96+
97+
location /sse {
98+
proxy_http_version 1.1;
99+
proxy_request_buffering off;
100+
proxy_buffering off;
101+
chunked_transfer_encoding off;
102+
proxy_read_timeout 620s;
103+
proxy_send_timeout 620s;
104+
proxy_set_header Connection "";
105+
proxy_set_header Accept "text/event-stream";
106+
proxy_set_header Host $host;
107+
proxy_set_header X-Forwarded-For $remote_addr;
108+
proxy_set_header X-Forwarded-Proto $scheme;
109+
proxy_pass http://app/sse;
110+
}
111+
112+
location /health {
113+
proxy_buffering off;
114+
proxy_read_timeout 5s;
115+
proxy_send_timeout 5s;
116+
proxy_set_header Host $host;
117+
proxy_set_header X-Forwarded-For $remote_addr;
118+
proxy_set_header X-Forwarded-Proto $scheme;
119+
proxy_pass http://app/health;
120+
}
121+
}
122+
}
123+
124+

0 commit comments

Comments
 (0)