Skip to content

Add 8 new models and fix MCP server list_models response#1

Open
Selcukatli wants to merge 3 commits intoilkerzg:mainfrom
Selcukatli:add-models-fix-mcp
Open

Add 8 new models and fix MCP server list_models response#1
Selcukatli wants to merge 3 commits intoilkerzg:mainfrom
Selcukatli:add-models-fix-mcp

Conversation

@Selcukatli
Copy link
Copy Markdown

@Selcukatli Selcukatli commented Sep 25, 2025

Summary

This PR adds 8 new FAL AI models and fixes a critical bug in the MCP server's list_models tool.

Changes

🎨 New Models Added (8 total)

  • Gemini 2.5 Flash (text-to-image and edit variants)
  • Nano Banana (text-to-image and edit variants)
  • FLUX Pro Kontext Edit
  • Gemini Flash Edit
  • Ideogram Character Edit
  • Qwen Image Edit Plus

🐛 Bug Fixes

  • Fixed MCP server list_models tool - Now returns proper format wrapped in content array with type/text structure, compatible with MCP protocol expectations

✨ Enhancements

  • Enhanced image extraction for edit models - Added support for single image responses, handles both 'image' and 'edited_image' response formats
  • Added schema fetcher utility (fetch-model-schemas.js) - Fetches schemas directly from FAL OpenAPI endpoints, automatically generates model configurations
  • Updated existing model configs - All models now have complete OpenAPI schemas with accurate parameter definitions

Testing

  • Tested all new models with CLI generation
  • Verified MCP server list_models fix
  • Confirmed edit models work with proper image_url parameters

Author: Selcuk Atli
Co-Authored-By: Claude


Summary by cubic

Adds 8 new FAL models and fixes the MCP server list_models response to be MCP-compliant. Also improves edit image handling and model schema generation.

  • New Features

    • Added 8 models: Gemini 2.5 Flash (image/edit), Nano Banana (image/edit), FLUX Pro Kontext Edit, Gemini Flash Edit, Ideogram Character Edit, Qwen Image Edit Plus.
    • Improved image URL extraction for edit flows (supports image, edited_image, output.image, and single URL strings).
    • Added schema fetcher (fetch-model-schemas.js) to pull OpenAPI and auto-generate accurate model configs; updated existing configs with full parameters.
    • New script: show-model-schemas.js; CLI now defaults output to ./generated-images when -o is not set.
  • Bug Fixes

    • list_models now returns content: [{ type: "text", text: "" }] per MCP protocol and safely handles missing args.

Summary by CodeRabbit

  • New Features
    • Added and updated image models (e.g., Gemini 2.5 Flash, Gemini Flash Edit, Ideogram Character Edit, Imagen 4 Ultra preview, Qwen Image/Edit Plus, Nano Banana, Flux variants) with structured parameters, safety options, and improved defaults.
    • CLI now saves to a “generated-images” folder by default when no output path is provided.
    • Model listing supports refined filtering with standardized responses.
  • Bug Fixes
    • More reliable extraction of image URLs from varied API responses.
  • Documentation
    • Comprehensive user guide and assistant-facing notes added.
  • Tests
    • Introduced an API smoke test script.

Selcukatli and others added 2 commits September 24, 2025 17:41
- Added 8 new FAL models:
  * Gemini 2.5 Flash (text-to-image and edit variants)
  * Nano Banana (text-to-image and edit variants)
  * FLUX Pro Kontext Edit
  * Gemini Flash Edit
  * Ideogram Character Edit
  * Qwen Image Edit Plus

- Fixed MCP server list_models tool to return proper format
  * Wrapped response in content array with type/text structure
  * Now compatible with MCP protocol expectations

- Enhanced image extraction for edit model responses
  * Added support for single image responses from edit models
  * Handles both 'image' and 'edited_image' response formats

- Added schema fetcher utility (fetch-model-schemas.js)
  * Fetches model schemas directly from FAL OpenAPI endpoints
  * Automatically generates model configurations with proper parameters
  * Supports both text-to-image and edit models

- Updated existing model configs with complete OpenAPI schemas
  * All models now have accurate parameter definitions
  * Includes types, descriptions, defaults, and constraints

Author: Selcuk Atli
Co-Authored-By: Claude <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Sep 25, 2025

@Selcukatli is attempting to deploy a commit to the ilkerzg's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 25, 2025

Walkthrough

Adds extensive model configuration files and schema-generation utilities, updates CLI behavior for default output directory, enhances image URL extraction normalization, modifies MCP server model listing response format and filtering, adds documentation, and includes scripts for displaying schemas and testing FAL API.

Changes

