mcp-google-merchant-center 1.0.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.
Files changed (3) hide show
  1. package/README.md +81 -0
  2. package/index.js +154 -0
  3. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # mcp-google-merchant-center
2
+
3
+ MCP server for Google Merchant Center — read products, check approval statuses, and analyze feeds across multiple accounts.
4
+
5
+ ## Features
6
+
7
+ - List products across multiple Merchant Center accounts
8
+ - Search products by title or brand
9
+ - Get product approval status and issues
10
+ - Inspect data sources and feeds
11
+ - Get account information
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g mcp-google-merchant-center
17
+ ```
18
+
19
+ Or use directly with npx (no install needed):
20
+
21
+ ```json
22
+ {
23
+ "mcpServers": {
24
+ "merchant-mcp": {
25
+ "command": "npx",
26
+ "args": ["-y", "mcp-google-merchant-center"],
27
+ "env": {
28
+ "MERCHANT_ID": "YOUR_DEFAULT_MERCHANT_ID",
29
+ "GOOGLE_APPLICATION_CREDENTIALS": "/path/to/your/application_default_credentials.json"
30
+ }
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## Authentication
37
+
38
+ This server uses Google Application Default Credentials (ADC). Generate them with:
39
+
40
+ ```bash
41
+ gcloud auth application-default login \
42
+ --client-id-file="YOUR_CLIENT_SECRET.json" \
43
+ --scopes="https://www.googleapis.com/auth/content"
44
+ ```
45
+
46
+ The credentials file is saved at `~/.config/gcloud/application_default_credentials.json`.
47
+
48
+ ## Environment Variables
49
+
50
+ | Variable | Required | Description |
51
+ |----------|----------|-------------|
52
+ | `MERCHANT_ID` | Yes | Default Merchant Center account ID |
53
+ | `GOOGLE_APPLICATION_CREDENTIALS` | Yes | Path to ADC credentials JSON file |
54
+
55
+ ## Multiple Accounts
56
+
57
+ All tools accept an optional `merchant_id` parameter to query a specific account:
58
+
59
+ > "List products for merchant 5747906518"
60
+ > "Get product status for account 5443978365"
61
+
62
+ ## Available Tools
63
+
64
+ | Tool | Description |
65
+ |------|-------------|
66
+ | `get_account` | Account info and settings |
67
+ | `list_products` | Browse all products with pagination |
68
+ | `get_product` | Full details for a single product |
69
+ | `search_products` | Filter products by title or brand |
70
+ | `list_data_sources` | List feeds and data sources |
71
+ | `get_product_status` | Approval status and disapproval reasons |
72
+
73
+ ## Requirements
74
+
75
+ - Node.js 18+
76
+ - Google Cloud project with [Merchant API](https://developers.google.com/merchant/api) enabled
77
+ - OAuth 2.0 credentials (Desktop app type)
78
+
79
+ ## License
80
+
81
+ MIT
package/index.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
5
+ import { google } from "googleapis";
6
+
7
+ const DEFAULT_MERCHANT_ID = process.env.MERCHANT_ID;
8
+ const ALLOWED_IDS = ["5291449515", "5747906518", "5443978365"];
9
+ const content = google.content("v2.1");
10
+
11
+ async function getAuth() {
12
+ const auth = new google.auth.GoogleAuth({
13
+ keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS,
14
+ scopes: ["https://www.googleapis.com/auth/content"],
15
+ });
16
+ return auth.getClient();
17
+ }
18
+
19
+ function resolveMerchantId(id) {
20
+ const resolved = id ? String(id) : DEFAULT_MERCHANT_ID;
21
+ if (!ALLOWED_IDS.includes(resolved)) {
22
+ throw new Error(`Merchant ID ${resolved} non autorizzato. ID disponibili: ${ALLOWED_IDS.join(", ")}`);
23
+ }
24
+ return resolved;
25
+ }
26
+
27
+ const merchantIdProp = {
28
+ merchant_id: {
29
+ type: "string",
30
+ description: `Merchant Center ID (opzionale, default ${DEFAULT_MERCHANT_ID}). Disponibili: ${ALLOWED_IDS.join(", ")}`,
31
+ },
32
+ };
33
+
34
+ const server = new Server(
35
+ { name: "merchant-mcp", version: "1.1.0" },
36
+ { capabilities: { tools: {} } }
37
+ );
38
+
39
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
40
+ tools: [
41
+ {
42
+ name: "get_account",
43
+ description: "Recupera informazioni sull'account Merchant Center",
44
+ inputSchema: { type: "object", properties: { ...merchantIdProp } },
45
+ },
46
+ {
47
+ name: "list_products",
48
+ description: "Lista prodotti nel Merchant Center",
49
+ inputSchema: {
50
+ type: "object",
51
+ properties: {
52
+ ...merchantIdProp,
53
+ max_results: { type: "number", description: "Numero massimo di prodotti (default 50)" },
54
+ page_token: { type: "string", description: "Token per paginazione" },
55
+ },
56
+ },
57
+ },
58
+ {
59
+ name: "get_product",
60
+ description: "Recupera dettagli di un prodotto specifico",
61
+ inputSchema: {
62
+ type: "object",
63
+ required: ["product_id"],
64
+ properties: {
65
+ ...merchantIdProp,
66
+ product_id: { type: "string", description: "ID prodotto (es. online:it:IT:123456)" },
67
+ },
68
+ },
69
+ },
70
+ {
71
+ name: "search_products",
72
+ description: "Cerca prodotti per titolo o brand",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: {
76
+ ...merchantIdProp,
77
+ query: { type: "string", description: "Testo da cercare nel titolo o brand" },
78
+ max_results: { type: "number", description: "Numero massimo risultati (default 50)" },
79
+ },
80
+ },
81
+ },
82
+ {
83
+ name: "list_data_sources",
84
+ description: "Lista feed e fonti dati del Merchant Center",
85
+ inputSchema: { type: "object", properties: { ...merchantIdProp } },
86
+ },
87
+ {
88
+ name: "get_product_status",
89
+ description: "Stato di approvazione e issues dei prodotti",
90
+ inputSchema: {
91
+ type: "object",
92
+ properties: {
93
+ ...merchantIdProp,
94
+ max_results: { type: "number", description: "Numero massimo di prodotti (default 50)" },
95
+ },
96
+ },
97
+ },
98
+ ],
99
+ }));
100
+
101
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
102
+ const auth = await getAuth();
103
+ const args = request.params.arguments || {};
104
+
105
+ try {
106
+ const merchantId = resolveMerchantId(args.merchant_id);
107
+
108
+ if (request.params.name === "get_account") {
109
+ const res = await content.accounts.get({ merchantId, accountId: merchantId, auth });
110
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
111
+ }
112
+
113
+ if (request.params.name === "list_products") {
114
+ const { max_results = 50, page_token } = args;
115
+ const res = await content.products.list({ merchantId, maxResults: max_results, pageToken: page_token, auth });
116
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
117
+ }
118
+
119
+ if (request.params.name === "get_product") {
120
+ const res = await content.products.get({ merchantId, productId: args.product_id, auth });
121
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
122
+ }
123
+
124
+ if (request.params.name === "search_products") {
125
+ const { query = "", max_results = 50 } = args;
126
+ const res = await content.products.list({ merchantId, maxResults: 250, auth });
127
+ const products = (res.data.resources || [])
128
+ .filter(p =>
129
+ p.title?.toLowerCase().includes(query.toLowerCase()) ||
130
+ p.brand?.toLowerCase().includes(query.toLowerCase())
131
+ )
132
+ .slice(0, max_results);
133
+ return { content: [{ type: "text", text: JSON.stringify({ products, total: products.length }, null, 2) }] };
134
+ }
135
+
136
+ if (request.params.name === "list_data_sources") {
137
+ const res = await content.datafeeds.list({ merchantId, auth });
138
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
139
+ }
140
+
141
+ if (request.params.name === "get_product_status") {
142
+ const { max_results = 50 } = args;
143
+ const res = await content.productstatuses.list({ merchantId, maxResults: max_results, auth });
144
+ return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
145
+ }
146
+
147
+ return { content: [{ type: "text", text: `Tool sconosciuto: ${request.params.name}` }] };
148
+ } catch (err) {
149
+ return { content: [{ type: "text", text: `Errore: ${err.message}` }], isError: true };
150
+ }
151
+ });
152
+
153
+ const transport = new StdioServerTransport();
154
+ await server.connect(transport);
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "mcp-google-merchant-center",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for Google Merchant Center — list products, check statuses, and analyze feeds across multiple accounts",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "mcp-google-merchant-center": "./index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "model-context-protocol",
16
+ "google-merchant-center",
17
+ "merchant-api",
18
+ "google-shopping",
19
+ "products",
20
+ "ecommerce",
21
+ "claude"
22
+ ],
23
+ "author": "Giovanni Rasulo",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/gioenjoy/mcp-google-merchant-center.git"
28
+ },
29
+ "homepage": "https://github.com/gioenjoy/mcp-google-merchant-center#readme",
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.29.0",
32
+ "googleapis": "^173.0.0"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ }
37
+ }