chore: clean up historical scripts, add MCP configurations, update agent rules
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
||||
import pg from 'pg';
|
||||
|
||||
const server = new Server(
|
||||
{
|
||||
name: "shopify-mcp-server",
|
||||
version: "1.0.0",
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
// Helper to get Shopify credentials from Odoo Database
|
||||
async function getShopifyCredentials() {
|
||||
const client = new pg.Client({
|
||||
host: '172.18.0.2',
|
||||
port: 5432,
|
||||
user: 'odoo',
|
||||
password: 'odoo',
|
||||
database: 'hazard_new'
|
||||
});
|
||||
|
||||
try {
|
||||
await client.connect();
|
||||
const res = await client.query('SELECT access_token, shop_url FROM shopify_config LIMIT 1;');
|
||||
if (res.rows.length === 0) {
|
||||
throw new Error("No Shopify configuration found in database.");
|
||||
}
|
||||
return {
|
||||
accessToken: res.rows[0].access_token,
|
||||
shopUrl: res.rows[0].shop_url
|
||||
};
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
}
|
||||
|
||||
// Define available tools
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
{
|
||||
name: "shopify_get_order",
|
||||
description: "Retrieve a complete Shopify order JSON by its order name (e.g., 4854)",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
order_name: {
|
||||
type: "string",
|
||||
description: "The order number/name without the # (e.g. 4854)",
|
||||
},
|
||||
},
|
||||
required: ["order_name"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "shopify_get_product_by_sku",
|
||||
description: "Retrieve product variants from Shopify matching a specific SKU",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sku: {
|
||||
type: "string",
|
||||
description: "The SKU of the product variant",
|
||||
},
|
||||
},
|
||||
required: ["sku"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "shopify_get_inventory_by_sku",
|
||||
description: "Retrieve inventory levels across all locations for a specific SKU",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sku: {
|
||||
type: "string",
|
||||
description: "The SKU of the product variant",
|
||||
},
|
||||
},
|
||||
required: ["sku"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "shopify_get_order_transactions",
|
||||
description: "Retrieve the financial transactions (payments/refunds) for an order by its name (e.g., 4854)",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
order_name: {
|
||||
type: "string",
|
||||
description: "The order number/name without the # (e.g. 4854)",
|
||||
},
|
||||
},
|
||||
required: ["order_name"],
|
||||
},
|
||||
}
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
// Handle tool execution
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
try {
|
||||
const creds = await getShopifyCredentials();
|
||||
const headers = {
|
||||
"X-Shopify-Access-Token": creds.accessToken,
|
||||
"Content-Type": "application/json"
|
||||
};
|
||||
const baseUrl = `https://${creds.shopUrl}/admin/api/2023-04`;
|
||||
|
||||
switch (request.params.name) {
|
||||
case "shopify_get_order": {
|
||||
const orderName = String(request.params.arguments.order_name).replace('#', '');
|
||||
const response = await fetch(`${baseUrl}/orders.json?name=${orderName}&status=any`, { headers });
|
||||
const data = await response.json();
|
||||
|
||||
if (!data.orders || data.orders.length === 0) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Order ${orderName} not found.` }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(data.orders[0], null, 2) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "shopify_get_product_by_sku": {
|
||||
const sku = String(request.params.arguments.sku);
|
||||
const query = `
|
||||
{
|
||||
productVariants(first: 5, query: "sku:${sku}") {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
title
|
||||
sku
|
||||
inventoryQuantity
|
||||
product {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const response = await fetch(`${baseUrl}/graphql.json`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ query })
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "shopify_get_inventory_by_sku": {
|
||||
const sku = String(request.params.arguments.sku);
|
||||
const query = `
|
||||
{
|
||||
productVariants(first: 5, query: "sku:${sku}") {
|
||||
edges {
|
||||
node {
|
||||
sku
|
||||
inventoryItem {
|
||||
inventoryLevels(first: 10) {
|
||||
edges {
|
||||
node {
|
||||
quantities(names: ["available"]) {
|
||||
name
|
||||
quantity
|
||||
}
|
||||
location {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
const response = await fetch(`${baseUrl}/graphql.json`, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({ query })
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
|
||||
};
|
||||
}
|
||||
|
||||
case "shopify_get_order_transactions": {
|
||||
const orderName = String(request.params.arguments.order_name).replace('#', '');
|
||||
// First get the order ID
|
||||
const orderResp = await fetch(`${baseUrl}/orders.json?name=${orderName}&status=any&fields=id,name`, { headers });
|
||||
const orderData = await orderResp.json();
|
||||
|
||||
if (!orderData.orders || orderData.orders.length === 0) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Order ${orderName} not found.` }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
const orderId = orderData.orders[0].id;
|
||||
const transResp = await fetch(`${baseUrl}/orders/${orderId}/transactions.json`, { headers });
|
||||
const transData = await transResp.json();
|
||||
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(transData, null, 2) }],
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
content: [{ type: "text", text: `Error: ${error.message}` }],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Run the server using stdio transport
|
||||
async function run() {
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
console.error("Shopify MCP Server running on stdio");
|
||||
}
|
||||
|
||||
run().catch((error) => {
|
||||
console.error("Server error:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
Generated
+1321
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "shopify-mcp",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"pg": "^8.22.0"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user