Cohort / File(s) Summary
Documentation
CLAUDE.md, rules/fal-cli-mcp-readme.md
Adds detailed repo/usage guidance for CLI and MCP server, security notes, model lists, and workflows tailored for assistants and users.
CLI Entrypoint & Defaults
bin/fal-cli, cli.js
Adds CLI entry file; in runDirectGeneration, introduces default output directory when --output not provided.
Core Image URL Extraction
core/image-generator.js
Extends extractImageUrls to normalize additional response shapes (single image fields and nested structures) without altering error handling.
MCP Server Model Listing
mcp-server.js
Updates list_models: safer arg defaults, conditional filter construction, and returns content-wrapped JSON text payload.
Schema Tools
fetch-model-schemas.js, show-model-schemas.js
Adds generator to fetch OpenAPI schemas and emit per-model JSON configs; adds viewer to print model schemas with defaults and parameter info.
FAL API Test Script
test-fal.js
New script subscribing to fal-ai/flux-pro/v1.1, logs first image URL on success; includes error handling and env checks.
Model JSON — Structural Updates
models/flux-kontext-max.json, models/flux-kontext-pro.json, models/flux-pro-ultra.json, models/imagen4-ultra.json, models/qwen-image.json
Adds root type, introduces structured parameters objects, adjusts defaultParams (e.g., aspect ratios, formats, safety, guidance), updates optimization prompts, and refines supported lists/max images.
Model JSON — New Additions
models/flux-pro-kontext-edit.json, models/gemini-25-flash-image.json, models/gemini-25-flash-edit.json, models/gemini-flash-edit.json, models/ideogram-character-edit.json, models/nano-banana.json, models/nano-banana-edit.json, models/qwen-image-edit-plus.json
Adds new image generation/edit model configurations with metadata, defaults, supported values, validation constraints, parameters schemas, and optimization prompts.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant CLI as CLI (cli.js)
  participant Gen as Generator
  U->>CLI: runDirectGeneration(options)
  alt options.output provided
    CLI->>CLI: outputDir = resolve(options.output)
  else no output provided
    CLI->>CLI: outputDir = join(cwd, "generated-images")
  end
  CLI->>Gen: generate(prompt, params, outputDir)
  Gen-->>CLI: result (image URLs, files)
  CLI-->>U: Print results
Loading
sequenceDiagram
  autonumber
  participant C as MCP Client
  participant S as MCP Server (mcp-server.js)
  participant M as Model Registry
  C->>S: call list_models(args?)
  S->>S: args = args || {}
  S->>S: build filters from provided fields
  S->>M: getFilteredModels(filters)
  M-->>S: models[]
  S->>S: apply quality filtering (if any)
  S-->>C: content: [{type: "text", text: JSON.stringify(response)}]
Loading
sequenceDiagram
  autonumber
  participant Dev as Developer
  participant G as fetch-model-schemas.js
  participant API as fal.ai OpenAPI
  participant FS as Filesystem
  Dev->>G: generateModelConfigs()
  loop for each model in MODELS_TO_FETCH
    G->>API: fetchModelSchema(modelId)
    alt success
      API-->>G: OpenAPI schema JSON
      G->>G: extractParametersFromSchema(schema, modelInfo)
      G->>FS: write models/<modelKey>.json
    else failure
      API-->>G: error/null
      G->>FS: write fallback config JSON
    end
  end
  G-->>Dev: Done (logs, counts)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

Thump-thump, my paws tap keys so bright,
New models bloom in JSON light.
CLI finds its cozy den,
MCP replies with text again.
Schemas fetched, URLs aligned—
A rabbit ships with peace of mind.
Hop, commit, and hit rewind! 🐇✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly summarizes the pull request’s main objectives by stating both the addition of eight new models and the MCP server list_models response fix, which directly aligns with the PR’s described changes.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
mcp-server.js (1)

642-681: Don't drop the structured list_models payload

Wrapping the response in content fixes the MCP protocol bug, but the new return shape now omits the actual models/metadata fields that downstream callers consume programmatically. Anything relying on result.models (including existing MCP clients and our own tooling) will now receive only a string blob, which breaks automation and forces manual JSON parsing. Please keep the structured payload alongside the text content.

-      return {
-        content: [
-          {
-            type: 'text',
-            text: JSON.stringify(response, null, 2)
-          }
-        ]
-      };
+      return {
+        ...response,
+        content: [
+          {
+            type: 'text',
+            text: JSON.stringify(response, null, 2)
+          }
+        ]
+      };
core/image-generator.js (1)

258-276: Always saving as .jpg — detect the correct extension from headers/URL

Files are saved with a .jpg suffix regardless of actual format (e.g., png). This causes downstream issues.

Apply this diff:

