flutterflow-mcp 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/build/utils/topic-map.js +7 -0
- package/docs/ff-yaml/00-overview.md +1 -1
- package/docs/ff-yaml/01-project-files.md +420 -0
- package/docs/ff-yaml/03-components.md +20 -0
- package/docs/ff-yaml/06-variables.md +15 -0
- package/docs/ff-yaml/08-custom-code.md +14 -69
- package/package.json +1 -1
- package/skills/flutterflow-mcp/SKILL.md +201 -0
package/README.md
CHANGED
|
@@ -263,9 +263,19 @@ This MCP ships with a comprehensive FlutterFlow YAML reference catalog that AI m
|
|
|
263
263
|
|
|
264
264
|
See [docs/ff-yaml/](docs/ff-yaml/) for the full catalog.
|
|
265
265
|
|
|
266
|
+
## AI Agent Skill
|
|
267
|
+
|
|
268
|
+
This MCP includes a [skills.sh](https://skills.sh)-compatible skill for AI agents. Install it to teach your AI assistant how to use FlutterFlow MCP effectively:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
npx skills add mohn93/ff-mcp --skill flutterflow-mcp
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Compatible with Claude Code, Cursor, GitHub Copilot, Codex, Goose, Windsurf, and 12+ other AI agents. The skill provides tool orchestration workflows, critical YAML rules, and detailed reference documentation for widgets, actions, data binding, theming, and more.
|
|
275
|
+
|
|
266
276
|
## Claude Code Skills
|
|
267
277
|
|
|
268
|
-
|
|
278
|
+
You can also copy Claude Code-specific skills from [`skills/`](skills/) into your project's `.claude/skills/` directory:
|
|
269
279
|
|
|
270
280
|
- **`ff-yaml-dev.md`** — Core workflow: reading, editing, and creating FlutterFlow pages/components
|
|
271
281
|
- **`ff-widget-patterns.md`** — Quick reference for common widget YAML patterns and snippets
|
package/build/utils/topic-map.js
CHANGED
|
@@ -84,6 +84,13 @@ export const TOPIC_MAP = {
|
|
|
84
84
|
parametervalues: "03-components.md",
|
|
85
85
|
callback: "03-components.md",
|
|
86
86
|
executecallbackaction: "03-components.md",
|
|
87
|
+
// Internationalization
|
|
88
|
+
translation: "01-project-files.md",
|
|
89
|
+
translations: "01-project-files.md",
|
|
90
|
+
i18n: "01-project-files.md",
|
|
91
|
+
localization: "01-project-files.md",
|
|
92
|
+
translatabletext: "01-project-files.md",
|
|
93
|
+
languages: "01-project-files.md",
|
|
87
94
|
// Universal patterns
|
|
88
95
|
inputvalue: "README.md",
|
|
89
96
|
mostrecentinputvalue: "README.md",
|
|
@@ -36,7 +36,7 @@ Every FlutterFlow project is a collection of YAML files accessed via file keys.
|
|
|
36
36
|
| `enums/id-XXX` | Enum definition with named values |
|
|
37
37
|
| `collections/id-XXX` | Firestore collection schema: fields, types, subcollections |
|
|
38
38
|
| `agent/id-XXX` | AI agent configuration |
|
|
39
|
-
| `custom-file/id-<TYPE>` | Custom file configs for native platform files. Known types: `MAIN` (main.dart startup actions), `ANDROID_MANIFEST` (XML injection hooks for AndroidManifest.xml), `PROGUARD` (ProGuard rule injection for proguard-rules.pro), `BUILD_GRADLE` (Gradle plugin/dependency/repository injection for build.gradle). Only appear after enabled in FF editor. Sub-file `custom-file/id
|
|
39
|
+
| `custom-file/id-<TYPE>` | Custom file configs for native platform files. Known types: `MAIN` (main.dart startup actions), `ANDROID_MANIFEST` (XML injection hooks for AndroidManifest.xml), `INFO_PLIST` (plist property injection for Info.plist), `ENTITLEMENTS` (iOS capability entitlements for Runner.entitlements), `APP_DELEGATE` (Swift code injection for AppDelegate.swift), `PROGUARD` (ProGuard rule injection for proguard-rules.pro), `BUILD_GRADLE` (Gradle plugin/dependency/repository injection for build.gradle). Only appear after enabled in FF editor. Sub-file `custom-file/id-<TYPE>/custom-file-code.dart` contains generated source. |
|
|
40
40
|
| `environment-settings` | Per-environment configuration values (API URLs, keys) |
|
|
41
41
|
| `dependencies` | FlutterFlow library package dependencies |
|
|
42
42
|
| `custom-code-dependencies` | Dart/Flutter pub dependencies for custom code |
|
|
@@ -444,6 +444,69 @@ persistLanguageSelection: true # Remember user's language choice
|
|
|
444
444
|
|
|
445
445
|
---
|
|
446
446
|
|
|
447
|
+
## languages/translation/id-{key} (Translation Files)
|
|
448
|
+
|
|
449
|
+
**Purpose:** Individual translation entries for user-defined translatable strings. Each file maps a unique key to translated text across all supported languages.
|
|
450
|
+
|
|
451
|
+
**File key pattern:** `languages/translation/id-<key>` (e.g., `languages/translation/id-ttk654j0`)
|
|
452
|
+
|
|
453
|
+
**Schema:**
|
|
454
|
+
```yaml
|
|
455
|
+
translationIdentifier:
|
|
456
|
+
key: ttk654j0 # Unique translation key (8-char alphanumeric)
|
|
457
|
+
translations:
|
|
458
|
+
- language:
|
|
459
|
+
language: en # ISO 639-1 code (must match languages.yaml)
|
|
460
|
+
text: Continue # Translated text for this language
|
|
461
|
+
- language:
|
|
462
|
+
language: es
|
|
463
|
+
text: Continuar
|
|
464
|
+
isFixed: false # false = user-editable, true = system/preset string
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
**Key fields:**
|
|
468
|
+
|
|
469
|
+
| Field | Type | Notes |
|
|
470
|
+
|---|---|---|
|
|
471
|
+
| `translationIdentifier.key` | string | Unique key matching the file key suffix. Referenced by widgets and parameter passes. |
|
|
472
|
+
| `translations` | list | One entry per language. Must include all languages from `languages.yaml`. |
|
|
473
|
+
| `translations[].language.language` | string | ISO 639-1 code (`en`, `es`, `fr`, etc.) |
|
|
474
|
+
| `translations[].text` | string | Translated text. Empty string `""` = untranslated (falls back to primary language). |
|
|
475
|
+
| `isFixed` | bool | `true` for system preset strings, `false` for user-defined translations. |
|
|
476
|
+
|
|
477
|
+
### Where translation keys are referenced
|
|
478
|
+
|
|
479
|
+
Translation keys appear in two contexts:
|
|
480
|
+
|
|
481
|
+
**1. On Text widgets** — via `translationIdentifier` in the `text` prop:
|
|
482
|
+
```yaml
|
|
483
|
+
# Widget-level translation (static, per-widget)
|
|
484
|
+
text:
|
|
485
|
+
translationIdentifier:
|
|
486
|
+
key: ttk654j0
|
|
487
|
+
textValue:
|
|
488
|
+
inputValue: Continue # English default / editor preview
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
**2. On component parameter passes** — via `translatableText` inside `inputValue`:
|
|
492
|
+
```yaml
|
|
493
|
+
# Parameter-level translation (per-instance, used when passing
|
|
494
|
+
# translated strings to component parameters)
|
|
495
|
+
paramIdentifier:
|
|
496
|
+
name: title
|
|
497
|
+
key: p1titl
|
|
498
|
+
inputValue:
|
|
499
|
+
translatableText:
|
|
500
|
+
translationIdentifier:
|
|
501
|
+
key: ms01ttl1
|
|
502
|
+
textValue:
|
|
503
|
+
inputValue: Histamine / Low DAO # English default
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
> **Important:** The `translatableText` wrapper is the correct way to pass translated strings as component parameters. Do NOT use `translationIdentifier` directly on the parameterPass (it will fail validation with "Unknown field name"). Instead, nest it inside `inputValue.translatableText`.
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
447
510
|
## app-state.yaml
|
|
448
511
|
|
|
449
512
|
**Purpose:** App-level state variables (global state accessible from any page/component).
|
|
@@ -1242,6 +1305,363 @@ parameters: # Template variables referenced in ho
|
|
|
1242
1305
|
|
|
1243
1306
|
---
|
|
1244
1307
|
|
|
1308
|
+
## custom-file/id-INFO_PLIST
|
|
1309
|
+
|
|
1310
|
+
**Purpose:** Allows injecting custom properties into the generated `Info.plist` for iOS builds, and defining template variables for dynamic values. Like `ANDROID_MANIFEST`, this is an abstraction layer — you define "hooks" (plist property injection) and "parameters" (template variables).
|
|
1311
|
+
|
|
1312
|
+
> **This file only exists when it has content.** If all hooks and parameters are removed (via UI or API), the file disappears from the server (API returns 404). It reappears when a user adds a hook or parameter in the FF editor.
|
|
1313
|
+
|
|
1314
|
+
> **WARNING: Pushing any `custom-file` deletes siblings.** The API treats all `custom-file/id-*` keys as a single collection. Pushing this file alone will delete all other custom files (MAIN, ANDROID_MANIFEST, PROGUARD, BUILD_GRADLE, etc.). **Always include all existing `custom-file` entries in the same push payload.** See [API Limitation #10](../flutterflow-api-limitations.md#10-pushing-one-custom-file-deletes-all-other-custom-file-entries).
|
|
1315
|
+
|
|
1316
|
+
> **Important — this is NOT the Info.plist itself.**
|
|
1317
|
+
> This is FlutterFlow's configuration that controls **property injection into the generated Info.plist** at build time. The file only appears after a user adds at least one property in the FF editor (Settings > Custom Code > Custom Files > Info.plist).
|
|
1318
|
+
|
|
1319
|
+
**Top-level keys:**
|
|
1320
|
+
- `type`
|
|
1321
|
+
- `identifier`
|
|
1322
|
+
- `hooks`
|
|
1323
|
+
- `parameters`
|
|
1324
|
+
|
|
1325
|
+
### Hook Types
|
|
1326
|
+
|
|
1327
|
+
Only one hook type:
|
|
1328
|
+
|
|
1329
|
+
| Hook Type | Where it injects in Info.plist |
|
|
1330
|
+
|---|---|
|
|
1331
|
+
| `INFO_PLIST_PROPERTY` | Inside the root `<dict>` — use for adding `<key>`/`<value>` pairs (strings, booleans, arrays, etc.) |
|
|
1332
|
+
|
|
1333
|
+
### Parameters (Template Variables)
|
|
1334
|
+
|
|
1335
|
+
Same pattern as ANDROID_MANIFEST — parameters are template variables that can be referenced in hook `content` using `{{variableName}}` syntax. Values can come from literal input or environment variables.
|
|
1336
|
+
|
|
1337
|
+
### Schema
|
|
1338
|
+
|
|
1339
|
+
```yaml
|
|
1340
|
+
type: INFO_PLIST
|
|
1341
|
+
identifier:
|
|
1342
|
+
name: Info.plist
|
|
1343
|
+
|
|
1344
|
+
hooks: # List of plist property injection hooks
|
|
1345
|
+
- type: INFO_PLIST_PROPERTY # Only hook type for Info.plist
|
|
1346
|
+
identifier:
|
|
1347
|
+
name: livetag # Human-readable hook name
|
|
1348
|
+
key: gh2m0b # Unique 6-char alphanumeric key
|
|
1349
|
+
content: "<key>live</key>\n<string>value</string>" # Raw plist XML to inject
|
|
1350
|
+
|
|
1351
|
+
parameters: # Template variables
|
|
1352
|
+
zini8l: # Parameter key
|
|
1353
|
+
parameter:
|
|
1354
|
+
identifier:
|
|
1355
|
+
name: fsdafd # Variable name — use {{fsdafd}} in hook content
|
|
1356
|
+
dataType:
|
|
1357
|
+
scalarType: String # Data type (String, Integer, etc.)
|
|
1358
|
+
value:
|
|
1359
|
+
inputValue:
|
|
1360
|
+
serializedValue: safdsaf # Literal value
|
|
1361
|
+
```
|
|
1362
|
+
|
|
1363
|
+
**Key fields:**
|
|
1364
|
+
|
|
1365
|
+
| Field | Type | Notes |
|
|
1366
|
+
|---|---|---|
|
|
1367
|
+
| `type` | string | Always `INFO_PLIST` for this file. |
|
|
1368
|
+
| `identifier.name` | string | Always `Info.plist`. |
|
|
1369
|
+
| `hooks` | list | List of plist property injection hooks. Each hook injects a key-value pair into the root `<dict>`. |
|
|
1370
|
+
| `hooks[].type` | enum | Always `INFO_PLIST_PROPERTY`. |
|
|
1371
|
+
| `hooks[].identifier.name` | string | Human-readable hook name. |
|
|
1372
|
+
| `hooks[].identifier.key` | string | Unique 6-char alphanumeric key. |
|
|
1373
|
+
| `hooks[].content` | string | Raw plist XML to inject. Typically `<key>name</key>\n<string>value</string>` or similar plist entries. Must be properly escaped in YAML. |
|
|
1374
|
+
| `parameters` | map | Map of parameter key to parameter definition. |
|
|
1375
|
+
| `parameters.<key>.parameter.identifier.name` | string | Variable name. Referenced in hook `content` as `{{variableName}}`. |
|
|
1376
|
+
| `parameters.<key>.parameter.dataType.scalarType` | enum | Data type (`String`, `Integer`, `Double`, `Boolean`, etc.). |
|
|
1377
|
+
| `parameters.<key>.value` | object | Value source — either `inputValue.serializedValue` (literal) or `variable` (environment reference). |
|
|
1378
|
+
|
|
1379
|
+
### Parameter value sources
|
|
1380
|
+
|
|
1381
|
+
Parameters support two value sources:
|
|
1382
|
+
|
|
1383
|
+
**Literal value:**
|
|
1384
|
+
```yaml
|
|
1385
|
+
value:
|
|
1386
|
+
inputValue:
|
|
1387
|
+
serializedValue: my-value # Hardcoded value
|
|
1388
|
+
```
|
|
1389
|
+
|
|
1390
|
+
**Environment variable reference:**
|
|
1391
|
+
```yaml
|
|
1392
|
+
value:
|
|
1393
|
+
variable:
|
|
1394
|
+
source: DEV_ENVIRONMENT
|
|
1395
|
+
baseVariable:
|
|
1396
|
+
environmentValue:
|
|
1397
|
+
identifier:
|
|
1398
|
+
name: myEnvVar # References environment-settings.yaml
|
|
1399
|
+
key: eji5p6
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
### Hook content examples
|
|
1403
|
+
|
|
1404
|
+
**Simple string property:**
|
|
1405
|
+
```yaml
|
|
1406
|
+
content: "<key>MyCustomKey</key>\n<string>MyCustomValue</string>"
|
|
1407
|
+
```
|
|
1408
|
+
|
|
1409
|
+
**Boolean property:**
|
|
1410
|
+
```yaml
|
|
1411
|
+
content: "<key>MyFeatureFlag</key>\n<true/>"
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
**Array property:**
|
|
1415
|
+
```yaml
|
|
1416
|
+
content: "<key>LSApplicationQueriesSchemes</key>\n<array>\n <string>myapp</string>\n <string>myapp-dev</string>\n</array>"
|
|
1417
|
+
```
|
|
1418
|
+
|
|
1419
|
+
**API capabilities:**
|
|
1420
|
+
|
|
1421
|
+
| Operation | Status | Notes |
|
|
1422
|
+
|---|---|---|
|
|
1423
|
+
| Reading config | Works | Full hook and parameter data returned. |
|
|
1424
|
+
| Adding hooks via API | Expected to work | Same structure as ANDROID_MANIFEST hooks. |
|
|
1425
|
+
| Adding parameters via API | Expected to work | Same structure as other custom file parameters. |
|
|
1426
|
+
| Hook name validation gap | Caution | Same as ANDROID_MANIFEST — avoid hyphens in names, use camelCase or spaces. |
|
|
1427
|
+
|
|
1428
|
+
### Code sub-file (`custom-file/id-INFO_PLIST/custom-file-code.dart`)
|
|
1429
|
+
|
|
1430
|
+
Contains the full generated `Info.plist` XML. This is the complete plist including all standard iOS keys (bundle identifiers, permissions, URL schemes, etc.) plus any injected hook content. It is **read-only** — modifications should be made through the hooks/parameters config, not by editing the XML directly.
|
|
1431
|
+
|
|
1432
|
+
---
|
|
1433
|
+
|
|
1434
|
+
## custom-file/id-ENTITLEMENTS
|
|
1435
|
+
|
|
1436
|
+
**Purpose:** Allows injecting custom entitlements into the generated `Runner.entitlements` file for iOS builds. Entitlements declare app capabilities such as push notifications, App Groups, iCloud, associated domains, and other iOS-specific permissions.
|
|
1437
|
+
|
|
1438
|
+
> **This file only exists when it has content.** If all hooks and parameters are removed (via UI or API), the file disappears from the server (API returns 404). It reappears when a user adds an entitlement or parameter in the FF editor.
|
|
1439
|
+
|
|
1440
|
+
> **WARNING: Pushing any `custom-file` deletes siblings.** The API treats all `custom-file/id-*` keys as a single collection. Pushing this file alone will delete all other custom files (MAIN, ANDROID_MANIFEST, INFO_PLIST, etc.). **Always include all existing `custom-file` entries in the same push payload.** See [API Limitation #10](../flutterflow-api-limitations.md#10-pushing-one-custom-file-deletes-all-other-custom-file-entries).
|
|
1441
|
+
|
|
1442
|
+
> **Important — this is an abstraction layer.**
|
|
1443
|
+
> This config controls **entitlement injection into the generated `Runner.entitlements`** at build time. The file only appears after a user adds at least one entitlement in the FF editor (Settings > Custom Code > Custom Files > Runner.entitlements).
|
|
1444
|
+
|
|
1445
|
+
**Top-level keys:**
|
|
1446
|
+
- `type`
|
|
1447
|
+
- `identifier`
|
|
1448
|
+
- `hooks`
|
|
1449
|
+
- `parameters`
|
|
1450
|
+
|
|
1451
|
+
### Hook Types
|
|
1452
|
+
|
|
1453
|
+
Only one hook type:
|
|
1454
|
+
|
|
1455
|
+
| Hook Type | Where it injects in Runner.entitlements |
|
|
1456
|
+
|---|---|
|
|
1457
|
+
| `ENTITLEMENT` | Inside the root `<dict>` of the entitlements plist — use for adding capability key-value pairs |
|
|
1458
|
+
|
|
1459
|
+
### Schema
|
|
1460
|
+
|
|
1461
|
+
```yaml
|
|
1462
|
+
type: ENTITLEMENTS
|
|
1463
|
+
identifier:
|
|
1464
|
+
name: Runner.entitlements
|
|
1465
|
+
|
|
1466
|
+
hooks:
|
|
1467
|
+
- type: ENTITLEMENT # Only hook type for entitlements
|
|
1468
|
+
identifier:
|
|
1469
|
+
name: environemnt # Human-readable hook name
|
|
1470
|
+
key: 5x527x # Unique 6-char alphanumeric key
|
|
1471
|
+
content: "<key>aps-environment</key>\n<string>development</string>" # Plist XML to inject
|
|
1472
|
+
|
|
1473
|
+
parameters: # Template variables — same as all other custom files
|
|
1474
|
+
f4cahu:
|
|
1475
|
+
parameter:
|
|
1476
|
+
identifier:
|
|
1477
|
+
name: variable1 # Variable name — use {{variable1}} in hook content
|
|
1478
|
+
dataType:
|
|
1479
|
+
scalarType: String
|
|
1480
|
+
value:
|
|
1481
|
+
inputValue:
|
|
1482
|
+
serializedValue: clear value # Default value
|
|
1483
|
+
```
|
|
1484
|
+
|
|
1485
|
+
**Key fields:**
|
|
1486
|
+
|
|
1487
|
+
| Field | Type | Notes |
|
|
1488
|
+
|---|---|---|
|
|
1489
|
+
| `type` | string | Always `ENTITLEMENTS` for this file. |
|
|
1490
|
+
| `identifier.name` | string | Always `Runner.entitlements`. |
|
|
1491
|
+
| `hooks` | list | List of entitlement injection hooks. Each hook injects a capability key-value pair into the entitlements plist. |
|
|
1492
|
+
| `hooks[].type` | enum | Always `ENTITLEMENT`. |
|
|
1493
|
+
| `hooks[].identifier.name` | string | Human-readable name for the entitlement. |
|
|
1494
|
+
| `hooks[].identifier.key` | string | Unique 6-char alphanumeric key. |
|
|
1495
|
+
| `hooks[].content` | string | Raw plist XML to inject. Typically `<key>capability-name</key>` followed by a value (`<string>`, `<true/>`, `<array>`, etc.). Must be properly escaped in YAML. |
|
|
1496
|
+
| `parameters` | map | Template variables keyed by parameter ID. Use `{{variableName}}` in `content` to reference them. Same structure as all other custom files. |
|
|
1497
|
+
|
|
1498
|
+
### Common entitlement content examples
|
|
1499
|
+
|
|
1500
|
+
**Push notifications (development):**
|
|
1501
|
+
```yaml
|
|
1502
|
+
content: "<key>aps-environment</key>\n<string>development</string>"
|
|
1503
|
+
```
|
|
1504
|
+
|
|
1505
|
+
**Push notifications (production):**
|
|
1506
|
+
```yaml
|
|
1507
|
+
content: "<key>aps-environment</key>\n<string>production</string>"
|
|
1508
|
+
```
|
|
1509
|
+
|
|
1510
|
+
**Associated domains (for universal links):**
|
|
1511
|
+
```yaml
|
|
1512
|
+
content: "<key>com.apple.developer.associated-domains</key>\n<array>\n <string>applinks:example.com</string>\n</array>"
|
|
1513
|
+
```
|
|
1514
|
+
|
|
1515
|
+
**App Groups:**
|
|
1516
|
+
```yaml
|
|
1517
|
+
content: "<key>com.apple.security.application-groups</key>\n<array>\n <string>group.com.example.myapp</string>\n</array>"
|
|
1518
|
+
```
|
|
1519
|
+
|
|
1520
|
+
### API capabilities
|
|
1521
|
+
|
|
1522
|
+
| Operation | Status | Notes |
|
|
1523
|
+
|---|---|---|
|
|
1524
|
+
| Reading config | Works | Full hook and parameter data returned. |
|
|
1525
|
+
| Adding hooks via API | Expected to work | Same structure as other custom file hooks. |
|
|
1526
|
+
| Adding parameters via API | Expected to work | Same structure as other custom file parameters. |
|
|
1527
|
+
| Hook name validation gap | Caution | Same as other custom files — avoid hyphens in names, use camelCase or spaces. |
|
|
1528
|
+
|
|
1529
|
+
---
|
|
1530
|
+
|
|
1531
|
+
## custom-file/id-APP_DELEGATE
|
|
1532
|
+
|
|
1533
|
+
**Purpose:** Allows injecting custom Swift code into the generated `AppDelegate.swift` for iOS builds. Supports import statements and initialization code that runs during the iOS app launch sequence.
|
|
1534
|
+
|
|
1535
|
+
> **This file only exists when it has content.** If all hooks and parameters are removed (via UI or API), the file disappears from the server (API returns 404). It reappears when a user adds a hook or parameter in the FF editor.
|
|
1536
|
+
|
|
1537
|
+
> **WARNING: Pushing any `custom-file` deletes siblings.** The API treats all `custom-file/id-*` keys as a single collection. Pushing this file alone will delete all other custom files (MAIN, ANDROID_MANIFEST, INFO_PLIST, etc.). **Always include all existing `custom-file` entries in the same push payload.** See [API Limitation #10](../flutterflow-api-limitations.md#10-pushing-one-custom-file-deletes-all-other-custom-file-entries).
|
|
1538
|
+
|
|
1539
|
+
> **Important — this is an abstraction layer.**
|
|
1540
|
+
> This config controls **Swift code injection into the generated `AppDelegate.swift`** at build time. The file only appears after a user adds at least one hook in the FF editor (Settings > Custom Code > Custom Files > AppDelegate.swift).
|
|
1541
|
+
|
|
1542
|
+
**Top-level keys:**
|
|
1543
|
+
- `type`
|
|
1544
|
+
- `identifier`
|
|
1545
|
+
- `hooks`
|
|
1546
|
+
- `parameters`
|
|
1547
|
+
|
|
1548
|
+
### Hook Types
|
|
1549
|
+
|
|
1550
|
+
Two hook types control where Swift code is injected in the generated `AppDelegate.swift`:
|
|
1551
|
+
|
|
1552
|
+
| Hook Type | Where it injects in AppDelegate.swift |
|
|
1553
|
+
|---|---|
|
|
1554
|
+
| `APP_DELEGATE_IMPORT_HOOK` | At the top of the file — use for `import` statements |
|
|
1555
|
+
| `APP_DELEGATE_INITIALIZATION_HOOK` | Inside `application(_:didFinishLaunchingWithOptions:)` — use for SDK init calls and setup code |
|
|
1556
|
+
|
|
1557
|
+
### Schema
|
|
1558
|
+
|
|
1559
|
+
```yaml
|
|
1560
|
+
type: APP_DELEGATE
|
|
1561
|
+
identifier:
|
|
1562
|
+
name: AppDelegate.swift
|
|
1563
|
+
|
|
1564
|
+
hooks:
|
|
1565
|
+
- type: APP_DELEGATE_IMPORT_HOOK # Injects at the top of the file (imports)
|
|
1566
|
+
identifier:
|
|
1567
|
+
name: UIkitimprot # Human-readable hook name
|
|
1568
|
+
key: rtmoen # Unique 6-char alphanumeric key
|
|
1569
|
+
content: import UIKit # Swift import statement
|
|
1570
|
+
|
|
1571
|
+
- type: APP_DELEGATE_INITIALIZATION_HOOK # Injects inside didFinishLaunchingWithOptions
|
|
1572
|
+
identifier:
|
|
1573
|
+
name: logsinit # Human-readable hook name
|
|
1574
|
+
key: 2b582i # Unique 6-char alphanumeric key
|
|
1575
|
+
content: Logs.init() # Swift initialization code
|
|
1576
|
+
|
|
1577
|
+
parameters: # Template variables — same as all other custom files
|
|
1578
|
+
74q7xg:
|
|
1579
|
+
parameter:
|
|
1580
|
+
identifier:
|
|
1581
|
+
name: vars1 # Variable name — use {{vars1}} in hook content
|
|
1582
|
+
dataType:
|
|
1583
|
+
scalarType: String
|
|
1584
|
+
value:
|
|
1585
|
+
inputValue:
|
|
1586
|
+
serializedValue: var val # Default value
|
|
1587
|
+
```
|
|
1588
|
+
|
|
1589
|
+
**Key fields:**
|
|
1590
|
+
|
|
1591
|
+
| Field | Type | Notes |
|
|
1592
|
+
|---|---|---|
|
|
1593
|
+
| `type` | string | Always `APP_DELEGATE` for this file. |
|
|
1594
|
+
| `identifier.name` | string | Always `AppDelegate.swift`. |
|
|
1595
|
+
| `hooks` | list | List of Swift code injection hooks. |
|
|
1596
|
+
| `hooks[].type` | enum | `APP_DELEGATE_IMPORT_HOOK` (imports) or `APP_DELEGATE_INITIALIZATION_HOOK` (init code). |
|
|
1597
|
+
| `hooks[].identifier.name` | string | Human-readable name for the hook. |
|
|
1598
|
+
| `hooks[].identifier.key` | string | Unique 6-char alphanumeric key. |
|
|
1599
|
+
| `hooks[].content` | string | Raw Swift code to inject. For imports: a single `import` statement. For initialization: Swift code that runs during app launch. |
|
|
1600
|
+
| `parameters` | map | Template variables keyed by parameter ID. Use `{{variableName}}` in `content` to reference them. Same structure as all other custom files. |
|
|
1601
|
+
|
|
1602
|
+
### Generated AppDelegate execution order
|
|
1603
|
+
|
|
1604
|
+
The generated `AppDelegate.swift` follows this structure:
|
|
1605
|
+
|
|
1606
|
+
```
|
|
1607
|
+
1. import Flutter ← Standard Flutter import
|
|
1608
|
+
2. import UIKit ← APP_DELEGATE_IMPORT_HOOK entries
|
|
1609
|
+
3. import MySDK ← APP_DELEGATE_IMPORT_HOOK entries
|
|
1610
|
+
4.
|
|
1611
|
+
5. @UIApplicationMain
|
|
1612
|
+
6. class AppDelegate: FlutterAppDelegate {
|
|
1613
|
+
7. override func application(...) -> Bool {
|
|
1614
|
+
8. GeneratedPluginRegistrant.register(with: self)
|
|
1615
|
+
9. Logs.init() ← APP_DELEGATE_INITIALIZATION_HOOK entries
|
|
1616
|
+
10. MySDK.configure() ← APP_DELEGATE_INITIALIZATION_HOOK entries
|
|
1617
|
+
11. return super.application(...)
|
|
1618
|
+
12. }
|
|
1619
|
+
13. }
|
|
1620
|
+
```
|
|
1621
|
+
|
|
1622
|
+
- **Import hooks** are placed at the top of the file alongside the standard Flutter/UIKit imports.
|
|
1623
|
+
- **Initialization hooks** are placed inside `application(_:didFinishLaunchingWithOptions:)` after plugin registration but before the `return` statement.
|
|
1624
|
+
|
|
1625
|
+
### Common hook content examples
|
|
1626
|
+
|
|
1627
|
+
**Import a framework:**
|
|
1628
|
+
```yaml
|
|
1629
|
+
- type: APP_DELEGATE_IMPORT_HOOK
|
|
1630
|
+
identifier:
|
|
1631
|
+
name: firebaseImport
|
|
1632
|
+
key: abc123
|
|
1633
|
+
content: import Firebase
|
|
1634
|
+
```
|
|
1635
|
+
|
|
1636
|
+
**Initialize an SDK:**
|
|
1637
|
+
```yaml
|
|
1638
|
+
- type: APP_DELEGATE_INITIALIZATION_HOOK
|
|
1639
|
+
identifier:
|
|
1640
|
+
name: firebaseInit
|
|
1641
|
+
key: def456
|
|
1642
|
+
content: FirebaseApp.configure()
|
|
1643
|
+
```
|
|
1644
|
+
|
|
1645
|
+
**Multi-line initialization:**
|
|
1646
|
+
```yaml
|
|
1647
|
+
- type: APP_DELEGATE_INITIALIZATION_HOOK
|
|
1648
|
+
identifier:
|
|
1649
|
+
name: oneSignalSetup
|
|
1650
|
+
key: ghi789
|
|
1651
|
+
content: "OneSignal.initialize(\"{{appId}}\")\nOneSignal.Notifications.requestPermission({ accepted in })"
|
|
1652
|
+
```
|
|
1653
|
+
|
|
1654
|
+
### API capabilities
|
|
1655
|
+
|
|
1656
|
+
| Operation | Status | Notes |
|
|
1657
|
+
|---|---|---|
|
|
1658
|
+
| Reading config | Works | Full hook and parameter data returned. |
|
|
1659
|
+
| Adding hooks via API | Expected to work | Same structure as other custom file hooks. |
|
|
1660
|
+
| Adding parameters via API | Expected to work | Same structure as other custom file parameters. |
|
|
1661
|
+
| Hook name validation gap | Caution | Same as other custom files — avoid hyphens in names, use camelCase or spaces. |
|
|
1662
|
+
|
|
1663
|
+
---
|
|
1664
|
+
|
|
1245
1665
|
## custom-file/id-PROGUARD
|
|
1246
1666
|
|
|
1247
1667
|
**Purpose:** Allows injecting custom ProGuard rules into the generated `proguard-rules.pro` file for Android builds. Controls code shrinking, obfuscation, and optimization rules.
|
|
@@ -335,6 +335,26 @@ widgetProperty:
|
|
|
335
335
|
inputValue: 460
|
|
336
336
|
```
|
|
337
337
|
|
|
338
|
+
**Translatable text (i18n):**
|
|
339
|
+
|
|
340
|
+
Use `translatableText` inside `inputValue` to pass a string that should be translated at runtime based on the app's current locale. This is the correct way to make component parameter text translatable.
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
paramIdentifier:
|
|
344
|
+
name: title
|
|
345
|
+
key: p1titl
|
|
346
|
+
inputValue:
|
|
347
|
+
translatableText:
|
|
348
|
+
translationIdentifier:
|
|
349
|
+
key: ms01ttl1 # References languages/translation/id-ms01ttl1
|
|
350
|
+
textValue:
|
|
351
|
+
inputValue: Histamine / Low DAO # English default / editor preview
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
Each `translationIdentifier.key` must have a corresponding `languages/translation/id-<key>` file with translations for all supported languages (see `01-project-files.md` for the translation file schema).
|
|
355
|
+
|
|
356
|
+
> **Note:** `translationIdentifier` is NOT valid as a direct sibling of `paramIdentifier` on a parameterPass — it must be nested inside `inputValue.translatableText`. Placing it at the wrong level causes a validation error.
|
|
357
|
+
|
|
338
358
|
---
|
|
339
359
|
|
|
340
360
|
## 7. isDummyRoot
|
|
@@ -831,4 +831,19 @@ inputValue:
|
|
|
831
831
|
value: "4294967295" # ARGB integer as string
|
|
832
832
|
```
|
|
833
833
|
|
|
834
|
+
**Translatable text (i18n):**
|
|
835
|
+
|
|
836
|
+
Used when passing a string that should be translated at runtime based on the app's locale. Wraps `translationIdentifier` and `textValue` inside `inputValue.translatableText`. Commonly used in component parameter passes to make per-instance text translatable.
|
|
837
|
+
|
|
838
|
+
```yaml
|
|
839
|
+
inputValue:
|
|
840
|
+
translatableText:
|
|
841
|
+
translationIdentifier:
|
|
842
|
+
key: ms01ttl1 # References languages/translation/id-ms01ttl1
|
|
843
|
+
textValue:
|
|
844
|
+
inputValue: Histamine / Low DAO # English default
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
Each key must have a corresponding translation file at `languages/translation/id-<key>` with entries for all supported languages. See `01-project-files.md` for the translation file schema.
|
|
848
|
+
|
|
834
849
|
The `mostRecentInputValue` field must always stay in sync with `inputValue` when both are present.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Custom Code
|
|
2
2
|
|
|
3
|
-
FlutterFlow supports four types of custom code: **Custom Actions** (async Dart functions with side effects), **Custom Functions** (pure synchronous Dart functions), **Custom Widgets** (Flutter widgets with parameters), and **AI Agents** (LLM-powered processing pipelines). Additionally, **App Action Components** provide reusable action chains that can be invoked from any page, and **Custom Files** allow overriding special project-level files like `main.dart` and `
|
|
3
|
+
FlutterFlow supports four types of custom code: **Custom Actions** (async Dart functions with side effects), **Custom Functions** (pure synchronous Dart functions), **Custom Widgets** (Flutter widgets with parameters), and **AI Agents** (LLM-powered processing pipelines). Additionally, **App Action Components** provide reusable action chains that can be invoked from any page, and **Custom Files** allow overriding special project-level files like `main.dart`, `AndroidManifest.xml`, `Info.plist`, `proguard-rules.pro`, and `build.gradle`.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -706,76 +706,21 @@ variable:
|
|
|
706
706
|
|
|
707
707
|
## Custom Files
|
|
708
708
|
|
|
709
|
-
Custom Files are special project-level files
|
|
709
|
+
Custom Files are special project-level files that override platform-specific configuration (e.g., `main.dart`, `AndroidManifest.xml`, `Info.plist`, `proguard-rules.pro`, `build.gradle`). Each has a metadata YAML file and a companion code file under `custom-file/`.
|
|
710
710
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
```
|
|
714
|
-
custom-file/
|
|
715
|
-
id-MAIN.yaml # Metadata for main.dart
|
|
716
|
-
id-MAIN/custom-file-code.dart.yaml # main.dart Dart code
|
|
717
|
-
id-ANDROID_MANIFEST.yaml # Metadata for AndroidManifest.xml
|
|
718
|
-
id-ANDROID_MANIFEST/custom-file-code.dart.yaml # AndroidManifest.xml content
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
### MAIN metadata (id-MAIN.yaml)
|
|
722
|
-
|
|
723
|
-
```yaml
|
|
724
|
-
type: MAIN
|
|
725
|
-
isUnlocked: false
|
|
726
|
-
actions:
|
|
727
|
-
- type: FINAL_ACTION
|
|
728
|
-
identifier:
|
|
729
|
-
name: initializeUlink
|
|
730
|
-
key: t6snt
|
|
731
|
-
projectId: ulink-21sajt
|
|
732
|
-
description: ""
|
|
733
|
-
```
|
|
734
|
-
|
|
735
|
-
### ANDROID_MANIFEST metadata (id-ANDROID_MANIFEST.yaml)
|
|
736
|
-
|
|
737
|
-
```yaml
|
|
738
|
-
type: ANDROID_MANIFEST
|
|
739
|
-
identifier:
|
|
740
|
-
name: AndroidManifest.xml
|
|
741
|
-
isUnlocked: true
|
|
742
|
-
parameters:
|
|
743
|
-
29c3b7b9-afe7-4429-9d20-abb2e09f7a40:
|
|
744
|
-
parameter:
|
|
745
|
-
identifier:
|
|
746
|
-
name: ulinkDomain
|
|
747
|
-
dataType:
|
|
748
|
-
scalarType: String
|
|
749
|
-
value:
|
|
750
|
-
variable:
|
|
751
|
-
source: DEV_ENVIRONMENT
|
|
752
|
-
baseVariable:
|
|
753
|
-
environmentValue:
|
|
754
|
-
identifier:
|
|
755
|
-
name: ulinkDomain
|
|
756
|
-
key: eji5p6
|
|
757
|
-
description: ""
|
|
758
|
-
```
|
|
759
|
-
|
|
760
|
-
### Definition fields
|
|
761
|
-
|
|
762
|
-
| Field | Required | Description |
|
|
763
|
-
|-------|----------|-------------|
|
|
764
|
-
| `type` | Yes | File type: `MAIN` or `ANDROID_MANIFEST` |
|
|
765
|
-
| `identifier` | For ANDROID_MANIFEST | `name` of the file |
|
|
766
|
-
| `isUnlocked` | No | Whether the file is editable (default: false) |
|
|
767
|
-
| `actions` | No | List of final actions (library initializers) that run at startup |
|
|
768
|
-
| `parameters` | No | Template parameter substitutions for the code file |
|
|
769
|
-
| `description` | No | Human-readable description |
|
|
770
|
-
|
|
771
|
-
### Code files
|
|
772
|
-
|
|
773
|
-
- **MAIN:** `custom-file/id-MAIN/custom-file-code.dart.yaml` contains the full `main.dart` with imports, `main()` function, Firebase/Supabase initialization, and library init calls.
|
|
774
|
-
- **ANDROID_MANIFEST:** `custom-file/id-ANDROID_MANIFEST/custom-file-code.dart.yaml` contains the XML manifest with template placeholders (e.g., `{{unlinkDomain}}`, `{{ulink-21sajt.ulinkSchema}}`). Parameters in metadata map to these placeholders.
|
|
711
|
+
> **Full documentation:** Custom Files are documented in detail in [01-project-files.md](01-project-files.md) under the `custom-file/id-*` sections, since they are project-level configuration files. See those sections for complete schemas, hook types, parameters, API capabilities, and warnings.
|
|
775
712
|
|
|
776
|
-
###
|
|
713
|
+
### Quick reference
|
|
777
714
|
|
|
778
|
-
|
|
715
|
+
| Type | File key | Description |
|
|
716
|
+
|------|----------|-------------|
|
|
717
|
+
| `MAIN` | `custom-file/id-MAIN` | App entry point (`main.dart`) — lifecycle actions (INITIAL/FINAL) |
|
|
718
|
+
| `ANDROID_MANIFEST` | `custom-file/id-ANDROID_MANIFEST` | Android manifest — XML injection hooks, template parameters |
|
|
719
|
+
| `INFO_PLIST` | `custom-file/id-INFO_PLIST` | iOS Info.plist — property injection hooks, template parameters |
|
|
720
|
+
| `ENTITLEMENTS` | `custom-file/id-ENTITLEMENTS` | iOS Runner.entitlements — capability entitlement injection |
|
|
721
|
+
| `APP_DELEGATE` | `custom-file/id-APP_DELEGATE` | iOS AppDelegate.swift — import and initialization code injection |
|
|
722
|
+
| `PROGUARD` | `custom-file/id-PROGUARD` | ProGuard rules — rule injection hooks |
|
|
723
|
+
| `BUILD_GRADLE` | `custom-file/id-BUILD_GRADLE` | Gradle config — plugin/dependency/repository injection hooks |
|
|
779
724
|
|
|
780
725
|
---
|
|
781
726
|
|
|
@@ -788,4 +733,4 @@ Parameters in ANDROID_MANIFEST metadata define template variables. Each key is a
|
|
|
788
733
|
| Custom Widget | `custom-widgets/id-<key>.yaml` | (code embedded or separate) | `custom-widgets/` |
|
|
789
734
|
| AI Agent | `agent/id-<key>.yaml` | N/A (no code file) | `agent/` |
|
|
790
735
|
| App Action Component | `app-action-components/id-<key>.yaml` | N/A (actions are inline) | `app-action-components/` |
|
|
791
|
-
| Custom File | `custom-file/id-<TYPE
|
|
736
|
+
| Custom File | `custom-file/id-<TYPE>` | `custom-file/id-<TYPE>/custom-file-code.dart` | `custom-file/` |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flutterflow-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "MCP server for the FlutterFlow Project API — AI-assisted FlutterFlow development through Claude and other MCP-compatible clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/index.js",
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flutterflow-mcp
|
|
3
|
+
description: >
|
|
4
|
+
Teaches AI assistants how to develop FlutterFlow apps using MCP tools.
|
|
5
|
+
Use this skill when working with FlutterFlow projects, editing FF YAML,
|
|
6
|
+
creating or inspecting pages and components, reading project configuration,
|
|
7
|
+
or navigating FlutterFlow widget trees. It covers all 25 MCP tools for
|
|
8
|
+
discovery, reading, editing, and settings. Triggers on: FlutterFlow,
|
|
9
|
+
FF YAML, FF page, FF component, FF widget, FF theme, FF project.
|
|
10
|
+
license: MIT
|
|
11
|
+
compatibility: Requires the flutterflow-mcp MCP server to be connected and a valid FLUTTERFLOW_API_TOKEN environment variable.
|
|
12
|
+
metadata:
|
|
13
|
+
author: mohn93
|
|
14
|
+
version: "1.0"
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
This skill requires the **flutterflow-mcp** MCP server to be installed and connected. Before proceeding, check if the `list_projects` tool is available. If not, the user needs to set up the MCP server first:
|
|
20
|
+
|
|
21
|
+
1. Get a FlutterFlow API token from **FlutterFlow > Profile > Account Settings > API Token** (requires a paid FlutterFlow subscription)
|
|
22
|
+
2. Add the MCP server to your AI client:
|
|
23
|
+
```bash
|
|
24
|
+
# Claude Code
|
|
25
|
+
claude mcp add flutterflow -e FLUTTERFLOW_API_TOKEN=<token> -- npx -y flutterflow-mcp
|
|
26
|
+
|
|
27
|
+
# Other clients (Claude Desktop, Cursor, Windsurf) — add to MCP config:
|
|
28
|
+
# { "command": "npx", "args": ["-y", "flutterflow-mcp"], "env": { "FLUTTERFLOW_API_TOKEN": "<token>" } }
|
|
29
|
+
```
|
|
30
|
+
3. Restart your AI client, then verify by calling `list_projects`
|
|
31
|
+
|
|
32
|
+
## Overview
|
|
33
|
+
|
|
34
|
+
The FlutterFlow MCP provides 25 tools for reading, inspecting, and editing FlutterFlow projects through YAML. It connects AI assistants to the FlutterFlow Project API, enabling programmatic access to pages, components, themes, actions, data models, and settings. All project data is represented as YAML files that can be fetched, cached locally, validated, and pushed back.
|
|
35
|
+
|
|
36
|
+
## Tool Catalog
|
|
37
|
+
|
|
38
|
+
### Discovery & Exploration
|
|
39
|
+
|
|
40
|
+
| Tool | Purpose |
|
|
41
|
+
|------|---------|
|
|
42
|
+
| `list_projects` | List all FF projects accessible to your API token |
|
|
43
|
+
| `list_project_files` | List YAML file keys in a project (supports prefix filter) |
|
|
44
|
+
| `list_pages` | List pages with human-readable names, scaffold IDs, and folders |
|
|
45
|
+
| `search_project_files` | Search file keys by keyword, prefix, or regex |
|
|
46
|
+
| `sync_project` | Download all project YAML to local cache for fast reads |
|
|
47
|
+
|
|
48
|
+
### Reading & Understanding
|
|
49
|
+
|
|
50
|
+
| Tool | Purpose |
|
|
51
|
+
|------|---------|
|
|
52
|
+
| `get_page_by_name` | Fetch full page YAML by human-readable name |
|
|
53
|
+
| `get_project_yaml` | Fetch specific YAML file(s) by file key |
|
|
54
|
+
| `get_page_summary` | Quick page overview: widget tree, actions, params (cache-based) |
|
|
55
|
+
| `get_component_summary` | Quick component overview: widget tree, params (cache-based) |
|
|
56
|
+
| `find_component_usages` | Find all pages/components that use a given component |
|
|
57
|
+
| `find_page_navigations` | Find all actions that navigate to a given page |
|
|
58
|
+
|
|
59
|
+
### Configuration & Settings
|
|
60
|
+
|
|
61
|
+
| Tool | Purpose |
|
|
62
|
+
|------|---------|
|
|
63
|
+
| `get_theme` | Theme colors, typography, breakpoints, widget defaults |
|
|
64
|
+
| `get_app_state` | App state variables, constants, environment settings |
|
|
65
|
+
| `get_api_endpoints` | API endpoint definitions (method, URL, headers, response) |
|
|
66
|
+
| `get_data_models` | Data structs, enums, Firestore collections, Supabase tables |
|
|
67
|
+
| `get_custom_code` | Custom actions, functions, widgets, AI agents (read-only) |
|
|
68
|
+
| `get_general_settings` | App Details, App Assets, Nav Bar & App Bar |
|
|
69
|
+
| `get_project_setup` | Firebase, Languages, Platforms, Permissions, Dependencies |
|
|
70
|
+
| `get_app_settings` | Authentication, Push Notifications, Deployment settings |
|
|
71
|
+
| `get_in_app_purchases` | Stripe, Braintree, RevenueCat, Razorpay config |
|
|
72
|
+
| `get_integrations` | Supabase, SQLite, GitHub, Algolia, Google Maps, AdMob, etc. |
|
|
73
|
+
|
|
74
|
+
### Editing & Documentation
|
|
75
|
+
|
|
76
|
+
| Tool | Purpose |
|
|
77
|
+
|------|---------|
|
|
78
|
+
| `get_editing_guide` | Get recommended workflow and docs for a specific editing task |
|
|
79
|
+
| `get_yaml_docs` | Search/retrieve YAML reference docs by topic or file path |
|
|
80
|
+
| `validate_yaml` | Validate YAML content before pushing changes |
|
|
81
|
+
| `update_project_yaml` | Push validated YAML changes to the FF project |
|
|
82
|
+
|
|
83
|
+
## Core Workflows
|
|
84
|
+
|
|
85
|
+
### Discover & Explore a Project
|
|
86
|
+
|
|
87
|
+
Use this workflow when first connecting to a FlutterFlow project or when you need to understand its structure.
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
1. list_projects → pick the target projectId
|
|
91
|
+
2. sync_project(projectId) → cache all YAML locally for fast reads
|
|
92
|
+
3. list_pages(projectId) → see all pages with human-readable names, scaffold IDs, folders
|
|
93
|
+
4. get_page_summary(projectId, pageName) → widget tree overview for any page of interest
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
After syncing, all cache-based tools (`get_page_summary`, `get_component_summary`, `get_theme`, `get_app_state`, etc.) work without additional API calls.
|
|
97
|
+
|
|
98
|
+
### Read / Inspect a Page or Component
|
|
99
|
+
|
|
100
|
+
Use this workflow to understand what a page contains, how it is structured, and how it connects to the rest of the app.
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
1. get_page_summary(projectId, pageName) → quick overview of widget tree, actions, params
|
|
104
|
+
2. get_page_by_name(projectId, pageName) → full YAML if you need complete details
|
|
105
|
+
3. find_page_navigations(projectId, pageName) → discover what actions navigate here
|
|
106
|
+
4. find_component_usages(projectId, componentName) → find everywhere a component is used
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For components, use `get_component_summary` instead of `get_page_summary`. Component summaries resolve nested component references so you can see the full hierarchy.
|
|
110
|
+
|
|
111
|
+
### Edit an Existing Widget
|
|
112
|
+
|
|
113
|
+
Use this workflow to modify a specific widget on a page without affecting the rest of the page.
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
1. get_page_by_name(projectId, pageName) → get the full page YAML
|
|
117
|
+
2. Identify the node file key for the target widget (format: page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_YYY)
|
|
118
|
+
3. get_project_yaml(projectId, fileName: "page/id-.../node/id-Widget_XXX") → fetch the individual node YAML
|
|
119
|
+
4. Modify the YAML — keep inputValue and mostRecentInputValue in sync
|
|
120
|
+
5. validate_yaml(projectId, fileKey, content) → check for errors before pushing
|
|
121
|
+
6. update_project_yaml(projectId, {fileKey: content}) → push changes
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Always edit at the node level. Editing the full page YAML for a single widget change risks overwriting unrelated content and is more error-prone.
|
|
125
|
+
|
|
126
|
+
### Add a New Widget to a Page
|
|
127
|
+
|
|
128
|
+
Use this workflow when you need to add new widgets to an existing page.
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
1. get_page_by_name(projectId, pageName) → understand the current widget tree structure
|
|
132
|
+
2. get_yaml_docs(topic: "WidgetType") → look up the YAML schema for the widget you want to add
|
|
133
|
+
3. Update the page-widget-tree-outline to include a reference to the new widget key
|
|
134
|
+
4. Create individual node files for each new widget (one file per widget)
|
|
135
|
+
5. validate_yaml → validate the tree outline first, then each node file
|
|
136
|
+
6. update_project_yaml → push tree outline + all node files together in one call
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Pushing the tree outline and node files in a single call is critical. The server strips inline widget children from the tree outline, so nodes must be separate files.
|
|
140
|
+
|
|
141
|
+
### Create a Reusable Component
|
|
142
|
+
|
|
143
|
+
Use this workflow to build a new component from scratch.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
1. get_yaml_docs(topic: "create component") → get the full walkthrough and required file structure
|
|
147
|
+
2. Design component parameters: name, dataType, isNullable for each param
|
|
148
|
+
3. Create these files: component metadata, widget-tree-outline, root node (with isDummyRoot: true), child nodes
|
|
149
|
+
4. validate_yaml → validate all files before pushing
|
|
150
|
+
5. update_project_yaml → push all component files in one call
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Remember: the root node of a component must have `isDummyRoot: true`. Callback triggers use `triggerType: CALLBACK` with a separate `parameterIdentifier` field. WidgetProperty params use `widgetProperty` in parameterPasses, not `inputValue`.
|
|
154
|
+
|
|
155
|
+
## Critical YAML Rules
|
|
156
|
+
|
|
157
|
+
1. **Sync inputValue and mostRecentInputValue** -- Both fields must always contain the same value when you set or update them. If you change one, change both. Exceptions: `fontWeightValue` and `fontSizeValue` only accept `inputValue` (they have no `mostRecentInputValue` field).
|
|
158
|
+
|
|
159
|
+
2. **Use node-level file keys for edits** -- Target `page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_YYY` for individual widget edits. Never edit the full page YAML (`page/id-Scaffold_XXX`) just to change a single widget. Full-page edits risk overwriting unrelated content and are harder to validate.
|
|
160
|
+
|
|
161
|
+
3. **Always validate before pushing** -- Call `validate_yaml` before every `update_project_yaml` call. Validation catches missing node files, unknown fields, invalid enum values, and structural problems. Skipping validation risks corrupting the project.
|
|
162
|
+
|
|
163
|
+
4. **Push tree outline and node files together** -- When adding new widgets, include the updated `page-widget-tree-outline` AND all individual node files in a single `update_project_yaml` call. Widget children embedded inline in the tree outline will be silently stripped by the FlutterFlow server.
|
|
164
|
+
|
|
165
|
+
5. **Column has no mainAxisSize field** -- To achieve shrink-to-content behavior (equivalent to `MainAxisSize.min` in Flutter), use `minSizeValue: { inputValue: true }` on the Column widget instead.
|
|
166
|
+
|
|
167
|
+
6. **AppBar templateType** -- Only `LARGE_HEADER` is a confirmed valid value. Do not use `STANDARD` as it may cause unexpected behavior. Control the AppBar height through the `toolbarHeight` property instead.
|
|
168
|
+
|
|
169
|
+
7. **Custom code is read-only** -- Custom actions, functions, widgets, and AI agents cannot be created or edited through the MCP API. Use `get_custom_code` to read their signatures and source code, but any modifications must be made directly in the FlutterFlow UI. Attempting to push custom code changes will silently corrupt or be ignored.
|
|
170
|
+
|
|
171
|
+
## Anti-Patterns
|
|
172
|
+
|
|
173
|
+
- **Don't use `list_project_files` to find pages** -- It returns raw file keys without human-readable names. Use `list_pages` instead, which gives you page names, scaffold IDs, and folder assignments.
|
|
174
|
+
|
|
175
|
+
- **Don't fetch pages one-by-one to browse a project** -- This is slow and wastes API calls. Use `sync_project` to cache everything locally first, then use `get_page_summary` for quick overviews of any page.
|
|
176
|
+
|
|
177
|
+
- **Don't edit full page YAML for a single widget change** -- Full-page edits can overwrite other widgets, actions, or parameters. Always use node-level file keys for targeted, safe edits.
|
|
178
|
+
|
|
179
|
+
- **Don't guess YAML field names or enum values** -- FlutterFlow YAML has specific field names and valid values that are not always intuitive. Use `get_yaml_docs(topic)` or `get_editing_guide(task)` to look up the correct schema before writing YAML.
|
|
180
|
+
|
|
181
|
+
- **Don't embed widget children inline in the tree outline** -- The FlutterFlow server silently strips inline children from the `page-widget-tree-outline` file. Always create separate node files for each widget.
|
|
182
|
+
|
|
183
|
+
- **Don't push custom code changes through the API** -- The API silently corrupts or ignores Dart code edits for custom actions, functions, and widgets. These must be edited in the FlutterFlow UI.
|
|
184
|
+
|
|
185
|
+
## Documentation Lookup
|
|
186
|
+
|
|
187
|
+
The MCP server ships with 21 built-in reference documents. Use these tools to look up schemas, patterns, and conventions **before** writing YAML:
|
|
188
|
+
|
|
189
|
+
| When you need... | Call |
|
|
190
|
+
|------------------|------|
|
|
191
|
+
| Widget schema (Button, Text, Container, etc.) | `get_yaml_docs(topic: "Button")` |
|
|
192
|
+
| Action chains, triggers, navigation | `get_yaml_docs(topic: "actions")` |
|
|
193
|
+
| Data binding, variable sources | `get_yaml_docs(topic: "variables")` |
|
|
194
|
+
| Colors, typography, dimensions | `get_yaml_docs(topic: "theming")` |
|
|
195
|
+
| Creating components from scratch | `get_yaml_docs(topic: "create component")` |
|
|
196
|
+
| Editing workflows and anti-patterns | `get_yaml_docs(topic: "editing")` |
|
|
197
|
+
| Data structs, enums, collections | `get_yaml_docs(topic: "data")` |
|
|
198
|
+
| Full docs index | `get_yaml_docs()` |
|
|
199
|
+
| Guided workflow for a specific task | `get_editing_guide(task: "change the button color")` |
|
|
200
|
+
|
|
201
|
+
Always consult the docs before writing YAML. They contain validated schemas, field references, enum values, and real examples.
|