@lehaotech/walmart-mcp 0.5.4

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.
Files changed (87) hide show
  1. package/.env.example +25 -0
  2. package/CHANGELOG.md +247 -0
  3. package/LICENSE +21 -0
  4. package/README.md +344 -0
  5. package/build/api/advertising/ad-client.d.ts +24 -0
  6. package/build/api/advertising/ad-client.js +174 -0
  7. package/build/api/advertising/advertising-api.d.ts +50 -0
  8. package/build/api/advertising/advertising-api.js +89 -0
  9. package/build/api/client.d.ts +19 -0
  10. package/build/api/client.js +150 -0
  11. package/build/api/feeds/feeds-api.d.ts +15 -0
  12. package/build/api/feeds/feeds-api.js +53 -0
  13. package/build/api/fulfillment/fulfillment-api.d.ts +37 -0
  14. package/build/api/fulfillment/fulfillment-api.js +81 -0
  15. package/build/api/index.d.ts +44 -0
  16. package/build/api/index.js +56 -0
  17. package/build/api/inventory/inventory-api.d.ts +27 -0
  18. package/build/api/inventory/inventory-api.js +49 -0
  19. package/build/api/items/items-api.d.ts +33 -0
  20. package/build/api/items/items-api.js +67 -0
  21. package/build/api/notifications/notifications-api.d.ts +14 -0
  22. package/build/api/notifications/notifications-api.js +33 -0
  23. package/build/api/orders/orders-api.d.ts +32 -0
  24. package/build/api/orders/orders-api.js +47 -0
  25. package/build/api/pricing/pricing-api.d.ts +32 -0
  26. package/build/api/pricing/pricing-api.js +60 -0
  27. package/build/api/reports/reports-api.d.ts +37 -0
  28. package/build/api/reports/reports-api.js +51 -0
  29. package/build/api/returns/returns-api.d.ts +26 -0
  30. package/build/api/returns/returns-api.js +37 -0
  31. package/build/api/settings/settings-api.d.ts +9 -0
  32. package/build/api/settings/settings-api.js +21 -0
  33. package/build/auth/oauth.d.ts +16 -0
  34. package/build/auth/oauth.js +125 -0
  35. package/build/config/environment.d.ts +22 -0
  36. package/build/config/environment.js +50 -0
  37. package/build/index.d.ts +2 -0
  38. package/build/index.js +180 -0
  39. package/build/scripts/client-configs.d.ts +36 -0
  40. package/build/scripts/client-configs.js +132 -0
  41. package/build/scripts/diagnose.d.ts +15 -0
  42. package/build/scripts/diagnose.js +320 -0
  43. package/build/scripts/setup.d.ts +17 -0
  44. package/build/scripts/setup.js +276 -0
  45. package/build/tools/definitions/advertising.d.ts +664 -0
  46. package/build/tools/definitions/advertising.js +315 -0
  47. package/build/tools/definitions/discovery.d.ts +24 -0
  48. package/build/tools/definitions/discovery.js +65 -0
  49. package/build/tools/definitions/feeds.d.ts +46 -0
  50. package/build/tools/definitions/feeds.js +42 -0
  51. package/build/tools/definitions/fulfillment.d.ts +1127 -0
  52. package/build/tools/definitions/fulfillment.js +272 -0
  53. package/build/tools/definitions/inventory.d.ts +392 -0
  54. package/build/tools/definitions/inventory.js +182 -0
  55. package/build/tools/definitions/items.d.ts +447 -0
  56. package/build/tools/definitions/items.js +223 -0
  57. package/build/tools/definitions/notifications.d.ts +84 -0
  58. package/build/tools/definitions/notifications.js +73 -0
  59. package/build/tools/definitions/orders.d.ts +2659 -0
  60. package/build/tools/definitions/orders.js +298 -0
  61. package/build/tools/definitions/pricing.d.ts +724 -0
  62. package/build/tools/definitions/pricing.js +254 -0
  63. package/build/tools/definitions/reports.d.ts +223 -0
  64. package/build/tools/definitions/reports.js +144 -0
  65. package/build/tools/definitions/returns.d.ts +441 -0
  66. package/build/tools/definitions/returns.js +126 -0
  67. package/build/tools/definitions/settings.d.ts +100 -0
  68. package/build/tools/definitions/settings.js +52 -0
  69. package/build/tools/definitions/shared-schemas.d.ts +40 -0
  70. package/build/tools/definitions/shared-schemas.js +47 -0
  71. package/build/tools/definitions/token-management.d.ts +16 -0
  72. package/build/tools/definitions/token-management.js +41 -0
  73. package/build/tools/index.d.ts +6924 -0
  74. package/build/tools/index.js +379 -0
  75. package/build/utils/api-error.d.ts +41 -0
  76. package/build/utils/api-error.js +97 -0
  77. package/build/utils/endpoint-catalog.d.ts +22 -0
  78. package/build/utils/endpoint-catalog.js +89 -0
  79. package/build/utils/env-file.d.ts +12 -0
  80. package/build/utils/env-file.js +27 -0
  81. package/build/utils/known-issues.d.ts +29 -0
  82. package/build/utils/known-issues.js +122 -0
  83. package/build/utils/logger.d.ts +15 -0
  84. package/build/utils/logger.js +56 -0
  85. package/build/utils/rate-limiter.d.ts +51 -0
  86. package/build/utils/rate-limiter.js +109 -0
  87. package/package.json +1 -0
