opendock-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 +93 -0
- package/dist/api/auth.d.ts +12 -0
- package/dist/api/auth.js +81 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/client.d.ts +14 -0
- package/dist/api/client.js +49 -0
- package/dist/api/client.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/appointments.d.ts +3 -0
- package/dist/tools/appointments.js +86 -0
- package/dist/tools/appointments.js.map +1 -0
- package/dist/tools/carriers.d.ts +3 -0
- package/dist/tools/carriers.js +21 -0
- package/dist/tools/carriers.js.map +1 -0
- package/dist/tools/docks.d.ts +3 -0
- package/dist/tools/docks.js +21 -0
- package/dist/tools/docks.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +18 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/loadtypes.d.ts +3 -0
- package/dist/tools/loadtypes.js +33 -0
- package/dist/tools/loadtypes.js.map +1 -0
- package/dist/tools/warehouses.d.ts +3 -0
- package/dist/tools/warehouses.js +36 -0
- package/dist/tools/warehouses.js.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Opendock MCP Server
|
|
2
|
+
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io/) server that connects AI assistants (Claude, etc.) to the [Opendock](https://www.opendock.com/) Neutron API for warehouse dock scheduling.
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
**17 tools** across 6 categories:
|
|
8
|
+
|
|
9
|
+
| Category | Tools |
|
|
10
|
+
|----------|-------|
|
|
11
|
+
| **Auth** | `get_profile` |
|
|
12
|
+
| **Warehouses** | `list_warehouses`, `get_warehouse`, `get_warehouse_hours` |
|
|
13
|
+
| **Docks** | `list_docks`, `get_dock` |
|
|
14
|
+
| **Load Types** | `list_load_types`, `get_load_type`, `get_load_type_availability` |
|
|
15
|
+
| **Appointments** | `list_appointments`, `search_appointments`, `get_appointment`, `create_appointment`, `update_appointment`, `delete_appointment` |
|
|
16
|
+
| **Carriers** | `list_carriers`, `get_carrier` |
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- Node.js 18+
|
|
21
|
+
- An Opendock account with API access
|
|
22
|
+
|
|
23
|
+
## Authentication
|
|
24
|
+
|
|
25
|
+
The server supports two authentication methods:
|
|
26
|
+
|
|
27
|
+
**Option 1: Username/password** (recommended) — the server handles login and token refresh automatically.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
OPENDOCK_USERNAME=user@example.com
|
|
31
|
+
OPENDOCK_PASSWORD=your-password
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Option 2: Pre-existing JWT token**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
OPENDOCK_TOKEN=your-jwt-token
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Optionally set the API URL (defaults to `https://neutron.opendock.com`):
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
OPENDOCK_API_URL=https://neutron.opendock.com
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Usage with Claude Desktop
|
|
47
|
+
|
|
48
|
+
Add to your `claude_desktop_config.json`:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"opendock": {
|
|
54
|
+
"command": "npx",
|
|
55
|
+
"args": ["-y", "opendock-mcp"],
|
|
56
|
+
"env": {
|
|
57
|
+
"OPENDOCK_USERNAME": "user@example.com",
|
|
58
|
+
"OPENDOCK_PASSWORD": "your-password"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Usage with Claude Code
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
claude mcp add opendock -- npx -y opendock-mcp
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Set the required environment variables before launching Claude Code, or pass them in the MCP config.
|
|
72
|
+
|
|
73
|
+
## Testing
|
|
74
|
+
|
|
75
|
+
Use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to test interactively:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
OPENDOCK_USERNAME=user@example.com OPENDOCK_PASSWORD=your-password \
|
|
79
|
+
npx @modelcontextprotocol/inspector npx -y opendock-mcp
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/Pollamin/opendock-mcp.git
|
|
86
|
+
cd opendock-mcp
|
|
87
|
+
npm install
|
|
88
|
+
npm run build
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Config } from "../config.js";
|
|
2
|
+
export declare class AuthManager {
|
|
3
|
+
private token;
|
|
4
|
+
private config;
|
|
5
|
+
constructor(config: Config);
|
|
6
|
+
getToken(): Promise<string>;
|
|
7
|
+
clearToken(): void;
|
|
8
|
+
private isExpiringSoon;
|
|
9
|
+
private decodeJwt;
|
|
10
|
+
private login;
|
|
11
|
+
private refresh;
|
|
12
|
+
}
|
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export class AuthManager {
|
|
2
|
+
token = null;
|
|
3
|
+
config;
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
if (config.token) {
|
|
7
|
+
this.token = config.token;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
async getToken() {
|
|
11
|
+
if (this.token && !this.isExpiringSoon(this.token)) {
|
|
12
|
+
return this.token;
|
|
13
|
+
}
|
|
14
|
+
if (this.token) {
|
|
15
|
+
try {
|
|
16
|
+
this.token = await this.refresh(this.token);
|
|
17
|
+
return this.token;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// refresh failed, fall through to login
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
this.token = await this.login();
|
|
24
|
+
return this.token;
|
|
25
|
+
}
|
|
26
|
+
clearToken() {
|
|
27
|
+
this.token = null;
|
|
28
|
+
}
|
|
29
|
+
isExpiringSoon(token) {
|
|
30
|
+
try {
|
|
31
|
+
const payload = this.decodeJwt(token);
|
|
32
|
+
if (!payload.exp)
|
|
33
|
+
return false;
|
|
34
|
+
const now = Math.floor(Date.now() / 1000);
|
|
35
|
+
return payload.exp - now < 60;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
decodeJwt(token) {
|
|
42
|
+
const parts = token.split(".");
|
|
43
|
+
if (parts.length !== 3)
|
|
44
|
+
throw new Error("Invalid JWT");
|
|
45
|
+
const payload = parts[1];
|
|
46
|
+
const padded = payload.replace(/-/g, "+").replace(/_/g, "/");
|
|
47
|
+
const json = Buffer.from(padded, "base64").toString("utf-8");
|
|
48
|
+
return JSON.parse(json);
|
|
49
|
+
}
|
|
50
|
+
async login() {
|
|
51
|
+
if (!this.config.username || !this.config.password) {
|
|
52
|
+
throw new Error("No credentials available for login");
|
|
53
|
+
}
|
|
54
|
+
const res = await fetch(`${this.config.apiUrl}/auth/login`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: { "Content-Type": "application/json" },
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
email: this.config.username,
|
|
59
|
+
password: this.config.password,
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
const body = await res.text();
|
|
64
|
+
throw new Error(`Login failed (${res.status}): ${body}`);
|
|
65
|
+
}
|
|
66
|
+
const data = (await res.json());
|
|
67
|
+
return data.access_token;
|
|
68
|
+
}
|
|
69
|
+
async refresh(currentToken) {
|
|
70
|
+
const res = await fetch(`${this.config.apiUrl}/auth/refresh`, {
|
|
71
|
+
method: "GET",
|
|
72
|
+
headers: { Authorization: `Bearer ${currentToken}` },
|
|
73
|
+
});
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
throw new Error(`Token refresh failed (${res.status})`);
|
|
76
|
+
}
|
|
77
|
+
const data = (await res.json());
|
|
78
|
+
return data.access_token;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AuthManager } from "./auth.js";
|
|
2
|
+
export interface ApiRequestOptions {
|
|
3
|
+
method?: string;
|
|
4
|
+
path: string;
|
|
5
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
6
|
+
body?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export declare class ApiClient {
|
|
9
|
+
private baseUrl;
|
|
10
|
+
private auth;
|
|
11
|
+
constructor(baseUrl: string, auth: AuthManager);
|
|
12
|
+
request<T = unknown>(opts: ApiRequestOptions): Promise<T>;
|
|
13
|
+
private doRequest;
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export class ApiClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
auth;
|
|
4
|
+
constructor(baseUrl, auth) {
|
|
5
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
6
|
+
this.auth = auth;
|
|
7
|
+
}
|
|
8
|
+
async request(opts) {
|
|
9
|
+
const response = await this.doRequest(opts);
|
|
10
|
+
if (response.status === 401) {
|
|
11
|
+
this.auth.clearToken();
|
|
12
|
+
const retry = await this.doRequest(opts);
|
|
13
|
+
if (!retry.ok) {
|
|
14
|
+
const body = await retry.text();
|
|
15
|
+
throw new Error(`API error ${retry.status}: ${body}`);
|
|
16
|
+
}
|
|
17
|
+
return (await retry.json());
|
|
18
|
+
}
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
const body = await response.text();
|
|
21
|
+
throw new Error(`API error ${response.status}: ${body}`);
|
|
22
|
+
}
|
|
23
|
+
if (response.status === 204) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return (await response.json());
|
|
27
|
+
}
|
|
28
|
+
async doRequest(opts) {
|
|
29
|
+
const token = await this.auth.getToken();
|
|
30
|
+
const url = new URL(`${this.baseUrl}${opts.path}`);
|
|
31
|
+
if (opts.query) {
|
|
32
|
+
for (const [key, value] of Object.entries(opts.query)) {
|
|
33
|
+
if (value !== undefined) {
|
|
34
|
+
url.searchParams.set(key, String(value));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const headers = {
|
|
39
|
+
Authorization: `Bearer ${token}`,
|
|
40
|
+
"Content-Type": "application/json",
|
|
41
|
+
};
|
|
42
|
+
return fetch(url.toString(), {
|
|
43
|
+
method: opts.method || "GET",
|
|
44
|
+
headers,
|
|
45
|
+
body: opts.body ? JSON.stringify(opts.body) : undefined,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,SAAS;IACZ,OAAO,CAAS;IAChB,IAAI,CAAc;IAE1B,YAAY,OAAe,EAAE,IAAiB;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,OAAO,CAAc,IAAuB;QAChD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAE5C,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,aAAa,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC;YACD,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAM,CAAC;QACnC,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,aAAa,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,SAAc,CAAC;QACxB,CAAC;QAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,IAAuB;QAC7C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAEnD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAA2B;YACtC,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,cAAc,EAAE,kBAAkB;SACnC,CAAC;QAEF,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;YAC5B,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SACxD,CAAC,CAAC;IACL,CAAC;CACF"}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function loadConfig() {
|
|
2
|
+
const apiUrl = process.env.OPENDOCK_API_URL || "https://neutron.opendock.com";
|
|
3
|
+
const username = process.env.OPENDOCK_USERNAME;
|
|
4
|
+
const password = process.env.OPENDOCK_PASSWORD;
|
|
5
|
+
const token = process.env.OPENDOCK_TOKEN;
|
|
6
|
+
if (!token && (!username || !password)) {
|
|
7
|
+
throw new Error("Either OPENDOCK_TOKEN or both OPENDOCK_USERNAME and OPENDOCK_PASSWORD must be set");
|
|
8
|
+
}
|
|
9
|
+
return { apiUrl, username, password, token };
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,8BAA8B,CAAC;IAC9E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAEzC,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,mFAAmF,CACpF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAC/C,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
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 { loadConfig } from "./config.js";
|
|
5
|
+
import { AuthManager } from "./api/auth.js";
|
|
6
|
+
import { ApiClient } from "./api/client.js";
|
|
7
|
+
import { registerAllTools } from "./tools/index.js";
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
const auth = new AuthManager(config);
|
|
10
|
+
const api = new ApiClient(config.apiUrl, auth);
|
|
11
|
+
const server = new McpServer({
|
|
12
|
+
name: "opendock",
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
});
|
|
15
|
+
registerAllTools(server, api);
|
|
16
|
+
const transport = new StdioServerTransport();
|
|
17
|
+
await server.connect(transport);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;AAC5B,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;AACrC,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAE/C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerAppointmentTools(server, api) {
|
|
3
|
+
server.tool("list_appointments", "List appointments with optional filters and pagination", {
|
|
4
|
+
page: z.number().optional().describe("Page number"),
|
|
5
|
+
limit: z.number().optional().describe("Items per page"),
|
|
6
|
+
warehouseId: z.string().optional().describe("Filter by warehouse ID"),
|
|
7
|
+
dockId: z.string().optional().describe("Filter by dock ID"),
|
|
8
|
+
status: z.string().optional().describe("Filter by status"),
|
|
9
|
+
startDate: z.string().optional().describe("Filter by start date (YYYY-MM-DD)"),
|
|
10
|
+
endDate: z.string().optional().describe("Filter by end date (YYYY-MM-DD)"),
|
|
11
|
+
}, async (params) => {
|
|
12
|
+
const data = await api.request({
|
|
13
|
+
path: "/appointment",
|
|
14
|
+
query: params,
|
|
15
|
+
});
|
|
16
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
17
|
+
});
|
|
18
|
+
server.tool("search_appointments", "Advanced search for appointments by carrier, reference number, status, or date range", {
|
|
19
|
+
carrierId: z.string().optional().describe("Filter by carrier ID"),
|
|
20
|
+
referenceNumber: z.string().optional().describe("Search by reference number"),
|
|
21
|
+
status: z.string().optional().describe("Filter by status"),
|
|
22
|
+
startDate: z.string().optional().describe("Start date (YYYY-MM-DD)"),
|
|
23
|
+
endDate: z.string().optional().describe("End date (YYYY-MM-DD)"),
|
|
24
|
+
warehouseId: z.string().optional().describe("Filter by warehouse ID"),
|
|
25
|
+
page: z.number().optional().describe("Page number"),
|
|
26
|
+
limit: z.number().optional().describe("Items per page"),
|
|
27
|
+
}, async (params) => {
|
|
28
|
+
const data = await api.request({
|
|
29
|
+
method: "POST",
|
|
30
|
+
path: "/search/appointments",
|
|
31
|
+
body: params,
|
|
32
|
+
});
|
|
33
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
34
|
+
});
|
|
35
|
+
server.tool("get_appointment", "Get details for a specific appointment", {
|
|
36
|
+
id: z.string().describe("Appointment ID"),
|
|
37
|
+
}, async ({ id }) => {
|
|
38
|
+
const data = await api.request({ path: `/appointment/${id}` });
|
|
39
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
40
|
+
});
|
|
41
|
+
server.tool("create_appointment", "Schedule a new appointment", {
|
|
42
|
+
warehouseId: z.string().describe("Warehouse ID"),
|
|
43
|
+
dockId: z.string().describe("Dock ID"),
|
|
44
|
+
loadTypeId: z.string().describe("Load type ID"),
|
|
45
|
+
startTime: z.string().describe("Start time (ISO 8601 datetime)"),
|
|
46
|
+
endTime: z.string().describe("End time (ISO 8601 datetime)"),
|
|
47
|
+
carrierId: z.string().optional().describe("Carrier ID"),
|
|
48
|
+
referenceNumber: z.string().optional().describe("Reference number"),
|
|
49
|
+
notes: z.string().optional().describe("Appointment notes"),
|
|
50
|
+
}, async (params) => {
|
|
51
|
+
const data = await api.request({
|
|
52
|
+
method: "POST",
|
|
53
|
+
path: "/appointment",
|
|
54
|
+
body: params,
|
|
55
|
+
});
|
|
56
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
57
|
+
});
|
|
58
|
+
server.tool("update_appointment", "Modify or reschedule an existing appointment", {
|
|
59
|
+
id: z.string().describe("Appointment ID"),
|
|
60
|
+
startTime: z.string().optional().describe("New start time (ISO 8601 datetime)"),
|
|
61
|
+
endTime: z.string().optional().describe("New end time (ISO 8601 datetime)"),
|
|
62
|
+
dockId: z.string().optional().describe("New dock ID"),
|
|
63
|
+
loadTypeId: z.string().optional().describe("New load type ID"),
|
|
64
|
+
carrierId: z.string().optional().describe("New carrier ID"),
|
|
65
|
+
referenceNumber: z.string().optional().describe("New reference number"),
|
|
66
|
+
notes: z.string().optional().describe("Updated notes"),
|
|
67
|
+
status: z.string().optional().describe("New status"),
|
|
68
|
+
}, async ({ id, ...body }) => {
|
|
69
|
+
const data = await api.request({
|
|
70
|
+
method: "PATCH",
|
|
71
|
+
path: `/appointment/${id}`,
|
|
72
|
+
body,
|
|
73
|
+
});
|
|
74
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
75
|
+
});
|
|
76
|
+
server.tool("delete_appointment", "Cancel/delete an appointment", {
|
|
77
|
+
id: z.string().describe("Appointment ID"),
|
|
78
|
+
}, async ({ id }) => {
|
|
79
|
+
await api.request({
|
|
80
|
+
method: "DELETE",
|
|
81
|
+
path: `/appointment/${id}`,
|
|
82
|
+
});
|
|
83
|
+
return { content: [{ type: "text", text: `Appointment ${id} deleted successfully.` }] };
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=appointments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appointments.js","sourceRoot":"","sources":["../../src/tools/appointments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerCarrierTools(server, api) {
|
|
3
|
+
server.tool("list_carriers", "List carriers with optional filters", {
|
|
4
|
+
page: z.number().optional().describe("Page number"),
|
|
5
|
+
limit: z.number().optional().describe("Items per page"),
|
|
6
|
+
name: z.string().optional().describe("Filter by carrier name"),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
const data = await api.request({
|
|
9
|
+
path: "/carrier",
|
|
10
|
+
query: params,
|
|
11
|
+
});
|
|
12
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
13
|
+
});
|
|
14
|
+
server.tool("get_carrier", "Get details for a specific carrier", {
|
|
15
|
+
id: z.string().describe("Carrier ID"),
|
|
16
|
+
}, async ({ id }) => {
|
|
17
|
+
const data = await api.request({ path: `/carrier/${id}` });
|
|
18
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=carriers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"carriers.js","sourceRoot":"","sources":["../../src/tools/carriers.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,oBAAoB,CAAC,MAAiB,EAAE,GAAc;IACpE,MAAM,CAAC,IAAI,CACT,eAAe,EACf,qCAAqC,EACrC;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACnD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QACvD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;KAC/D,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,MAAqD;SAC7D,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,oCAAoC,EACpC;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;KACtC,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerDockTools(server, api) {
|
|
3
|
+
server.tool("list_docks", "List docks with optional filters", {
|
|
4
|
+
warehouseId: z.string().optional().describe("Filter by warehouse ID"),
|
|
5
|
+
page: z.number().optional().describe("Page number"),
|
|
6
|
+
limit: z.number().optional().describe("Items per page"),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
const data = await api.request({
|
|
9
|
+
path: "/dock",
|
|
10
|
+
query: params,
|
|
11
|
+
});
|
|
12
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
13
|
+
});
|
|
14
|
+
server.tool("get_dock", "Get details for a specific dock", {
|
|
15
|
+
id: z.string().describe("Dock ID"),
|
|
16
|
+
}, async ({ id }) => {
|
|
17
|
+
const data = await api.request({ path: `/dock/${id}` });
|
|
18
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=docks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docks.js","sourceRoot":"","sources":["../../src/tools/docks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,GAAc;IACjE,MAAM,CAAC,IAAI,CACT,YAAY,EACZ,kCAAkC,EAClC;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACrE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACnD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;KACxD,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,MAAqD;SAC7D,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,UAAU,EACV,iCAAiC,EACjC;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC;KACnC,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QACxD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { registerWarehouseTools } from "./warehouses.js";
|
|
2
|
+
import { registerDockTools } from "./docks.js";
|
|
3
|
+
import { registerLoadTypeTools } from "./loadtypes.js";
|
|
4
|
+
import { registerAppointmentTools } from "./appointments.js";
|
|
5
|
+
import { registerCarrierTools } from "./carriers.js";
|
|
6
|
+
export function registerAllTools(server, api) {
|
|
7
|
+
// Auth
|
|
8
|
+
server.tool("get_profile", "Get the current authenticated user's profile", {}, async () => {
|
|
9
|
+
const data = await api.request({ path: "/auth/profile" });
|
|
10
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
11
|
+
});
|
|
12
|
+
registerWarehouseTools(server, api);
|
|
13
|
+
registerDockTools(server, api);
|
|
14
|
+
registerLoadTypeTools(server, api);
|
|
15
|
+
registerAppointmentTools(server, api);
|
|
16
|
+
registerCarrierTools(server, api);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,GAAc;IAChE,OAAO;IACP,MAAM,CAAC,IAAI,CACT,aAAa,EACb,8CAA8C,EAC9C,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;QAC1D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;IAEF,sBAAsB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACpC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC/B,qBAAqB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,wBAAwB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACtC,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerLoadTypeTools(server, api) {
|
|
3
|
+
server.tool("list_load_types", "List load types with optional filters", {
|
|
4
|
+
warehouseId: z.string().optional().describe("Filter by warehouse ID"),
|
|
5
|
+
page: z.number().optional().describe("Page number"),
|
|
6
|
+
limit: z.number().optional().describe("Items per page"),
|
|
7
|
+
}, async (params) => {
|
|
8
|
+
const data = await api.request({
|
|
9
|
+
path: "/loadtype",
|
|
10
|
+
query: params,
|
|
11
|
+
});
|
|
12
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
13
|
+
});
|
|
14
|
+
server.tool("get_load_type", "Get details for a specific load type", {
|
|
15
|
+
id: z.string().describe("Load type ID"),
|
|
16
|
+
}, async ({ id }) => {
|
|
17
|
+
const data = await api.request({ path: `/loadtype/${id}` });
|
|
18
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
19
|
+
});
|
|
20
|
+
server.tool("get_load_type_availability", "Get available appointment slots for a load type", {
|
|
21
|
+
id: z.string().describe("Load type ID"),
|
|
22
|
+
startDate: z.string().describe("Start date (YYYY-MM-DD)"),
|
|
23
|
+
endDate: z.string().describe("End date (YYYY-MM-DD)"),
|
|
24
|
+
}, async ({ id, startDate, endDate }) => {
|
|
25
|
+
const data = await api.request({
|
|
26
|
+
method: "POST",
|
|
27
|
+
path: `/loadtype/${id}/get-availability`,
|
|
28
|
+
body: { startDate, endDate },
|
|
29
|
+
});
|
|
30
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=loadtypes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadtypes.js","sourceRoot":"","sources":["../../src/tools/loadtypes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,GAAc;IACrE,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,uCAAuC,EACvC;QACE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACrE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;QACnD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;KACxD,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;YAC7B,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,MAAqD;SAC7D,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,sCAAsC,EACtC;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;KACxC,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,4BAA4B,EAC5B,iDAAiD,EACjD;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;QACvC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QACzD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;KACtD,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,aAAa,EAAE,mBAAmB;YACxC,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;SAC7B,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACvF,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerWarehouseTools(server, api) {
|
|
3
|
+
server.tool("list_warehouses", "List warehouses with optional filters and pagination", {
|
|
4
|
+
page: z.number().optional().describe("Page number"),
|
|
5
|
+
limit: z.number().optional().describe("Items per page"),
|
|
6
|
+
name: z.string().optional().describe("Filter by warehouse name"),
|
|
7
|
+
city: z.string().optional().describe("Filter by city"),
|
|
8
|
+
state: z.string().optional().describe("Filter by state"),
|
|
9
|
+
zip: z.string().optional().describe("Filter by zip code"),
|
|
10
|
+
}, async (params) => {
|
|
11
|
+
const data = await api.request({
|
|
12
|
+
path: "/warehouse",
|
|
13
|
+
query: params,
|
|
14
|
+
});
|
|
15
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
16
|
+
});
|
|
17
|
+
server.tool("get_warehouse", "Get details for a specific warehouse", {
|
|
18
|
+
id: z.string().describe("Warehouse ID"),
|
|
19
|
+
}, async ({ id }) => {
|
|
20
|
+
const data = await api.request({ path: `/warehouse/${id}` });
|
|
21
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
22
|
+
});
|
|
23
|
+
server.tool("get_warehouse_hours", "Get hours of operation for a warehouse's docks", {
|
|
24
|
+
id: z.string().describe("Warehouse ID"),
|
|
25
|
+
startDate: z.string().optional().describe("Start date (YYYY-MM-DD)"),
|
|
26
|
+
endDate: z.string().optional().describe("End date (YYYY-MM-DD)"),
|
|
27
|
+
}, async ({ id, ...body }) => {
|
|
28
|
+
const data = await api.request({
|
|
29
|
+
method: "POST",
|
|
30
|
+
path: `/warehouse/${id}/get-hours-of-operation`,
|
|
31
|
+
body: Object.keys(body).length > 0 ? body : undefined,
|
|
32
|
+
});
|
|
33
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=warehouses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warehouses.js","sourceRoot":"","sources":["../../src/tools/warehouses.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opendock-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for the Opendock Neutron API",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"opendock-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"opendock",
|
|
22
|
+
"warehouse",
|
|
23
|
+
"dock-scheduling",
|
|
24
|
+
"model-context-protocol"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/Pollamin/opendock-mcp.git"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
33
|
+
"zod": "^3.24.4"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/node": "^22.15.3",
|
|
37
|
+
"typescript": "^5.8.3"
|
|
38
|
+
}
|
|
39
|
+
}
|