-    const filename = `${modelName}_${timestamp}_${randomSuffix}_${i + 1}.jpg`;
-    const filepath = path.join(outputDir, filename);
-
     try {
       // Download and save image
       const response = await fetch(imageUrl);
       if (!response.ok) {
         throw new Error(`HTTP ${response.status}: ${response.statusText}`);
       }
 
-      const buffer = await response.arrayBuffer();
-      await fs.writeFile(filepath, Buffer.from(buffer));
+      const contentType = response.headers.get('content-type') || '';
+      let ext = 'jpg';
+      const lowerUrl = imageUrl.toLowerCase();
+      if (contentType.includes('png') || lowerUrl.endsWith('.png')) {
+        ext = 'png';
+      } else if (contentType.includes('jpeg') || lowerUrl.endsWith('.jpeg') || lowerUrl.endsWith('.jpg')) {
+        ext = 'jpg';
+      }
+      const filename = `${modelName}_${timestamp}_${randomSuffix}_${i + 1}.${ext}`;
+      const filepath = path.join(outputDir, filename);
+
+      const buffer = await response.arrayBuffer();
+      await fs.writeFile(filepath, Buffer.from(buffer));
 
       savedFiles.push({
         url: imageUrl,
         filepath,
         filename,
         size: buffer.byteLength
       });
🧹 Nitpick comments (25)
rules/fal-cli-integration.md (1)

93-98: Add a language to fenced code block (markdownlint MD040).

Use a language hint for the tree-style output block, e.g., text.

-```
+```text
 output_directory/
 └── gen_{timestamp}_{id}/
     └── {model}_{prompt#}_{iteration}_{image#}_{timestamp}_{random}.png

</blockquote></details>
<details>
<summary>show-model-schemas.js (2)</summary><blockquote>

`44-58`: **Derive API Schema from model.parameters instead of hardcoding fields.**

Print required/optional params based on each model’s schema for accuracy.


```diff
-    // Additional schema details
-    console.log(chalk.cyan('\n  API Schema:'));
-    console.log('    Required parameters:');
-    console.log('      • prompt (string): The text description of the image to generate');
-    console.log('    Optional parameters:');
-    console.log('      • num_images (integer): Number of images to generate (1-' + model.maxImages + ')');
-    console.log('      • aspect_ratio (string): Image aspect ratio');
+    // Additional schema details
+    console.log(chalk.cyan('\n  API Schema:'));
+    const params = model.parameters || {};
+    const entries = Object.entries(params);
+    if (entries.length === 0) {
+      console.log('    (No schema details available)');
+    } else {
+      const required = entries.filter(([,v]) => v?.required);
+      const optional = entries.filter(([,v]) => !v?.required);
+      console.log('    Required parameters:');
+      required.forEach(([k, v]) => {
+        const t = v?.type ?? 'unknown';
+        const desc = v?.description ? `: ${v.description}` : '';
+        console.log(`      • ${k} (${t})${desc}`);
+      });
+      console.log('    Optional parameters:');
+      optional.forEach(([k, v]) => {
+        const t = v?.type ?? 'unknown';
+        const def = v?.default !== undefined ? ` (default: ${JSON.stringify(v.default)})` : '';
+        const desc = v?.description ? `: ${v.description}` : '';
+        console.log(`      • ${k} (${t})${def}${desc}`);
+      });
+    }

33-42: Guard against empty arrays to avoid printing blank lines.

Only print when arrays are non-empty.

-    if (model.supportedAspectRatios) {
+    if (Array.isArray(model.supportedAspectRatios) && model.supportedAspectRatios.length) {
       console.log(chalk.cyan('\n  Supported Aspect Ratios:'));
       console.log(`    ${model.supportedAspectRatios.join(', ')}`);
     }
-    if (model.supportedFormats) {
+    if (Array.isArray(model.supportedFormats) && model.supportedFormats.length) {
       console.log(chalk.cyan('\n  Supported Output Formats:'));
       console.log(`    ${model.supportedFormats.join(', ')}`);
     }
models/ideogram-character-edit.json (3)

61-70: Array items type not specified for reference arrays.

Specify items type to improve validation and tooling.

   "reference_mask_urls": {
     "type": "array",
     "required": false,
-    "description": "A set of masks to apply to the character references. Currently only 1 mask is supported, rest will be ignored. (maximum total size 10MB across all character references). The masks should be in JPEG, PNG or WebP format"
+    "description": "A set of masks to apply to the character references. Currently only 1 mask is supported, rest will be ignored. (maximum total size 10MB across all character references). The masks should be in JPEG, PNG or WebP format",
+    "items": { "type": "string", "format": "uri" }
   },
   "reference_image_urls": {
     "type": "array",
     "required": true,
-    "description": "A set of images to use as character references. Currently only 1 image is supported, rest will be ignored. (maximum total size 10MB across all character references). The images should be in JPEG, PNG or WebP format"
+    "description": "A set of images to use as character references. Currently only 1 image is supported, rest will be ignored. (maximum total size 10MB across all character references). The images should be in JPEG, PNG or WebP format",
+    "items": { "type": "string", "format": "uri" }
   },

102-105: Missing type for seed.

Declare type for correct validation.

-    "seed": {
-      "required": false,
+    "seed": {
+      "type": "integer",
+      "required": false,
       "description": "Seed for the random number generator"
     },

88-95: Types absent for style_codes and color_palette; confirm expected shapes.

Schema consumers likely expect explicit types here. Please align with the OpenAPI (style_codes commonly array of strings; color_palette may be object or enum/string).

rules/fal-mcp-integration.md (7)

94-97: Add language to fenced block (MD040).

Mark assistant-usage examples as text.

-```
+```text
 Generate a cyberpunk city scene using flux-pro-ultra model with 16:9 aspect ratio

---

`106-109`: **Add language to fenced block (MD040).**


```diff
-```
+```text
 List all Ultra Quality models with their pricing

---

`118-122`: **Add language to fenced block (MD040).**


```diff
-```
+```text
 Optimize "a cat sitting" for photorealistic style

---

`131-135`: **Add language to fenced block (MD040).**


```diff
-```
+```text
 Generate 3 different hero images using flux-kontext-pro

---

`143-147`: **Add language to fenced block (MD040).**


```diff
-```
+```text
 Calculate cost for 5 images with imagen4-ultra

---

`155-159`: **Add language to fenced block (MD040).**


```diff
-```
+```text
 Get details about flux-pro-ultra including parameters

---

`195-198`: **Add language to fenced block (MD040).**


```diff
-```
+```text
 "Use the FAL MCP server to generate a simple test image with the cheapest model"

</blockquote></details>
<details>
<summary>models/gemini-flash-edit.json (1)</summary><blockquote>

`23-34`: **Consider adding num_images to parameters (matches defaultParams).**

Keeps schema self-consistent and discoverable.


```diff
   "parameters": {
     "prompt": {
       "type": "string",
       "required": true,
       "description": "Description of the edit to make"
     },
+    "num_images": {
+      "type": "integer",
+      "required": false,
+      "description": "Number of images to generate",
+      "default": 1,
+      "minimum": 1,
+      "maximum": 4
+    },
     "image_url": {
       "type": "string",
       "required": true,
       "description": "URL of the image to edit"
     }
   },
fetch-model-schemas.js (3)

169-181: Handle non-JSON content types (multipart/form-data, x-www-form-urlencoded).

Some endpoints define inputs under multipart/form-data; broaden schema extraction.

-  if (paths[mainPath]?.post?.requestBody?.content?.['application/json']?.schema) {
-      const schema = paths[mainPath].post.requestBody.content['application/json'].schema;
+  const content = paths[mainPath]?.post?.requestBody?.content;
+  const schema =
+    content?.['application/json']?.schema ||
+    content?.['multipart/form-data']?.schema ||
+    content?.['application/x-www-form-urlencoded']?.schema;
+  if (schema) {
       // Handle $ref to components
       if (schema.$ref) {
         const refName = schema.$ref.split('/').pop();
         if (openApiSchema.components?.schemas?.[refName]) {
           inputSchema = openApiSchema.components.schemas[refName];
         }
       } else {
         inputSchema = schema;
       }
-    }
+  }

342-344: Robust direct-invocation check for ESM.

Compare file paths, not URLs, for reliability across platforms/symlinks.

-if (import.meta.url === `file://${process.argv[1]}`) {
+if (fileURLToPath(import.meta.url) === process.argv[1]) {
   generateModelConfigs().catch(console.error);
 }

198-229: Array/item metadata is dropped; consider capturing items.type and nested constraints.

Improve extraction to include items.type and minItems/maxItems when present to preserve fidelity.

Would you like me to extend extractParametersFromSchema to support array items and basic oneOf/allOf merging?

core/image-generator.js (7)

43-48: Docstring mismatch: duration/savedFiles naming

The doc says executionTime and savedPaths; code returns duration and savedFiles.

Apply this diff:

- *   - savedPaths: Local file paths (if outputDir provided)
- *   - executionTime: Time taken for generation
+ *   - savedFiles: Saved file metadata (if outputDir provided)
+ *   - duration: Time taken for generation (ms)

234-235: Return type doc for saveImagesToDisk is inaccurate

Function returns objects, not string paths.

Apply this diff:

- * @returns {Promise<Array<string>>} Array of saved file paths (absolute paths)
+ * @returns {Promise<Array<{url: string, filepath: string, filename: string, size: number}>>}
+ *   Array of saved file metadata

109-112: Seed extraction should look under result.data

When using @fal-ai/client, seed lives under result.data.

Apply this diff:

-        seed: result.seed || parameters.seed || null
+        seed: (result?.data?.seed ?? parameters.seed ?? null)

186-196: Handle nested data.output (url/image) variants

Some endpoints wrap outputs under data.output.*. Extend handling accordingly.

Apply this diff:

-  } else if (result.output && result.output.url) {
-    // Direct output URL
-    images.push(result.output.url);
-  } else if (result.output && result.output.image) {
-    // Output with nested image
-    if (result.output.image.url) {
-      images.push(result.output.image.url);
-    } else if (typeof result.output.image === 'string') {
-      images.push(result.output.image);
-    }
+  } else if (
+    (result.output && result.output.url) ||
+    (result.data && result.data.output && result.data.output.url)
+  ) {
+    // Direct output URL
+    images.push(result.output?.url || result.data.output.url);
+  } else if (
+    (result.output && result.output.image) ||
+    (result.data && result.data.output && result.data.output.image)
+  ) {
+    // Output with nested image
+    const img = result.output?.image || result.data.output.image;
+    if (img?.url) {
+      images.push(img.url);
+    } else if (typeof img === 'string') {
+      images.push(img);
+    }

207-211: Also collect from data.output.images[]

Support images array under data.output.

Apply this diff:

-  } else if (result.output && result.output.images) {
-    result.output.images.forEach(img => {
-      if (img.url) images.push(img.url);
-    });
+  } else if (
+    (result.output && result.output.images) ||
+    (result.data && result.data.output && result.data.output.images)
+  ) {
+    const arr = result.output?.images || result.data.output.images;
+    arr.forEach(img => {
+      if (img?.url) images.push(img.url);
+      else if (typeof img === 'string') images.push(img);
+    });

213-214: Deduplicate image URLs

Avoid duplicates when multiple branches point to the same URL.

Apply this diff:

-  return images;
+  return Array.from(new Set(images));

69-71: Avoid global fal.config mutation; prefer per-instance client

fal.config() mutates global state. For isolation and concurrency safety, prefer createFalClient with per-call credentials.

Example:

import { createFalClient } from '@fal-ai/client';
const client = createFalClient({ credentials: apiKey });
const result = await client.subscribe(model, { input: { prompt, ...parameters }, logs: false });
CLAUDE.md (1)

113-118: Update note about non-existent core modules

core/image-generator.js now exists; the warning is stale.

Apply this diff:

-- MCP server imports from non-existent `core/` modules (need to be implemented or references updated)
+- MCP server relies on shared modules under `core/` (e.g., image-generator). Ensure imports stay in sync with implementations.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5d23856 and 432ddb9.

📒 Files selected for processing (23)
  • CLAUDE.md (1 hunks)
  • bin/fal-cli (1 hunks)
  • cli.js (1 hunks)
  • core/image-generator.js (1 hunks)
  • fetch-model-schemas.js (1 hunks)
  • mcp-server.js (3 hunks)
  • models/flux-kontext-max.json (1 hunks)
  • models/flux-kontext-pro.json (1 hunks)
  • models/flux-pro-kontext-edit.json (1 hunks)
  • models/flux-pro-ultra.json (1 hunks)
  • models/gemini-25-flash-edit.json (1 hunks)
  • models/gemini-25-flash-image.json (1 hunks)
  • models/gemini-flash-edit.json (1 hunks)
  • models/ideogram-character-edit.json (1 hunks)
  • models/imagen4-ultra.json (1 hunks)
  • models/nano-banana-edit.json (1 hunks)
  • models/nano-banana.json (1 hunks)
  • models/qwen-image-edit-plus.json (1 hunks)
  • models/qwen-image.json (1 hunks)
  • rules/fal-cli-integration.md (1 hunks)
  • rules/fal-mcp-integration.md (1 hunks)
  • show-model-schemas.js (1 hunks)
  • test-fal.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
test-fal.js (1)
cli.js (3)
  • FAL_KEY (87-87)
  • result (618-626)
  • result (994-1010)
core/image-generator.js (2)
cli.js (2)
  • result (618-626)
  • result (994-1010)
core/prompt-optimizer.js (1)
  • result (80-87)
show-model-schemas.js (1)
cli.js (7)
  • models (379-379)
  • models (1353-1353)
  • models (1383-1383)
  • models (1456-1456)
  • models (1521-1521)
  • models (1545-1545)
  • model (1354-1354)
cli.js (1)
core/image-generator.js (1)
  • options (293-298)
mcp-server.js (1)
core/model-manager.js (7)
  • models (71-71)
  • models (105-105)
  • models (115-115)
  • models (163-163)
  • models (251-251)
  • models (312-312)
  • getFilteredModels (114-156)
fetch-model-schemas.js (2)
core/image-generator.js (5)
  • __dirname (25-25)
  • response (99-113)
  • response (263-263)
  • filename (258-258)
  • filepath (259-259)
mcp-server.js (5)
  • __dirname (49-49)
  • response (643-672)
  • modelsDir (843-843)
  • filename (898-898)
  • filepath (899-899)
🪛 markdownlint-cli2 (0.18.1)
rules/fal-mcp-integration.md

94-94: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


106-106: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


119-119: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


132-132: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


144-144: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


156-156: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


196-196: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (6)
cli.js (1)

1375-1376: Sensible default output directory.

Matches the interactive flow’s default and keeps direct runs from cluttering the cwd without explicit -o.

rules/fal-cli-integration.md (1)

204-206: No secrets leaked by fal-cli config --show
Verified the command only indicates whether an API key is set or stored and prints paths—never the key itself.

test-fal.js (1)

18-29: Verify endpoint ID and input schema

Confirm that 'fal-ai/flux-pro/v1.1' is valid and that this model accepts image_size as an object with width/height.

models/gemini-25-flash-image.json (1)

1-57: LGTM: schema is consistent and minimal

Model ID, type, defaults, and parameters look coherent with the rest of the repo.

models/nano-banana.json (1)

1-57: LGTM: consistent with new model schema

No blocking issues spotted.

models/flux-kontext-max.json (1)

81-92: Confirm safety_tolerance upper bound.

The enum now allows "6", but the description still states the range is 1–5. Please double-check the upstream schema/API before we ship an impossible value.

Comment thread bin/fal-cli
@@ -0,0 +1 @@
../lib/node_modules/fal-cli/cli.js No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Symlink points at non-existent path

Right now the symlink resolves to bin/../lib/node_modules/fal-cli/cli.js, but we don’t ship a lib/node_modules tree in this repo. The CLI entry point should target our actual CLI bundle (e.g. the real cli.js under dist/ or wherever it lives), otherwise fal-cli will break at runtime when the symlink is followed. Please update the link to the real file we publish with the package.

🤖 Prompt for AI Agents
In bin/fal-cli around line 1 the symlink target points to a non-existent path
(bin/../lib/node_modules/fal-cli/cli.js); update the symlink to point at the
actual CLI bundle we publish (for example dist/cli.js or the real path under the
package), and ensure the package's "files" or publish layout includes that
target file so the symlink is valid at runtime; verify the symlink uses the
correct relative path from bin/fal-cli to the published CLI entry and update
package.json "bin" if needed.

Comment thread fetch-model-schemas.js
Comment on lines +232 to +244
// For edit models, ensure we have image_url parameter
if (modelInfo.isEditModel) {
config.parameters.image_url = {
type: 'string',
required: true,
description: 'URL of the image to edit'
};
config.parameters.prompt = {
type: 'string',
required: true,
description: 'Description of the edit to make'
};
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t force both image_url and image_urls required for edit models.

Add only missing image parameter and avoid unsatisfiable requirements.

-    if (modelInfo.isEditModel) {
-      config.parameters.image_url = {
-        type: 'string',
-        required: true,
-        description: 'URL of the image to edit'
-      };
-      config.parameters.prompt = {
-        type: 'string',
-        required: true,
-        description: 'Description of the edit to make'
-      };
-    }
+    if (modelInfo.isEditModel) {
+      const hasImageUrl = Object.prototype.hasOwnProperty.call(config.parameters, 'image_url');
+      const hasImageUrls = Object.prototype.hasOwnProperty.call(config.parameters, 'image_urls');
+      if (!hasImageUrl && !hasImageUrls) {
+        config.parameters.image_url = {
+          type: 'string',
+          required: true,
+          description: 'URL of the image to edit'
+        };
+      } else if (hasImageUrl && hasImageUrls) {
+        // Avoid both being required at once
+        if (config.parameters.image_urls && config.parameters.image_urls.required === true) {
+          config.parameters.image_urls.required = false;
+        }
+      }
+      if (!Object.prototype.hasOwnProperty.call(config.parameters, 'prompt')) {
+        config.parameters.prompt = {
+          type: 'string',
+          required: true,
+          description: 'Description of the edit to make'
+        };
+      }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// For edit models, ensure we have image_url parameter
if (modelInfo.isEditModel) {
config.parameters.image_url = {
type: 'string',
required: true,
description: 'URL of the image to edit'
};
config.parameters.prompt = {
type: 'string',
required: true,
description: 'Description of the edit to make'
};
}
// For edit models, ensure we have image_url parameter
if (modelInfo.isEditModel) {
const hasImageUrl = Object.prototype.hasOwnProperty.call(config.parameters, 'image_url');
const hasImageUrls = Object.prototype.hasOwnProperty.call(config.parameters, 'image_urls');
if (!hasImageUrl && !hasImageUrls) {
config.parameters.image_url = {
type: 'string',
required: true,
description: 'URL of the image to edit'
};
} else if (hasImageUrl && hasImageUrls) {
// Avoid both being required at once
if (config.parameters.image_urls.required === true) {
config.parameters.image_urls.required = false;
}
}
if (!Object.prototype.hasOwnProperty.call(config.parameters, 'prompt')) {
config.parameters.prompt = {
type: 'string',
required: true,
description: 'Description of the edit to make'
};
}
}
🤖 Prompt for AI Agents
In fetch-model-schemas.js around lines 232 to 244, the current logic for edit
models unconditionally sets both image_url and prompt required which can create
unsatisfiable requirements when image_urls already exists; update the logic so
it only adds the missing image parameter: if neither image_url nor image_urls
exists, add image_url as required; if image_urls exists, do not add image_url or
change its required state; ensure prompt is added only if missing.

Comment on lines +80 to +93
"safety_tolerance": {
"type": "string",
"required": false,
"description": "The safety tolerance level for the generated image. 1 being the most strict and 5 being the most permissive.",
"default": "2",
"enum": [
"1",
"2",
"3",
"4",
"5",
"6"
]
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

safety_tolerance enum includes unsupported value

Description states levels 1–5, but enum includes "6". Remove "6" or update description; recommended: remove "6".

Apply this diff:

-      "enum": [
-        "1",
-        "2",
-        "3",
-        "4",
-        "5",
-        "6"
-      ]
+      "enum": ["1", "2", "3", "4", "5"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"safety_tolerance": {
"type": "string",
"required": false,
"description": "The safety tolerance level for the generated image. 1 being the most strict and 5 being the most permissive.",
"default": "2",
"enum": [
"1",
"2",
"3",
"4",
"5",
"6"
]
},
"safety_tolerance": {
"type": "string",
"required": false,
"description": "The safety tolerance level for the generated image. 1 being the most strict and 5 being the most permissive.",
"default": "2",
"enum": ["1", "2", "3", "4", "5"]
},
🤖 Prompt for AI Agents
In models/flux-kontext-pro.json around lines 80 to 93, the safety_tolerance enum
includes an unsupported value "6" while the description specifies levels 1–5;
remove the "6" entry from the enum so it only contains "1" through "5" (or
alternatively update the description if you intend to support "6", but prefer
removing "6"); update the enum array accordingly to match the description.

Comment on lines +83 to +96
"safety_tolerance": {
"type": "string",
"required": false,
"description": "The safety tolerance level for the generated image. 1 being the most strict and 5 being the most permissive.",
"default": "2",
"enum": [
"1",
"2",
"3",
"4",
"5",
"6"
]
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Safety tolerance description vs enum mismatch (mentions 1–5 but enum includes 6).

Align description with allowed values or adjust enum.

-      "description": "The safety tolerance level for the generated image. 1 being the most strict and 5 being the most permissive.",
+      "description": "The safety tolerance level for the generated image. 1 being the most strict and 6 being the most permissive.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"safety_tolerance": {
"type": "string",
"required": false,
"description": "The safety tolerance level for the generated image. 1 being the most strict and 5 being the most permissive.",
"default": "2",
"enum": [
"1",
"2",
"3",
"4",
"5",
"6"
]
},
"safety_tolerance": {
"type": "string",
"required": false,
"description": "The safety tolerance level for the generated image. 1 being the most strict and 6 being the most permissive.",
"default": "2",
"enum": [
"1",
"2",
"3",
"4",
"5",
"6"
]
},
🤖 Prompt for AI Agents
In models/flux-pro-kontext-edit.json around lines 83 to 96, the safety_tolerance
field description states allowed values are 1–5 but the enum includes "6";
update them to match by either expanding the description to say 1–6 if "6" is
valid, or remove "6" from the enum (and adjust the default if needed) so the
description and enum are consistent; ensure the default remains a valid enum
member after the change.

Comment on lines +36 to +44
"aspect_ratio": {
"required": false,
"description": "The aspect ratio of the generated image.",
"default": "16:9"
},
"enhance_prompt": {
"type": "boolean",
"required": false,
"description": "Whether to enhance the prompt for better results.",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add missing type for aspect_ratio parameter.

Every other parameter in this schema declares a type. Leaving it off here makes the schema inconsistent and breaks consumers that expect a type field (e.g., the new schema tooling introduced in this PR). Please add the missing "type": "string" entry.

     "aspect_ratio": {
+      "type": "string",
       "required": false,
       "description": "The aspect ratio of the generated image.",
       "default": "16:9"
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"aspect_ratio": {
"required": false,
"description": "The aspect ratio of the generated image.",
"default": "16:9"
},
"enhance_prompt": {
"type": "boolean",
"required": false,
"description": "Whether to enhance the prompt for better results.",
"aspect_ratio": {
"type": "string",
"required": false,
"description": "The aspect ratio of the generated image.",
"default": "16:9"
},
"enhance_prompt": {
"type": "boolean",
"required": false,
"description": "Whether to enhance the prompt for better results.",
🤖 Prompt for AI Agents
In models/flux-pro-ultra.json around lines 36 to 44, the "aspect_ratio"
parameter is missing its "type" property which breaks schema consumers; add
"type": "string" to the "aspect_ratio" object so it matches other parameters and
tools that expect a type field, keeping existing "required", "description", and
"default" entries intact.

Comment on lines +98 to +119
"image_urls": {
"type": "array",
"required": true,
"description": "The URLs of the images to edit."
},
"negative_prompt": {
"type": "string",
"required": false,
"description": "The negative prompt for the generation",
"default": " "
},
"seed": {
"type": "integer",
"required": false,
"description": "\n The same seed and the same prompt given to the same version of the model\n will output the same image every time.\n "
},
"image_url": {
"type": "string",
"required": true,
"description": "URL of the image to edit"
}
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Conflicting requirements: image_urls and image_url both required

Same issue as other edit models. Make image_url optional and enforce a minimum on image_urls.

Apply this diff:

     "image_urls": {
       "type": "array",
-      "required": true,
+      "required": true,
       "description": "The URLs of the images to edit."
+    , "minItems": 1
     },
@@
     "image_url": {
       "type": "string",
-      "required": true,
+      "required": false,
       "description": "URL of the image to edit"
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"image_urls": {
"type": "array",
"required": true,
"description": "The URLs of the images to edit."
},
"negative_prompt": {
"type": "string",
"required": false,
"description": "The negative prompt for the generation",
"default": " "
},
"seed": {
"type": "integer",
"required": false,
"description": "\n The same seed and the same prompt given to the same version of the model\n will output the same image every time.\n "
},
"image_url": {
"type": "string",
"required": true,
"description": "URL of the image to edit"
}
},
"image_urls": {
"type": "array",
"required": true,
"description": "The URLs of the images to edit.",
"minItems": 1
},
"negative_prompt": {
"type": "string",
"required": false,
"description": "The negative prompt for the generation",
"default": " "
},
"seed": {
"type": "integer",
"required": false,
"description": "\n The same seed and the same prompt given to the same version of the model\n will output the same image every time.\n "
},
"image_url": {
"type": "string",
"required": false,
"description": "URL of the image to edit"
}
🤖 Prompt for AI Agents
In models/qwen-image-edit-plus.json around lines 98 to 119, the schema currently
marks both image_urls and image_url as required which conflicts; make
"image_url" optional by removing it from the required list and enforce that
"image_urls" contains at least one entry by adding "minItems": 1 to the
"image_urls" property (keep "required": true for image_urls, remove or set
"required": false for image_url so only image_urls is mandatory). Ensure the
JSON schema's required array and property entries are updated accordingly so
validation requires at least one URL in image_urls and does not mandate
image_url.

Comment thread models/qwen-image.json
Comment on lines +46 to +50
"image_size": {
"required": false,
"description": "The size of the generated image.",
"default": "landscape_4_3"
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Declare type for image_size.

This parameter is missing its "type" field, unlike every other entry. Without it, schema consumers (including the new schema tooling added in this PR) will treat the config as invalid. Please add "type": "string".

     "image_size": {
+      "type": "string",
       "required": false,
       "description": "The size of the generated image.",
       "default": "landscape_4_3"
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"image_size": {
"required": false,
"description": "The size of the generated image.",
"default": "landscape_4_3"
},
"image_size": {
"type": "string",
"required": false,
"description": "The size of the generated image.",
"default": "landscape_4_3"
},
🤖 Prompt for AI Agents
In models/qwen-image.json around lines 46 to 50, the image_size property is
missing its "type" field causing schema validation failures; add "type":
"string" to the image_size object so it matches other entries and is accepted by
the schema tooling (keep the existing required, description, and default
fields).

Comment thread rules/fal-cli-integration.md Outdated
Comment thread rules/fal-mcp-integration.md Outdated
Comment thread test-fal.js
Comment on lines +31 to +35
console.log('Success! Result:', result);

if (result.images && result.images.length > 0) {
console.log('Image URL:', result.images[0].url);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix result handling for @fal-ai/client: access data.images

subscribe() returns { data, requestId }. You're checking result.images, which will be undefined.

Apply this diff:

-    if (result.images && result.images.length > 0) {
-      console.log('Image URL:', result.images[0].url);
-    }
+    const data = result?.data ?? result;
+    const firstImage = Array.isArray(data?.images) && data.images[0];
+    if (firstImage) {
+      console.log('Image URL:', firstImage.url ?? firstImage.image_url ?? (typeof firstImage === 'string' ? firstImage : undefined));
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log('Success! Result:', result);
if (result.images && result.images.length > 0) {
console.log('Image URL:', result.images[0].url);
}
console.log('Success! Result:', result);
const data = result?.data ?? result;
const firstImage = Array.isArray(data?.images) && data.images[0];
if (firstImage) {
console.log(
'Image URL:',
firstImage.url ??
firstImage.image_url ??
(typeof firstImage === 'string' ? firstImage : undefined)
);
}
🤖 Prompt for AI Agents
In test-fal.js around lines 31 to 35, the handler treats subscribe()'s return
value as result.images but subscribe() returns an object shaped { data,
requestId }; update the code to read images from result.data (e.g., check
result.data && result.data.images && result.data.images.length > 0) and log
result.data.images[0].url (and the data or requestId as needed) instead of
result.images to correctly access the image URL.

- Merged fal-cli-integration.md and fal-mcp-integration.md
- Created comprehensive fal-cli-mcp-readme.md
- Added Claude Code CLI integration instructions
- Updated with all 13 models and pricing
- Improved MCP tool documentation with examples
- Better organization separating CLI and MCP interfaces

Author: Selcuk Atli
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
rules/fal-cli-mcp-readme.md (1)

266-270: Add a language tag to the directory tree block.

markdownlint is currently failing (MD040) because this fenced block lacks a language hint. Tag it (e.g., text) to satisfy linting.

-```
+```text
 output_directory/
 └── gen_{timestamp}_{id}/
     └── {model}_{prompt#}_{iteration}_{image#}_{timestamp}_{random}.png
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 432ddb9 and 234b633.

📒 Files selected for processing (1)
  • rules/fal-cli-mcp-readme.md (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
rules/fal-cli-mcp-readme.md

266-266: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant