Skip to content

Commit 701f003

Browse files
JonasJesus42claude
andauthored
feat(magento): use connection-level Authorization token instead of form field (#518)
Removes apiToken from the configSchema form and StateSchema — users now set their Magento integration token in the encrypted Token field of the HTTP connection. resolveCredentials reads MESH_REQUEST_CONTEXT.authorization (strips Bearer prefix) with MAGENTO_API_TOKEN env var as a local fallback. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 843251b commit 701f003

9 files changed

Lines changed: 28 additions & 29 deletions

File tree

magento/app.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@
1313
"title": "Base URL",
1414
"description": "Magento store base URL, e.g. https://loja.granado.com.br (no trailing slash, no /rest)"
1515
},
16-
"apiToken": {
17-
"type": "string",
18-
"title": "API Token",
19-
"description": "Magento integration access token (sent as Authorization: Bearer)",
20-
"format": "password"
21-
},
2216
"storeCode": {
2317
"type": "string",
2418
"title": "Store Code",
@@ -49,7 +43,7 @@
4943
}
5044
}
5145
},
52-
"required": ["baseUrl", "apiToken"]
46+
"required": ["baseUrl"]
5347
}
5448
},
5549
"description": "MCP for Magento 2 REST APIs — live sales dashboard widgets (orders per hour, sales cards, cancellation rate, top products, status breakdown) plus curated tools for orders, catalog, customers, inventory and CMS.",

magento/server/lib/client.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const INITIAL_RETRY_DELAY_MS = 500;
1414
export const DEFAULT_STORE_CODE = "all";
1515
export const DEFAULT_CURRENCY = "BRL";
1616

17-
type CredentialSource = "state" | "env" | "missing";
17+
type CredentialSource = "authorization" | "state" | "env" | "missing";
1818

