flutterflow-mcp 0.1.0
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 +124 -0
- package/build/api/flutterflow.d.ts +11 -0
- package/build/api/flutterflow.js +61 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +54 -0
- package/build/prompts/dev-workflow.d.ts +2 -0
- package/build/prompts/dev-workflow.js +68 -0
- package/build/prompts/generate-page.d.ts +2 -0
- package/build/prompts/generate-page.js +36 -0
- package/build/prompts/inspect-project.d.ts +2 -0
- package/build/prompts/inspect-project.js +30 -0
- package/build/prompts/modify-component.d.ts +2 -0
- package/build/prompts/modify-component.js +39 -0
- package/build/resources/docs.d.ts +2 -0
- package/build/resources/docs.js +76 -0
- package/build/resources/projects.d.ts +3 -0
- package/build/resources/projects.js +60 -0
- package/build/tools/find-component-usages.d.ts +7 -0
- package/build/tools/find-component-usages.js +225 -0
- package/build/tools/find-page-navigations.d.ts +7 -0
- package/build/tools/find-page-navigations.js +228 -0
- package/build/tools/get-component-summary.d.ts +22 -0
- package/build/tools/get-component-summary.js +193 -0
- package/build/tools/get-page-by-name.d.ts +3 -0
- package/build/tools/get-page-by-name.js +56 -0
- package/build/tools/get-page-summary.d.ts +22 -0
- package/build/tools/get-page-summary.js +220 -0
- package/build/tools/get-yaml-docs.d.ts +6 -0
- package/build/tools/get-yaml-docs.js +217 -0
- package/build/tools/get-yaml.d.ts +3 -0
- package/build/tools/get-yaml.js +47 -0
- package/build/tools/list-files.d.ts +3 -0
- package/build/tools/list-files.js +30 -0
- package/build/tools/list-pages.d.ts +25 -0
- package/build/tools/list-pages.js +101 -0
- package/build/tools/list-projects.d.ts +3 -0
- package/build/tools/list-projects.js +19 -0
- package/build/tools/sync-project.d.ts +3 -0
- package/build/tools/sync-project.js +144 -0
- package/build/tools/update-yaml.d.ts +3 -0
- package/build/tools/update-yaml.js +24 -0
- package/build/tools/validate-yaml.d.ts +3 -0
- package/build/tools/validate-yaml.js +22 -0
- package/build/utils/cache.d.ts +48 -0
- package/build/utils/cache.js +162 -0
- package/build/utils/decode-yaml.d.ts +7 -0
- package/build/utils/decode-yaml.js +31 -0
- package/build/utils/page-summary/action-summarizer.d.ts +9 -0
- package/build/utils/page-summary/action-summarizer.js +291 -0
- package/build/utils/page-summary/formatter.d.ts +13 -0
- package/build/utils/page-summary/formatter.js +121 -0
- package/build/utils/page-summary/node-extractor.d.ts +17 -0
- package/build/utils/page-summary/node-extractor.js +207 -0
- package/build/utils/page-summary/tree-walker.d.ts +6 -0
- package/build/utils/page-summary/tree-walker.js +55 -0
- package/build/utils/page-summary/types.d.ts +56 -0
- package/build/utils/page-summary/types.js +4 -0
- package/build/utils/parse-folders.d.ts +9 -0
- package/build/utils/parse-folders.js +29 -0
- package/docs/ff-yaml/00-overview.md +137 -0
- package/docs/ff-yaml/01-project-files.md +513 -0
- package/docs/ff-yaml/02-pages.md +572 -0
- package/docs/ff-yaml/03-components.md +413 -0
- package/docs/ff-yaml/04-widgets/README.md +122 -0
- package/docs/ff-yaml/04-widgets/button.md +444 -0
- package/docs/ff-yaml/04-widgets/container.md +358 -0
- package/docs/ff-yaml/04-widgets/dropdown.md +579 -0
- package/docs/ff-yaml/04-widgets/form.md +256 -0
- package/docs/ff-yaml/04-widgets/image.md +276 -0
- package/docs/ff-yaml/04-widgets/layout.md +355 -0
- package/docs/ff-yaml/04-widgets/misc.md +553 -0
- package/docs/ff-yaml/04-widgets/text-field.md +326 -0
- package/docs/ff-yaml/04-widgets/text.md +302 -0
- package/docs/ff-yaml/05-actions.md +843 -0
- package/docs/ff-yaml/06-variables.md +834 -0
- package/docs/ff-yaml/07-data.md +591 -0
- package/docs/ff-yaml/08-custom-code.md +715 -0
- package/docs/ff-yaml/09-theming.md +592 -0
- package/docs/ff-yaml/10-editing-guide.md +454 -0
- package/docs/ff-yaml/README.md +105 -0
- package/package.json +55 -0
- package/skills/ff-widget-patterns.md +141 -0
- package/skills/ff-yaml-dev.md +58 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# 10 - Editing FlutterFlow via MCP API
|
|
2
|
+
|
|
3
|
+
How to use the MCP tools to read, inspect, modify, and push FlutterFlow YAML. This covers the complete workflow from syncing a project to pushing widget changes, including critical rules for adding new widgets.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Reading Workflow
|
|
8
|
+
|
|
9
|
+
### Step 1: Sync the project to local cache
|
|
10
|
+
|
|
11
|
+
Download all YAML files for fast offline reads. Run this once per project.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
sync_project(projectId)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This creates a local cache at `.ff-cache/<projectId>/` containing every YAML file in the project. To force a re-sync (e.g., after making changes in the FlutterFlow UI):
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
sync_project(projectId, force: true)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Step 2: Get quick summaries from cache
|
|
24
|
+
|
|
25
|
+
Use cache-based tools for fast overviews -- no API calls needed.
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
get_page_summary(projectId, pageName: "Welcome")
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Returns: widget tree structure, actions (with triggers), page parameters, page state variables, and disabled action indicators.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
get_component_summary(projectId, componentName: "PhoneSignInComponent")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Returns: component widget tree, parameters, and actions.
|
|
38
|
+
|
|
39
|
+
### Step 3: Find navigation flow and component usage
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
find_page_navigations(projectId, pageName: "PaywallPage")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Returns: all actions across the project that navigate to the specified page, including the source page, trigger type, disabled status, and any passed parameters.
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
find_component_usages(projectId, componentName: "MyComponent")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Returns: every page and component where `MyComponent` is embedded, with parameter pass details.
|
|
52
|
+
|
|
53
|
+
### Step 4: Fetch specific YAML for detailed reading
|
|
54
|
+
|
|
55
|
+
For full page YAML (name, widget tree, class model):
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
get_page_by_name(projectId, "Welcome")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For a specific file by key (node-level widget, config file, component):
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
get_project_yaml(projectId, "page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Button_YYY")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Reading tool selection guide
|
|
68
|
+
|
|
69
|
+
| Goal | Tool | API Calls? |
|
|
70
|
+
|------|------|------------|
|
|
71
|
+
| Quick page overview | `get_page_summary` | No (cache) |
|
|
72
|
+
| Quick component overview | `get_component_summary` | No (cache) |
|
|
73
|
+
| Find where a component is used | `find_component_usages` | No (cache) |
|
|
74
|
+
| Find navigation sources | `find_page_navigations` | No (cache) |
|
|
75
|
+
| Full page YAML by name | `get_page_by_name` | Yes |
|
|
76
|
+
| Specific node/config YAML | `get_project_yaml` | Yes |
|
|
77
|
+
| List all pages with names | `list_pages` | Yes |
|
|
78
|
+
| List all file keys | `list_project_files` | Yes |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 2. Editing Workflow
|
|
83
|
+
|
|
84
|
+
### The standard edit cycle
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Read --> Modify --> Validate --> Push
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Step 1: Read the current YAML
|
|
91
|
+
|
|
92
|
+
Fetch the **node-level** file for the widget you want to edit (not the full page):
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
get_project_yaml(projectId, "page/id-Scaffold_7o6kzmdm/page-widget-tree-outline/node/id-Button_7c3kwr61")
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
To find the widget key, first fetch the full page via `get_page_by_name`, locate the widget in the tree, and note its `key` field (e.g., `Button_7c3kwr61`).
|
|
99
|
+
|
|
100
|
+
### Step 2: Modify the YAML
|
|
101
|
+
|
|
102
|
+
Change the values you need. **Critical rule:** always update BOTH `inputValue` AND `mostRecentInputValue` to the same value.
|
|
103
|
+
|
|
104
|
+
```yaml
|
|
105
|
+
# CORRECT
|
|
106
|
+
textValue:
|
|
107
|
+
inputValue: New Label
|
|
108
|
+
mostRecentInputValue: New Label
|
|
109
|
+
|
|
110
|
+
# WRONG -- will cause sync issues in FlutterFlow
|
|
111
|
+
textValue:
|
|
112
|
+
inputValue: New Label
|
|
113
|
+
mostRecentInputValue: Old Label
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Step 3: Validate before pushing
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
validate_yaml(projectId, fileKey, modifiedYaml)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This returns `{ success: true }` or a list of validation errors. Always validate before pushing.
|
|
123
|
+
|
|
124
|
+
### Step 4: Push the changes
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
update_project_yaml(projectId, { fileKey: modifiedYaml })
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Returns `{ success: true }` on success.
|
|
131
|
+
|
|
132
|
+
### Complete edit example
|
|
133
|
+
|
|
134
|
+
**Task:** Change a button label from "Old Text" to "New Text" on the Welcome page.
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
Step 1: list_pages(projectId)
|
|
138
|
+
--> Find Welcome page: scaffoldId = Scaffold_7o6kzmdm
|
|
139
|
+
|
|
140
|
+
Step 2: get_page_by_name(projectId, "Welcome")
|
|
141
|
+
--> Read full page YAML, find the button widget
|
|
142
|
+
--> Button key: Button_7c3kwr61
|
|
143
|
+
|
|
144
|
+
Step 3: get_project_yaml(projectId,
|
|
145
|
+
"page/id-Scaffold_7o6kzmdm/page-widget-tree-outline/node/id-Button_7c3kwr61")
|
|
146
|
+
--> Get fresh node-level YAML for just the button
|
|
147
|
+
|
|
148
|
+
Step 4: Modify the YAML -- change textValue.inputValue AND mostRecentInputValue
|
|
149
|
+
|
|
150
|
+
Step 5: validate_yaml(projectId, fileKey, modifiedYaml)
|
|
151
|
+
--> Confirm { success: true }
|
|
152
|
+
|
|
153
|
+
Step 6: update_project_yaml(projectId, { fileKey: modifiedYaml })
|
|
154
|
+
--> Confirm { success: true }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 3. Adding Widgets (CRITICAL)
|
|
160
|
+
|
|
161
|
+
Adding new widgets to a page is the most error-prone operation. The full page YAML file (`page/id-Scaffold_XXX`) only stores page metadata -- the server **strips any inline children**. You MUST push widgets as individual node-level files.
|
|
162
|
+
|
|
163
|
+
### Required files for adding widgets
|
|
164
|
+
|
|
165
|
+
You need to push **three types of files** in a **single** `update_project_yaml` call:
|
|
166
|
+
|
|
167
|
+
| File | Key Pattern | Purpose |
|
|
168
|
+
|------|-------------|---------|
|
|
169
|
+
| Widget tree outline | `page/id-Scaffold_XXX/page-widget-tree-outline` | Defines the tree structure (which children belong to which parent) |
|
|
170
|
+
| Parent node | `page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Column_YYY` | The container widget (Column, Row, Stack, etc.) |
|
|
171
|
+
| Each child node | `page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_ZZZ` | Individual widget YAML with full props |
|
|
172
|
+
|
|
173
|
+
### File key pattern breakdown
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
page/id-{ScaffoldKey} # Page metadata
|
|
177
|
+
page/id-{ScaffoldKey}/page-widget-tree-outline # Tree structure
|
|
178
|
+
page/id-{ScaffoldKey}/page-widget-tree-outline/node/id-{WidgetKey} # Individual widget node
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Step-by-step example
|
|
182
|
+
|
|
183
|
+
**Task:** Add a Text widget and Button to the "testing" page (Scaffold_tjgkshke, body Column_gjy4w42f).
|
|
184
|
+
|
|
185
|
+
**File 1 -- Widget tree outline:**
|
|
186
|
+
```yaml
|
|
187
|
+
# File key: page/id-Scaffold_tjgkshke/page-widget-tree-outline
|
|
188
|
+
node:
|
|
189
|
+
key: Scaffold_tjgkshke
|
|
190
|
+
body:
|
|
191
|
+
key: Column_gjy4w42f
|
|
192
|
+
children:
|
|
193
|
+
- key: Text_mytext01
|
|
194
|
+
- key: Button_mybtn01
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**File 2 -- Text widget node:**
|
|
198
|
+
```yaml
|
|
199
|
+
# File key: page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Text_mytext01
|
|
200
|
+
key: Text_mytext01
|
|
201
|
+
type: Text
|
|
202
|
+
props:
|
|
203
|
+
text:
|
|
204
|
+
fontFamily: Open Sans
|
|
205
|
+
themeStyle: BODY_MEDIUM
|
|
206
|
+
isCustomFont: false
|
|
207
|
+
selectable: false
|
|
208
|
+
textValue:
|
|
209
|
+
inputValue: Hello World
|
|
210
|
+
fontSizeValue:
|
|
211
|
+
inputValue: 24
|
|
212
|
+
colorValue:
|
|
213
|
+
inputValue:
|
|
214
|
+
themeColor: PRIMARY_TEXT
|
|
215
|
+
fontWeightValue:
|
|
216
|
+
inputValue: w700
|
|
217
|
+
responsiveVisibility: {}
|
|
218
|
+
opacity:
|
|
219
|
+
opacityValue:
|
|
220
|
+
inputValue: 1
|
|
221
|
+
mostRecentInputValue: 1
|
|
222
|
+
name: myText
|
|
223
|
+
parameterValues: {}
|
|
224
|
+
valueKey: {}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**File 3 -- Button widget node:**
|
|
228
|
+
```yaml
|
|
229
|
+
# File key: page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Button_mybtn01
|
|
230
|
+
key: Button_mybtn01
|
|
231
|
+
type: Button
|
|
232
|
+
props:
|
|
233
|
+
button:
|
|
234
|
+
text:
|
|
235
|
+
themeStyle: TITLE_SMALL
|
|
236
|
+
textValue:
|
|
237
|
+
inputValue: Click Me
|
|
238
|
+
mostRecentInputValue: Click Me
|
|
239
|
+
colorValue:
|
|
240
|
+
inputValue:
|
|
241
|
+
themeColor: PRIMARY_BACKGROUND
|
|
242
|
+
fontWeightValue:
|
|
243
|
+
inputValue: w700
|
|
244
|
+
borderRadius:
|
|
245
|
+
type: FF_BORDER_RADIUS_ALL
|
|
246
|
+
allValue:
|
|
247
|
+
inputValue: 40
|
|
248
|
+
mostRecentInputValue: 40
|
|
249
|
+
dimensions:
|
|
250
|
+
width:
|
|
251
|
+
pixelsValue:
|
|
252
|
+
inputValue: Infinity
|
|
253
|
+
mostRecentInputValue: Infinity
|
|
254
|
+
height:
|
|
255
|
+
pixelsValue:
|
|
256
|
+
inputValue: 48
|
|
257
|
+
elevationValue:
|
|
258
|
+
inputValue: 0
|
|
259
|
+
mostRecentInputValue: 0
|
|
260
|
+
fillColorValue:
|
|
261
|
+
inputValue:
|
|
262
|
+
themeColor: PRIMARY
|
|
263
|
+
responsiveVisibility: {}
|
|
264
|
+
opacity:
|
|
265
|
+
opacityValue:
|
|
266
|
+
inputValue: 1
|
|
267
|
+
mostRecentInputValue: 1
|
|
268
|
+
parameterValues: {}
|
|
269
|
+
valueKey: {}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Push all files in one call:**
|
|
273
|
+
```
|
|
274
|
+
update_project_yaml(projectId, {
|
|
275
|
+
"page/id-Scaffold_tjgkshke/page-widget-tree-outline": treeOutlineYaml,
|
|
276
|
+
"page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Column_gjy4w42f": columnNodeYaml,
|
|
277
|
+
"page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Text_mytext01": textNodeYaml,
|
|
278
|
+
"page/id-Scaffold_tjgkshke/page-widget-tree-outline/node/id-Button_mybtn01": buttonNodeYaml
|
|
279
|
+
})
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Validation tip
|
|
283
|
+
|
|
284
|
+
Validate the tree outline first. It reports `"File is referenced but is empty"` for missing node files, telling you exactly which node files you still need to create.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 4. Common Validation Errors
|
|
289
|
+
|
|
290
|
+
| Error | Cause | Fix |
|
|
291
|
+
|-------|-------|-----|
|
|
292
|
+
| `"Unknown field name 'X'"` | Invalid YAML field name for this widget type | Check the widget YAML reference. Field names are specific to each widget type (e.g., `text:` not `textValue:` at the widget props level). |
|
|
293
|
+
| `"Unknown enum value"` | Invalid enum constant (wrong case, typo, or unsupported value) | Use exact enum values: `BODY_MEDIUM`, `ALIGN_CENTER`, `w700`, `FF_PADDING_ALL`, etc. |
|
|
294
|
+
| `"File is referenced but is empty"` | The widget tree outline references a node key, but no node file exists for it | Create the missing node file with that key and push it alongside the tree outline. |
|
|
295
|
+
| `"Duplicate key"` | Two nodes in the tree have the same key | Generate a unique key for each widget (format: `Type_randomchars`, e.g., `Button_abc12345`). |
|
|
296
|
+
| Buffer/size error | Page YAML is too large to fetch or decode | Use node-level sub-files instead of fetching the full page. |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 5. Anti-Patterns (Things That Do NOT Work)
|
|
301
|
+
|
|
302
|
+
### Embedding widget children in full page YAML
|
|
303
|
+
|
|
304
|
+
The full page file (`page/id-Scaffold_XXX`) only stores page metadata. The FlutterFlow server strips any inline children from this file. You MUST push widgets as individual node files.
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
BAD: Push children inside page/id-Scaffold_XXX
|
|
308
|
+
GOOD: Push each widget as page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_ZZZ
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Using shell commands to construct YAML
|
|
312
|
+
|
|
313
|
+
Shell escaping (especially with newlines, quotes, and special characters) will corrupt the YAML. The MCP tools handle JSON serialization automatically.
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
BAD: echo "key: value\ntype: Button" | some_command
|
|
317
|
+
GOOD: Pass YAML as a normal multi-line string directly to MCP tools
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Forgetting to sync inputValue and mostRecentInputValue
|
|
321
|
+
|
|
322
|
+
Every value field in FlutterFlow YAML has two copies. If they diverge, the FlutterFlow editor will show inconsistent state and may overwrite your changes.
|
|
323
|
+
|
|
324
|
+
```yaml
|
|
325
|
+
# BAD -- values out of sync
|
|
326
|
+
textValue:
|
|
327
|
+
inputValue: New Text
|
|
328
|
+
mostRecentInputValue: Old Text
|
|
329
|
+
|
|
330
|
+
# GOOD -- always identical
|
|
331
|
+
textValue:
|
|
332
|
+
inputValue: New Text
|
|
333
|
+
mostRecentInputValue: New Text
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Fetching all YAML without a fileName
|
|
337
|
+
|
|
338
|
+
Calling `get_project_yaml` without specifying a `fileName` downloads the entire project. This can exceed buffer/transport limits on large projects and is almost never what you want.
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
BAD: get_project_yaml(projectId) # Downloads everything
|
|
342
|
+
GOOD: get_project_yaml(projectId, "theme.yaml") # Downloads one file
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### Using list_project_files to find pages
|
|
346
|
+
|
|
347
|
+
`list_project_files` returns raw file keys, which are scaffold IDs with no human-readable names. Use `list_pages` instead -- it returns page names, scaffold IDs, and folder assignments.
|
|
348
|
+
|
|
349
|
+
```
|
|
350
|
+
BAD: list_project_files(projectId) # Returns raw keys like "page/id-Scaffold_abc123"
|
|
351
|
+
GOOD: list_pages(projectId) # Returns { name: "Welcome", scaffoldId: "Scaffold_abc123", folder: "Auth" }
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Editing full page YAML for a single widget change
|
|
355
|
+
|
|
356
|
+
Fetching and re-pushing the full page YAML risks overwriting concurrent changes and is unnecessarily slow. Use node-level file keys for targeted edits.
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
BAD: get_project_yaml(projectId, "page/id-Scaffold_XXX") # Full page
|
|
360
|
+
GOOD: get_project_yaml(projectId, "page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Button_YYY") # Just the button
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Pushing without validating
|
|
364
|
+
|
|
365
|
+
Always call `validate_yaml` before `update_project_yaml`. Pushing invalid YAML can corrupt the page state in FlutterFlow.
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 6. YAML Content Formatting
|
|
370
|
+
|
|
371
|
+
When passing YAML content to `validate_yaml` and `update_project_yaml`:
|
|
372
|
+
|
|
373
|
+
- Pass YAML as a **normal multi-line string**
|
|
374
|
+
- Do NOT escape newlines as literal `\n` characters
|
|
375
|
+
- Do NOT use shell commands to construct YAML
|
|
376
|
+
- The MCP SDK handles JSON serialization automatically
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## 7. Tool Reference Summary
|
|
381
|
+
|
|
382
|
+
### Discovery tools
|
|
383
|
+
|
|
384
|
+
| Tool | Input | Output |
|
|
385
|
+
|------|-------|--------|
|
|
386
|
+
| `list_projects` | (none) | All projects with IDs |
|
|
387
|
+
| `list_pages` | `projectId` | Pages with names, scaffold IDs, folders |
|
|
388
|
+
| `list_project_files` | `projectId` | All raw file keys (rarely needed) |
|
|
389
|
+
|
|
390
|
+
### Cache tools (require `sync_project` first)
|
|
391
|
+
|
|
392
|
+
| Tool | Input | Output |
|
|
393
|
+
|------|-------|--------|
|
|
394
|
+
| `sync_project` | `projectId`, optional `force` | Downloads all YAML to local cache |
|
|
395
|
+
| `get_page_summary` | `projectId`, `pageName` or `scaffoldId` | Widget tree, actions, params, state |
|
|
396
|
+
| `get_component_summary` | `projectId`, `componentName` or `componentId` | Widget tree, params, actions |
|
|
397
|
+
| `find_component_usages` | `projectId`, `componentName` or `componentId` | All pages/components using the component |
|
|
398
|
+
| `find_page_navigations` | `projectId`, `pageName` or `scaffoldId` | All navigate actions targeting the page |
|
|
399
|
+
|
|
400
|
+
### Read tools (API calls)
|
|
401
|
+
|
|
402
|
+
| Tool | Input | Output |
|
|
403
|
+
|------|-------|--------|
|
|
404
|
+
| `get_page_by_name` | `projectId`, `pageName` | Full page YAML resolved by name |
|
|
405
|
+
| `get_project_yaml` | `projectId`, `fileName` | Any YAML file by key |
|
|
406
|
+
|
|
407
|
+
### Write tools (API calls)
|
|
408
|
+
|
|
409
|
+
| Tool | Input | Output |
|
|
410
|
+
|------|-------|--------|
|
|
411
|
+
| `validate_yaml` | `projectId`, `fileKey`, `fileContent` | Validation result |
|
|
412
|
+
| `update_project_yaml` | `projectId`, `fileKeyToContent` (map) | Push result |
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## 8. Recommended Workflow Patterns
|
|
417
|
+
|
|
418
|
+
### Inspecting a project for the first time
|
|
419
|
+
|
|
420
|
+
```
|
|
421
|
+
list_projects
|
|
422
|
+
--> sync_project(projectId)
|
|
423
|
+
--> get_page_summary(projectId, pageName: "HomePage")
|
|
424
|
+
--> get_component_summary(projectId, componentName: "NavBar")
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### Editing an existing widget
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
list_pages(projectId)
|
|
431
|
+
--> get_page_by_name(projectId, "PageName")
|
|
432
|
+
--> get_project_yaml(projectId, "page/id-Scaffold_XXX/.../node/id-Widget_YYY")
|
|
433
|
+
--> [modify YAML]
|
|
434
|
+
--> validate_yaml(projectId, fileKey, yaml)
|
|
435
|
+
--> update_project_yaml(projectId, { fileKey: yaml })
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Adding new widgets to a page
|
|
439
|
+
|
|
440
|
+
```
|
|
441
|
+
list_pages(projectId)
|
|
442
|
+
--> get_page_by_name(projectId, "PageName")
|
|
443
|
+
--> [construct tree outline + node files]
|
|
444
|
+
--> validate_yaml for each file
|
|
445
|
+
--> update_project_yaml(projectId, { treeOutlineKey: ..., nodeKey1: ..., nodeKey2: ... })
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Understanding navigation flow
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
sync_project(projectId)
|
|
452
|
+
--> find_page_navigations(projectId, pageName: "TargetPage")
|
|
453
|
+
--> get_page_summary for each source page
|
|
454
|
+
```
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# FlutterFlow YAML Reference for AI Agents
|
|
2
|
+
|
|
3
|
+
A structured reference catalog of FlutterFlow's YAML schema, derived from real production projects. Use this to read, create, and modify FlutterFlow project files programmatically via the MCP API. Each document covers one domain with exact field names, valid enum values, and copy-paste-ready templates.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Which file do I need?
|
|
8
|
+
|
|
9
|
+
| I want to... | Read this |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Understand FF project structure | `00-overview.md` |
|
|
12
|
+
| Read/modify project settings | `01-project-files.md` |
|
|
13
|
+
| Work with pages | `02-pages.md` |
|
|
14
|
+
| Work with components | `03-components.md` |
|
|
15
|
+
| Build/modify a specific widget | `04-widgets/` (see index inside) |
|
|
16
|
+
| Add/modify action chains | `05-actions.md` |
|
|
17
|
+
| Bind dynamic data to widgets | `06-variables.md` |
|
|
18
|
+
| Define data models | `07-data.md` |
|
|
19
|
+
| Write custom Dart code | `08-custom-code.md` |
|
|
20
|
+
| Customize colors/fonts | `09-theming.md` |
|
|
21
|
+
| Push changes via MCP API | `10-editing-guide.md` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Universal patterns
|
|
26
|
+
|
|
27
|
+
These four patterns appear across all FlutterFlow YAML files. Internalize them before reading any other document.
|
|
28
|
+
|
|
29
|
+
### 1. `inputValue` / `mostRecentInputValue` sync
|
|
30
|
+
|
|
31
|
+
Every settable value uses a dual-field pattern. **Both fields must always contain the same value.** Failing to sync them causes silent data corruption in the FlutterFlow editor.
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
# Correct
|
|
35
|
+
textValue:
|
|
36
|
+
inputValue: Hello World
|
|
37
|
+
mostRecentInputValue: Hello World
|
|
38
|
+
|
|
39
|
+
# Wrong -- will cause sync issues
|
|
40
|
+
textValue:
|
|
41
|
+
inputValue: Hello World
|
|
42
|
+
mostRecentInputValue: Old Value
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
This applies to most value types: text, color, numeric, boolean, enum, icon, dimension, opacity, border radius, padding, and alignment values.
|
|
46
|
+
|
|
47
|
+
**Exceptions — fields that only accept `inputValue`:**
|
|
48
|
+
- `fontWeightValue` — does NOT support `mostRecentInputValue`
|
|
49
|
+
- `fontSizeValue` — does NOT support `mostRecentInputValue`
|
|
50
|
+
|
|
51
|
+
Adding `mostRecentInputValue` to these fields will cause a validation error (`Unknown field name 'mostRecentInputValue'`). When in doubt, check the field reference table for the specific widget.
|
|
52
|
+
|
|
53
|
+
### 2. `identifier: { name, key }` pattern
|
|
54
|
+
|
|
55
|
+
Named entities (params, state fields, data types, components) are referenced via an identifier block:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
identifier:
|
|
59
|
+
name: userName # Human-readable name
|
|
60
|
+
key: Parameter_abc123 # Unique machine key
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
When creating new identifiers, generate a unique key using the pattern `<Type>_<8 alphanumeric chars>` (e.g., `Parameter_k7m2x9p1`).
|
|
64
|
+
|
|
65
|
+
### 3. Theme color references
|
|
66
|
+
|
|
67
|
+
Colors can be literal ARGB or theme references. Theme references use a fixed set of token names:
|
|
68
|
+
|
|
69
|
+
```yaml
|
|
70
|
+
# Theme reference (preferred)
|
|
71
|
+
colorValue:
|
|
72
|
+
inputValue:
|
|
73
|
+
themeColor: PRIMARY
|
|
74
|
+
mostRecentInputValue:
|
|
75
|
+
themeColor: PRIMARY
|
|
76
|
+
|
|
77
|
+
# Literal ARGB (decimal string)
|
|
78
|
+
colorValue:
|
|
79
|
+
inputValue:
|
|
80
|
+
value: "4294940319"
|
|
81
|
+
mostRecentInputValue:
|
|
82
|
+
value: "4294940319"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Valid `themeColor` tokens:** `PRIMARY`, `SECONDARY`, `TERTIARY`, `ALTERNATE`, `PRIMARY_TEXT`, `SECONDARY_TEXT`, `PRIMARY_BACKGROUND`, `SECONDARY_BACKGROUND`, `ACCENT1`, `ACCENT2`, `ACCENT3`, `ACCENT4`, `SUCCESS`, `WARNING`, `ERROR`, `INFO`.
|
|
86
|
+
|
|
87
|
+
### 4. File key naming
|
|
88
|
+
|
|
89
|
+
File keys map directly to API endpoints. The naming convention encodes hierarchy:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
page/id-Scaffold_XXX # Page metadata
|
|
93
|
+
page/id-Scaffold_XXX/page-widget-tree-outline # Widget tree structure
|
|
94
|
+
page/id-Scaffold_XXX/page-widget-tree-outline/node/id-Widget_YYY # Individual widget node
|
|
95
|
+
component/id-Container_XXX # Component metadata
|
|
96
|
+
component/id-Container_XXX/component-widget-tree-outline # Component widget tree
|
|
97
|
+
api-endpoint/id-XXX # API endpoint
|
|
98
|
+
custom-actions/id-XXX # Custom action
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Rules:
|
|
102
|
+
- Keys use `/` as separator, never `\`
|
|
103
|
+
- IDs are prefixed with `id-`
|
|
104
|
+
- Page scaffolds use `Scaffold_` prefix; components use `Container_` prefix
|
|
105
|
+
- Widget nodes use type-specific prefixes: `Text_`, `Button_`, `Column_`, `Row_`, `Container_`, `Image_`, `Icon_`, `TextField_`, etc.
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "flutterflow-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for the FlutterFlow Project API — AI-assisted FlutterFlow development through Claude and other MCP-compatible clients",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"flutterflow-mcp": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build",
|
|
12
|
+
"docs/ff-yaml",
|
|
13
|
+
"skills"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc && chmod 755 build/index.js",
|
|
17
|
+
"dev": "tsc --watch",
|
|
18
|
+
"start": "node build/index.js",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"flutterflow",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"ai",
|
|
26
|
+
"claude",
|
|
27
|
+
"yaml",
|
|
28
|
+
"no-code",
|
|
29
|
+
"low-code"
|
|
30
|
+
],
|
|
31
|
+
"author": "mohn93",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/mohn93/ff-mcp.git"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/mohn93/ff-mcp#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/mohn93/ff-mcp/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
46
|
+
"adm-zip": "^0.5.16",
|
|
47
|
+
"yaml": "^2.8.2",
|
|
48
|
+
"zod": "^4.3.6"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/adm-zip": "^0.5.7",
|
|
52
|
+
"@types/node": "^25.2.3",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
|
+
}
|
|
55
|
+
}
|