Skip to content

fix(links): send the store-URL field names the API accepts (SIT-423) - #1

Open
onamfc wants to merge 1 commit into
mainfrom
brandon/sit-423-mcp-store-url-fields
Open

fix(links): send the store-URL field names the API accepts (SIT-423)#1
onamfc wants to merge 1 commit into
mainfrom
brandon/sit-423-mcp-store-url-fields

Conversation

@onamfc

@onamfc onamfc commented Sep 9, 2026

Copy link
Copy Markdown
Member

Summary

create_link and update_link declared iosUrl / androidUrl and forwarded their parsed args verbatim to the Cloud API. The API accepts iosAppStoreUrl / androidAppStoreUrl, and its schema strips unknown keys instead of rejecting them — so every MCP call carrying store URLs returned success and created a link with none.

Four lines, but a live defect: a store URL passed through MCP is discarded before it reaches the database.

Severity, corrected. I first described this as every affected link losing its store URLs. That overstated it. The create handler applies a fallback chain (links.ts:341-342) — user input → template default → workspace app config → null. Because the field is stripped, data.iosAppStoreUrl is undefined, so the handler falls through to the template default, which most workspaces configure.

  • Common case: the caller's link-specific URL is silently ignored and the template's value used instead. Wrong URL, usually still a working store link.
  • Rarer, worse case: neither template nor workspace config has store URLs, and the link gets no mobile destination at all.

Real either way — an explicit argument is discarded — but narrower than first stated.

Why nothing caught it

Nothing could. The MCP schema validated fine, the HTTP call succeeded, the API returned 201, and the link existed. iosAppStoreUrl appeared nowhere in this repo, so there was no mismatch for a type check to find — the two sides simply never agreed on a name, and the transport in between discards disagreements.

Found while correcting the API reference documentation (SIT-421), which had the same wrong field names.

Scope check

bulk_create_links reuses linkInputSchema, so it was affected too and is fixed by the same change.

I diffed the whole MCP link surface against createLinkSchema in cloud/backend/src/routes/links.ts:

  • Fields MCP sends that Cloud discards: none. That was 2 before this change; it is 0 now.
  • Templates already nest their defaults under settings, matching the Cloud template schema.
  • The UTM schemas already use bare keys (source, medium, campaign) rather than the utm_-prefixed form that broke the docs in SIT-422.

Tool descriptions never named the parameters, so they remain accurate without edits.

Not fixed here

Seven fields the Cloud API accepts that MCP cannot set: appScheme, iosUniversalLink, androidAppLink, deepLinkPath, customSchemeUrl (present), domainId, eventAttributionWindowHours, appendClickId. Those are feature gaps rather than defects — nothing is silently lost — and the ticket scoped them out. Worth their own ticket if MCP should reach parity.

Verification

  • npx tsc --noEmit — clean
  • npm run build — clean
  • grep -rn "iosUrl\|androidUrl" src/ returns nothing

One check I could not run: the ticket asks for a live call against a real workspace confirming ios_app_store_url comes back populated. That needs credentials and writes a real link, so it is left for the reviewer. It is the only check that exercises the actual fix end to end — a type check cannot see this class of bug, which is how it shipped.

Existing links, and why they cannot be counted

This fixes new writes. Links already created through MCP keep whatever the fallback chain gave them — the template's store URLs rather than the caller's, or none.

The affected set cannot be measured. POST /api/links hardcodes source = 'dashboard' (links.ts:393) whether the caller is the dashboard UI or an API key, and nothing else records the transport. MCP-created links are indistinguishable from dashboard-created ones in the database. Isolating them would need a signal recorded at write time, which is what SIT-424 introduces.

Closes SIT-423

create_link and update_link declared iosUrl and androidUrl and forwarded
args verbatim. The Cloud API accepts iosAppStoreUrl and androidAppStoreUrl,
and its schema strips unknown keys rather than rejecting them — so every
call carrying store URLs returned success and created a link with none.

bulk_create_links reuses linkInputSchema, so it was affected too and is
fixed by the same change.

The rest of the tool surface was diffed against createLinkSchema: nothing
else MCP sends is discarded. Templates already nest their defaults under
settings and the UTM schemas already use bare keys, both correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant