@@ -133,6 +133,9 @@ function createClient(apiKey?: string): FirecrawlApp {
133
133
134
134
const ORIGIN = 'mcp-fastmcp' ;
135
135
136
+ // Safe mode is enabled by default for cloud service to comply with ChatGPT safety requirements
137
+ const SAFE_MODE = process . env . CLOUD_SERVICE === 'true' ;
138
+
136
139
function getClient ( session ?: SessionData ) : FirecrawlApp {
137
140
// For cloud service, API key is required
138
141
if ( process . env . CLOUD_SERVICE === 'true' ) {
@@ -156,6 +159,15 @@ function asText(data: unknown): string {
156
159
157
160
// scrape tool (v2 semantics, minimal args)
158
161
// Centralized scrape params (used by scrape, and referenced in search/crawl scrapeOptions)
162
+
163
+ // Define safe action types
164
+ const safeActionTypes = [ 'wait' , 'screenshot' , 'scroll' , 'scrape' ] as const ;
165
+ const otherActions = [ 'click' , 'write' , 'press' , 'executeJavascript' , 'generatePDF' ] as const ;
166
+ const allActionTypes = [ ...safeActionTypes , ...otherActions ] as const ;
167
+
168
+ // Use appropriate action types based on safe mode
169
+ const allowedActionTypes = SAFE_MODE ? safeActionTypes : allActionTypes ;
170
+
159
171
const scrapeParamsSchema = z . object ( {
160
172
url : z . string ( ) . url ( ) ,
161
173
formats : z
@@ -190,30 +202,22 @@ const scrapeParamsSchema = z.object({
190
202
includeTags : z . array ( z . string ( ) ) . optional ( ) ,
191
203
excludeTags : z . array ( z . string ( ) ) . optional ( ) ,
192
204
waitFor : z . number ( ) . optional ( ) ,
193
- actions : z
194
- . array (
195
- z . object ( {
196
- type : z . enum ( [
197
- 'wait' ,
198
- 'click' ,
199
- 'screenshot' ,
200
- 'write' ,
201
- 'press' ,
202
- 'scroll' ,
203
- 'scrape' ,
204
- 'executeJavascript' ,
205
- 'generatePDF' ,
206
- ] ) ,
207
- selector : z . string ( ) . optional ( ) ,
208
- milliseconds : z . number ( ) . optional ( ) ,
209
- text : z . string ( ) . optional ( ) ,
210
- key : z . string ( ) . optional ( ) ,
211
- direction : z . enum ( [ 'up' , 'down' ] ) . optional ( ) ,
212
- script : z . string ( ) . optional ( ) ,
213
- fullPage : z . boolean ( ) . optional ( ) ,
214
- } )
215
- )
216
- . optional ( ) ,
205
+ ...( SAFE_MODE ? { } : {
206
+ actions : z
207
+ . array (
208
+ z . object ( {
209
+ type : z . enum ( allowedActionTypes ) ,
210
+ selector : z . string ( ) . optional ( ) ,
211
+ milliseconds : z . number ( ) . optional ( ) ,
212
+ text : z . string ( ) . optional ( ) ,
213
+ key : z . string ( ) . optional ( ) ,
214
+ direction : z . enum ( [ 'up' , 'down' ] ) . optional ( ) ,
215
+ script : z . string ( ) . optional ( ) ,
216
+ fullPage : z . boolean ( ) . optional ( ) ,
217
+ } )
218
+ )
219
+ . optional ( ) ,
220
+ } ) ,
217
221
mobile : z . boolean ( ) . optional ( ) ,
218
222
skipTlsVerification : z . boolean ( ) . optional ( ) ,
219
223
removeBase64Images : z . boolean ( ) . optional ( ) ,
@@ -250,6 +254,7 @@ This is the most powerful, fastest and most reliable scraper tool, if available
250
254
\`\`\`
251
255
**Performance:** Add maxAge parameter for 500% faster scrapes using cached data.
252
256
**Returns:** Markdown, HTML, or other formats as specified.
257
+ ${ SAFE_MODE ? '**Safe Mode:** Read-only content extraction. Interactive actions (click, write, executeJavascript) are disabled for security.' : '' }
253
258
` ,
254
259
parameters : scrapeParamsSchema ,
255
260
execute : async (
@@ -405,6 +410,7 @@ server.addTool({
405
410
}
406
411
\`\`\`
407
412
**Returns:** Operation ID for status checking; use firecrawl_check_crawl_status to check progress.
413
+ ${ SAFE_MODE ? '**Safe Mode:** Read-only crawling. Webhooks and interactive actions are disabled for security.' : '' }
408
414
` ,
409
415
parameters : z . object ( {
410
416
url : z . string ( ) ,
@@ -419,15 +425,17 @@ server.addTool({
419
425
crawlEntireDomain : z . boolean ( ) . optional ( ) ,
420
426
delay : z . number ( ) . optional ( ) ,
421
427
maxConcurrency : z . number ( ) . optional ( ) ,
422
- webhook : z
423
- . union ( [
424
- z . string ( ) ,
425
- z . object ( {
426
- url : z . string ( ) ,
427
- headers : z . record ( z . string ( ) , z . string ( ) ) . optional ( ) ,
428
- } ) ,
429
- ] )
430
- . optional ( ) ,
428
+ ...( SAFE_MODE ? { } : {
429
+ webhook : z
430
+ . union ( [
431
+ z . string ( ) ,
432
+ z . object ( {
433
+ url : z . string ( ) ,
434
+ headers : z . record ( z . string ( ) , z . string ( ) ) . optional ( ) ,
435
+ } ) ,
436
+ ] )
437
+ . optional ( ) ,
438
+ } ) ,
431
439
deduplicateSimilarURLs : z . boolean ( ) . optional ( ) ,
432
440
ignoreQueryParameters : z . boolean ( ) . optional ( ) ,
433
441
scrapeOptions : scrapeParamsSchema . omit ( { url : true } ) . partial ( ) . optional ( ) ,
0 commit comments