Add 8 new models and fix MCP server list_models response#1
Add 8 new models and fix MCP server list_models response#1Selcukatli wants to merge 3 commits intoilkerzg:mainfrom
Conversation
- 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>
|
@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. |
WalkthroughAdds 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
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
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)}]
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)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests
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.
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. Comment |
There was a problem hiding this comment.
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 structuredlist_modelspayloadWrapping the response in
contentfixes the MCP protocol bug, but the new return shape now omits the actualmodels/metadatafields that downstream callers consume programmatically. Anything relying onresult.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/URLFiles 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 namingThe 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 inaccurateFunction 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.dataWhen 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) variantsSome 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 URLsAvoid 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 clientfal.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 modulescore/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
📒 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 byfal-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 schemaConfirm 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 minimalModel 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 schemaNo blocking issues spotted.
models/flux-kontext-max.json (1)
81-92: Confirmsafety_toleranceupper 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.
| @@ -0,0 +1 @@ | |||
| ../lib/node_modules/fal-cli/cli.js No newline at end of file | |||
There was a problem hiding this comment.
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.
| // 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' | ||
| }; | ||
| } |
There was a problem hiding this comment.
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.
| // 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.
| "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" | ||
| ] | ||
| }, |
There was a problem hiding this comment.
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.
| "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.
| "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" | ||
| ] | ||
| }, |
There was a problem hiding this comment.
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.
| "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.
| "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.", |
There was a problem hiding this comment.
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.
| "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.
| "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" | ||
| } | ||
| }, |
There was a problem hiding this comment.
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.
| "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.
| "image_size": { | ||
| "required": false, | ||
| "description": "The size of the generated image.", | ||
| "default": "landscape_4_3" | ||
| }, |
There was a problem hiding this comment.
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.
| "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).
| console.log('Success! Result:', result); | ||
|
|
||
| if (result.images && result.images.length > 0) { | ||
| console.log('Image URL:', result.images[0].url); | ||
| } |
There was a problem hiding this comment.
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.
| 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
There was a problem hiding this comment.
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
📒 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)
Summary
This PR adds 8 new FAL AI models and fixes a critical bug in the MCP server's
list_modelstool.Changes
🎨 New Models Added (8 total)
🐛 Bug Fixes
list_modelstool - Now returns proper format wrapped in content array with type/text structure, compatible with MCP protocol expectations✨ Enhancements
fetch-model-schemas.js) - Fetches schemas directly from FAL OpenAPI endpoints, automatically generates model configurationsTesting
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
Bug Fixes
Summary by CodeRabbit