softr-vibe-coding 1.12.0 → 2.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.
@@ -2,12 +2,14 @@
2
2
 
3
3
  Fast lookup for imports, hook signatures, field mapping syntax, and common patterns. Use when you already know what you need and just want the shape.
4
4
 
5
+ The current platform compiles TypeScript with modern syntax (`?.`, `??`, arrows, `const`, generics) — verified live 2026-08-25. Snippets below in `var` style predate that and remain valid; both styles compile.
6
+
5
7
  ## Imports
6
8
 
7
9
  ```jsx
8
10
  // DATASOURCE (add `datasource` when the block connects to more than one source)
9
11
  import { datasource, useRecords, useRecord, useRecordCreate, useRecordUpdate, useRecordDelete,
10
- useCurrentRecordId, useLinkedRecords, useUpload, useMetric, useChartData,
12
+ useCurrentRecordId, useLinkedRecords, useFieldOptions, useUpload, useMetric, useChartData,
11
13
  q, metric } from "@/lib/datasource";
12
14
 
13
15
  // USER
@@ -50,6 +52,7 @@ var ds = datasource.define({ // values MUST be inline string literals
50
52
  });
51
53
 
52
54
  useRecords({ from: ds.people, select: select }); // `from:` required once >1 source
55
+ var proxyFetch = useProxyFetch(ds.people); // REST API source: alias is the ARGUMENT, not a from: option
53
56
  ```
54
57
 
55
58
  Ids are plain UUIDs. Get them by asking Studio's AI chat to **write code**, never to recite a
@@ -59,9 +62,13 @@ value — it fabricates them in prose. Full detail: [../datasources/multi-dataso
59
62
 
60
63
  ```jsx
61
64
  var result = useRecords({ select: select, count: 100 });
62
- var records = (result.data && result.data.pages) ? result.data.pages.flatMap(function(p) { return p.items; }) : [];
65
+ var records = result.data?.pages.flatMap(p => p.items) ?? [];
63
66
  ```
64
67
 
68
+ ⚠ The options object MUST be an inline literal — `useRecords(opts)` with `opts` built in a
69
+ variable or returned by a wrapper function **fails to compile** (verified live 2026-08-25).
70
+ Share `q.select` mappings, not options objects.
71
+
65
72
  ## Filter + Sort
66
73
 
67
74
  ```jsx
@@ -84,8 +91,9 @@ var result = useRecord({ recordId: recordId, select: select });
84
91
  ## Current User
85
92
 
86
93
  ```jsx
87
- var currentUser = useCurrentUser(); // { id, fullName, email, avatar }
88
- var softrUser = window.__softr_current_user; // full object with userGroups
94
+ var currentUser = useCurrentUser(); // { id, fullName, firstName, lastName, email, avatar } | null; id only with user sync
95
+ var withProps = useCurrentUser({ properties: { plan: "FIELD_ID" } }); // custom user fields → withProps.properties.plan
96
+ var softrUser = window.__softr_current_user; // userGroups/role ONLY — not exposed by the hook
89
97
  ```
90
98
 
91
99
  ## Create
@@ -96,7 +104,7 @@ var createRecord = useRecordCreate({
96
104
  onSuccess: function(newRecord) { refetch(); },
97
105
  onError: function(err) { toast.error(err.message); },
98
106
  });
99
- createRecord.mutate({ name: "Jane", email: "jane@example.com" });
107
+ createRecord.mutate({ name: "Jane", email: "jane@example.com" }); // FLAT — no { fields } wrapper
100
108
  ```
101
109
 
102
110
  ## Update (THE CORRECT PATTERN)
@@ -108,7 +116,7 @@ var updateRecord = useRecordUpdate({
108
116
  onError: function(err) { toast.error(err.message); },
109
117
  });
110
118
 
111
- // Call .mutate() — NOT .mutateAsync() — and use the nested {recordId, fields:{}} shape.
119
+ // Payload is the nested {recordId, fields:{}} shape (create is flat — the asymmetry is by design).
112
120
  // Per-call onSuccess/onError go in the second argument.
113
121
  updateRecord.mutate(
114
122
  { recordId: record.id, fields: { name: "New" } },
@@ -119,11 +127,26 @@ updateRecord.mutate(
119
127
  );
120
128
  ```
121
129
 
122
- **Two parser requirements both must hold or `enabled` stays `false`:**
123
- 1. `.mutate(...)` — NOT `.mutateAsync(...).then(...)` (parser ignores `mutateAsync`)
124
- 2. Payload is `{ recordId, fields: {...} }` NOT flat `{ recordId, status: "..." }`
130
+ **Payload shapes or `enabled` stays `false`:**
131
+ 1. Update payload is `{ recordId, fields: {...} }` — NOT flat `{ recordId, status: "..." }`
132
+ 2. Create payload is FLAT — `{ name: "..." }`, no `fields` wrapper
133
+
134
+ See [datasources/writing.md](../datasources/writing.md#critical-the-userecordupdate-payload-shape-and-the-retired-mutate-only-rule) for the full debugging path.
125
135
 
126
- See [datasources/writing.md](../datasources/writing.md#critical-two-parser-requirements-for-userecordupdate) for the full debugging path.
136
+ ## Sequential Multi-Row Saves (mutateAsync)
137
+
138
+ `mutateAsync` is fully supported (verified live 2026-08-25 — the old ".mutate() only" parser
139
+ rule is retired). It's the tool whenever writes must happen in order:
140
+
141
+ ```tsx
142
+ const header = await createHeader.mutateAsync({ name, date }); // header first
143
+ for (const line of lines) {
144
+ await createLine.mutateAsync({ header: [header.id], ...line }); // then lines, in order
145
+ }
146
+ ```
147
+
148
+ Stop on the first failure, render it with a Retry, never re-issue completed writes. Full queue
149
+ pattern: [datasources/writing.md](../datasources/writing.md#sequential-multi-row-writes-mutateasync).
127
150
 
128
151
  ## Delete
129
152
 
@@ -138,7 +161,10 @@ deleteRecord.mutate(record.id); // Just the ID string
138
161
 
139
162
  `.enabled`, `.status`, `.error`, `.mutate()`, `.mutateAsync()`, `.reset()`
140
163
 
141
- `.mutateAsync()` exists at runtime but is **invisible to Softr's Action parser** — using it on `useRecordUpdate` leaves `enabled` permanently `false`. Always call `.mutate(payload, { onSuccess, onError })` for updates.
164
+ Both `.mutate(payload, { onSuccess, onError })` and `await .mutateAsync(payload)` derive
165
+ Actions correctly on the current platform (verified 2026-08-25). Use `.mutate` for
166
+ fire-and-forget single writes, `mutateAsync` for sequenced flows. (Pre-2026-08 platforms only
167
+ recognized the literal `.mutate(` token — relevant only when maintaining old apps.)
142
168
 
143
169
  ## Linked Records Picker
144
170
 
@@ -152,9 +178,12 @@ var options = (result.data && result.data.pages) ? result.data.pages.flatMap(fun
152
178
  ## Linked Records in Mutations
153
179
 
154
180
  ```jsx
155
- teamMembers: [{ id: "MEMBER_ID" }]
181
+ teamMembers: ["MEMBER_ID_1", "MEMBER_ID_2"] // array of record-id STRINGS (verified Softr DB, 2026-08-25)
156
182
  ```
157
183
 
184
+ Legacy/Airtable: the `[{ id: "..." }]` object shape was the verified form on Airtable-backed
185
+ blocks (May 2026) — try it if a string-array write fails there.
186
+
158
187
  ## Formula Booleans
159
188
 
160
189
  ```jsx
@@ -0,0 +1,140 @@
1
+ # Softr MCP Server
2
+
3
+ The official Softr MCP server (`https://mcp.softr.io/mcp`) gives an AI assistant (Claude Code, Claude Desktop, claude.ai, Cursor, ChatGPT, Mistral) direct access to a Softr **workspace**: databases, applications, vibe coding blocks, integrations (external data sources), and workflows. Everything the assistant does happens as the connected user, with their permissions, and shows up in Studio like any other change.
4
+
5
+ **This file is a sibling concern to the [../datasources/](../datasources/) guides, which cover in-block data fetching (`useRecords` + `q.select()`).** The MCP runs at chat-build time, not inside the block. For Vibe Coding work it matters twice: it answers "what fields does this table have?" without any paste-ins, and it can create and deploy the block itself — no copy-paste into Studio.
6
+
7
+ > Historical note: this file was previously named `softr-database-mcp.md` and described a databases-only server with granular scopes. That server has since grown into the workspace-wide MCP documented here; the old "does NOT cover external sources" limitation is gone (see [Integrations](#browsing-integrations-external-data-sources)).
8
+
9
+ ## Contents
10
+
11
+ - [What it covers](#what-it-covers)
12
+ - [Connection and auth](#connection-and-auth)
13
+ - [Permissions model](#permissions-model)
14
+ - [Vibe coding block tools](#vibe-coding-block-tools)
15
+ - [Vibe coding gotchas (official)](#vibe-coding-gotchas-official)
16
+ - [Browsing integrations (external data sources)](#browsing-integrations-external-data-sources)
17
+ - [Softr Database tools](#softr-database-tools)
18
+ - [Two delivery paths for this skill](#two-delivery-paths-for-this-skill)
19
+ - [When the MCP is not installed](#when-the-mcp-is-not-installed)
20
+
21
+ ## What it covers
22
+
23
+ | Area | What the assistant can do | Official docs |
24
+ |---|---|---|
25
+ | Databases | Query, filter, aggregate; create/update records; build tables and fields | https://docs.softr.io/mcp/databases |
26
+ | Applications | Read apps, pages, blocks, permissions; preview; publish | https://docs.softr.io/mcp/apps |
27
+ | Vibe coding blocks | Create and edit blocks, manage settings, visibility, versions, data source connections | https://docs.softr.io/mcp/vibe-coding |
28
+ | Integrations | Browse external data sources connected to the workspace, down to field level | https://docs.softr.io/mcp/integrations |
29
+ | Workflows | Build, test, and publish workflows | https://docs.softr.io/mcp/workflows |
30
+
31
+ `list_workspaces` is often the first call — it turns "my Sales workspace" into the workspace ID every other tool needs.
32
+
33
+ ## Connection and auth
34
+
35
+ - **Server URL:** `https://mcp.softr.io/mcp` (streamable HTTP)
36
+ - **Official docs:** https://docs.softr.io/mcp/overview
37
+
38
+ Install in Claude Code:
39
+
40
+ ```bash
41
+ claude mcp add --transport http softr https://mcp.softr.io/mcp
42
+ ```
43
+
44
+ Then start a new session and run `/mcp` to complete OAuth in the browser.
45
+
46
+ Two auth methods:
47
+
48
+ 1. **OAuth (recommended)** — pre-built clients exist for Claude (claude.ai), Cursor, ChatGPT, and Mistral. If a Client ID is requested, use the value from the [overview docs](https://docs.softr.io/mcp/overview); leave Client Secret blank (Softr's OAuth clients are public). The assistant cannot request permissions — the user always picks them on Softr's authorization screen.
49
+ 2. **Personal access token** — for custom clients. Created in Softr under **Settings → API tokens** (name, expiry, workspace + permission scoping), then used as a Bearer token.
50
+
51
+ Revoke or edit access anytime in **Settings → API tokens** (Authorized apps section for OAuth, token list for PATs).
52
+
53
+ ## Permissions model
54
+
55
+ Permissions are chosen per workspace across **three areas with bundled levels** — not granular per-tool scopes. Each level includes everything below it (no "write without read").
56
+
57
+ | Area | Levels | Highest level adds |
58
+ |---|---|---|
59
+ | Applications & Forms | Full access · Read only · None | Creating/editing vibe coding blocks, previewing, publishing |
60
+ | Databases | Full access · Edit data · View only · None | Schema changes (tables/fields); Edit data adds record writes |
61
+ | Workflows | Full access · Read only · None | Building, testing, publishing workflows |
62
+
63
+ For block-building work you need **Applications & Forms: Full access** (to create/edit blocks) plus at least **Databases: View only** (schema discovery). Integrations browsing rides on Applications & Forms read access.
64
+
65
+ ## Vibe coding block tools
66
+
67
+ Before writing any block code through the MCP, call `get_vibe_coding_docs` — it returns the current version of the [Vibe Coding Developer Guide](https://docs.softr.io/vibe-coding-developer-guide), which is the authority on hook signatures if it and this skill ever disagree.
68
+
69
+ | Group | Tools |
70
+ |---|---|
71
+ | Create / read | `get_vibe_coding_docs`, `create_vibe_coding_block`, `get_vibe_coding_block_code`, `get_vibe_coding_block_settings` |
72
+ | Edit code | `update_vibe_coding_block_code` (full replace), `update_vibe_coding_block_code_search_replace` (targeted edit) |
73
+ | Settings / visibility | `update_vibe_coding_block_settings`, `set_vibe_coding_block_visibility`, `set_vibe_coding_block_action_visibility` |
74
+ | Versions | `list_vibe_coding_block_versions`, `restore_vibe_coding_block_version`, `duplicate_vibe_coding_block_from_version` |
75
+ | Data sources | `connect_vibe_coding_block_data_source`, `disconnect_vibe_coding_block_data_source`, `set_vibe_coding_block_data_source_sort`, `set_vibe_coding_block_data_source_record_filters` |
76
+
77
+ Editable settings via MCP are the same fields as the block's **Content → Settings** panel; sort and record filters are the same as the **Source** tab. Duplicating from a version is the safe way to try an alternative — the original keeps working while you experiment on the copy.
78
+
79
+ ## Vibe coding gotchas (official)
80
+
81
+ From the official MCP docs — these hold for MCP-driven and Studio-driven edits alike:
82
+
83
+ - **A broken block can't be saved.** Code is validated before storage; on failure the block keeps its last working state and nothing is lost.
84
+ - **A version is a snapshot of the whole block** — code, settings, visibility, AND data source connections. Setting-only changes don't create a version.
85
+ - **Rolling back reverts more than the code.** Restoring a version also restores settings, visibility, and data source connections as they were at that point.
86
+ - **Changing the code resets action permissions.** Any code change rebuilds the block's record actions at default visibility — restrictions to user groups must be re-applied. (This is Hard Constraint 21 in SKILL.md, now officially documented: tighten Action permissions only after the LAST redeploy.)
87
+ - **A block with an unconnected data source saves without complaint**, then errors when the page loads. If a freshly created block looks broken but the code seems right, check its data source connection first.
88
+
89
+ ## Browsing integrations (external data sources)
90
+
91
+ An integration is an external data source connected once per workspace (the builder says "integrations", the tools say "data sources" — same thing). Five read-only tools drill down from workspace to fields; each level needs an ID from the level above:
92
+
93
+ ```
94
+ list_data_sources workspace's integrations
95
+ └── list_data_source_databases a base, spreadsheet, or database
96
+ └── list_data_source_schemas SQL schemas — Supabase only (usually just `postgres`)
97
+ └── list_data_source_tables tables or sheets
98
+ └── list_data_source_table_fields fields, types, options, primary field
99
+ ```
100
+
101
+ **Only five integration types are browsable/connectable through MCP today:** Softr Databases, Airtable, Google Sheets, Notion, and Supabase. Anything else still appears in `list_data_sources` but must be connected through the block's **Source** tab in Studio, with schema discovery via the manual workflows in [../datasources/fields.md](../datasources/fields.md#field-inspector-block).
102
+
103
+ `list_data_source_table_fields` also tells you **how fields must be referenced in `q.select()`**:
104
+
105
+ | Integration | Reference fields by |
106
+ |---|---|
107
+ | Airtable, Google Sheets, Notion | Name |
108
+ | Softr Databases, Supabase | ID (for Supabase, the SQL column name) |
109
+
110
+ Getting this wrong **fails silently** — the code compiles, saves, and looks right in the builder, then returns nothing at page load. If a block renders but its data is empty, check this first.
111
+
112
+ ## Softr Database tools
113
+
114
+ For Softr's native databases the MCP goes far beyond browsing: `get_schema` (authoritative field-type + filter-operator reference — call it before building tables or filters), database/table/field CRUD, `list_views`, record reads (`list_records`, `search_records`, `get_record`), record writes (`create_record`, `create_records` batch, `update_record`), and `aggregate_data` for grouped summaries.
115
+
116
+ Known limits and behaviors (per official docs):
117
+
118
+ - Record field keys are **field IDs**, not labels — `list_fields` maps between them.
119
+ - Computed fields (formula, lookup, rollup, count) and system fields (created/updated time and by, autonumber, record ID) are read-only; a field's type cannot be changed after creation.
120
+ - **Nothing can be deleted through the MCP yet** — no record/table/field/database delete tools (docs say deletion is coming). Deletions happen in the builder.
121
+ - Limits: 100 records per `create_records` call, 200 records per read (silently capped, not an error), 2 group-by fields in `aggregate_data`. For big tables prefer a filter or aggregate over paging.
122
+
123
+ Typical Vibe Coding uses: "list every field on `Wigs` with id, name, type, and dropdown options", "what's the option id for `Payment status` = 'Partially paid'?", "show 3 sample records so we know value shapes", "verify the field id in my `q.select()` exists". This eliminates the field-id-typo / wrong-option-uuid class of bugs entirely.
124
+
125
+ ## Two delivery paths for this skill
126
+
127
+ When generating a block, pick the delivery path by what's connected:
128
+
129
+ 1. **MCP connected with Applications & Forms full access** — write the `.tsx` file locally first (it remains the source of truth and the reviewable artifact), then offer to deploy it directly: `create_vibe_coding_block` (or `update_vibe_coding_block_code` for edits), then `connect_vibe_coding_block_data_source` to wire up the data. Remember the action-permissions reset gotcha after every code push.
130
+ 2. **No MCP (or read-only access)** — classic path: write the `.tsx` file and have the user paste it into Studio's Vibe Coding editor, then connect the data source in the **Source** tab themselves.
131
+
132
+ Either way, never deliver code inline in chat (JSX character corruption — see SKILL.md workflow step 5).
133
+
134
+ ## When the MCP is not installed
135
+
136
+ If the user hasn't installed the MCP (and doesn't want to right now), fall back to the schema-discovery methods documented per source:
137
+
138
+ - **Softr Database:** bundled CLI script — see [../datasources/softr-database.md](../datasources/softr-database.md#bundled-cli-script-get-softr-database); or the `tablespace-with-tables` network paste — see [../datasources/fields.md](../datasources/fields.md#field-inspector-block).
139
+ - **Airtable:** bundled `get-airtable-base` script — see [../datasources/airtable.md](../datasources/airtable.md#bundled-cli-script-get-airtable-base).
140
+ - **Other sources:** Field Inspector block and vendor workflows in [../datasources/fields.md](../datasources/fields.md#field-inspector-block).
@@ -1,59 +0,0 @@
1
- # Softr Database MCP Server
2
-
3
- Out-of-band integration for AI-assisted Vibe Coding workflows. The MCP server lets the AI assistant (Claude Code, Claude Desktop, Cursor, ChatGPT, Mistral) read schema, list field IDs, query records, and write data directly into Softr Databases — eliminating the manual "paste `tablespace-with-tables` JSON" step and removing transcription errors on field IDs and dropdown option UUIDs.
4
-
5
- **This file is a sibling concern to [../datasources/softr-database.md](../datasources/softr-database.md), which covers in-block data fetching (`useRecords` + `q.select()`).** The MCP runs at chat-build time, not inside the block. Same parallel as [airtable-automations.md](airtable-automations.md) sits next to [../datasources/airtable.md](../datasources/airtable.md).
6
-
7
- ## Connection
8
-
9
- - **Server URL:** `https://mcp.softr.io/mcp`
10
- - **Transport:** streamable HTTP
11
- - **Auth:** OAuth (pre-configured for Claude / Cursor / ChatGPT / Mistral) or Personal API Token (`Settings → API Tokens` in Softr)
12
- - **Official docs:** https://docs.softr.io/mcp-server
13
-
14
- ## Install (Claude Code)
15
-
16
- ```bash
17
- claude mcp add --transport http softr https://mcp.softr.io/mcp
18
- ```
19
-
20
- Then start a new Claude Code session and run `/mcp` to complete the OAuth authorization in the browser. See [the Softr docs](https://docs.softr.io/mcp-server) for Cursor / ChatGPT / Mistral / custom client setup.
21
-
22
- ## Permissions (three granular scopes)
23
-
24
- Grant only what you need:
25
-
26
- | Scope | Use case for Vibe Coding |
27
- |-----------------------------|-----------------------------------------------------------------------|
28
- | `databases.records:read` | AI discovers field IDs, dropdown UUIDs, verifies value shapes |
29
- | `databases.records:write` | AI mutates live data (e.g. seeding test records, bulk updates) |
30
- | `databases.schema:write` | AI provisions databases / tables / fields for you |
31
-
32
- For block-writing workflows, **read scopes are the most valuable** — they cover the AI's schema-discovery needs (the bottleneck the MCP solves) without any blast-radius into live data. Add write scopes only when you want the AI to mutate records; schema-write only when you want it to provision tables.
33
-
34
- ## Tools available (20 total)
35
-
36
- - **Databases (4):** list / get / create / update
37
- - **Tables (8):** list tables, list fields, list views, get table schema, create / update tables, create / update fields
38
- - **Records (8):** list / get / create (batch ≤ 100) / update / delete + filter-based and view-filtered search
39
-
40
- ## Why this changes Vibe Coding workflows
41
-
42
- Without the MCP, the AI needs schema shared manually — either paste `tablespace-with-tables` network JSON or describe fields by name. Both are slow, and verbal-name approaches lose dropdown option UUIDs entirely without a second copy step.
43
-
44
- With the MCP installed, you can ask things like:
45
-
46
- - "List every field on the `Wigs` table with id, name, type, and dropdown options."
47
- - "What's the option id for `Wigs.Payment status` = 'Partially paid'?"
48
- - "Show me 3 sample records from `Wig Services` so we know the value shapes."
49
- - "Verify the field id I used for `q.select({ status: 'sel...' })` exists on this table."
50
-
51
- The AI then writes `q.select()` keys and write payloads against the live schema, eliminating an entire class of "field id typo" / "wrong option uuid" bugs.
52
-
53
- ## Scope: Softr Database only
54
-
55
- The MCP server exposes Softr's **native** databases only. It does NOT proxy external sources (Airtable, Google Sheets, HubSpot, Notion, Xano, etc.) — those still need the schema-discovery workflows documented in [../datasources/fields.md](../datasources/fields.md#field-inspector-block) (Field Inspector block, vendor APIs, network inspector paste, etc.). If your Softr app blends Softr DB with external sources, the MCP helps only with the Softr DB tables.
56
-
57
- ## When the MCP is not installed
58
-
59
- If the user hasn't installed the MCP (and doesn't want to right now), fall back to the schema-sharing methods documented in [../datasources/fields.md](../datasources/fields.md#field-inspector-block) — primarily the `tablespace-with-tables` network paste, which gives the AI everything it needs in one shot.