{"_id":"@akito.sakuraba/notify-mcp","name":"@akito.sakuraba/notify-mcp","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@akito.sakuraba/notify-mcp","version":"0.1.0","description":"Cross-platform desktop notification MCP server (macOS / Windows / Linux). Replaces per-host hook setup for Claude Code / Claude Desktop.","type":"module","bin":{"notify-mcp":"dist/index.js"},"main":"dist/index.js","exports":{".":"./dist/index.js"},"scripts":{"build":"tsc -p tsconfig.json","clean":"rm -rf dist","prepare":"npm run build","prepublishOnly":"npm run clean && npm run build && npm run typecheck && npm test","start":"node dist/index.js","dev":"tsx src/index.ts","test":"vitest run","test:watch":"vitest","typecheck":"tsc -p tsconfig.json --noEmit","format":"prettier --write \"src/**/*.ts\" \"test/**/*.ts\"","format:check":"prettier --check \"src/**/*.ts\" \"test/**/*.ts\"","smoke":"node scripts/smoke.mjs"},"dependencies":{"@modelcontextprotocol/sdk":"^1.0.4","smol-toml":"^1.6.1","zod":"^4.4.3"},"devDependencies":{"@types/node":"^22.5.0","prettier":"^3.3.3","tsx":"^4.22.2","typescript":"^5.6.0","vitest":"^4.1.6"},"engines":{"node":">=18.17"},"license":"MIT","author":{"name":"Akito Sakuraba","url":"https://github.com/AkitoSakurabaCreator"},"repository":{"type":"git","url":"git+https://github.com/AkitoSakurabaCreator/notify-mcp.git"},"homepage":"https://github.com/AkitoSakurabaCreator/notify-mcp#readme","bugs":{"url":"https://github.com/AkitoSakurabaCreator/notify-mcp/issues"},"keywords":["mcp","model-context-protocol","notification","desktop-notification","cross-platform","macos","windows","linux","claude","claude-code"],"publishConfig":{"access":"public"},"_id":"@akito.sakuraba/notify-mcp@0.1.0","gitHead":"9aabf68b7706843dd2d9fcf208f32e254f58f257","types":"./dist/index.d.ts","_nodeVersion":"24.7.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-mxxr9ejVmqfN10Ky30IRqAbDBaS0DOASIVtzQQdpL1qOvgsaPQ2Qf5egmIr/ME+Vf5LxoF0+C+ZTOYCDgGjduw==","shasum":"44843b2230ef6f7ff87e07d4146959a24a2f4095","tarball":"https://registry.npmjs.org/@akito.sakuraba/notify-mcp/-/notify-mcp-0.1.0.tgz","fileCount":40,"unpackedSize":102065,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBeWNXoUGWumF4CKEvxsML9um8sx/1tuBz5HKVU7JxuGAiAemNwvv/aPTU7BXgRCeANfL4Qb8EGwRtQyZxR3fTomYA=="}]},"_npmUser":{"name":"akito.sakuraba","email":"sakurabaakitocreations@gmail.com"},"directories":{},"maintainers":[{"name":"akito.sakuraba","email":"sakurabaakitocreations@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/notify-mcp_0.1.0_1779118065398_0.31587921585791734"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-18T15:27:45.272Z","0.1.0":"2026-05-18T15:27:45.567Z","modified":"2026-05-18T15:27:46.223Z"},"maintainers":[{"name":"akito.sakuraba","email":"sakurabaakitocreations@gmail.com"}],"description":"Cross-platform desktop notification MCP server (macOS / Windows / Linux). Replaces per-host hook setup for Claude Code / Claude Desktop.","homepage":"https://github.com/AkitoSakurabaCreator/notify-mcp#readme","keywords":["mcp","model-context-protocol","notification","desktop-notification","cross-platform","macos","windows","linux","claude","claude-code"],"repository":{"type":"git","url":"git+https://github.com/AkitoSakurabaCreator/notify-mcp.git"},"author":{"name":"Akito Sakuraba","url":"https://github.com/AkitoSakurabaCreator"},"bugs":{"url":"https://github.com/AkitoSakurabaCreator/notify-mcp/issues"},"license":"MIT","readme":"# notify-mcp\n\n[![npm version](https://img.shields.io/npm/v/@akito.sakuraba/notify-mcp.svg)](https://www.npmjs.com/package/@akito.sakuraba/notify-mcp)\n[![CI](https://github.com/AkitoSakurabaCreator/notify-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/AkitoSakurabaCreator/notify-mcp/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![Node](https://img.shields.io/node/v/@akito.sakuraba/notify-mcp.svg)](./package.json)\n\n> 🇯🇵 **日本語の README は [README.ja.md](./README.ja.md) にあります。**\n\nCross-platform desktop notification MCP server. One install, three OSes, five clients.\n\n`notify-mcp` is a small [Model Context Protocol](https://modelcontextprotocol.io) server that exposes three tools — `notify`, `list_sounds`, `play_sound` — so any MCP client (Claude Code, Claude Desktop, Cursor, OpenAI Codex CLI, Google Antigravity, …) can pop a desktop notification on **macOS**, **Windows**, or **Linux** without per-host hook configuration.\n\n- Single npm package, runs over MCP stdio.\n- No native dependencies. Pure Node, uses each OS's built-in notifier:\n  - **macOS** → `osascript` (`display notification`)\n  - **Windows** → PowerShell + WinRT `ToastNotificationManager`\n  - **Linux** → `notify-send` (libnotify)\n- Sound support: built-in OS system sounds, or any absolute `.wav` / `.aiff` path.\n- **Built-in installer** (`notify-mcp install <client>`) writes the right config block into each client — no more hand-editing JSON / TOML on every machine.\n- Security-conscious: argv-only subprocess invocation, env-var passthrough for untrusted strings, input sanitization, length caps, file-size cap.\n\n---\n\n## Install\n\nThe package is intended to be run via `npx` so users do not have to install it globally.\n\n```sh\n# one-shot (recommended)\nnpx -y @akito.sakuraba/notify-mcp\n\n# or install globally\npnpm add -g @akito.sakuraba/notify-mcp\nnpm  i  -g @akito.sakuraba/notify-mcp\n```\n\n## One-command client setup\n\nInstead of hand-editing each client's config, use the bundled installer:\n\n```sh\n# Install into a specific client (creates the config if missing, merges if existing).\nnpx -y @akito.sakuraba/notify-mcp install claude-code\nnpx -y @akito.sakuraba/notify-mcp install claude-desktop\nnpx -y @akito.sakuraba/notify-mcp install cursor\nnpx -y @akito.sakuraba/notify-mcp install codex\nnpx -y @akito.sakuraba/notify-mcp install antigravity\n\n# Install into every supported client at once.\nnpx -y @akito.sakuraba/notify-mcp install --all\n\n# Preview without writing.\nnpx -y @akito.sakuraba/notify-mcp install --all --dry-run\n\n# Use a different server key inside mcpServers / mcp_servers.\nnpx -y @akito.sakuraba/notify-mcp install cursor --name desktop-notify\n\n# Show every config path the installer would touch, and whether it exists.\nnpx -y @akito.sakuraba/notify-mcp list-clients\n\n# Remove the entry later.\nnpx -y @akito.sakuraba/notify-mcp uninstall claude-code\n```\n\nThe installer:\n\n1. Reads the existing config (JSON for Claude Code / Claude Desktop / Cursor / Antigravity, TOML for Codex).\n2. Backs it up to `<path>.bak-YYYYMMDD-HHmmss` before overwriting.\n3. Merges (or creates) the `notify` entry under `mcpServers` (or `mcp_servers` for Codex).\n4. Leaves every other field of your config untouched.\n\nIf a config file is malformed, the installer still writes a backup, then rewrites a clean file containing your `notify` entry.\n\n### Where each client stores its config\n\n| Client | Path | Format |\n|---|---|---|\n| Claude Code (CLI) | `~/.claude.json` | JSON |\n| Claude Desktop (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` | JSON |\n| Claude Desktop (Windows) | `%APPDATA%\\Claude\\claude_desktop_config.json` | JSON |\n| Claude Desktop (Linux, unofficial) | `~/.config/Claude/claude_desktop_config.json` | JSON |\n| Cursor | `~/.cursor/mcp.json` | JSON |\n| OpenAI Codex CLI | `~/.codex/config.toml` (table `[mcp_servers.<name>]`) | TOML |\n| Google Antigravity | `~/.gemini/antigravity/mcp_config.json` | JSON |\n\nIf you prefer to edit by hand, all five clients accept the same shape:\n\n```jsonc\n// JSON clients (claude-code, claude-desktop, cursor, antigravity)\n{\n  \"mcpServers\": {\n    \"notify\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@akito.sakuraba/notify-mcp\"]\n    }\n  }\n}\n```\n\n```toml\n# OpenAI Codex CLI (~/.codex/config.toml)\n[mcp_servers.notify]\ncommand = \"npx\"\nargs = [\"-y\", \"@akito.sakuraba/notify-mcp\"]\n```\n\nAfter editing, restart the client. The tools `notify`, `list_sounds`, and `play_sound` will appear.\n\n---\n\n## Tools\n\n### `notify`\n\nSend a desktop notification.\n\n| Field | Type | Required | Notes |\n|---|---|---|---|\n| `title` | string (1–256) | yes | Notification title shown to the user. |\n| `message` | string (1–4096) | yes | Notification body. |\n| `urgency` | `\"low\" \\| \"normal\" \\| \"critical\"` | no | Linux `notify-send` only. Ignored elsewhere. |\n| `sound` | string (1–1024) | no | `\"system:NAME\"` (see `list_sounds`) or an **absolute** file path. |\n\nReturns:\n\n```json\n{\n  \"delivered\": true,\n  \"platform\": \"darwin\",\n  \"method\": \"osascript\",\n  \"sound\": { \"played\": true, \"method\": \"afplay\" }\n}\n```\n\n### `list_sounds`\n\nReturn the platform's built-in system-sound names. Example output on macOS:\n\n```json\n{\n  \"platform\": \"darwin\",\n  \"sounds\": [\"Basso\", \"Blow\", \"Bottle\", \"Frog\", \"Funk\", \"Glass\", \"Hero\",\n             \"Morse\", \"Ping\", \"Pop\", \"Purr\", \"Sosumi\", \"Submarine\", \"Tink\"]\n}\n```\n\n- Windows: `Beep, Asterisk, Exclamation, Hand, Question`\n- Linux: a small libcanberra set (`bell, message, complete, alarm, dialog-warning`)\n\n### `play_sound`\n\nPlay a sound **without** sending a notification.\n\n| Field | Type | Required |\n|---|---|---|\n| `sound` | string (1–1024): `\"system:NAME\"` or absolute path | yes |\n\n## Custom sound files\n\nAbsolute paths only. The file must exist, be a regular file, and be ≤ 10 MB. macOS uses `afplay`, Windows uses `System.Media.SoundPlayer`, Linux tries `paplay` then `aplay`.\n\n---\n\n## Security\n\n- All subprocesses are spawned with `execFile` / `spawn` — **no shell**, so argv values are never interpreted by `/bin/sh` / `cmd.exe`.\n- Windows PowerShell scripts are fixed-literal strings. Untrusted values are passed through **environment variables**, not interpolated.\n- macOS AppleScript values are escaped per AppleScript string-literal rules (`\\` → `\\\\`, `\"` → `\\\"`).\n- Windows WinRT toast XML is escaped per XML rules (`& < > \" '`).\n- Control characters (except TAB / LF / CR) are stripped from `title` and `message`.\n- Length caps: title 256, message 4096, sound spec 1024.\n- Sound file: absolute path required, size capped at 10 MB.\n- Notification subprocess timeout: 5 s. Sound subprocess timeout: 10 s.\n- The installer backs up every existing config before overwriting it.\n\n## Platform-specific notes\n\n### macOS\n\n- First-time `display notification` triggers a one-time permission grant for \"Script Editor\". After that, banners just work.\n- Sound files: `.aiff`, `.wav`, `.mp3`, etc. — anything `afplay` accepts.\n\n### Windows\n\n- Requires PowerShell 5.1+ (ships with Windows 10/11). No third-party PowerShell module needed.\n- Toast notifications appear in the Action Center.\n- Some Windows policies suppress toast for non-AppUserModelID processes; using `npx -y @akito.sakuraba/notify-mcp` is the simplest robust default.\n\n### Linux (Ubuntu / etc.)\n\n- Requires `libnotify-bin` (provides `notify-send`). Install: `sudo apt install libnotify-bin`.\n- For built-in system sounds: `libcanberra-gtk-module` / `canberra-gtk-play`.\n- For file sounds: `pulseaudio-utils` (`paplay`) or `alsa-utils` (`aplay`).\n\n---\n\n## Development\n\n```sh\npnpm install\npnpm typecheck    # tsc --noEmit\npnpm test         # vitest run (64 cases)\npnpm build        # tsc → dist/\npnpm smoke        # spawn dist/index.js and run a real notification flow\n```\n\n### Repository layout\n\n```\nsrc/\n  index.ts       # bin entrypoint (CLI + stdio transport)\n  cli.ts         # argv parser, install/uninstall/list-clients/help/version\n  install.ts     # client registry, JSON+TOML merge, backups\n  server.ts      # MCP server + tool registrations\n  notifier.ts    # cross-platform notification dispatcher\n  sound.ts       # cross-platform sound player\n  sanitize.ts    # input sanitization + per-platform escapes\n  platform.ts    # OS detection\n  errors.ts      # typed error helpers\ntest/\n  *.test.ts      # vitest specs (sanitize / sound / notifier / server / cli / install)\nscripts/\n  smoke.mjs      # end-to-end smoke runner\n```\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n","readmeFilename":"README.md","_rev":"1-cb4c64ba84e7503959807be90b9ab966"}