Skip to main content
Glama
jonmmease

Jon's Pushover MCP Server

by jonmmease

send_notification

Send push notifications to devices with customizable messages, titles, URLs, priorities, and sounds for alerts and messages.

Instructions

Send a push notification via Pushover.

Args: message: The notification message body (required). title: Title shown at top of notification. Defaults to app name. url: URL to include (tappable in notification). url_title: Label for the URL instead of showing raw URL. priority: Priority level from -2 (silent) to 2 (emergency). Default 0. sound: Notification sound name. See Pushover docs for available sounds.

Returns: Dictionary with 'status' (1 for success) and 'request' (UUID string).

Raises: ValueError: If priority is out of range or sound is invalid. PushoverError: If Pushover API returns an error or credentials are missing.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
messageYes
titleNo
urlNo
url_titleNo
priorityNo
soundNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The primary handler function for the 'send_notification' tool. It validates inputs, retrieves credentials from environment variables, constructs the API request payload, sends an HTTP POST to the Pushover API using httpx, parses the response, and returns success details or raises errors.
    async def send_notification(
        message: str,
        title: str | None = None,
        url: str | None = None,
        url_title: str | None = None,
        priority: int = 0,
        sound: str | None = None,
    ) -> dict[str, str | int]:
        """Send a push notification via Pushover.
    
        Args:
            message: The notification message body (required).
            title: Title shown at top of notification. Defaults to app name.
            url: URL to include (tappable in notification).
            url_title: Label for the URL instead of showing raw URL.
            priority: Priority level from -2 (silent) to 2 (emergency). Default 0.
            sound: Notification sound name. See Pushover docs for available sounds.
    
        Returns:
            Dictionary with 'status' (1 for success) and 'request' (UUID string).
    
        Raises:
            ValueError: If priority is out of range or sound is invalid.
            PushoverError: If Pushover API returns an error or credentials are missing.
        """
        # Get credentials from environment
        api_token = os.environ.get("PUSHOVER_API_TOKEN")
        user_key = os.environ.get("PUSHOVER_USER_KEY")
    
        if not api_token:
            raise PushoverError("PUSHOVER_API_TOKEN environment variable is not set")
        if not user_key:
            raise PushoverError("PUSHOVER_USER_KEY environment variable is not set")
    
        # Validate priority
        if not PUSHOVER_PRIORITY_MIN <= priority <= PUSHOVER_PRIORITY_MAX:
            raise ValueError(
                f"Priority must be between {PUSHOVER_PRIORITY_MIN} and "
                f"{PUSHOVER_PRIORITY_MAX}, got {priority}"
            )
    
        # Validate sound if provided
        if sound is not None and sound not in PUSHOVER_VALID_SOUNDS:
            raise ValueError(
                f"Invalid sound '{sound}'. Valid sounds: {', '.join(PUSHOVER_VALID_SOUNDS)}"
            )
    
        # Build form data
        data: dict[str, str | int] = {
            "token": api_token,
            "user": user_key,
            "message": message,
        }
    
        if title is not None:
            data["title"] = title
        if url is not None:
            data["url"] = url
        if url_title is not None:
            data["url_title"] = url_title
        if priority != 0:
            data["priority"] = priority
        if sound is not None:
            data["sound"] = sound
    
        # Send request
        async with httpx.AsyncClient(timeout=REQUEST_TIMEOUT) as client:
            response = await client.post(PUSHOVER_API_URL, data=data)
    
        # Parse response
        result = response.json()
    
        if response.status_code != 200 or result.get("status") != 1:
            errors = result.get("errors", [])
            raise PushoverError(
                "Pushover API request failed",
                status_code=response.status_code,
                errors=errors,
            )
    
        return {"status": result["status"], "request": result["request"]}
  • The line where the send_notification tool is registered with the FastMCP server instance using mcp.tool().
    mcp.tool(send_notification)
  • Import of the send_notification tool into the server module from the tools package.
    from .tools import send_notification
  • Export of send_notification in the tools package __all__ list, making it available for import.
    "send_notification",
  • Import of the handler from pushover.py into the tools __init__.py for package-level access.
    from .pushover import send_notification
Behavior4/5

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

With no annotations provided, the description carries full burden and does well by disclosing key behavioral traits: it explains the return format (dictionary with status and request UUID), error conditions (ValueError for invalid inputs, PushoverError for API/credential issues), and default values for parameters. It doesn't mention rate limits, authentication requirements, or notification delivery guarantees.

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

Conciseness5/5

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

The description is well-structured with clear sections (Args, Returns, Raises), front-loaded with the core purpose, and every sentence adds value. No redundant information or fluff - each parameter explanation is necessary and concise.

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

Completeness4/5

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

Given no annotations, 6 parameters with 0% schema coverage, and an output schema present, the description does very well. It explains parameters thoroughly, documents return values and errors. Minor gap: doesn't mention authentication/credential setup or rate limits, which would be helpful for a notification-sending tool.

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

Parameters5/5

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

Schema description coverage is 0%, so the description must compensate fully. It provides excellent parameter semantics: explains each parameter's purpose, indicates required vs. optional, provides default values, explains priority range (-2 to 2), and references external documentation for sounds. This adds substantial meaning beyond the bare schema.

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 clearly states the tool's purpose with specific verb ('Send') and resource ('push notification via Pushover'), and distinguishes it from any alternatives by specifying the service provider. The first sentence directly answers 'what does this tool do?' without ambiguity.

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 provides implied usage context through parameter explanations (e.g., priority levels, URL inclusion) but doesn't explicitly state when to use this tool versus alternatives. Since there are no sibling tools mentioned, the lack of explicit comparison is less critical, but no guidance on prerequisites or typical use cases is provided.

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

Install Server

Other Tools

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/jonmmease/jons-mcp-pushover'

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