Skip to main content
Glama
khughitt

Polybar Notification MCP

by khughitt

ohai

MCP for displaying Quickshell-based notifications on Linux.

Installation

npm install
npm run build

Related MCP server: ntfy-mcp-server

Tools

ohai

Display a notification popup.

Parameter

Type

Required

Description

message

string

yes

Message body

title

string

no

Popup title (defaults to message)

severity

info | warn | crit

no

Accent color (default: info)

color

string

no

Custom accent color (CSS/hex; overrides severity)

timeoutSeconds

number

no

Auto-hide delay (default: 8; 0 = persistent)

pattern

string

no

Background pattern ID or path

image

string

no

Image ID or path (default: ghost)

projectPath

string

no

Path used to resolve configured project visual defaults

workspace

string

no

Workspace to switch to on backtick

app

string

no

App/window to focus on backtick

windowId

number

no

Niri window id to focus from the notification action button

transition

glow | ghost | ripple | none

no

Entry transition effect (default: glow)

ohai_status

Check if Quickshell is running with the ohai IPC target registered.

Transition Effects

Effect

Description

glow

Soft blur glow pulse (default)

ghost

Expanding/fading copies of actual notification content

ripple

Border ripples emanating outward

none

No transition effect

Set a default transition via environment variable:

export OHAI_TRANSITION=ghost

Quickshell Setup

  1. Start the popup daemon:

qs -p /path/to/ohai-mcp/ohai/shell.qml
  1. Verify the IPC target is registered:

qs ipc -p /path/to/ohai-mcp/ohai/shell.qml --any-display show
# Should list: target ohai
  1. Test manually:

qs ipc -p /path/to/ohai-mcp/ohai/shell.qml --any-display call ohai notify "Hello" "Test message" "info" 5 "" "" "" "" "glow"
  1. Controls while popup is visible:

    • Escape - hide popup

    • Backtick (`) - switch to workspace or focus app (if configured), then hide

Testing with ohai-test

A CLI helper for testing notification appearance:

bin/ohai-test [preset]           # Run a preset
bin/ohai-test themes             # List project visual themes
bin/ohai-test theme <name>       # Preview a project visual theme
bin/ohai-test theme all          # Cycle through all project visual themes
bin/ohai-test project <path>     # Preview the project profile matched by a path
bin/ohai-test custom [options]   # Custom notification

Presets:

Preset

Description

info

Basic info notification (default)

warn

Warning notification

crit

Critical notification

long

Long text (test layout)

short

Minimal notification

claude

Claude-themed

openai

OpenAI-themed

grid

Grid pattern background

stripes

Stripes pattern background

waves

Waves pattern background

glow

Test glow transition effect

ghost

Test ghost echo transition effect

ripple

Test ripple transition effect

all

Cycle through all presets

Theme previews:

bin/ohai-test themes
bin/ohai-test theme aquatic
bin/ohai-test theme all

Project profile diagnostics:

bin/ohai-theme resolve ~/d/software/ohai
bin/ohai-test project ~/d/software/ohai

ohai-theme resolve prints JSON with the config path, normalized project path, matched project, resolved visuals, and focus target. ohai-test project sends a real notification using the same resolved profile values.

Custom options:

bin/ohai-test custom \
  -t "Title" \
  -b "Body text" \
  -s warn \
  -i claude \
  -p grid-01 \
  -d 10 \
  -c "#ff00ff" \
  -x ghost

Option

Description

-t, --title

Title text

-b, --body

Body text

-s, --severity

info | warn | crit

-i, --image

Image ID or path

-p, --pattern

Pattern ID or path

-d, --duration

Timeout in seconds

-c, --color

Custom accent color (hex)

-w, --workspace

Workspace to switch on backtick

-a, --app

App to focus on backtick

-x, --transition

glow | ghost | ripple | none

Bundled Assets

Patterns (background overlays):

  • waves-01, grid-01, stripes-01, sunset-01

Images (left panel):

  • ghost (default), claude, openai

Use an absolute path for custom assets.

Asset Trust Model

image and pattern accept bundled asset IDs or custom local asset paths. Custom paths are treated as trusted desktop input and are passed to Quickshell for rendering; ohai validates basic string shape at the MCP boundary, but it does not sandbox QML asset loading.

Prefer bundled IDs for routine notifications. Use custom absolute paths only for local files you intend Quickshell to read, and configure this MCP server only for trusted clients.

Integration

Use environment variables to configure defaults per client.

Claude Code

To add via the CLI for user scope:

claude mcp add ohai \
    --scope user \
    --env OHAI_TRANSITION=glow \
    --env OHAI_DEFAULT_IMAGE=claude \
    -- node <OHAI_PATH>/bin/ohai-mcp

~/.claude.json:

{
  "mcpServers": {
    "ohai": {
      "type": "stdio",
      "command": "node",
      "args": ["/path/to/ohai-mcp/bin/ohai-mcp"],
      "env": {
        "OHAI_DEFAULT_IMAGE": "claude",
        "OHAI_TRANSITION": "glow"
      }
    }
  }
}

Cursor

Add to MCP settings:

{
  "mcpServers": {
    "ohai": {
      "command": "node",
      "args": ["/path/to/ohai-mcp/bin/ohai-mcp"],
      "env": {
        "OHAI_DEFAULT_IMAGE": "claude",
        "OHAI_TRANSITION": "ghost"
      }
    }
  }
}

codex-cli

~/.codex/config.toml:

[mcp_servers.ohai]
command = "node"
args = ["/path/to/ohai-mcp/bin/ohai-mcp"]

[mcp_servers.ohai.env]
OHAI_DEFAULT_IMAGE = "openai"
OHAI_TRANSITION = "glow"

Auto-launch (Hyprland)

exec-once = qs -p /path/to/ohai-mcp/ohai/shell.qml

Environment Variables

Variable

Description

OHAI_DEFAULT_IMAGE

Default image when image param is not specified (e.g., claude, openai, ghost)

OHAI_TRANSITION

Default transition effect (e.g., glow, ghost, ripple, none)

OHAI_BEZEL

Bezel rendering mode. Unset (default): translucent plate suitable for compositor blur. fake: opaque plate with static noise overlay (use when compositor blur is unavailable).

OHAI_CONFIG_PATH

Override project-profile config path. Defaults to $XDG_CONFIG_HOME/ohai/config.yaml, or ~/.config/ohai/config.yaml when XDG_CONFIG_HOME is unset.

OHAI_COMPOSITOR

Override the global focus-action compositor. Supported values: hyprland, niri.

OHAI_ORIGIN_CAPTURE

Override origin-window capture. Supported values: off, focusedWindow.

NIRI_PATH

Override the niri binary used for focused-window origin capture.

Project Profiles

Use project profiles to give notifications a visual identity based on the originating project. The MCP caller passes projectPath; ohai matches it against configured project roots and applies the matched profile's theme defaults.

Config path:

  • OHAI_CONFIG_PATH when set

  • $XDG_CONFIG_HOME/ohai/config.yaml when XDG_CONFIG_HOME is set

  • ~/.config/ohai/config.yaml otherwise

Global focus actions can be made compositor-aware with compositor: hyprland or compositor: niri. OHAI_COMPOSITOR overrides the YAML value. If neither is set, workspace and app focus actions keep the existing Hyprland command shape. Origin capture is opt-in with originCapture: focusedWindow or OHAI_ORIGIN_CAPTURE=focusedWindow.

Example:

compositor: niri
originCapture: focusedWindow

projects:
  - id: ohai
    name: ohai
    roots:
      - ~/d/software/ohai
    theme: aquatic
    workspace: dev

  - id: infra
    name: Infrastructure
    roots:
      - ~/d/infra
    theme: terminal
    transition: ripple

Built-in themes:

Theme

Image

Color

Pattern

Transition

ghost

ghost

#7ad7ff

none

ghost

aquatic

openai

#7ad7ff

waves-01

glow

frog

ghost

#c3e88d

grid-01

ripple

ember

claude

#ff9e64

stripes-01

glow

violet

openai

#bb9af7

grid-01

ghost

terminal

ghost

#9ece6a

stripes-01

none

sunset

claude

#f7768e

sunset-01

ripple

matrix

openai

#73daca

grid-01

glow

Profile matching uses normalized roots and chooses the longest matching prefix. Visual precedence is: explicit ohai tool input, then project overrides, then theme defaults, then environment defaults and built-in defaults. Unknown themes make config loading fail early.

Profiles may also define one focus target for notification actions:

compositor: niri
originCapture: focusedWindow

projects:
  - id: ohai
    roots:
      - ~/d/software/ohai
    theme: aquatic
    workspace: dev

  - id: terminal-tools
    roots:
      - ~/d/tools
    theme: ghost
    app: kitty

Supported profile focus fields are workspace, app, and windowId. Specify only one per profile. Explicit workspace, app, or windowId values passed to the ohai tool override the matched project profile focus target.

With compositor: niri, workspace uses niri msg action focus-workspace <workspace> and windowId uses niri msg action focus-window --id <id>. app focus is Hyprland-only because niri does not expose a direct app-title focus action; for niri use workspace or windowId.

With originCapture: focusedWindow, ohai runs niri msg --json focused-window when sending a notification without an explicit or project-profile focus target. If niri returns a focused window id, ohai uses that id as the notification action target. Focus precedence is: explicit MCP target, then project profile target, then captured focused window, then no focus target.

Use the CLI helpers to inspect profile matching before wiring an MCP client:

bin/ohai-theme resolve ~/d/software/ohai

Example shape, with paths abbreviated for readability:

{
  "configPath": "~/.config/ohai/config.yaml",
  "projectPath": "~/d/software/ohai",
  "matched": true,
  "project": {
    "id": "ohai",
    "name": "ohai",
    "theme": "aquatic",
    "matchedRoot": "~/d/software/ohai"
  },
  "compositor": "niri",
  "originCapture": "focusedWindow",
  "visuals": {
    "image": "openai",
    "color": "#7ad7ff",
    "pattern": "waves-01",
    "transition": "glow"
  },
  "focus": {
    "type": "workspace",
    "value": "dev"
  }
}

When no profile matches, matched is false and project is null.

For the frosted-glass bezel effect, add the following to your hyprland.conf:

layerrule = blur, ^ohai$
layerrule = ignorezero, ^ohai$

The anchored regex (^ohai$) ensures the rule applies only to the ohai notification surface. ignorezero tells Hyprland to skip blur on transparent regions of the surface — important because the popup window includes transparent padding around the visible bezel for transition-effect overflow; without this rule, the entire rectangular surface gets blurred.

Verify with hyprctl layers after reloading Hyprland — you should see ohai listed with the rules applied.

If you don't add these rules, the bezel will render as a translucent dark plate without compositor blur. This is still acceptable, just less visually distinct. Alternatively, set OHAI_BEZEL=fake for a more opaque bezel with a static noise texture.

Architecture

┌─────────────┐     qs ipc call      ┌─────────────────┐
│  MCP Client │ ──────────────────▶  │   Quickshell    │
│  (Claude)   │                      │   (shell.qml)   │
└─────────────┘                      └─────────────────┘
       │                                     │
       │                                     │
       ▼                                     ▼
┌─────────────┐                      ┌─────────────────┐
│  ohai-mcp   │                      │  IpcHandler     │
│  (Node.js)  │                      │  target: "ohai" │
└─────────────┘                      └─────────────────┘

The MCP server communicates with Quickshell via its built-in IPC mechanism (qs ipc call), which uses a Unix socket for instant, reliable delivery.

The internal notify IPC call takes 9 ordered arguments: title, body, severity, timeoutSeconds, pattern, image, actionTarget, color, transition. actionTarget is empty, an app/window title, workspace:<id>, window:<id>, or a compositor-prefixed target such as niri:workspace:<name> or hyprland:app:<title>.

Development

npm run dev      # Watch mode
npm run build    # Build
npm run lint     # Lint
npm run format   # Format

Requirements

  • Linux with Quickshell

  • Node.js 18+

Credit

Original implementation adapted from neotanx/neomcps - sound notification mcp.

Install Server
F
license - not found
B
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/khughitt/ohai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server