1919
export interface ResolvedCredentials extends MagentoCredentials {
2020
/** Where each credential value came from — useful for diagnosing missing config. */
@@ -35,15 +35,26 @@ function pickSource(
3535
return { value: "", source: "missing" };
3636
}
3737

38+
export interface MeshRequestContext {
39+
authorization?: string;
40+
state?: Partial<MagentoCredentials>;
41+
}
42+
3843
export function resolveCredentials(
39-
state: Partial<MagentoCredentials> | undefined,
44+
ctx: MeshRequestContext | undefined,
4045
): ResolvedCredentials {
41-
const safeState = state ?? {};
46+
const safeState = ctx?.state ?? {};
47+
4248
const baseUrl = pickSource(safeState.baseUrl, process.env.MAGENTO_BASE_URL);
43-
const apiToken = pickSource(
44-
safeState.apiToken,
45-
process.env.MAGENTO_API_TOKEN,
46-
);
49+
50+
const rawAuth = ctx?.authorization;
51+
const tokenFromAuth = rawAuth
52+
? rawAuth.replace(/^Bearer\s+/i, "")
53+
: undefined;
54+
const apiToken: { value: string; source: CredentialSource } = tokenFromAuth
55+
? { value: tokenFromAuth, source: "authorization" }
56+
: pickSource(undefined, process.env.MAGENTO_API_TOKEN);
57+
4758
const storeCode = pickSource(
4859
safeState.storeCode,
4960
process.env.MAGENTO_STORE_CODE,
@@ -54,11 +65,10 @@ export function resolveCredentials(
5465
);
5566

5667
if (baseUrl.source === "missing") {
57-
const stateKeys = state ? Object.keys(state) : [];
68+
const stateKeys = safeState ? Object.keys(safeState) : [];
5869
console.warn(
5970
"[Magento] resolveCredentials: baseUrl is missing — neither MESH_REQUEST_CONTEXT.state.baseUrl nor process.env.MAGENTO_BASE_URL is set.",
6071
JSON.stringify({
61-
receivedStateType: state === undefined ? "undefined" : typeof state,
6272
receivedStateKeys: stateKeys,
6373
envMagentoBaseUrlSet: Boolean(process.env.MAGENTO_BASE_URL),
6474
}),
@@ -94,7 +104,7 @@ export function assertValidCredentials(
94104
}
95105
if (!creds.apiToken) {
96106
throw new Error(
97-
`Magento apiToken is missing${where} — set MESH_REQUEST_CONTEXT.state.apiToken or the MAGENTO_API_TOKEN env var (integration access token).`,
107+
`Magento apiToken is missing${where} — set the Token field in the MCP connection (Authorization: Bearer) or the MAGENTO_API_TOKEN env var (integration access token).`,
98108
);
99109
}
100110
}

magento/server/tools/custom/cancellation-rate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const cancellationRate = (_env: Env) =>
4242
annotations: { readOnlyHint: true },
4343
execute: async ({ context, runtimeContext }) => {
4444
const env = runtimeContext.env as Env;
45-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
45+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
4646
assertValidCredentials(creds, TOOL_ID);
4747

4848
const timezone = creds.timezone ?? DEFAULT_STORE_TIMEZONE;

magento/server/tools/custom/orders-sales-card.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const ordersSalesCard = (_env: Env) =>
5555
annotations: { readOnlyHint: true },
5656
execute: async ({ context, runtimeContext }) => {
5757
const env = runtimeContext.env as Env;
58-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
58+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
5959
assertValidCredentials(creds, TOOL_ID);
6060

6161
const timezone = creds.timezone ?? DEFAULT_STORE_TIMEZONE;

magento/server/tools/custom/orders-timeline.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export const ordersTimeline = (_env: Env) =>
3636
annotations: { readOnlyHint: true },
3737
execute: async ({ runtimeContext }) => {
3838
const env = runtimeContext.env as Env;
39-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
39+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
4040
assertValidCredentials(creds, TOOL_ID);
4141

4242
const timezone = creds.timezone ?? DEFAULT_STORE_TIMEZONE;

magento/server/tools/custom/status-breakdown.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const statusBreakdown = (_env: Env) =>
4848
annotations: { readOnlyHint: true },
4949
execute: async ({ context, runtimeContext }) => {
5050
const env = runtimeContext.env as Env;
51-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
51+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
5252
assertValidCredentials(creds, TOOL_ID);
5353

5454
const timezone = creds.timezone ?? DEFAULT_STORE_TIMEZONE;

magento/server/tools/custom/top-products.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const topProducts = (_env: Env) =>
6262
annotations: { readOnlyHint: true },
6363
execute: async ({ context, runtimeContext }) => {
6464
const env = runtimeContext.env as Env;
65-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
65+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
6666
assertValidCredentials(creds, TOOL_ID);
6767

6868
const timezone = creds.timezone ?? DEFAULT_STORE_TIMEZONE;

magento/server/tools/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function createSearchTool(config: {
7171
annotations: { readOnlyHint: true },
7272
execute: async ({ context, runtimeContext }) => {
7373
const env = runtimeContext.env as Env;
74-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
74+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
7575
assertValidCredentials(creds, config.id);
7676

7777
const params = buildSearchCriteriaParams({
@@ -115,7 +115,7 @@ function createGetTool<TSchema extends z.ZodObject<z.ZodRawShape>>(config: {
115115
annotations: { readOnlyHint: true },
116116
execute: async ({ context, runtimeContext }) => {
117117
const env = runtimeContext.env as Env;
118-
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT?.state);
118+
const creds = resolveCredentials(env.MESH_REQUEST_CONTEXT);
119119
assertValidCredentials(creds, config.id);
120120

121121
const input = context as z.infer<TSchema>;

magento/server/types/env.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ export const StateSchema = z.object({
1010
.describe(
1111
"Magento store base URL, e.g. https://loja.granado.com.br (no trailing slash, no /rest)",
1212
),
13-
apiToken: z
14-
.string()
15-
.describe(
16-
"Magento integration access token, sent as Authorization: Bearer",
17-
),
1813
storeCode: z
1914
.string()
2015
.optional()

0 commit comments

Comments
 (0)