From 9c220389551cd5ce0432ae1886abd949fb03554a Mon Sep 17 00:00:00 2001 From: guitavano Date: Tue, 18 Aug 2026 17:20:34 -0300 Subject: [PATCH 1/2] fix(shopify): drop "shopify" token from OAuth URLs Shopify forbids the word "shopify" in app URLs. Rename the OAuth callback path and point the MCP at a neutral host: - callback path /oauth/shopify/callback -> /oauth/store/callback (not /oauth/callback, which the runtime mounts on this origin) - host sites-shopify.deco.site -> mcp-commerce-store.deco.site (app.json connection.url + DEFAULT_SELF_URL) Follow-ups (external): map mcp-commerce-store.deco.site to the service and register the new redirect_uri in the Shopify Partners app. Co-Authored-By: Claude Opus 4.8 --- shopify/app.json | 2 +- shopify/server/lib/oauth.test.ts | 6 +++--- shopify/server/lib/oauth.ts | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/shopify/app.json b/shopify/app.json index 78fd295b..3dffb5dd 100644 --- a/shopify/app.json +++ b/shopify/app.json @@ -4,7 +4,7 @@ "friendlyName": "Shopify", "connection": { "type": "HTTP", - "url": "https://sites-shopify.deco.site/mcp" + "url": "https://mcp-commerce-store.deco.site/mcp" }, "description": "MCP for the Shopify Admin GraphQL API — read products, collections, orders, draft orders, customers, inventory, fulfillment, discounts, online store content, B2B, markets, Shopify Payments and ShopifyQL analytics, plus edit theme files (Liquid & assets).", "icon": "https://github.com/shopify.png", diff --git a/shopify/server/lib/oauth.test.ts b/shopify/server/lib/oauth.test.ts index da274834..1ab90755 100644 --- a/shopify/server/lib/oauth.test.ts +++ b/shopify/server/lib/oauth.test.ts @@ -13,7 +13,7 @@ import { } from "./token.ts"; import { createHmac } from "node:crypto"; -const SELF = "https://sites-shopify.deco.site"; +const SELF = "https://mcp-commerce-store.deco.site"; const MESH = "https://api.decocms.com"; const SECRET = "oauth-test-secret"; const CLIENT_ID = "test-client-id"; @@ -58,7 +58,7 @@ describe("authorizationUrl", () => { test("defaults to the prod domain (not localhost) when SELF_URL is unset", () => { delete process.env.SELF_URL; const url = new URL(shopifyOAuth.authorizationUrl(CALLBACK)); - expect(url.origin).toBe("https://sites-shopify.deco.site"); + expect(url.origin).toBe("https://mcp-commerce-store.deco.site"); }); }); @@ -167,7 +167,7 @@ describe("GET /oauth/custom", () => { }); }); -describe("GET /oauth/shopify/callback", () => { +describe("GET /oauth/store/callback", () => { function callbackUrl(overrides: Record = {}): string { const state = signState({ cb: CALLBACK }, SECRET); const base: Record = { diff --git a/shopify/server/lib/oauth.ts b/shopify/server/lib/oauth.ts index 8edf44ba..4ca72840 100644 --- a/shopify/server/lib/oauth.ts +++ b/shopify/server/lib/oauth.ts @@ -13,7 +13,7 @@ * 2. `/oauth/custom` renders a form; on submit it 302s to Shopify's * `/admin/oauth/authorize` with `redirect_uri` pointing back at us and the * mesh callback URL signed into `state`. - * 3. Shopify → `/oauth/shopify/callback?code&shop&state&hmac`. We verify the + * 3. Shopify → `/oauth/store/callback?code&shop&state&hmac`. We verify the * HMAC + state, exchange the code for an *expiring* offline token, seal the * `{shop, access, refresh, expiresIn}` grant into an encrypted blob, and * 302 back to the mesh callback with it as `code`. @@ -41,7 +41,9 @@ import { } from "./token.ts"; export const OAUTH_CONNECT_PATH = "/oauth/custom"; -export const OAUTH_CALLBACK_PATH = "/oauth/shopify/callback"; +// Kept free of the "shopify" token (Shopify forbids it in app URLs) and distinct +// from `/oauth/callback`, which the runtime mounts on this same origin. +export const OAUTH_CALLBACK_PATH = "/oauth/store/callback"; /** * Scopes requested during the grant. Almost all are read scopes; `write_themes` @@ -82,7 +84,7 @@ export function getScopes(): string { /** This MCP's own public origin. Deployed at a fixed domain, so we default to * it; override with SELF_URL for local dev (e.g. http://localhost:8001). */ -const DEFAULT_SELF_URL = "https://sites-shopify.deco.site"; +const DEFAULT_SELF_URL = "https://mcp-commerce-store.deco.site"; interface OAuthEnv { clientId: string; @@ -374,7 +376,7 @@ function handleConnect(url: URL, env: OAuthEnv): Response { return Response.redirect(authorize.toString(), 302); } -/** GET /oauth/shopify/callback — validate Shopify's redirect, exchange the code +/** GET /oauth/store/callback — validate Shopify's redirect, exchange the code * for an expiring offline token, seal the grant, and bounce back to the mesh * callback. */ async function handleCallback(url: URL, env: OAuthEnv): Promise { From 8fff1eb2762084f94d354501b832ec0abcadf2da Mon Sep 17 00:00:00 2001 From: guitavano Date: Tue, 18 Aug 2026 17:23:51 -0300 Subject: [PATCH 2/2] chore: rebuild registry.json for shopify host change Co-Authored-By: Claude Opus 4.8 --- registry.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry.json b/registry.json index 470a4b82..ef46219c 100644 --- a/registry.json +++ b/registry.json @@ -3059,7 +3059,7 @@ "remotes": [ { "type": "HTTP", - "url": "https://sites-shopify.deco.site/mcp", + "url": "https://mcp-commerce-store.deco.site/mcp", "name": "shopify", "title": "Shopify", "description": "MCP for the Shopify Admin GraphQL API — read products, collections, orders, draft orders, customers, inventory, fulfillment, discounts, online store content, B2B, markets, Shopify Payments and ShopifyQL analytics, plus edit theme files (Liquid & assets)."