@@ -0,0 +1,21 @@
1
+ export class SettingsApi {
2
+ client;
3
+ constructor(client) {
4
+ this.client = client;
5
+ }
6
+ async getShippingSettings() {
7
+ return await this.client.get('/v3/settings/shipping');
8
+ }
9
+ async updateShippingSettings(data) {
10
+ return await this.client.put('/v3/settings/shipping', data);
11
+ }
12
+ async getFulfillmentCenters() {
13
+ return await this.client.get('/v3/settings/shippingprofile');
14
+ }
15
+ async getPartnerInfo() {
16
+ // Walmart has no dedicated partner endpoint; the seller/partner record is
17
+ // returned as the `partner` object on the shipping-profile settings payload.
18
+ const data = await this.client.get('/v3/settings/shippingprofile');
19
+ return data?.partner ?? data;
20
+ }
21
+ }
@@ -0,0 +1,16 @@
1
+ import { type WalmartConfig } from '../config/environment.js';
2
+ export declare class WalmartOAuthClient {
3
+ private config;
4
+ private accessToken;
5
+ private tokenExpiry;
6
+ private isRefreshing;
7
+ private refreshPromise;
8
+ constructor(config: WalmartConfig);
9
+ initialize(): Promise<void>;
10
+ getAccessToken(): Promise<string>;
11
+ refreshToken(): Promise<void>;
12
+ private _doRefresh;
13
+ getTokenDetail(): Promise<object>;
14
+ getTokenInfo(): object;
15
+ private updateEnvFile;
16
+ }
@@ -0,0 +1,125 @@
1
+ import axios from 'axios';
2
+ import { randomUUID } from 'crypto';
3
+ import { getBaseUrl } from '../config/environment.js';
4
+ import { authLogger } from '../utils/logger.js';
5
+ import { upsertEnvVars } from '../utils/env-file.js';
6
+ export class WalmartOAuthClient {
7
+ config;
8
+ accessToken = null;
9
+ tokenExpiry = 0;
10
+ isRefreshing = false;
11
+ refreshPromise = null;
12
+ constructor(config) {
13
+ this.config = config;
14
+ }
15
+ async initialize() {
16
+ if (this.config.accessToken && this.config.accessTokenExpiry) {
17
+ this.accessToken = this.config.accessToken;
18
+ this.tokenExpiry = this.config.accessTokenExpiry;
19
+ if (Date.now() < this.tokenExpiry - 120_000) {
20
+ authLogger.info('Loaded cached token from .env');
21
+ return;
22
+ }
23
+ }
24
+ try {
25
+ await this.refreshToken();
26
+ }
27
+ catch (error) {
28
+ authLogger.warn('Initial token fetch failed (credentials may not be configured yet)');
29
+ }
30
+ }
31
+ async getAccessToken() {
32
+ // Token valid and more than 2 min remaining
33
+ if (this.accessToken && Date.now() < this.tokenExpiry - 120_000) {
34
+ return this.accessToken;
35
+ }
36
+ // Prevent concurrent refresh
37
+ if (this.isRefreshing && this.refreshPromise) {
38
+ await this.refreshPromise;
39
+ return this.accessToken;
40
+ }
41
+ await this.refreshToken();
42
+ return this.accessToken;
43
+ }
44
+ async refreshToken() {
45
+ this.isRefreshing = true;
46
+ this.refreshPromise = this._doRefresh();
47
+ try {
48
+ await this.refreshPromise;
49
+ }
50
+ finally {
51
+ this.isRefreshing = false;
52
+ this.refreshPromise = null;
53
+ }
54
+ }
55
+ async _doRefresh() {
56
+ if (!this.config.clientId || !this.config.clientSecret) {
57
+ throw new Error('Walmart API credentials are not configured. Set WALMART_CLIENT_ID and '
58
+ + 'WALMART_CLIENT_SECRET in your MCP server "env" (or a .env file), or call the '
59
+ + 'walmart_set_credentials tool with your Client ID and Secret. '
60
+ + 'Get credentials at https://developer.walmart.com/. '
61
+ + 'Run the walmart_setup_guide tool for step-by-step setup.');
62
+ }
63
+ const baseUrl = getBaseUrl(this.config.environment);
64
+ const credentials = Buffer.from(`${this.config.clientId}:${this.config.clientSecret}`).toString('base64');
65
+ authLogger.info(`Requesting token from ${this.config.environment} environment`);
66
+ try {
67
+ const response = await axios.post(`${baseUrl}/v3/token`, 'grant_type=client_credentials', {
68
+ headers: {
69
+ 'Authorization': `Basic ${credentials}`,
70
+ 'Content-Type': 'application/x-www-form-urlencoded',
71
+ 'Accept': 'application/json',
72
+ 'WM_QOS.CORRELATION_ID': randomUUID(),
73
+ 'WM_SVC.NAME': this.config.svcName,
74
+ },
75
+ timeout: 15_000,
76
+ });
77
+ this.accessToken = response.data.access_token;
78
+ this.tokenExpiry = Date.now() + response.data.expires_in * 1000;
79
+ authLogger.info(`Token obtained, expires in ${response.data.expires_in}s`);
80
+ this.updateEnvFile({
81
+ WALMART_ACCESS_TOKEN: this.accessToken,
82
+ WALMART_ACCESS_TOKEN_EXPIRY: String(this.tokenExpiry),
83
+ });
84
+ }
85
+ catch (error) {
86
+ const msg = axios.isAxiosError(error)
87
+ ? error.response?.data?.error_description || error.message
88
+ : String(error);
89
+ authLogger.error(`Token refresh failed: ${msg}`);
90
+ throw new Error(`Authentication failed: ${msg}`);
91
+ }
92
+ }
93
+ async getTokenDetail() {
94
+ const token = await this.getAccessToken();
95
+ const baseUrl = getBaseUrl(this.config.environment);
96
+ const response = await axios.get(`${baseUrl}/v3/token/detail`, {
97
+ headers: {
98
+ 'WM_SEC.ACCESS_TOKEN': token,
99
+ 'WM_QOS.CORRELATION_ID': randomUUID(),
100
+ 'WM_SVC.NAME': this.config.svcName,
101
+ 'Content-Type': 'application/json',
102
+ },
103
+ timeout: 15_000,
104
+ });
105
+ return response.data;
106
+ }
107
+ getTokenInfo() {
108
+ return {
109
+ hasToken: !!this.accessToken,
110
+ expiresAt: this.tokenExpiry ? new Date(this.tokenExpiry).toISOString() : null,
111
+ expiresInSeconds: this.tokenExpiry
112
+ ? Math.max(0, Math.round((this.tokenExpiry - Date.now()) / 1000))
113
+ : 0,
114
+ environment: this.config.environment,
115
+ };
116
+ }
117
+ updateEnvFile(updates) {
118
+ try {
119
+ upsertEnvVars(updates);
120
+ }
121
+ catch {
122
+ // Silent failure - don't interfere with MCP stdout
123
+ }
124
+ }
125
+ }
@@ -0,0 +1,22 @@
1
+ export type WalmartEnvironment = 'sandbox' | 'production';
2
+ export type WalmartMarket = 'us' | 'CA' | 'mx';
3
+ export interface WalmartConfig {
4
+ clientId: string;
5
+ clientSecret: string;
6
+ environment: WalmartEnvironment;
7
+ market: WalmartMarket;
8
+ svcName: string;
9
+ consumerChannelType?: string;
10
+ partnerId?: string;
11
+ accessToken?: string;
12
+ accessTokenExpiry?: number;
13
+ logLevel: string;
14
+ enableFileLogging: boolean;
15
+ adConsumerId?: string;
16
+ adPrivateKey?: string;
17
+ adKeyVersion?: string;
18
+ }
19
+ export declare function getBaseUrl(env: WalmartEnvironment): string;
20
+ export declare function getAdBaseUrl(env: WalmartEnvironment): string;
21
+ export declare function getConfig(): WalmartConfig;
22
+ export declare function validateConfig(config: WalmartConfig): void;
@@ -0,0 +1,50 @@
1
+ import * as dotenv from 'dotenv';
2
+ dotenv.config();
3
+ const BASE_URLS = {
4
+ production: 'https://marketplace.walmartapis.com',
5
+ sandbox: 'https://sandbox.walmartapis.com',
6
+ };
7
+ const AD_BASE_URLS = {
8
+ production: 'https://developer.api.walmart.com/api-proxy/service/WPA/Api',
9
+ sandbox: 'https://developer.api.stg.walmart.com/api-proxy/service/WPA/Api',
10
+ };
11
+ export function getBaseUrl(env) {
12
+ return BASE_URLS[env];
13
+ }
14
+ export function getAdBaseUrl(env) {
15
+ return AD_BASE_URLS[env];
16
+ }
17
+ export function getConfig() {
18
+ return {
19
+ clientId: process.env.WALMART_CLIENT_ID || '',
20
+ clientSecret: process.env.WALMART_CLIENT_SECRET || '',
21
+ environment: process.env.WALMART_ENVIRONMENT || 'sandbox',
22
+ market: process.env.WALMART_MARKET || 'us',
23
+ svcName: process.env.WALMART_SVC_NAME || 'Walmart Marketplace',
24
+ consumerChannelType: process.env.WALMART_CONSUMER_CHANNEL_TYPE || undefined,
25
+ partnerId: process.env.WALMART_PARTNER_ID || undefined,
26
+ accessToken: process.env.WALMART_ACCESS_TOKEN || undefined,
27
+ accessTokenExpiry: process.env.WALMART_ACCESS_TOKEN_EXPIRY
28
+ ? parseInt(process.env.WALMART_ACCESS_TOKEN_EXPIRY, 10)
29
+ : undefined,
30
+ logLevel: process.env.WALMART_LOG_LEVEL || 'info',
31
+ enableFileLogging: process.env.WALMART_ENABLE_FILE_LOGGING === 'true',
32
+ adConsumerId: process.env.WALMART_AD_CONSUMER_ID || undefined,
33
+ adPrivateKey: process.env.WALMART_AD_PRIVATE_KEY || undefined,
34
+ adKeyVersion: process.env.WALMART_AD_KEY_VERSION || '1',
35
+ };
36
+ }
37
+ export function validateConfig(config) {
38
+ if (!config.clientId || !config.clientSecret) {
39
+ console.error('\n┌─ walmart-mcp: setup required ────────────────────────────────────\n'
40
+ + '│ No API credentials found. The server will start, but Walmart calls\n'
41
+ + '│ will fail until you provide credentials. To fix:\n'
42
+ + '│ 1. Get a Client ID + Secret at https://developer.walmart.com/\n'
43
+ + '│ 2. Set WALMART_CLIENT_ID and WALMART_CLIENT_SECRET in your MCP\n'
44
+ + '│ server "env" (or a .env file), then restart — OR call the\n'
45
+ + '│ walmart_set_credentials tool at runtime.\n'
46
+ + '│ Run the walmart_setup_guide tool for full setup steps.\n'
47
+ + `│ Environment: ${config.environment} Market: ${config.market}\n`
48
+ + '└──────────────────────────────────────────────────────────────────\n');
49
+ }
50
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/build/index.js ADDED
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { z, ZodError } from 'zod';
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { getConfig, validateConfig } from './config/environment.js';
9
+ import { WalmartSellerApi } from './api/index.js';
10
+ import { getToolDefinitions, executeTool } from './tools/index.js';
11
+ import { serverLogger } from './utils/logger.js';
12
+ import { WalmartApiError } from './utils/api-error.js';
13
+ // Resolve package.json once at module load so the MCP server's reported
14
+ // version stays in lockstep with what's actually installed. Avoids drift like
15
+ // the earlier hard-coded '0.3.2' which lagged through five releases.
16
+ function readPackageVersion() {
17
+ try {
18
+ const here = dirname(fileURLToPath(import.meta.url));
19
+ // build/index.js -> ../package.json. Works the same when running via tsx
20
+ // from src/ because tsx evaluates in place under the repo root.
21
+ const pkgPath = join(here, '..', 'package.json');
22
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
23
+ return pkg.version ?? '0.0.0';
24
+ }
25
+ catch {
26
+ return '0.0.0';
27
+ }
28
+ }
29
+ const PACKAGE_VERSION = readPackageVersion();
30
+ class WalmartMcpServer {
31
+ server;
32
+ api;
33
+ constructor() {
34
+ const config = getConfig();
35
+ validateConfig(config);
36
+ this.server = new McpServer({
37
+ name: 'walmart-mcp',
38
+ version: PACKAGE_VERSION,
39
+ });
40
+ this.api = new WalmartSellerApi(config);
41
+ this.setupHandlers();
42
+ }
43
+ setupHandlers() {
44
+ const tools = getToolDefinitions();
45
+ serverLogger.info(`Registering ${tools.length} tools`);
46
+ for (const toolDef of tools) {
47
+ const hasSchema = Object.keys(toolDef.inputSchema).length > 0;
48
+ this.server.registerTool(toolDef.name, {
49
+ description: toolDef.description,
50
+ inputSchema: hasSchema
51
+ ? toolDef.inputSchema
52
+ : undefined,
53
+ }, async (rawArgs) => {
54
+ // Re-parse args through the tool's zod schema. The MCP SDK does shape
55
+ // validation against the inputSchema, but explicit z.object(...).parse
56
+ // here also runs any .refine() business rules and fills in defaults so
57
+ // the downstream dispatcher always sees a fully-resolved payload.
58
+ let args = rawArgs;
59
+ try {
60
+ if (hasSchema) {
61
+ const schemaObj = z.object(toolDef.inputSchema);
62
+ args = schemaObj.parse(rawArgs);
63
+ }
64
+ }
65
+ catch (validationError) {
66
+ if (validationError instanceof ZodError) {
67
+ serverLogger.warn(`Tool ${toolDef.name} input validation failed: ${validationError.message}`);
68
+ return {
69
+ content: [{
70
+ type: 'text',
71
+ text: JSON.stringify({
72
+ error: 'Input validation failed before any Walmart API call.',
73
+ tool: toolDef.name,
74
+ issues: validationError.issues.map((iss) => ({
75
+ path: iss.path,
76
+ message: iss.message,
77
+ code: iss.code,
78
+ })),
79
+ }, null, 2),
80
+ }],
81
+ isError: true,
82
+ };
83
+ }
84
+ throw validationError;
85
+ }
86
+ try {
87
+ const result = await executeTool(this.api, toolDef.name, args);
88
+ return {
89
+ content: [{
90
+ type: 'text',
91
+ text: JSON.stringify(result, null, 2),
92
+ }],
93
+ };
94
+ }
95
+ catch (error) {
96
+ const errorMsg = error instanceof Error ? error.message : String(error);
97
+ serverLogger.error(`Tool ${toolDef.name} failed: ${errorMsg}`);
98
+ let payload;
99
+ if (error instanceof WalmartApiError) {
100
+ // Attach the MCP tool name so the LLM can correlate the failing
101
+ // call to a tool it knows about. endpoint + hint are already set
102
+ // by the API client's interceptor.
103
+ error.tool = toolDef.name;
104
+ payload = error.toResponse();
105
+ }
106
+ else {
107
+ payload = { error: errorMsg, tool: toolDef.name };
108
+ }
109
+ return {
110
+ content: [{
111
+ type: 'text',
112
+ text: JSON.stringify(payload, null, 2),
113
+ }],
114
+ isError: true,
115
+ };
116
+ }
117
+ });
118
+ }
119
+ }
120
+ async run() {
121
+ await this.api.initialize();
122
+ const transport = new StdioServerTransport();
123
+ await this.server.connect(transport);
124
+ serverLogger.info('Walmart MCP Server running on stdio');
125
+ process.on('SIGINT', async () => {
126
+ serverLogger.info('Shutting down...');
127
+ await this.server.close();
128
+ process.exit(0);
129
+ });
130
+ process.on('SIGTERM', async () => {
131
+ serverLogger.info('Shutting down...');
132
+ await this.server.close();
133
+ process.exit(0);
134
+ });
135
+ }
136
+ }
137
+ // ============================================================
138
+ // Subcommand dispatch — make a single bin handle:
139
+ // walmart-mcp -> run the MCP server (default)
140
+ // walmart-mcp setup -> run the interactive setup wizard
141
+ // walmart-mcp diagnose -> run the self-check (--export OK)
142
+ // walmart-mcp version -> print the package version
143
+ // Everything after the subcommand is forwarded as process.argv to the
144
+ // child script (so `walmart-mcp diagnose --export` works).
145
+ // ============================================================
146
+ const subcommand = process.argv[2];
147
+ async function dispatch() {
148
+ if (subcommand === 'setup') {
149
+ process.argv = [process.argv[0], 'setup', ...process.argv.slice(3)];
150
+ await import('./scripts/setup.js');
151
+ return;
152
+ }
153
+ if (subcommand === 'diagnose') {
154
+ process.argv = [process.argv[0], 'diagnose', ...process.argv.slice(3)];
155
+ await import('./scripts/diagnose.js');
156
+ return;
157
+ }
158
+ if (subcommand === 'version' || subcommand === '--version' || subcommand === '-v') {
159
+ console.log(`walmart-mcp v${PACKAGE_VERSION}`);
160
+ return;
161
+ }
162
+ if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h') {
163
+ console.log('walmart-mcp — Walmart Marketplace MCP server');
164
+ console.log('');
165
+ console.log('Usage:');
166
+ console.log(' walmart-mcp Run the MCP server over stdio (default).');
167
+ console.log(' walmart-mcp setup Interactive setup wizard.');
168
+ console.log(' walmart-mcp diagnose Self-check (env / token / config).');
169
+ console.log(' walmart-mcp version Print version.');
170
+ console.log('');
171
+ console.log('Docs: https://github.com/yufakang0826-hue/walmart-mcp');
172
+ return;
173
+ }
174
+ const server = new WalmartMcpServer();
175
+ await server.run();
176
+ }
177
+ dispatch().catch((error) => {
178
+ console.error('Fatal error:', error);
179
+ process.exit(1);
180
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * MCP client config detection + write helpers used by `npm run setup`.
3
+ *
4
+ * Each client uses a slightly different config schema. Most follow Claude
5
+ * Desktop's `{ mcpServers: { name: { command, args, env } } }` shape, but
6
+ * Cursor and Zed differ.
7
+ */
8
+ export type ClientId = 'claude-desktop' | 'claude-code-cli' | 'cursor' | 'cline' | 'continue' | 'windsurf' | 'zed';
9
+ export interface ClientSpec {
10
+ id: ClientId;
11
+ name: string;
12
+ /** Get the OS-resolved absolute config path for this client. */
13
+ resolvePath: () => string | null;
14
+ /** How the `mcpServers` block is keyed in this client's config. */
15
+ serverKey: 'mcpServers' | 'servers';
16
+ }
17
+ export declare const CLIENT_SPECS: ReadonlyArray<ClientSpec>;
18
+ /** Returns the subset of clients whose config files already exist. */
19
+ export declare function detectInstalled(): ReadonlyArray<ClientSpec & {
20
+ path: string;
21
+ }>;
22
+ export interface WalmartMcpEntry {
23
+ type: 'stdio';
24
+ command: 'node';
25
+ args: string[];
26
+ env: Record<string, string>;
27
+ }
28
+ /**
29
+ * Read existing config (or start from empty), insert / overwrite the
30
+ * `walmart` entry under the appropriate server-key, and write back. Backs up
31
+ * the original to `.before-walmart-setup.bak` on first write.
32
+ */
33
+ export declare function writeWalmartEntry(spec: ClientSpec, configPath: string, walmartEntry: WalmartMcpEntry): {
34
+ backedUp: boolean;
35
+ overwrote: boolean;
36
+ };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * MCP client config detection + write helpers used by `npm run setup`.
3
+ *
4
+ * Each client uses a slightly different config schema. Most follow Claude
5
+ * Desktop's `{ mcpServers: { name: { command, args, env } } }` shape, but
6
+ * Cursor and Zed differ.
7
+ */
8
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
9
+ import { join, dirname } from 'node:path';
10
+ import { homedir, platform } from 'node:os';
11
+ const APP_DATA = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
12
+ const LOCAL_APP_DATA = process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local');
13
+ export const CLIENT_SPECS = [
14
+ {
15
+ id: 'claude-desktop',
16
+ name: 'Claude Desktop',
17
+ serverKey: 'mcpServers',
18
+ resolvePath: () => {
19
+ const plat = platform();
20
+ if (plat === 'darwin') {
21
+ return join(homedir(), 'Library/Application Support/Claude/claude_desktop_config.json');
22
+ }
23
+ if (plat === 'win32') {
24
+ return join(APP_DATA, 'Claude', 'claude_desktop_config.json');
25
+ }
26
+ return join(homedir(), '.config/Claude/claude_desktop_config.json');
27
+ },
28
+ },
29
+ {
30
+ id: 'claude-code-cli',
31
+ name: 'Claude Code CLI',
32
+ serverKey: 'mcpServers',
33
+ resolvePath: () => join(homedir(), '.claude.json'),
34
+ },
35
+ {
36
+ id: 'cursor',
37
+ name: 'Cursor',
38
+ serverKey: 'mcpServers',
39
+ resolvePath: () => join(homedir(), '.cursor', 'mcp.json'),
40
+ },
41
+ {
42
+ id: 'cline',
43
+ name: 'Cline (VSCode extension)',
44
+ serverKey: 'mcpServers',
45
+ resolvePath: () => {
46
+ const plat = platform();
47
+ const segment = 'User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json';
48
+ if (plat === 'darwin') {
49
+ return join(homedir(), 'Library/Application Support/Code', segment);
50
+ }
51
+ if (plat === 'win32') {
52
+ return join(APP_DATA, 'Code', segment);
53
+ }
54
+ return join(homedir(), '.config/Code', segment);
55
+ },
56
+ },
57
+ {
58
+ id: 'continue',
59
+ name: 'Continue.dev',
60
+ serverKey: 'mcpServers',
61
+ resolvePath: () => join(homedir(), '.continue', 'config.json'),
62
+ },
63
+ {
64
+ id: 'windsurf',
65
+ name: 'Windsurf (Codeium)',
66
+ serverKey: 'mcpServers',
67
+ resolvePath: () => join(homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
68
+ },
69
+ {
70
+ id: 'zed',
71
+ name: 'Zed Editor',
72
+ serverKey: 'servers',
73
+ resolvePath: () => {
74
+ const plat = platform();
75
+ if (plat === 'darwin') {
76
+ return join(homedir(), 'Library/Application Support/Zed/settings.json');
77
+ }
78
+ if (plat === 'win32') {
79
+ return join(LOCAL_APP_DATA, 'Zed', 'settings.json');
80
+ }
81
+ return join(homedir(), '.config/zed/settings.json');
82
+ },
83
+ },
84
+ ];
85
+ /** Returns the subset of clients whose config files already exist. */
86
+ export function detectInstalled() {
87
+ const found = [];
88
+ for (const spec of CLIENT_SPECS) {
89
+ const p = spec.resolvePath();
90
+ if (p && existsSync(p))
91
+ found.push({ ...spec, path: p });
92
+ }
93
+ return found;
94
+ }
95
+ /**
96
+ * Read existing config (or start from empty), insert / overwrite the
97
+ * `walmart` entry under the appropriate server-key, and write back. Backs up
98
+ * the original to `.before-walmart-setup.bak` on first write.
99
+ */
100
+ export function writeWalmartEntry(spec, configPath, walmartEntry) {
101
+ let backedUp = false;
102
+ let overwrote = false;
103
+ let config = {};
104
+ if (existsSync(configPath)) {
105
+ config = JSON.parse(readFileSync(configPath, 'utf8'));
106
+ const backup = `${configPath}.before-walmart-setup.bak`;
107
+ writeFileSync(backup, readFileSync(configPath));
108
+ backedUp = true;
109
+ }
110
+ else {
111
+ mkdirSync(dirname(configPath), { recursive: true });
112
+ }
113
+ let servers = config[spec.serverKey] ?? {};
114
+ if (spec.id === 'zed') {
115
+ // Zed nests MCP under `mcp.servers`; load the nested level.
116
+ const mcp = config.mcp ?? {};
117
+ servers = mcp.servers ?? {};
118
+ if ('walmart' in servers)
119
+ overwrote = true;
120
+ servers.walmart = walmartEntry;
121
+ mcp.servers = servers;
122
+ config.mcp = mcp;
123
+ }
124
+ else {
125
+ if ('walmart' in servers)
126
+ overwrote = true;
127
+ servers.walmart = walmartEntry;
128
+ config[spec.serverKey] = servers;
129
+ }
130
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
131
+ return { backedUp, overwrote };
132
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * walmart-mcp diagnose
3
+ * ------------------------------------------------------------
4
+ * Self-check script. Run via `npm run diagnose`.
5
+ *
6
+ * Reports environment readiness, credential validity, and MCP-client config
7
+ * presence without revealing credential values. Use `--export` to dump a
8
+ * JSON report suitable for attaching to bug reports.
9
+ *
10
+ * Exit codes:
11
+ * 0 all checks passed (or only warnings)
12
+ * 1 one or more errors — configuration must be fixed before the MCP works
13
+ * 2 fatal (script itself crashed)
14
+ */
15
+ export {};