Skip to main content
Glama

Ring MCP

An MCP (Model Context Protocol) server for Claude Code that shows always-on-top notification popups with sound when tasks complete — with a graceful OS-native notification fallback if the popup can't open.

Never miss when Claude finishes a task again!

Features

  • One window, many tabs — every concurrent ring (across sessions, MCP clients, anything) becomes a tab in the same always-on-top window. No popup spam, no overlapping cascades

  • Always-on-top — wins over fullscreen apps via screen-saver window level; renders on the monitor your cursor is on

  • Bell sound + Mute toggle — pleasant ring loops until you respond; click 🔊 Sound (or Ctrl+M) to silence the bell while keeping the popup

  • Interactive responses — type a free-form reply, pick from a list of options (checkboxes / radios), or both

  • Quick-pick keyboard1-9 toggle options, Enter answer, Esc dismiss current tab, Tab / Shift+Tab cycle tabs

  • No timeout by default — popups wait until you handle them manually. Opt-in timeoutMs if you want auto-dismiss

  • Dismiss-all — one click in the toolbar resolves every pending tab as dismissed

  • Per-tab draft preservation — switching tabs keeps your typed text + selections intact

  • Native notification fallback — if Electron can't launch (no display, missing binary, etc.), falls back to PowerShell toast (Windows), osascript (macOS), or notify-send (Linux) and reports the failure reason back to Claude

  • Cross-platform — Windows, macOS, Linux

  • One-click setup — automatic Claude Code configuration with atomic config writes and timestamped backups

Related MCP server: Toast MCP Server

Quick Install

npx ring-mcp-setup

Option 2: Global install

npm install -g ring-mcp
ring-mcp-setup

Option 3: Clone from GitHub

git clone https://github.com/drgost1/ring-mcp.git
cd ring-mcp
npm install
npm run setup

After installation, restart Claude Code to activate the ring tool.

Usage

Once installed, Claude Code automatically has access to the ring tool. Claude will use it intelligently to notify you when:

  • A build or compilation finishes

  • Tests complete (pass or fail)

  • A feature implementation is done

  • An error needs your attention

  • User input is required to continue

Manual usage

You can also ask Claude to use it directly:

"Use the ring tool to notify me when you're done"

Example tool calls

Simple notification:

ring({
  title: "Build Complete",
  message: "The project compiled successfully. Ready for testing?"
})

Multi-select checklist — let the user pick several items in one click:

ring({
  title: "Pick tasks to run now",
  message: "Which of these should I do this session?",
  options: [
    "Build YoPekka",
    "Deploy bangopower.com",
    "Fix shinbao login bug",
    "Review PRs",
    "Update dependencies"
  ]
  // selectionMode defaults to "multiple", allowText defaults to false when options are present
})

Single-select with optional note:

ring({
  title: "Stack choice",
  message: "Which framework for the admin panel?",
  options: ["Livewire", "Plain Blade", "Inertia + Vue"],
  selectionMode: "single",
  allowText: true   // user can also leave a note
})

Tool parameters

Field

Type

Required

Description

title

string

yes

Title shown in the tab (max 200 chars)

message

string

yes

Body shown in the tab (max 5000 chars)

options

string[]

no

If provided, the tab renders checkboxes / radios instead of plain text input. Up to 12 items, each up to 200 chars

selectionMode

"single" | "multiple"

no

How options behave. Default "multiple" (checkboxes). Ignored without options

allowText

boolean

no

When options is set, also show the text input for a free-form note. Default: false with options, true without

timeoutMs

number

no

Auto-dismiss timeout in ms (1000–3600000). Default 0 = wait forever — the user explicitly handles each ring

Keyboard shortcuts

Key

Action

Enter

Submit the active tab

Esc

Dismiss the active tab

1-9

Toggle the corresponding option

Tab / Shift+Tab

Cycle through open tabs

Ctrl+M / ⌘M

Mute / unmute the bell

Response format

Plain text reply: User answered: <text>

Options selected: User answered: Selected: opt1, opt3

Options + text: User answered: Selected: opt1, opt3 | Note: <text>

Dismissed: User dismissed the notification without answering.

Timed out: Notification auto-dismissed after <ms>ms with no response.

How it works

Ring uses a shared daemon + tabs model so multiple concurrent rings never spam your screen:

  1. Claude (or any MCP client) calls the ring tool with a title, message, and optional options

  2. The MCP server writes a request file to <tmpdir>/ring-mcp/requests/<uuid>.json

  3. A single Electron daemon (started on first request, shared across every Claude Code session) picks the file up via fs.watch and opens a new tab in the same always-on-top window

  4. You answer or dismiss — the daemon writes a response file to <tmpdir>/ring-mcp/responses/<uuid>.json

  5. Each MCP call resolves with its own response, in whatever order you handled them

  6. When all tabs are gone (or you click Dismiss-all / close the window), the daemon exits

If the Electron daemon cannot launch (no display, missing binary, sandbox restriction), the server falls back to an OS-native notification (PowerShell toast / osascript / notify-send) and reports the failure to Claude — the user can't reply through the fallback.

Configuration

The setup script atomically updates ~/.claude.json:

{
  "mcpServers": {
    "ring": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/ring-mcp/dist/index.js"],
      "env": {}
    }
  }
}

If your existing ~/.claude.json is already present, setup creates a timestamped backup (.bak-<timestamp>) before writing. If the existing file is malformed JSON, setup quarantines it as .broken-<timestamp>.bak and writes a fresh config instead of failing.

Environment variables

You can tweak runtime behaviour without re-running setup by adding env vars to the env object in ~/.claude.json:

Variable

Effect

RING_TIMEOUT_MS

Default auto-dismiss timeout in ms (overrides the 5-minute default)

RING_DISABLED=1

Skip the popup entirely. The tool returns a stub response and logs to stderr — useful for headless /loop runs

Making Claude use it automatically

Add this to your project's CLAUDE.md or ~/.claude/CLAUDE.md:

## Notification Behavior

When you complete a significant task, use the `ring` tool to notify the user.
Use it for: builds, tests, deployments, feature completions, or when you need input.
Don't use it for: simple Q&A, quick edits, or rapid back-and-forth chat.

Troubleshooting

Ring tool not available

  1. Run claude mcp list to check if the server is connected

  2. If not listed, run ring-mcp-setup again

  3. Restart Claude Code

Notification not appearing

  1. Check Electron is installed: npx electron --version

  2. Rebuild: cd /path/to/ring-mcp && npm run build

  3. Check Claude's stderr — the server logs the exact failure reason and whether the native notification fallback fired

Electron crashes on launch (Windows)

The server already disables hardware acceleration and the GPU sandbox. If it still crashes, try RING_DISABLED=1 to confirm the rest of the chain works, then look at the Electron stderr for the underlying GPU/sandbox error.

Sound not playing

The ring uses the Web Audio API. If no sound plays:

  • Check system volume

  • Some systems block audio from headless / sandboxed Electron apps — the popup remains visible regardless

Development

git clone https://github.com/drgost1/ring-mcp.git
cd ring-mcp
npm install
npm run build

# End-to-end test: 3 concurrent rings → one window with 3 tabs
printf '%s\n%s\n%s\n%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1.0"}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"ring","arguments":{"title":"Tab #1","message":"Pick one","options":["A","B","C"],"selectionMode":"single"}}}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"ring","arguments":{"title":"Tab #2","message":"Pick many","options":["X","Y","Z"]}}}' \
  '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"ring","arguments":{"title":"Tab #3","message":"Free text"}}}' \
  | node dist/index.js

# Direct daemon (skip MCP layer):
npx electron electron/main.cjs --ring-from-env  # legacy single-popup mode
npx electron electron/main.cjs --daemon         # daemon mode (drop request files into <tmp>/ring-mcp/requests/)

Tech stack

  • TypeScript — MCP server

  • Electron — desktop notification UI

  • Web Audio API — sound generation

  • Model Context Protocol SDK — Claude Code integration

License

MIT

Contributing

Contributions welcome! Please open an issue or PR.


Made with Claude Code

Available Tools

1 tool
ringA

Ring a notification bell that opens a tab in a single always-on-top popup window. Multiple concurrent rings appear as tabs in the same window — the user switches between them and answers each independently. Each tab supports a free-form text reply, multi/single-select options (1-9 keys to toggle, Enter to submit, Esc to dismiss), or both. There is no auto-dismiss by default; the popup waits for the user. The user can also Mute the bell or Dismiss All from the toolbar. If the popup cannot be shown, the server falls back to an OS-native notification and reports the failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
titleYesNotification title (max 200 chars)
messageYesNotification body (max 5000 chars)
optionsNoOptional list of choices. When provided, the tab renders checkboxes (or radios in 'single' selectionMode) instead of just a text field. Up to 12 items, each up to 200 chars.
allowTextNoWhen options are provided, also show the free-form text input alongside them. Default: false when options are provided, true when no options.
timeoutMsNoOptional auto-dismiss timeout in milliseconds (1000–3600000). Default 0 = wait forever (the user explicitly handles each ring manually).
selectionModeNoHow options behave: 'single' = radio buttons, 'multiple' = checkboxes. Default 'multiple'. Ignored when no options are provided.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of transparency and does well: it discloses no auto-dismiss by default, popup waits for user, supports mute/dismiss-all, and falls back to OS notification if popup fails. It also explains concurrent rings and interaction keys. It stops short of detailing return semantics, but otherwise provides extensive behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and front-loaded with the core purpose, then progressively adds operational details. It is moderately long but every sentence contributes meaningful behavior; no redundant filler. Slightly dense but justified for a feature-rich tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is complex (interactive popup with options), yet the description omits what the function returns to the caller. Since there is no output schema, the agent cannot know whether the result includes the user's text reply, selected options, or timeout status. This is a critical gap for a tool meant to gather user input. The fallback failure is mentioned, but success response semantics are missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers all parameters with descriptions, achieving 100% coverage. The description adds interaction context (e.g., 1-9 keys to toggle, Esc to dismiss) and relates options/selectionMode behavior, but does not significantly enhance parameter meaning beyond what the schema already provides. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear, specific action: 'Ring a notification bell that opens a tab in a single always-on-top popup window.' It distinguishes the tool's interactive nature (tabs, options, text replies) and its notification behavior, making the purpose unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use the tool (to present interactive notifications), but it does not provide explicit when-to-use guidance or exclusions since no sibling tools are listed. It does clarify behavior like blocking until user action and fallback, but lacks direct alternatives or recommended scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool updatev1.3.0
    • First observedring

TDQS

A3.9/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of confusion or overlap. The tool's purpose is singular and clearly described.

Naming Consistency5/5

The single tool name 'ring' is a clear verb that matches its action. Since there is only one tool, consistency is trivially maintained.

Tool Count3/5

The server has only one tool, which feels thin even for a narrowly scoped purpose. However, the tool is rich enough to cover the core functionality, making the count borderline but not unreasonable.

Completeness5/5

The tool fully covers the domain of ringing and managing notification bells, including multiple concurrent rings, replies, options, and fallback behavior. There are no obvious missing operations for the server's stated purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that plays notification sounds when AI coding assistants like Windsurf or Cursor require user attention, such as when coding is complete or when user approval is needed.
    6 npm
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that displays desktop notifications on Windows 10 and macOS, compatible with VSCode Cline and supporting customizable notification parameters.
    3
    MIT
  • A
    license
    B
    quality
    F
    maintenance
    An MCP server that enables AI assistants like Claude to send native macOS notifications with tmux integration, allowing notifications to focus specific tmux sessions when clicked.
    3
    6 npm
    14
    MIT