shoptet-mcp 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.
- package/README.md +179 -0
- package/dist/__tests__/client.test.d.ts +1 -0
- package/dist/__tests__/client.test.js +72 -0
- package/dist/__tests__/server.test.d.ts +1 -0
- package/dist/__tests__/server.test.js +60 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.js +65 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +30 -0
- package/dist/prompts.d.ts +2 -0
- package/dist/prompts.js +54 -0
- package/dist/resources.d.ts +2 -0
- package/dist/resources.js +21 -0
- package/dist/tools/customers.d.ts +2 -0
- package/dist/tools/customers.js +20 -0
- package/dist/tools/documents.d.ts +2 -0
- package/dist/tools/documents.js +91 -0
- package/dist/tools/eshop.d.ts +2 -0
- package/dist/tools/eshop.js +8 -0
- package/dist/tools/orders.d.ts +2 -0
- package/dist/tools/orders.js +71 -0
- package/dist/tools/products.d.ts +2 -0
- package/dist/tools/products.js +53 -0
- package/dist/tools/webhooks.d.ts +2 -0
- package/dist/tools/webhooks.js +24 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# Shoptet MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/shoptet-mcp)
|
|
4
|
+
|
|
5
|
+
MCP (Model Context Protocol) server for the [Shoptet](https://www.shoptet.cz/) e-commerce platform API. Provides 42 tools for managing orders, products, customers, documents, webhooks, and more — directly from AI assistants like Claude.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Orders** — list, create, update status, get PDF, history, remarks, change tracking
|
|
10
|
+
- **Products** — list, detail, stock levels, brands, categories, change tracking
|
|
11
|
+
- **Customers** — list and detail with filtering
|
|
12
|
+
- **Documents** — invoices, proforma invoices, credit notes, delivery notes, proof of payments
|
|
13
|
+
- **Webhooks** — create, list, delete webhook subscriptions
|
|
14
|
+
- **Eshop info** — basic shop metadata
|
|
15
|
+
- **AI Prompts** — built-in prompts for order analysis, low stock check, daily summary, customer lookup
|
|
16
|
+
- **Resources** — quick access to eshop info and order statuses
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- Node.js 18+
|
|
21
|
+
- Shoptet API token ([how to get one](https://www.shoptet.cz/api/))
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
No installation needed — just configure your AI client with `npx`:
|
|
26
|
+
|
|
27
|
+
### Claude Code (CLI)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
claude mcp add shoptet -e SHOPTET_API_TOKEN=your-token -- npx shoptet-mcp
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or add to your project's `.mcp.json`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"shoptet": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["shoptet-mcp"],
|
|
41
|
+
"env": {
|
|
42
|
+
"SHOPTET_API_TOKEN": "your-token"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Claude Desktop
|
|
50
|
+
|
|
51
|
+
Open **Settings → Developer → Edit Config** and add to `claude_desktop_config.json`:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"shoptet": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": ["shoptet-mcp"],
|
|
59
|
+
"env": {
|
|
60
|
+
"SHOPTET_API_TOKEN": "your-token"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### VS Code (Copilot / Claude extension)
|
|
68
|
+
|
|
69
|
+
Add to `.vscode/mcp.json` in your workspace:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"servers": {
|
|
74
|
+
"shoptet": {
|
|
75
|
+
"command": "npx",
|
|
76
|
+
"args": ["shoptet-mcp"],
|
|
77
|
+
"env": {
|
|
78
|
+
"SHOPTET_API_TOKEN": "your-token"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### JetBrains IDEs
|
|
86
|
+
|
|
87
|
+
Go to **Settings → Tools → AI Assistant → MCP Servers → Add**, then configure:
|
|
88
|
+
|
|
89
|
+
- **Name:** `shoptet`
|
|
90
|
+
- **Command:** `npx`
|
|
91
|
+
- **Args:** `shoptet-mcp`
|
|
92
|
+
- **Environment:** `SHOPTET_API_TOKEN=your-token`
|
|
93
|
+
|
|
94
|
+
### Cursor
|
|
95
|
+
|
|
96
|
+
Add to `.cursor/mcp.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"shoptet": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["shoptet-mcp"],
|
|
104
|
+
"env": {
|
|
105
|
+
"SHOPTET_API_TOKEN": "your-token"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Windsurf
|
|
113
|
+
|
|
114
|
+
Add to `~/.codeium/windsurf/mcp_config.json`:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"mcpServers": {
|
|
119
|
+
"shoptet": {
|
|
120
|
+
"command": "npx",
|
|
121
|
+
"args": ["shoptet-mcp"],
|
|
122
|
+
"env": {
|
|
123
|
+
"SHOPTET_API_TOKEN": "your-token"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Cline (VS Code extension)
|
|
131
|
+
|
|
132
|
+
Open MCP settings in Cline and add:
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{
|
|
136
|
+
"mcpServers": {
|
|
137
|
+
"shoptet": {
|
|
138
|
+
"command": "npx",
|
|
139
|
+
"args": ["shoptet-mcp"],
|
|
140
|
+
"env": {
|
|
141
|
+
"SHOPTET_API_TOKEN": "your-token"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Available Tools
|
|
149
|
+
|
|
150
|
+
| Category | Tools |
|
|
151
|
+
|----------|-------|
|
|
152
|
+
| **Orders** | `list_orders`, `get_order`, `create_order`, `update_order_status`, `get_order_statuses`, `get_order_pdf`, `get_order_history`, `add_order_remark`, `get_order_changes` |
|
|
153
|
+
| **Products** | `list_products`, `get_product`, `get_product_changes`, `get_stock`, `list_brands`, `create_brand`, `list_categories` |
|
|
154
|
+
| **Customers** | `list_customers`, `get_customer` |
|
|
155
|
+
| **Documents** | `list_invoices`, `get_invoice`, `create_invoice_from_order`, `get_invoice_pdf`, `list_proforma_invoices`, `get_proforma_invoice`, `list_credit_notes`, `get_credit_note`, `create_credit_note_from_invoice`, `list_delivery_notes`, `create_delivery_note`, `list_proof_payments`, `get_proof_payment` |
|
|
156
|
+
| **Webhooks** | `list_webhooks`, `create_webhook`, `delete_webhook` |
|
|
157
|
+
| **Eshop** | `get_eshop_info` |
|
|
158
|
+
|
|
159
|
+
## Development
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git clone https://github.com/tomaskalina/shoptet-mcp.git
|
|
163
|
+
cd shoptet-mcp
|
|
164
|
+
npm install
|
|
165
|
+
npm run build
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npm run dev # Watch mode (TypeScript compilation)
|
|
170
|
+
npm run test # Run tests
|
|
171
|
+
npm run test:watch # Watch mode tests
|
|
172
|
+
npm run lint # Lint
|
|
173
|
+
npm run typecheck # Type check
|
|
174
|
+
npm run check # All checks (typecheck + lint + test)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
// Must set env before importing client
|
|
3
|
+
process.env.SHOPTET_API_TOKEN = "test-token";
|
|
4
|
+
import { safePath, buildQuery, text, errorResult, safeCall } from "../client.js";
|
|
5
|
+
describe("safePath", () => {
|
|
6
|
+
it("encodes a simple string", () => {
|
|
7
|
+
expect(safePath("abc123")).toBe("abc123");
|
|
8
|
+
});
|
|
9
|
+
it("encodes special characters", () => {
|
|
10
|
+
expect(safePath("hello world")).toBe("hello%20world");
|
|
11
|
+
});
|
|
12
|
+
it("rejects path traversal", () => {
|
|
13
|
+
expect(() => safePath("../etc")).toThrow("Invalid path segment");
|
|
14
|
+
});
|
|
15
|
+
it("rejects slashes", () => {
|
|
16
|
+
expect(() => safePath("foo/bar")).toThrow("Invalid path segment");
|
|
17
|
+
});
|
|
18
|
+
it("rejects query strings", () => {
|
|
19
|
+
expect(() => safePath("foo?bar=1")).toThrow("Invalid path segment");
|
|
20
|
+
});
|
|
21
|
+
it("rejects fragments", () => {
|
|
22
|
+
expect(() => safePath("foo#bar")).toThrow("Invalid path segment");
|
|
23
|
+
});
|
|
24
|
+
it("handles numbers", () => {
|
|
25
|
+
expect(safePath(42)).toBe("42");
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe("buildQuery", () => {
|
|
29
|
+
it("returns empty string for no params", () => {
|
|
30
|
+
expect(buildQuery({})).toBe("");
|
|
31
|
+
});
|
|
32
|
+
it("builds query string from params", () => {
|
|
33
|
+
expect(buildQuery({ page: 1, itemsPerPage: 10 })).toBe("?page=1&itemsPerPage=10");
|
|
34
|
+
});
|
|
35
|
+
it("skips undefined values", () => {
|
|
36
|
+
expect(buildQuery({ page: 1, status: undefined })).toBe("?page=1");
|
|
37
|
+
});
|
|
38
|
+
it("handles string values", () => {
|
|
39
|
+
expect(buildQuery({ email: "test@example.com" })).toBe("?email=test%40example.com");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe("text", () => {
|
|
43
|
+
it("wraps data as JSON text content", () => {
|
|
44
|
+
const result = text({ foo: "bar" });
|
|
45
|
+
expect(result.content).toHaveLength(1);
|
|
46
|
+
const item = result.content[0];
|
|
47
|
+
expect(item.type).toBe("text");
|
|
48
|
+
expect("text" in item && JSON.parse(item.text)).toEqual({ foo: "bar" });
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe("errorResult", () => {
|
|
52
|
+
it("returns error content with isError flag", () => {
|
|
53
|
+
const result = errorResult(new Error("test error"));
|
|
54
|
+
expect(result.isError).toBe(true);
|
|
55
|
+
const item = result.content[0];
|
|
56
|
+
expect("text" in item && item.text).toContain("test error");
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe("safeCall", () => {
|
|
60
|
+
it("returns result on success", async () => {
|
|
61
|
+
const result = await safeCall(async () => text({ ok: true }));
|
|
62
|
+
expect(result.isError).toBeUndefined();
|
|
63
|
+
});
|
|
64
|
+
it("catches errors and returns error result", async () => {
|
|
65
|
+
const result = await safeCall(async () => {
|
|
66
|
+
throw new Error("boom");
|
|
67
|
+
});
|
|
68
|
+
expect(result.isError).toBe(true);
|
|
69
|
+
const item = result.content[0];
|
|
70
|
+
expect("text" in item && item.text).toContain("boom");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeAll } from "vitest";
|
|
2
|
+
// Set env before any imports
|
|
3
|
+
process.env.SHOPTET_API_TOKEN = "test-token";
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { registerOrderTools } from "../tools/orders.js";
|
|
6
|
+
import { registerProductTools } from "../tools/products.js";
|
|
7
|
+
import { registerCustomerTools } from "../tools/customers.js";
|
|
8
|
+
import { registerDocumentTools } from "../tools/documents.js";
|
|
9
|
+
import { registerWebhookTools } from "../tools/webhooks.js";
|
|
10
|
+
import { registerEshopTools } from "../tools/eshop.js";
|
|
11
|
+
import { registerResources } from "../resources.js";
|
|
12
|
+
import { registerPrompts } from "../prompts.js";
|
|
13
|
+
describe("MCP Server registration", () => {
|
|
14
|
+
let server;
|
|
15
|
+
beforeAll(() => {
|
|
16
|
+
server = new McpServer({ name: "shoptet-test", version: "1.0.0" });
|
|
17
|
+
});
|
|
18
|
+
it("registers order tools without error", () => {
|
|
19
|
+
expect(() => registerOrderTools(server)).not.toThrow();
|
|
20
|
+
});
|
|
21
|
+
it("registers product tools without error", () => {
|
|
22
|
+
expect(() => registerProductTools(server)).not.toThrow();
|
|
23
|
+
});
|
|
24
|
+
it("registers customer tools without error", () => {
|
|
25
|
+
expect(() => registerCustomerTools(server)).not.toThrow();
|
|
26
|
+
});
|
|
27
|
+
it("registers document tools without error", () => {
|
|
28
|
+
expect(() => registerDocumentTools(server)).not.toThrow();
|
|
29
|
+
});
|
|
30
|
+
it("registers webhook tools without error", () => {
|
|
31
|
+
expect(() => registerWebhookTools(server)).not.toThrow();
|
|
32
|
+
});
|
|
33
|
+
it("registers eshop tools without error", () => {
|
|
34
|
+
expect(() => registerEshopTools(server)).not.toThrow();
|
|
35
|
+
});
|
|
36
|
+
it("registers resources without error", () => {
|
|
37
|
+
expect(() => registerResources(server)).not.toThrow();
|
|
38
|
+
});
|
|
39
|
+
it("registers prompts without error", () => {
|
|
40
|
+
expect(() => registerPrompts(server)).not.toThrow();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe("API error handling", () => {
|
|
44
|
+
it("shoptet() throws on non-OK response", async () => {
|
|
45
|
+
const originalFetch = globalThis.fetch;
|
|
46
|
+
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
47
|
+
ok: false,
|
|
48
|
+
status: 401,
|
|
49
|
+
text: async () => "Unauthorized",
|
|
50
|
+
headers: new Headers(),
|
|
51
|
+
});
|
|
52
|
+
try {
|
|
53
|
+
const { shoptet } = await import("../client.js");
|
|
54
|
+
await expect(shoptet("/api/eshop")).rejects.toThrow("401");
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
globalThis.fetch = originalFetch;
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
export declare function safePath(segment: string | number): string;
|
|
4
|
+
export declare function shoptet(path: string, method?: string, body?: unknown): Promise<unknown>;
|
|
5
|
+
export declare const pagingSchema: {
|
|
6
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
itemsPerPage: z.ZodOptional<z.ZodNumber>;
|
|
8
|
+
};
|
|
9
|
+
export declare function buildQuery(params: Record<string, string | number | undefined>): string;
|
|
10
|
+
export declare function text(data: unknown): CallToolResult;
|
|
11
|
+
export declare function errorResult(err: unknown): CallToolResult;
|
|
12
|
+
export declare function safeCall(fn: () => Promise<CallToolResult>): Promise<CallToolResult>;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const API_BASE = "https://api.myshoptet.com";
|
|
3
|
+
function getToken() {
|
|
4
|
+
const t = process.env.SHOPTET_API_TOKEN;
|
|
5
|
+
if (!t)
|
|
6
|
+
throw new Error("SHOPTET_API_TOKEN environment variable is required");
|
|
7
|
+
return t;
|
|
8
|
+
}
|
|
9
|
+
export function safePath(segment) {
|
|
10
|
+
const s = String(segment);
|
|
11
|
+
if (s.includes("/") || s.includes("?") || s.includes("#") || s.includes("..")) {
|
|
12
|
+
throw new Error(`Invalid path segment: ${s}`);
|
|
13
|
+
}
|
|
14
|
+
return encodeURIComponent(s);
|
|
15
|
+
}
|
|
16
|
+
export async function shoptet(path, method = "GET", body) {
|
|
17
|
+
const res = await fetch(`${API_BASE}${path}`, {
|
|
18
|
+
method,
|
|
19
|
+
headers: {
|
|
20
|
+
"Shoptet-Access-Token": getToken(),
|
|
21
|
+
...(body ? { "Content-Type": "application/json" } : {}),
|
|
22
|
+
},
|
|
23
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
24
|
+
});
|
|
25
|
+
if (res.status === 429) {
|
|
26
|
+
const retryAfter = res.headers.get("Retry-After");
|
|
27
|
+
await new Promise((r) => setTimeout(r, (Number(retryAfter) || 2) * 1000));
|
|
28
|
+
return shoptet(path, method, body);
|
|
29
|
+
}
|
|
30
|
+
if (!res.ok) {
|
|
31
|
+
const errText = await res.text();
|
|
32
|
+
throw new Error(`Shoptet API ${res.status}: ${errText}`);
|
|
33
|
+
}
|
|
34
|
+
return res.json();
|
|
35
|
+
}
|
|
36
|
+
export const pagingSchema = {
|
|
37
|
+
page: z.number().optional().describe("Page number (starts at 1)"),
|
|
38
|
+
itemsPerPage: z.number().optional().describe("Items per page (max 100)"),
|
|
39
|
+
};
|
|
40
|
+
export function buildQuery(params) {
|
|
41
|
+
const query = new URLSearchParams();
|
|
42
|
+
for (const [key, value] of Object.entries(params)) {
|
|
43
|
+
if (value !== undefined)
|
|
44
|
+
query.set(key, String(value));
|
|
45
|
+
}
|
|
46
|
+
const qs = query.toString();
|
|
47
|
+
return qs ? `?${qs}` : "";
|
|
48
|
+
}
|
|
49
|
+
export function text(data) {
|
|
50
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
51
|
+
}
|
|
52
|
+
export function errorResult(err) {
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: "text", text: String(err) }],
|
|
55
|
+
isError: true,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export async function safeCall(fn) {
|
|
59
|
+
try {
|
|
60
|
+
return await fn();
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
return errorResult(err);
|
|
64
|
+
}
|
|
65
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { registerOrderTools } from "./tools/orders.js";
|
|
5
|
+
import { registerProductTools } from "./tools/products.js";
|
|
6
|
+
import { registerCustomerTools } from "./tools/customers.js";
|
|
7
|
+
import { registerDocumentTools } from "./tools/documents.js";
|
|
8
|
+
import { registerWebhookTools } from "./tools/webhooks.js";
|
|
9
|
+
import { registerEshopTools } from "./tools/eshop.js";
|
|
10
|
+
import { registerResources } from "./resources.js";
|
|
11
|
+
import { registerPrompts } from "./prompts.js";
|
|
12
|
+
const server = new McpServer({
|
|
13
|
+
name: "shoptet",
|
|
14
|
+
version: "1.0.0",
|
|
15
|
+
});
|
|
16
|
+
// Tools
|
|
17
|
+
registerOrderTools(server);
|
|
18
|
+
registerProductTools(server);
|
|
19
|
+
registerCustomerTools(server);
|
|
20
|
+
registerDocumentTools(server);
|
|
21
|
+
registerWebhookTools(server);
|
|
22
|
+
registerEshopTools(server);
|
|
23
|
+
// Resources & Prompts
|
|
24
|
+
registerResources(server);
|
|
25
|
+
registerPrompts(server);
|
|
26
|
+
const transport = new StdioServerTransport();
|
|
27
|
+
server.connect(transport).catch((err) => {
|
|
28
|
+
console.error("Fatal error:", err);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
package/dist/prompts.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerPrompts(server) {
|
|
3
|
+
server.prompt("analyze-orders", "Analyze recent orders — summarize totals, statuses, and trends", { days: z.string().optional().describe("Number of days to look back (default: 7)") }, async ({ days }) => {
|
|
4
|
+
const d = Number(days) || 7;
|
|
5
|
+
const from = new Date(Date.now() - d * 86400000).toISOString().slice(0, 16).replace("T", " ");
|
|
6
|
+
return {
|
|
7
|
+
messages: [
|
|
8
|
+
{
|
|
9
|
+
role: "user",
|
|
10
|
+
content: {
|
|
11
|
+
type: "text",
|
|
12
|
+
text: `Use the list_orders tool with creationTimeFrom="${from}" to fetch recent orders. Then analyze them:\n\n1. Total number of orders and total revenue\n2. Breakdown by order status\n3. Top customers by order value\n4. Any notable trends or anomalies\n\nPresent the results in a clear summary with tables where appropriate.`,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
server.prompt("low-stock-check", "Check for products with low inventory levels", {}, async () => ({
|
|
19
|
+
messages: [
|
|
20
|
+
{
|
|
21
|
+
role: "user",
|
|
22
|
+
content: {
|
|
23
|
+
type: "text",
|
|
24
|
+
text: "Use list_products to get all products, then check stock levels for each using get_stock. Identify products with low or zero inventory. Present a table of products sorted by stock level (lowest first) including product name, current stock, and any variants.",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
}));
|
|
29
|
+
server.prompt("daily-summary", "Generate a daily business summary for the eshop", {}, async () => {
|
|
30
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
31
|
+
return {
|
|
32
|
+
messages: [
|
|
33
|
+
{
|
|
34
|
+
role: "user",
|
|
35
|
+
content: {
|
|
36
|
+
type: "text",
|
|
37
|
+
text: `Generate a daily business summary for ${today}:\n\n1. Use get_eshop_info to get the shop name\n2. Use list_orders with creationTimeFrom="${today} 00:00" to get today's orders\n3. Use get_order_changes to see recent activity\n4. Summarize: new orders count, revenue, status distribution\n\nFormat as a concise daily report.`,
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
server.prompt("customer-lookup", "Look up a customer and their order history", { email: z.string().describe("Customer email address") }, async ({ email }) => ({
|
|
44
|
+
messages: [
|
|
45
|
+
{
|
|
46
|
+
role: "user",
|
|
47
|
+
content: {
|
|
48
|
+
type: "text",
|
|
49
|
+
text: `Look up the customer with email "${email}":\n\n1. Use list_customers with email filter to find them\n2. Use get_customer to get their full profile\n3. Use list_orders to find their orders\n4. Summarize: customer info, total orders, total spent, most recent order`,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { shoptet } from "./client.js";
|
|
2
|
+
export function registerResources(server) {
|
|
3
|
+
server.resource("eshop-info", "shoptet://eshop/info", { description: "Basic eshop information: name, URL, contact, currency, settings" }, async () => ({
|
|
4
|
+
contents: [
|
|
5
|
+
{
|
|
6
|
+
uri: "shoptet://eshop/info",
|
|
7
|
+
mimeType: "application/json",
|
|
8
|
+
text: JSON.stringify(await shoptet("/api/eshop"), null, 2),
|
|
9
|
+
},
|
|
10
|
+
],
|
|
11
|
+
}));
|
|
12
|
+
server.resource("order-statuses", "shoptet://orders/statuses", { description: "All available order statuses with IDs and names" }, async () => ({
|
|
13
|
+
contents: [
|
|
14
|
+
{
|
|
15
|
+
uri: "shoptet://orders/statuses",
|
|
16
|
+
mimeType: "application/json",
|
|
17
|
+
text: JSON.stringify(await shoptet("/api/orders/statuses"), null, 2),
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { shoptet, buildQuery, text, safePath, pagingSchema, safeCall } from "../client.js";
|
|
3
|
+
export function registerCustomerTools(server) {
|
|
4
|
+
server.registerTool("list_customers", {
|
|
5
|
+
title: "List Customers",
|
|
6
|
+
description: "List registered customers with optional filtering by email or creation date.",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
...pagingSchema,
|
|
9
|
+
email: z.string().optional().describe("Filter by email address"),
|
|
10
|
+
creationTimeFrom: z.string().optional().describe("Created from date (YYYY-MM-DD)"),
|
|
11
|
+
},
|
|
12
|
+
annotations: { readOnlyHint: true },
|
|
13
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/customers${buildQuery(params)}`))));
|
|
14
|
+
server.registerTool("get_customer", {
|
|
15
|
+
title: "Get Customer Detail",
|
|
16
|
+
description: "Get full customer profile including contact info, addresses, and account details.",
|
|
17
|
+
inputSchema: { guid: z.string().describe("Customer GUID") },
|
|
18
|
+
annotations: { readOnlyHint: true },
|
|
19
|
+
}, ({ guid }) => safeCall(async () => text(await shoptet(`/api/customers/${safePath(guid)}`))));
|
|
20
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { shoptet, buildQuery, text, safePath, pagingSchema, safeCall } from "../client.js";
|
|
3
|
+
export function registerDocumentTools(server) {
|
|
4
|
+
// ── Invoices ──────────────────────────────────────────
|
|
5
|
+
server.registerTool("list_invoices", {
|
|
6
|
+
title: "List Invoices",
|
|
7
|
+
description: "List invoices with optional date filtering. Returns invoice summaries with codes, amounts, and dates.",
|
|
8
|
+
inputSchema: {
|
|
9
|
+
...pagingSchema,
|
|
10
|
+
creationTimeFrom: z.string().optional().describe("Created from date (YYYY-MM-DD)"),
|
|
11
|
+
creationTimeTo: z.string().optional().describe("Created to date (YYYY-MM-DD)"),
|
|
12
|
+
},
|
|
13
|
+
annotations: { readOnlyHint: true },
|
|
14
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/invoices${buildQuery(params)}`))));
|
|
15
|
+
server.registerTool("get_invoice", {
|
|
16
|
+
title: "Get Invoice Detail",
|
|
17
|
+
description: "Get full invoice detail including items, amounts, tax, and customer billing info.",
|
|
18
|
+
inputSchema: { code: z.string().describe("Invoice code") },
|
|
19
|
+
annotations: { readOnlyHint: true },
|
|
20
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/invoices/${safePath(code)}`))));
|
|
21
|
+
server.registerTool("create_invoice_from_order", {
|
|
22
|
+
title: "Create Invoice from Order",
|
|
23
|
+
description: "Generate an invoice from an existing order.",
|
|
24
|
+
inputSchema: { orderCode: z.string().describe("Order code") },
|
|
25
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
26
|
+
}, ({ orderCode }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(orderCode)}/invoice`, "POST"))));
|
|
27
|
+
server.registerTool("get_invoice_pdf", {
|
|
28
|
+
title: "Get Invoice PDF",
|
|
29
|
+
description: "Get invoice document as PDF.",
|
|
30
|
+
inputSchema: { code: z.string().describe("Invoice code") },
|
|
31
|
+
annotations: { readOnlyHint: true },
|
|
32
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/invoices/${safePath(code)}/pdf`))));
|
|
33
|
+
// ── Proforma Invoices ─────────────────────────────────
|
|
34
|
+
server.registerTool("list_proforma_invoices", {
|
|
35
|
+
title: "List Proforma Invoices",
|
|
36
|
+
description: "List proforma (advance) invoices.",
|
|
37
|
+
inputSchema: pagingSchema,
|
|
38
|
+
annotations: { readOnlyHint: true },
|
|
39
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/proforma-invoices${buildQuery(params)}`))));
|
|
40
|
+
server.registerTool("get_proforma_invoice", {
|
|
41
|
+
title: "Get Proforma Invoice Detail",
|
|
42
|
+
description: "Get full proforma invoice detail.",
|
|
43
|
+
inputSchema: { code: z.string().describe("Proforma invoice code") },
|
|
44
|
+
annotations: { readOnlyHint: true },
|
|
45
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/proforma-invoices/${safePath(code)}`))));
|
|
46
|
+
// ── Credit Notes ──────────────────────────────────────
|
|
47
|
+
server.registerTool("list_credit_notes", {
|
|
48
|
+
title: "List Credit Notes",
|
|
49
|
+
description: "List credit notes (refund documents).",
|
|
50
|
+
inputSchema: pagingSchema,
|
|
51
|
+
annotations: { readOnlyHint: true },
|
|
52
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/credit-notes${buildQuery(params)}`))));
|
|
53
|
+
server.registerTool("get_credit_note", {
|
|
54
|
+
title: "Get Credit Note Detail",
|
|
55
|
+
description: "Get full credit note detail including refunded items and amounts.",
|
|
56
|
+
inputSchema: { code: z.string().describe("Credit note code") },
|
|
57
|
+
annotations: { readOnlyHint: true },
|
|
58
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/credit-notes/${safePath(code)}`))));
|
|
59
|
+
server.registerTool("create_credit_note_from_invoice", {
|
|
60
|
+
title: "Create Credit Note from Invoice",
|
|
61
|
+
description: "Create a credit note (refund) from an existing invoice.",
|
|
62
|
+
inputSchema: { invoiceCode: z.string().describe("Invoice code") },
|
|
63
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
64
|
+
}, ({ invoiceCode }) => safeCall(async () => text(await shoptet(`/api/invoices/${safePath(invoiceCode)}/credit-note`, "POST"))));
|
|
65
|
+
// ── Delivery Notes ────────────────────────────────────
|
|
66
|
+
server.registerTool("list_delivery_notes", {
|
|
67
|
+
title: "List Delivery Notes",
|
|
68
|
+
description: "List delivery notes (shipping documents).",
|
|
69
|
+
inputSchema: pagingSchema,
|
|
70
|
+
annotations: { readOnlyHint: true },
|
|
71
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/delivery-notes${buildQuery(params)}`))));
|
|
72
|
+
server.registerTool("create_delivery_note", {
|
|
73
|
+
title: "Create Delivery Note from Order",
|
|
74
|
+
description: "Generate a delivery note from an existing order.",
|
|
75
|
+
inputSchema: { orderCode: z.string().describe("Order code") },
|
|
76
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
77
|
+
}, ({ orderCode }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(orderCode)}/delivery-notes`, "POST"))));
|
|
78
|
+
// ── Proof of Payments ─────────────────────────────────
|
|
79
|
+
server.registerTool("list_proof_payments", {
|
|
80
|
+
title: "List Proof of Payments",
|
|
81
|
+
description: "List proof of payment documents.",
|
|
82
|
+
inputSchema: pagingSchema,
|
|
83
|
+
annotations: { readOnlyHint: true },
|
|
84
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/proof-payments${buildQuery(params)}`))));
|
|
85
|
+
server.registerTool("get_proof_payment", {
|
|
86
|
+
title: "Get Proof of Payment Detail",
|
|
87
|
+
description: "Get full proof of payment detail.",
|
|
88
|
+
inputSchema: { code: z.string().describe("Proof of payment code") },
|
|
89
|
+
annotations: { readOnlyHint: true },
|
|
90
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/proof-payments/${safePath(code)}`))));
|
|
91
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { shoptet, text, safeCall } from "../client.js";
|
|
2
|
+
export function registerEshopTools(server) {
|
|
3
|
+
server.registerTool("get_eshop_info", {
|
|
4
|
+
title: "Get Eshop Info",
|
|
5
|
+
description: "Get basic information about the eshop: name, URL, contact info, currency, and settings.",
|
|
6
|
+
annotations: { readOnlyHint: true },
|
|
7
|
+
}, () => safeCall(async () => text(await shoptet("/api/eshop"))));
|
|
8
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { shoptet, buildQuery, text, safePath, pagingSchema, safeCall } from "../client.js";
|
|
3
|
+
export function registerOrderTools(server) {
|
|
4
|
+
server.registerTool("list_orders", {
|
|
5
|
+
title: "List Orders",
|
|
6
|
+
description: "List orders with optional filtering. Returns paginated results with order summaries including code, status, customer, and totals.",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
...pagingSchema,
|
|
9
|
+
statusId: z.number().optional().describe("Filter by status ID (use get_order_statuses to see available)"),
|
|
10
|
+
creationTimeFrom: z.string().optional().describe("Filter from date (YYYY-MM-DD HH:MM)"),
|
|
11
|
+
creationTimeTo: z.string().optional().describe("Filter to date (YYYY-MM-DD HH:MM)"),
|
|
12
|
+
code: z.string().optional().describe("Filter by order code"),
|
|
13
|
+
},
|
|
14
|
+
annotations: { readOnlyHint: true },
|
|
15
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/orders${buildQuery(params)}`))));
|
|
16
|
+
server.registerTool("get_order", {
|
|
17
|
+
title: "Get Order Detail",
|
|
18
|
+
description: "Get full order detail including items, shipping, payment, and customer info.",
|
|
19
|
+
inputSchema: { code: z.string().describe("Order code (e.g. '2024000123')") },
|
|
20
|
+
annotations: { readOnlyHint: true },
|
|
21
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(code)}`))));
|
|
22
|
+
server.registerTool("create_order", {
|
|
23
|
+
title: "Create Order",
|
|
24
|
+
description: "Create a new order. Requires at minimum customer info and order items.",
|
|
25
|
+
inputSchema: { order: z.record(z.unknown()).describe("Order data object") },
|
|
26
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
27
|
+
}, ({ order }) => safeCall(async () => text(await shoptet("/api/orders", "POST", order))));
|
|
28
|
+
server.registerTool("update_order_status", {
|
|
29
|
+
title: "Update Order Status",
|
|
30
|
+
description: "Change the status of an order. Use get_order_statuses to see available status IDs.",
|
|
31
|
+
inputSchema: {
|
|
32
|
+
code: z.string().describe("Order code"),
|
|
33
|
+
statusId: z.number().describe("New status ID"),
|
|
34
|
+
},
|
|
35
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true },
|
|
36
|
+
}, ({ code, statusId }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(code)}/status`, "PATCH", { statusId }))));
|
|
37
|
+
server.registerTool("get_order_statuses", {
|
|
38
|
+
title: "List Order Statuses",
|
|
39
|
+
description: "List all available order statuses with their IDs and names. Useful for filtering orders or updating order status.",
|
|
40
|
+
annotations: { readOnlyHint: true },
|
|
41
|
+
}, () => safeCall(async () => text(await shoptet("/api/orders/statuses"))));
|
|
42
|
+
server.registerTool("get_order_pdf", {
|
|
43
|
+
title: "Get Order PDF",
|
|
44
|
+
description: "Get order document as PDF. Returns a download URL or base64-encoded content.",
|
|
45
|
+
inputSchema: { code: z.string().describe("Order code") },
|
|
46
|
+
annotations: { readOnlyHint: true },
|
|
47
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(code)}/pdf`))));
|
|
48
|
+
server.registerTool("get_order_history", {
|
|
49
|
+
title: "Get Order History",
|
|
50
|
+
description: "Get order history log and user remarks. Shows status changes, edits, and internal notes.",
|
|
51
|
+
inputSchema: { code: z.string().describe("Order code") },
|
|
52
|
+
annotations: { readOnlyHint: true },
|
|
53
|
+
}, ({ code }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(code)}/history`))));
|
|
54
|
+
server.registerTool("add_order_remark", {
|
|
55
|
+
title: "Add Order Remark",
|
|
56
|
+
description: "Add an internal remark/note to an order. Visible only in admin, not to customers.",
|
|
57
|
+
inputSchema: {
|
|
58
|
+
code: z.string().describe("Order code"),
|
|
59
|
+
remark: z.string().describe("Remark text"),
|
|
60
|
+
},
|
|
61
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
62
|
+
}, ({ code, remark }) => safeCall(async () => text(await shoptet(`/api/orders/${safePath(code)}/history`, "POST", { remark }))));
|
|
63
|
+
server.registerTool("get_order_changes", {
|
|
64
|
+
title: "Get Order Changes",
|
|
65
|
+
description: "Get list of recently changed orders. Useful for syncing or monitoring order updates.",
|
|
66
|
+
inputSchema: {
|
|
67
|
+
lastChangeFrom: z.string().optional().describe("Changes from date (YYYY-MM-DD HH:MM)"),
|
|
68
|
+
},
|
|
69
|
+
annotations: { readOnlyHint: true },
|
|
70
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/orders/changes${buildQuery(params)}`))));
|
|
71
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { shoptet, buildQuery, text, safePath, pagingSchema, safeCall } from "../client.js";
|
|
3
|
+
export function registerProductTools(server) {
|
|
4
|
+
server.registerTool("list_products", {
|
|
5
|
+
title: "List Products",
|
|
6
|
+
description: "List products with optional filtering by category, brand, or visibility. Returns paginated product summaries.",
|
|
7
|
+
inputSchema: {
|
|
8
|
+
...pagingSchema,
|
|
9
|
+
categoryGuid: z.string().optional().describe("Filter by category GUID"),
|
|
10
|
+
brandCode: z.string().optional().describe("Filter by brand code"),
|
|
11
|
+
visibility: z.string().optional().describe("Filter by visibility (visible, hidden, etc.)"),
|
|
12
|
+
creationTimeFrom: z.string().optional().describe("Created from date (YYYY-MM-DD)"),
|
|
13
|
+
creationTimeTo: z.string().optional().describe("Created to date (YYYY-MM-DD)"),
|
|
14
|
+
},
|
|
15
|
+
annotations: { readOnlyHint: true },
|
|
16
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/products${buildQuery(params)}`))));
|
|
17
|
+
server.registerTool("get_product", {
|
|
18
|
+
title: "Get Product Detail",
|
|
19
|
+
description: "Get full product detail including variants, pricing, images, and descriptions.",
|
|
20
|
+
inputSchema: { guid: z.string().describe("Product GUID") },
|
|
21
|
+
annotations: { readOnlyHint: true },
|
|
22
|
+
}, ({ guid }) => safeCall(async () => text(await shoptet(`/api/products/${safePath(guid)}`))));
|
|
23
|
+
server.registerTool("get_product_changes", {
|
|
24
|
+
title: "Get Product Changes",
|
|
25
|
+
description: "Get list of recently changed products. Useful for syncing product catalog.",
|
|
26
|
+
inputSchema: { lastChangeFrom: z.string().optional().describe("Changes from date (YYYY-MM-DD)") },
|
|
27
|
+
annotations: { readOnlyHint: true },
|
|
28
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/products/changes${buildQuery(params)}`))));
|
|
29
|
+
server.registerTool("get_stock", {
|
|
30
|
+
title: "Get Product Stock",
|
|
31
|
+
description: "Get inventory/stock levels for a product across all warehouses.",
|
|
32
|
+
inputSchema: { guid: z.string().describe("Product GUID") },
|
|
33
|
+
annotations: { readOnlyHint: true },
|
|
34
|
+
}, ({ guid }) => safeCall(async () => text(await shoptet(`/api/products/${safePath(guid)}/stock`))));
|
|
35
|
+
server.registerTool("list_brands", {
|
|
36
|
+
title: "List Brands",
|
|
37
|
+
description: "List all product brands in the eshop.",
|
|
38
|
+
inputSchema: pagingSchema,
|
|
39
|
+
annotations: { readOnlyHint: true },
|
|
40
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/brands${buildQuery(params)}`))));
|
|
41
|
+
server.registerTool("create_brand", {
|
|
42
|
+
title: "Create Brand",
|
|
43
|
+
description: "Create a new product brand.",
|
|
44
|
+
inputSchema: { brand: z.record(z.unknown()).describe("Brand data object") },
|
|
45
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
46
|
+
}, ({ brand }) => safeCall(async () => text(await shoptet("/api/brands", "POST", brand))));
|
|
47
|
+
server.registerTool("list_categories", {
|
|
48
|
+
title: "List Categories",
|
|
49
|
+
description: "List product categories with their hierarchy structure.",
|
|
50
|
+
inputSchema: pagingSchema,
|
|
51
|
+
annotations: { readOnlyHint: true },
|
|
52
|
+
}, (params) => safeCall(async () => text(await shoptet(`/api/categories${buildQuery(params)}`))));
|
|
53
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { shoptet, text, safePath, safeCall } from "../client.js";
|
|
3
|
+
export function registerWebhookTools(server) {
|
|
4
|
+
server.registerTool("list_webhooks", {
|
|
5
|
+
title: "List Webhooks",
|
|
6
|
+
description: "List all registered webhooks and their event subscriptions.",
|
|
7
|
+
annotations: { readOnlyHint: true },
|
|
8
|
+
}, () => safeCall(async () => text(await shoptet("/api/webhooks"))));
|
|
9
|
+
server.registerTool("create_webhook", {
|
|
10
|
+
title: "Create Webhook",
|
|
11
|
+
description: "Register a new webhook to receive real-time notifications. Events: order:create, order:update, product:create, product:update, etc.",
|
|
12
|
+
inputSchema: {
|
|
13
|
+
event: z.string().describe("Event type (e.g. order:create, order:update, product:create)"),
|
|
14
|
+
url: z.string().describe("Callback URL that will receive POST notifications"),
|
|
15
|
+
},
|
|
16
|
+
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
17
|
+
}, ({ event, url }) => safeCall(async () => text(await shoptet("/api/webhooks", "POST", { event, url }))));
|
|
18
|
+
server.registerTool("delete_webhook", {
|
|
19
|
+
title: "Delete Webhook",
|
|
20
|
+
description: "Remove a registered webhook by its ID.",
|
|
21
|
+
inputSchema: { id: z.number().describe("Webhook ID") },
|
|
22
|
+
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
23
|
+
}, ({ id }) => safeCall(async () => text(await shoptet(`/api/webhooks/${safePath(id)}`, "DELETE"))));
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "shoptet-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Shoptet e-commerce platform API — manage orders, products, customers, documents, and webhooks from AI assistants",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"shoptet-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"shoptet",
|
|
16
|
+
"ecommerce",
|
|
17
|
+
"model-context-protocol",
|
|
18
|
+
"ai",
|
|
19
|
+
"claude"
|
|
20
|
+
],
|
|
21
|
+
"author": "Tonda Kalina",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/tomaskalina/shoptet-mcp.git"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/tomaskalina/shoptet-mcp#readme",
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"start": "node dist/index.js",
|
|
31
|
+
"dev": "tsc --watch",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"lint": "eslint src/",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"check": "npm run typecheck && npm run lint && npm run test",
|
|
37
|
+
"prepublishOnly": "npm run check && npm run build"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
41
|
+
"zod": "^3.24.4"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@eslint/js": "^10.0.1",
|
|
45
|
+
"@types/node": "^22.15.3",
|
|
46
|
+
"eslint": "^10.1.0",
|
|
47
|
+
"typescript": "^5.8.3",
|
|
48
|
+
"typescript-eslint": "^8.58.0",
|
|
49
|
+
"vitest": "^4.1.2"
|
|
50
|
+
},
|
|
51
|
+
"packageManager": "yarn@3.8.1+sha512.8cfec856814c797ccb480703ca5270824327fac5abce240835e2699e01732229fd22bbeb1bb87047a0069f7698be9b2e3d9a926e6046e851faa9908fdacdeacf"
|
|
52
|
+
}
|