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 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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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":"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"}
@@ -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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=setup-notifier.d.ts.map
@@ -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":";;;;;;AAEA,4CAAoB;AACpB,gDAAwB;AAExB,oBAAoB;AACpB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;IAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACxD,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AAEzE,SAAS,aAAa;IACpB,MAAM,OAAO,GAAG,cAAI,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAChE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACxC,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAC5E,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO;gBACL,cAAI,CAAC,IAAI,CACP,OAAO,EACP,eAAe,EACf,cAAc,EACd,eAAe,EACf,QAAQ,EACR,aAAa,EACb,uBAAuB,CACxB;aACF,CAAC;QACJ,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,gBAAgB;IAClB,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,oBAAoB;IAC3B,MAAM,aAAa,GAAG;QACpB,WAAW;QACX,cAAI,CAAC,IAAI,CACP,WAAW,EACX,cAAc,EACd,eAAe,EACf,QAAQ,EACR,aAAa,EACb,uBAAuB,CACxB;QACD,yBAAyB;QACzB,GAAG,aAAa,EAAE;KACnB,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,IAAI,YAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,mBAAmB,GAAG,oBAAoB,EAAE,CAAC;AAEnD,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACzB,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,oDAAoD;AACpD,MAAM,SAAS,GAAG,cAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACpD,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;AAEnD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC7B,YAAE,CAAC,UAAU,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,YAAY,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAClE,MAAM,SAAS,GAAG,cAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAEhE,8BAA8B;AAC9B,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,UAAU,CAAC,CAAC;IAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,CAAC;IACH,oBAAoB;IACpB,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACvD,YAAE,CAAC,YAAY,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAEzC,wCAAwC;IACxC,IAAI,YAAY,GAAG,YAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAEtD,uDAAuD;IACvD,YAAY,GAAG,YAAY,CAAC,OAAO,CACjC,wDAAwD,EACxD,uDAAuD,CACxD,CAAC;IAEF,yDAAyD;IACzD,YAAY,GAAG,YAAY,CAAC,OAAO,CACjC,0DAA0D,EAC1D,6DAA6D,CAC9D,CAAC;IAEF,mEAAmE;IACnE,YAAY,GAAG,YAAY,CAAC,OAAO,CACjC,oDAAoD,EACpD,mDAAmD,CACpD,CAAC;IAEF,YAAE,CAAC,aAAa,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAElC,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;AACzD,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,OAAO,CAAC,CAAC;IAC7D,yBAAyB;IACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -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