mcpal 1.1.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 +158 -0
- package/dist/assets/clients/claude.png +0 -0
- package/dist/assets/clients/cursor.png +0 -0
- package/dist/assets/clients/gpt.png +0 -0
- package/dist/assets/clients/vscode.png +0 -0
- package/dist/assets/mcpal.icns +0 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/notify.d.ts +20 -0
- package/dist/notify.d.ts.map +1 -0
- package/dist/notify.js +142 -0
- package/dist/notify.js.map +1 -0
- package/dist/scripts/setup-notifier.d.ts +3 -0
- package/dist/scripts/setup-notifier.d.ts.map +1 -0
- package/dist/scripts/setup-notifier.js +91 -0
- package/dist/scripts/setup-notifier.js.map +1 -0
- package/dist/scripts/test-notification.d.ts +15 -0
- package/dist/scripts/test-notification.d.ts.map +1 -0
- package/dist/scripts/test-notification.js +89 -0
- package/dist/scripts/test-notification.js.map +1 -0
- package/license.md +21 -0
- package/package.json +68 -0
- package/src/assets/clients/claude.png +0 -0
- package/src/assets/clients/cursor.png +0 -0
- package/src/assets/clients/gpt.png +0 -0
- package/src/assets/clients/vscode.png +0 -0
- package/src/assets/mcpal.icns +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# MCPal
|
|
2
|
+
|
|
3
|
+
MCP server that sends native macOS notifications with support for action buttons, text replies, and LLM-aware icons.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Add to your MCP Config:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"mcpal": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["mcpal"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Tool: `send_notification`
|
|
21
|
+
|
|
22
|
+
Send native notifications with optional features.
|
|
23
|
+
|
|
24
|
+
### Parameters
|
|
25
|
+
|
|
26
|
+
| Parameter | Type | Required | Description |
|
|
27
|
+
|-----------|------|----------|-------------|
|
|
28
|
+
| `message` | string | Yes | The notification body text |
|
|
29
|
+
| `title` | string | No | The notification title (default: "Notification") |
|
|
30
|
+
| `actions` | string[] | No | Action buttons (e.g., `["Yes", "No", "Maybe"]`) |
|
|
31
|
+
| `dropdownLabel` | string | No | Label for actions dropdown (required for multiple actions) |
|
|
32
|
+
| `reply` | boolean | No | Enable text reply input |
|
|
33
|
+
|
|
34
|
+
### Examples
|
|
35
|
+
|
|
36
|
+
**Simple notification:**
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"message": "Build complete!",
|
|
40
|
+
"title": "CI/CD"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**With actions:**
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"message": "Deploy to production?",
|
|
48
|
+
"title": "Deployment",
|
|
49
|
+
"actions": ["Deploy", "Cancel"],
|
|
50
|
+
"dropdownLabel": "Choose"
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**With reply:**
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"message": "What should I name this file?",
|
|
58
|
+
"title": "Question",
|
|
59
|
+
"reply": true
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## LLM-Aware Icons
|
|
64
|
+
|
|
65
|
+
MCPal automatically detects which LLM client is calling the tool and displays the appropriate icon in notifications:
|
|
66
|
+
|
|
67
|
+
| Client | Icon |
|
|
68
|
+
|--------|------|
|
|
69
|
+
| Claude Desktop / Claude Code | Claude logo |
|
|
70
|
+
| Cursor | Cursor logo |
|
|
71
|
+
| VS Code | VS Code logo |
|
|
72
|
+
| OpenAI / ChatGPT | OpenAI logo |
|
|
73
|
+
| Unknown | No icon |
|
|
74
|
+
|
|
75
|
+
This works via the MCP protocol's client identification - each client sends its name during initialization.
|
|
76
|
+
|
|
77
|
+
### Adding New Client Icons
|
|
78
|
+
|
|
79
|
+
To add support for a new LLM client, add a PNG to `src/assets/clients/` and update the mapping in `src/notify.ts`.
|
|
80
|
+
|
|
81
|
+
**Icon Specifications:**
|
|
82
|
+
|
|
83
|
+
| Property | Requirement |
|
|
84
|
+
|----------|-------------|
|
|
85
|
+
| Format | PNG with transparency (RGBA) |
|
|
86
|
+
| Dimensions | 128×128 pixels |
|
|
87
|
+
| File size | <10KB (use pngquant for compression) |
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Optimize a new icon
|
|
91
|
+
convert input.png -resize 128x128 -background none -gravity center -extent 128x128 temp.png
|
|
92
|
+
pngquant --quality=65-80 --output src/assets/clients/newclient.png temp.png
|
|
93
|
+
rm temp.png
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Custom App Icon
|
|
97
|
+
|
|
98
|
+
The package includes a custom notification icon that replaces the default Terminal icon on macOS. This is automatically configured during installation via the `postinstall` script.
|
|
99
|
+
|
|
100
|
+
### Notification Permissions
|
|
101
|
+
|
|
102
|
+
After the first notification, macOS may prompt you to allow notifications from "MCPal". You can manage this in:
|
|
103
|
+
|
|
104
|
+
**System Settings > Notifications > MCPal**
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Install dependencies
|
|
110
|
+
pnpm install
|
|
111
|
+
|
|
112
|
+
# Build
|
|
113
|
+
pnpm run build
|
|
114
|
+
|
|
115
|
+
# Type check
|
|
116
|
+
pnpm run typecheck
|
|
117
|
+
|
|
118
|
+
# Lint
|
|
119
|
+
pnpm run lint:fix
|
|
120
|
+
|
|
121
|
+
# Format
|
|
122
|
+
pnpm run format:fix
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### MCP Inspector
|
|
126
|
+
|
|
127
|
+
Test the MCP server interactively using the official inspector:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
pnpx @modelcontextprotocol/inspector node dist/index.js
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This opens a web UI where you can:
|
|
134
|
+
- View available tools and their schemas
|
|
135
|
+
- Send test notifications with different parameters
|
|
136
|
+
- See raw MCP protocol messages
|
|
137
|
+
|
|
138
|
+
### Testing Notifications
|
|
139
|
+
|
|
140
|
+
Test the notification system directly without running the MCP server:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Simple notification (default)
|
|
144
|
+
pnpm run test:notification
|
|
145
|
+
|
|
146
|
+
# With action buttons
|
|
147
|
+
pnpm run test:notification actions
|
|
148
|
+
|
|
149
|
+
# With reply input
|
|
150
|
+
pnpm run test:notification reply
|
|
151
|
+
|
|
152
|
+
# Run all tests
|
|
153
|
+
pnpm run test:notification all
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
MIT
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const notify_js_1 = require("./notify.js");
|
|
8
|
+
const server = new mcp_js_1.McpServer({
|
|
9
|
+
name: "mcpal",
|
|
10
|
+
version: "1.0.0",
|
|
11
|
+
}, {
|
|
12
|
+
instructions: `MCPal is your friendly notification buddy! Use me to send native desktop notifications to the user.
|
|
13
|
+
|
|
14
|
+
IMPORTANT: When you need user input (questions, clarifications, or feedback), use reply=true to let them type a response directly in the notification. This is the fastest way to continue a conversation without switching windows.
|
|
15
|
+
|
|
16
|
+
Use cases:
|
|
17
|
+
- Task complete → simple notification
|
|
18
|
+
- Need a decision → actions (Yes/No buttons)
|
|
19
|
+
- Need free-form input → reply=true (PREFERRED for questions)`,
|
|
20
|
+
});
|
|
21
|
+
server.registerTool("send_notification", {
|
|
22
|
+
description: `Send a native desktop notification. Use reply=true when you need user input - they can type a response directly! Perfect for asking questions or getting feedback without interrupting their flow.`,
|
|
23
|
+
title: "MCPal Notification",
|
|
24
|
+
inputSchema: {
|
|
25
|
+
message: zod_1.z.string().describe("The notification body text"),
|
|
26
|
+
title: zod_1.z.string().optional().describe("The notification title"),
|
|
27
|
+
actions: zod_1.z
|
|
28
|
+
.array(zod_1.z.string())
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Action buttons for choices (e.g., ['Yes', 'No']). Use for simple decisions."),
|
|
31
|
+
dropdownLabel: zod_1.z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Label for actions dropdown (required when using multiple actions)"),
|
|
35
|
+
reply: zod_1.z
|
|
36
|
+
.boolean()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("RECOMMENDED: Enable text reply input. Use this when you need free-form user input - they can respond without switching windows!"),
|
|
39
|
+
timeout: zod_1.z
|
|
40
|
+
.number()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe("Custom timeout in seconds. Defaults: 20s (simple), 30s (actions), 60s (reply)"),
|
|
43
|
+
},
|
|
44
|
+
}, async ({ message, title, actions, dropdownLabel, reply, timeout }) => {
|
|
45
|
+
try {
|
|
46
|
+
// Get client info to determine which icon to show
|
|
47
|
+
const clientInfo = server.server.getClientVersion();
|
|
48
|
+
const contentImage = (0, notify_js_1.getContentImageForClient)(clientInfo?.name);
|
|
49
|
+
const result = await (0, notify_js_1.notify)({
|
|
50
|
+
message,
|
|
51
|
+
title: title ?? "MCPal",
|
|
52
|
+
actions,
|
|
53
|
+
dropdownLabel,
|
|
54
|
+
reply,
|
|
55
|
+
contentImage,
|
|
56
|
+
timeout,
|
|
57
|
+
});
|
|
58
|
+
// Build a friendly response
|
|
59
|
+
const parts = [];
|
|
60
|
+
parts.push(`Hey! I delivered your message to the user.`);
|
|
61
|
+
parts.push(`Title: "${title ?? "MCPal"}"`);
|
|
62
|
+
parts.push(`Message: "${message}"`);
|
|
63
|
+
// Describe user's response
|
|
64
|
+
if (result.activationType === "contentsClicked") {
|
|
65
|
+
parts.push(`The user clicked the notification.`);
|
|
66
|
+
}
|
|
67
|
+
else if (result.activationType === "actionClicked") {
|
|
68
|
+
parts.push(`The user clicked: ${result.response}`);
|
|
69
|
+
}
|
|
70
|
+
else if (result.activationType === "replied") {
|
|
71
|
+
parts.push(`The user replied: "${result.reply}"`);
|
|
72
|
+
}
|
|
73
|
+
else if (result.response === "timeout") {
|
|
74
|
+
parts.push(`The notification timed out (no response).`);
|
|
75
|
+
}
|
|
76
|
+
else if (result.response === "closed") {
|
|
77
|
+
parts.push(`The user dismissed the notification.`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
parts.push(`User response: ${result.response}`);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: "text", text: parts.join("\n") }],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
content: [
|
|
89
|
+
{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: `Oops! I couldn't deliver that notification. Error: ${error}`,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
isError: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
async function main() {
|
|
99
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
100
|
+
await server.connect(transport);
|
|
101
|
+
}
|
|
102
|
+
main().catch(console.error);
|
|
103
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,oEAAoE;AACpE,wEAAiF;AACjF,6BAAwB;AAExB,2CAA+D;AAE/D,MAAM,MAAM,GAAG,IAAI,kBAAS,CAC1B;IACE,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,OAAO;CACjB,EACD;IACE,YAAY,EAAE;;;;;;;8DAO4C;CAC3D,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;IACE,WAAW,EAAE,oMAAoM;IACjN,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EAAE;QACX,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QAC1D,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QAC/D,OAAO,EAAE,OAAC;aACP,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CACP,6EAA6E,CAC9E;QACH,aAAa,EAAE,OAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,mEAAmE,CACpE;QACH,KAAK,EAAE,OAAC;aACL,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,iIAAiI,CAClI;QACH,OAAO,EAAE,OAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,+EAA+E,CAChF;KACJ;CACF,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;IACnE,IAAI,CAAC;QACH,kDAAkD;QAClD,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACpD,MAAM,YAAY,GAAG,IAAA,oCAAwB,EAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAG,MAAM,IAAA,kBAAM,EAAC;YAC1B,OAAO;YACP,KAAK,EAAE,KAAK,IAAI,OAAO;YACvB,OAAO;YACP,aAAa;YACb,KAAK;YACL,YAAY;YACZ,OAAO;SACR,CAAC,CAAC;QAEH,4BAA4B;QAC5B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QACzD,KAAK,CAAC,IAAI,CAAC,WAAW,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;QAC3C,KAAK,CAAC,IAAI,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC;QAEpC,2BAA2B;QAC3B,IAAI,MAAM,CAAC,cAAc,KAAK,iBAAiB,EAAE,CAAC;YAChD,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACnD,CAAC;aAAM,IAAI,MAAM,CAAC,cAAc,KAAK,eAAe,EAAE,CAAC;YACrD,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;YAC/C,KAAK,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QACpD,CAAC;aAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzC,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1D,CAAC;aAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,kBAAkB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SACpD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,sDAAsD,KAAK,EAAE;iBACpE;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC,CACF,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
package/dist/notify.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function getNotifierPath(): string | undefined;
|
|
2
|
+
export declare const CLIENT_ICONS: Record<string, string>;
|
|
3
|
+
export declare function getClientsDir(): string;
|
|
4
|
+
export declare function getContentImageForClient(clientName?: string): string | undefined;
|
|
5
|
+
export interface NotifyOptions {
|
|
6
|
+
message: string;
|
|
7
|
+
title: string;
|
|
8
|
+
actions?: string[];
|
|
9
|
+
dropdownLabel?: string;
|
|
10
|
+
reply?: boolean;
|
|
11
|
+
contentImage?: string;
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface NotifyResult {
|
|
15
|
+
response: string;
|
|
16
|
+
reply?: string;
|
|
17
|
+
activationType?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function notify(options: NotifyOptions): Promise<NotifyResult>;
|
|
20
|
+
//# sourceMappingURL=notify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.d.ts","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"AAqCA,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAiCpD;AAGD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAQ/C,CAAC;AAEF,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,wBAAwB,CACtC,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAoBpB;AAOD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAgCD,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAwBpE"}
|
package/dist/notify.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.CLIENT_ICONS = void 0;
|
|
7
|
+
exports.getNotifierPath = getNotifierPath;
|
|
8
|
+
exports.getClientsDir = getClientsDir;
|
|
9
|
+
exports.getContentImageForClient = getContentImageForClient;
|
|
10
|
+
exports.notify = notify;
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const node_notifier_1 = __importDefault(require("node-notifier"));
|
|
13
|
+
const os_1 = __importDefault(require("os"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const isMacOS = os_1.default.platform() === "darwin";
|
|
16
|
+
// Find pnpm paths for node-notifier
|
|
17
|
+
function findPnpmPaths() {
|
|
18
|
+
const projectRoot = path_1.default.resolve(__dirname, "..");
|
|
19
|
+
const pnpmDir = path_1.default.join(projectRoot, "node_modules", ".pnpm");
|
|
20
|
+
if (!fs_1.default.existsSync(pnpmDir)) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const entries = fs_1.default.readdirSync(pnpmDir);
|
|
25
|
+
const nodeNotifierDir = entries.find((e) => e.startsWith("node-notifier@"));
|
|
26
|
+
if (nodeNotifierDir) {
|
|
27
|
+
return [
|
|
28
|
+
path_1.default.join(pnpmDir, nodeNotifierDir, "node_modules", "node-notifier", "vendor", "mac.noindex"),
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Ignore errors
|
|
34
|
+
}
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
// Get the path to the renamed MCPal.app notifier executable
|
|
38
|
+
function getNotifierPath() {
|
|
39
|
+
const projectRoot = path_1.default.resolve(__dirname, "..");
|
|
40
|
+
const possiblePaths = [
|
|
41
|
+
// pnpm - check for MCPal.app first
|
|
42
|
+
...findPnpmPaths().map((p) => path_1.default.join(p, "MCPal.app")),
|
|
43
|
+
// npm/yarn - check for MCPal.app first
|
|
44
|
+
path_1.default.join(projectRoot, "node_modules", "node-notifier", "vendor", "mac.noindex", "MCPal.app"),
|
|
45
|
+
// Fallback to terminal-notifier.app (before rename)
|
|
46
|
+
...findPnpmPaths().map((p) => path_1.default.join(p, "terminal-notifier.app")),
|
|
47
|
+
path_1.default.join(projectRoot, "node_modules", "node-notifier", "vendor", "mac.noindex", "terminal-notifier.app"),
|
|
48
|
+
];
|
|
49
|
+
for (const p of possiblePaths) {
|
|
50
|
+
const execPath = path_1.default.join(p, "Contents", "MacOS", "terminal-notifier");
|
|
51
|
+
if (fs_1.default.existsSync(execPath)) {
|
|
52
|
+
return execPath;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
// Map client names to icon filenames
|
|
58
|
+
exports.CLIENT_ICONS = {
|
|
59
|
+
claude: "claude.png",
|
|
60
|
+
"claude-desktop": "claude.png",
|
|
61
|
+
"claude-code": "claude.png",
|
|
62
|
+
cursor: "cursor.png",
|
|
63
|
+
vscode: "vscode.png",
|
|
64
|
+
openai: "openai.png",
|
|
65
|
+
chatgpt: "openai.png",
|
|
66
|
+
};
|
|
67
|
+
function getClientsDir() {
|
|
68
|
+
return path_1.default.resolve(__dirname, "assets", "clients");
|
|
69
|
+
}
|
|
70
|
+
function getContentImageForClient(clientName) {
|
|
71
|
+
// contentImage is a macOS-specific feature (terminal-notifier)
|
|
72
|
+
if (!isMacOS || !clientName) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
// Normalize client name (lowercase, no spaces)
|
|
76
|
+
const normalized = clientName.toLowerCase().replace(/\s+/g, "-");
|
|
77
|
+
// Check for exact match or partial match
|
|
78
|
+
const iconFile = exports.CLIENT_ICONS[normalized] ??
|
|
79
|
+
Object.entries(exports.CLIENT_ICONS).find(([key]) => normalized.includes(key))?.[1];
|
|
80
|
+
if (!iconFile) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const iconPath = path_1.default.join(getClientsDir(), iconFile);
|
|
84
|
+
return fs_1.default.existsSync(iconPath) ? iconPath : undefined;
|
|
85
|
+
}
|
|
86
|
+
// Default timeouts (in seconds)
|
|
87
|
+
const TIMEOUT_SIMPLE = 20; // Simple notification
|
|
88
|
+
const TIMEOUT_ACTIONS = 30; // Notification with action buttons
|
|
89
|
+
const TIMEOUT_REPLY = 60; // Notification with text reply input
|
|
90
|
+
// Create a notifier instance
|
|
91
|
+
// On macOS: uses customPath pointing to our renamed MCPal.app
|
|
92
|
+
// On other platforms: uses default node-notifier (Linux: notify-send, Windows: toast)
|
|
93
|
+
function getNotifier() {
|
|
94
|
+
if (isMacOS) {
|
|
95
|
+
const customPath = getNotifierPath();
|
|
96
|
+
if (customPath) {
|
|
97
|
+
// Create a NotificationCenter instance with customPath in constructor options
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
99
|
+
return new node_notifier_1.default.NotificationCenter({ customPath });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// On non-macOS or if customPath not found, use default notifier
|
|
103
|
+
return node_notifier_1.default;
|
|
104
|
+
}
|
|
105
|
+
// Determine appropriate timeout based on notification type
|
|
106
|
+
function getTimeout(options) {
|
|
107
|
+
if (options.timeout !== undefined) {
|
|
108
|
+
return options.timeout; // User-specified timeout takes precedence
|
|
109
|
+
}
|
|
110
|
+
if (options.reply) {
|
|
111
|
+
return TIMEOUT_REPLY; // Reply needs most time (typing)
|
|
112
|
+
}
|
|
113
|
+
if (options.actions && options.actions.length > 0) {
|
|
114
|
+
return TIMEOUT_ACTIONS; // Actions need moderate time
|
|
115
|
+
}
|
|
116
|
+
return TIMEOUT_SIMPLE; // Simple notifications are quick
|
|
117
|
+
}
|
|
118
|
+
function notify(options) {
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const notificationOptions = {
|
|
121
|
+
title: options.title,
|
|
122
|
+
message: options.message,
|
|
123
|
+
wait: true,
|
|
124
|
+
timeout: getTimeout(options),
|
|
125
|
+
actions: options.actions,
|
|
126
|
+
dropdownLabel: options.dropdownLabel,
|
|
127
|
+
reply: options.reply,
|
|
128
|
+
...(options.contentImage && { contentImage: options.contentImage }),
|
|
129
|
+
};
|
|
130
|
+
getNotifier().notify(notificationOptions, (err, response, metadata) => {
|
|
131
|
+
if (err) {
|
|
132
|
+
return reject(err);
|
|
133
|
+
}
|
|
134
|
+
resolve({
|
|
135
|
+
response: String(response),
|
|
136
|
+
reply: metadata?.activationValue,
|
|
137
|
+
activationType: metadata?.activationType,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notify.js","sourceRoot":"","sources":["../src/notify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-notifier.d.ts","sourceRoot":"","sources":["../../src/scripts/setup-notifier.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
// Only run on macOS
|
|
10
|
+
if (process.platform !== "darwin") {
|
|
11
|
+
console.log("Skipping macOS-specific notification icon setup");
|
|
12
|
+
process.exit(0);
|
|
13
|
+
}
|
|
14
|
+
const projectRoot = path_1.default.resolve(__dirname, "..", "..");
|
|
15
|
+
const icnsSource = path_1.default.join(projectRoot, "src", "assets", "mcpal.icns");
|
|
16
|
+
function findPnpmPaths() {
|
|
17
|
+
const pnpmDir = path_1.default.join(projectRoot, "node_modules", ".pnpm");
|
|
18
|
+
if (!fs_1.default.existsSync(pnpmDir)) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const entries = fs_1.default.readdirSync(pnpmDir);
|
|
23
|
+
const nodeNotifierDir = entries.find((e) => e.startsWith("node-notifier@"));
|
|
24
|
+
if (nodeNotifierDir) {
|
|
25
|
+
return [
|
|
26
|
+
path_1.default.join(pnpmDir, nodeNotifierDir, "node_modules", "node-notifier", "vendor", "mac.noindex", "terminal-notifier.app"),
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// Ignore errors
|
|
32
|
+
}
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
function findTerminalNotifier() {
|
|
36
|
+
const possiblePaths = [
|
|
37
|
+
// npm/yarn
|
|
38
|
+
path_1.default.join(projectRoot, "node_modules", "node-notifier", "vendor", "mac.noindex", "terminal-notifier.app"),
|
|
39
|
+
// pnpm (search in .pnpm)
|
|
40
|
+
...findPnpmPaths(),
|
|
41
|
+
];
|
|
42
|
+
for (const p of possiblePaths) {
|
|
43
|
+
if (fs_1.default.existsSync(p)) {
|
|
44
|
+
return p;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const terminalNotifierApp = findTerminalNotifier();
|
|
50
|
+
if (!terminalNotifierApp) {
|
|
51
|
+
console.log("terminal-notifier.app not found, skipping icon setup");
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
// Rename to MCPal.app for proper macOS registration
|
|
55
|
+
const parentDir = path_1.default.dirname(terminalNotifierApp);
|
|
56
|
+
const mcpalApp = path_1.default.join(parentDir, "MCPal.app");
|
|
57
|
+
if (!fs_1.default.existsSync(mcpalApp)) {
|
|
58
|
+
fs_1.default.renameSync(terminalNotifierApp, mcpalApp);
|
|
59
|
+
console.log("Renamed app bundle to MCPal.app");
|
|
60
|
+
}
|
|
61
|
+
const resourcesDir = path_1.default.join(mcpalApp, "Contents", "Resources");
|
|
62
|
+
const infoPlist = path_1.default.join(mcpalApp, "Contents", "Info.plist");
|
|
63
|
+
// Check if source icon exists
|
|
64
|
+
if (!fs_1.default.existsSync(icnsSource)) {
|
|
65
|
+
console.log("Icon file not found:", icnsSource);
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
// Copy the new icon
|
|
70
|
+
const icnsDest = path_1.default.join(resourcesDir, "mcpal.icns");
|
|
71
|
+
fs_1.default.copyFileSync(icnsSource, icnsDest);
|
|
72
|
+
console.log("Copied icon to:", icnsDest);
|
|
73
|
+
// Update Info.plist to use the new icon
|
|
74
|
+
let plistContent = fs_1.default.readFileSync(infoPlist, "utf8");
|
|
75
|
+
// Replace icon reference (Terminal.icns -> mcpal.icns)
|
|
76
|
+
plistContent = plistContent.replace(/<key>CFBundleIconFile<\/key>\s*<string>[^<]+<\/string>/, "<key>CFBundleIconFile</key>\n\t<string>mcpal</string>");
|
|
77
|
+
// Optionally update bundle identifier to avoid conflicts
|
|
78
|
+
plistContent = plistContent.replace(/<key>CFBundleIdentifier<\/key>\s*<string>[^<]+<\/string>/, "<key>CFBundleIdentifier</key>\n\t<string>com.mcpal</string>");
|
|
79
|
+
// Update bundle name (shown in System Preferences > Notifications)
|
|
80
|
+
plistContent = plistContent.replace(/<key>CFBundleName<\/key>\s*<string>[^<]+<\/string>/, "<key>CFBundleName</key>\n\t<string>MCPal</string>");
|
|
81
|
+
fs_1.default.writeFileSync(infoPlist, plistContent);
|
|
82
|
+
console.log("Updated Info.plist");
|
|
83
|
+
console.log("macOS notification icon setup complete!");
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
87
|
+
console.error("Failed to setup notification icon:", message);
|
|
88
|
+
// Don't fail the install
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=setup-notifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-notifier.js","sourceRoot":"","sources":["../../src/scripts/setup-notifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Test script for MCPal
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* pnpm run test:notification [test-type]
|
|
7
|
+
*
|
|
8
|
+
* Test types:
|
|
9
|
+
* simple - Basic notification (default)
|
|
10
|
+
* actions - Notification with action buttons
|
|
11
|
+
* reply - Notification with text reply input
|
|
12
|
+
* all - Run all tests sequentially
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=test-notification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-notification.d.ts","sourceRoot":"","sources":["../../src/scripts/test-notification.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* Test script for MCPal
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* pnpm run test:notification [test-type]
|
|
8
|
+
*
|
|
9
|
+
* Test types:
|
|
10
|
+
* simple - Basic notification (default)
|
|
11
|
+
* actions - Notification with action buttons
|
|
12
|
+
* reply - Notification with text reply input
|
|
13
|
+
* all - Run all tests sequentially
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
const notify_js_1 = require("../notify.js");
|
|
17
|
+
// For testing, simulate being a Claude client
|
|
18
|
+
const testClientName = "claude";
|
|
19
|
+
const contentImage = (0, notify_js_1.getContentImageForClient)(testClientName);
|
|
20
|
+
console.log("Clients dir:", (0, notify_js_1.getClientsDir)());
|
|
21
|
+
console.log("Test client:", testClientName);
|
|
22
|
+
console.log("Content image:", contentImage ?? "(none)");
|
|
23
|
+
const testType = process.argv[2] || "simple";
|
|
24
|
+
async function testSimple() {
|
|
25
|
+
console.log("\n--- Testing: Simple Notification ---");
|
|
26
|
+
const result = await (0, notify_js_1.notify)({
|
|
27
|
+
title: "Test Notification",
|
|
28
|
+
message: "This is a simple test notification.",
|
|
29
|
+
contentImage,
|
|
30
|
+
});
|
|
31
|
+
console.log("Result:", result);
|
|
32
|
+
}
|
|
33
|
+
async function testActions() {
|
|
34
|
+
console.log("\n--- Testing: Notification with Actions ---");
|
|
35
|
+
console.log('Click "Show" to see the dropdown menu.');
|
|
36
|
+
const result = await (0, notify_js_1.notify)({
|
|
37
|
+
title: "Action Test",
|
|
38
|
+
message: "Choose an option from the dropdown.",
|
|
39
|
+
actions: ["Accept", "Reject", "Later"],
|
|
40
|
+
dropdownLabel: "Choose Action",
|
|
41
|
+
contentImage,
|
|
42
|
+
});
|
|
43
|
+
console.log("Result:", result);
|
|
44
|
+
}
|
|
45
|
+
async function testReply() {
|
|
46
|
+
console.log("\n--- Testing: Notification with Reply ---");
|
|
47
|
+
console.log("Type a reply in the text field.");
|
|
48
|
+
const result = await (0, notify_js_1.notify)({
|
|
49
|
+
title: "Reply Test",
|
|
50
|
+
message: "What would you like to say?",
|
|
51
|
+
reply: true,
|
|
52
|
+
contentImage,
|
|
53
|
+
});
|
|
54
|
+
console.log("Result:", result);
|
|
55
|
+
}
|
|
56
|
+
async function runTests() {
|
|
57
|
+
try {
|
|
58
|
+
switch (testType) {
|
|
59
|
+
case "simple":
|
|
60
|
+
await testSimple();
|
|
61
|
+
break;
|
|
62
|
+
case "actions":
|
|
63
|
+
await testActions();
|
|
64
|
+
break;
|
|
65
|
+
case "reply":
|
|
66
|
+
await testReply();
|
|
67
|
+
break;
|
|
68
|
+
case "all":
|
|
69
|
+
await testSimple();
|
|
70
|
+
await testActions();
|
|
71
|
+
await testReply();
|
|
72
|
+
console.log("\n--- All tests complete ---");
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
console.error(`Unknown test type: ${testType}`);
|
|
76
|
+
console.log("Available: simple, actions, reply, all");
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
console.error("Test failed:", err);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
console.log("MCPal Test Script");
|
|
86
|
+
console.log("============================");
|
|
87
|
+
console.log(`Running test: ${testType}`);
|
|
88
|
+
runTests();
|
|
89
|
+
//# sourceMappingURL=test-notification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-notification.js","sourceRoot":"","sources":["../../src/scripts/test-notification.ts"],"names":[],"mappings":"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"}
|
package/license.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcpal",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "MCP server that sends native notifications with LLM-aware icons",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mcpal": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/",
|
|
11
|
+
"src/assets/"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"postinstall": "node dist/scripts/setup-notifier.js",
|
|
15
|
+
"test:notification": "node dist/scripts/test-notification.js",
|
|
16
|
+
"build": "tsc && cp -r src/assets dist/",
|
|
17
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
18
|
+
"lint": "eslint . --ext .ts",
|
|
19
|
+
"lint:fix": "eslint . --ext .ts --fix",
|
|
20
|
+
"format:fix": "prettier --write \"src/**/*.ts\"",
|
|
21
|
+
"prepare": "husky",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"prepublishOnly": "pnpm run build && pnpm run typecheck"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"mcp",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"notifications",
|
|
29
|
+
"macos",
|
|
30
|
+
"linux",
|
|
31
|
+
"windows",
|
|
32
|
+
"claude",
|
|
33
|
+
"llm",
|
|
34
|
+
"desktop-notifications"
|
|
35
|
+
],
|
|
36
|
+
"author": "MJ Lee",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/mjkid221/mcPal.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/mjkid221/mcPal#readme",
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/mjkid221/mcPal/issues"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18.0.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
51
|
+
"node-notifier": "^10.0.1",
|
|
52
|
+
"zod": "^4.3.6"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/ms": "^2.1.0",
|
|
56
|
+
"@types/node": "^25.2.0",
|
|
57
|
+
"@types/node-notifier": "^8.0.5",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^8.18.2",
|
|
59
|
+
"@typescript-eslint/parser": "^8.18.2",
|
|
60
|
+
"eslint": "^8.56.0",
|
|
61
|
+
"eslint-config-prettier": "^9.1.0",
|
|
62
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
63
|
+
"husky": "^9.1.7",
|
|
64
|
+
"lint-staged": "^15.3.0",
|
|
65
|
+
"tsx": "^4.19.2",
|
|
66
|
+
"typescript": "^5.7.3"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|