Koskamo

SignOps MCP

An official MCP server provided by SignOps that allows AI coding agents to interact with the SignOps API. It enables sending push notifications to Android, iOS, and web, managing user devices and topics, creating login approvals, and handling authenticator codes, all via a streamable HTTP endpoint requiring an API key.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

SignOps MCP logo, by SignOpsVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-01Operated by SignOps
You need:Get an API keyKeep secret keys on your server onlyUse a test key ( sk_test_ ) while buildingConnect with a secret key in the Authorization header
MCP endpoint (Streamable HTTP)
https://api.signops.dev/mcp
Vendor documentation

What you can do with it

  • Send push notifications to users or topics
  • Manage user devices and registration tokens
  • Create and manage login approvals via push
  • Check or remove user authenticator codes

Source and maintenance

Vendor evidenceRegistry 1.0.0

Protocol and capabilities

Server
signops 1.0.0
MCP protocol
2025-06-18
Tools
23 advertised
Resources
Not advertised
Resource templates
Not advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": false
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

SignOps: push notifications to Android, iOS and the web, push approval of logins, passkeys and authenticator app codes, on your own user ids. The key you connected with decides the app and the mode: sk_test_ reaches only test devices, sk_live_ reaches real users, so prefer a test key while building. Every tool is one call to https://api.signops.dev/v1; the docs are at https://signops.dev/docs/.

Tools

23 advertised

send_push — Send a push
Advertised by the server during the last successful anonymous check.
Open-world

Send a push notification to one user (user_id), a list (user_ids, up to 1,000), a topic, or everyone (all: true). Give exactly one target. A push to one user, sent now, answers with its result at once; others answer with status sending or scheduled. With a test key (sk_test_) only test devices receive it.

send_push input schema
{
  "type": "object",
  "required": [],
  "properties": {
    "all": {
      "type": "boolean",
      "description": "true to send to every device of the app."
    },
    "body": {
      "type": "string",
      "description": "The text under it."
    },
    "data": {
      "type": "object",
      "description": "Key and value pairs the app reads. With no title, the push is silent.",
      "additionalProperties": {
        "type": "string"
      }
    },
    "link": {
      "type": "string",
      "description": "A deep link or URL opened on tap."
    },
    "image": {
      "type": "string",
      "description": "An https image URL."
    },
    "title": {
      "type": "string",
      "description": "The notification title."
    },
    "topic": {
      "type": "string",
      "description": "A topic name."
    },
    "fields": {
      "type": "object",
      "description": "Values for the template's {{fields}}."
    },
    "send_at": {
      "type": "string",
      "description": "An ISO time with a zone, up to 30 days ahead, like 2026-10-24T18:00:00+05:30."
    },
    "user_id": {
      "type": "string",
      "description": "Your own id for one user."
    },
    "template": {
      "type": "string",
      "description": "A saved template's name; title, body and the rest come from it."
    },
    "user_ids": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Up to 1,000 of your user ids."
    },
    "marketing": {
      "type": "boolean",
      "description": "true applies the app's daily cap of marketing pushes per user."
    },
    "fields_by_user": {
      "type": "object",
      "description": "With user_ids: each user's own field values, keyed by user id."
    },
    "idempotency_key": {
      "type": "string",
      "description": "Optional. The same key within 24 hours replays the first answer instead of sending again."
    }
  },
  "additionalProperties": false
}
send_push annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
get_push — Get a push
Advertised by the server during the last successful anonymous check.
Advertised read-only

One push by id: status, devices, sent and failed, per platform.

get_push input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "The push id, msg_..."
    }
  },
  "additionalProperties": false
}
get_push annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
list_pushes — List pushes
Advertised by the server during the last successful anonymous check.
Advertised read-only

Pushes, newest first. On the Free plan only pushes still to go are listed (no delivery logs).

list_pushes input schema
{
  "type": "object",
  "required": [],
  "properties": {
    "limit": {
      "type": "integer",
      "maximum": 100,
      "minimum": 1
    },
    "before": {
      "type": "string",
      "description": "The next value from the previous page."
    }
  },
  "additionalProperties": false
}
list_pushes annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
cancel_push — Cancel a scheduled push
Advertised by the server during the last successful anonymous check.
Advertised destructive

Cancel a push that is scheduled and has not started sending.

cancel_push input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "The push id, msg_..."
    }
  },
  "additionalProperties": false
}
cancel_push annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
register_device — Register a device
Advertised by the server during the last successful anonymous check.

Store a device's push token under your user id. Android and iOS tokens come from the Firebase or Apple SDK; for web, token is the PushSubscription as JSON.

register_device input schema
{
  "type": "object",
  "required": [
    "user_id",
    "token",
    "platform"
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "Optional label, like Rushi's iPhone."
    },
    "token": {
      "type": "string",
      "description": "The push token."
    },
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    },
    "platform": {
      "enum": [
        "android",
        "ios",
        "web"
      ],
      "type": "string"
    }
  },
  "additionalProperties": false
}
register_device annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
list_devices — List a user's devices
Advertised by the server during the last successful anonymous check.
Advertised read-only

The devices registered for one user id, newest first, with platform and whether each is trusted for approvals.

list_devices input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
list_devices annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
remove_device — Remove a device
Advertised by the server during the last successful anonymous check.
Advertised destructive

Remove one device by id; it gets no more pushes.

remove_device input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "The device id, dev_..."
    }
  },
  "additionalProperties": false
}
remove_device annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
list_topics — List topics
Advertised by the server during the last successful anonymous check.
Advertised read-only

Topics with how many users each has.

list_topics input schema
{
  "type": "object",
  "required": [],
  "properties": {},
  "additionalProperties": false
}
list_topics annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
subscribe_topic — Subscribe a user to a topic
Advertised by the server during the last successful anonymous check.

Add a user to a topic. The topic exists once it has a user.

subscribe_topic input schema
{
  "type": "object",
  "required": [
    "topic",
    "user_id"
  ],
  "properties": {
    "topic": {
      "type": "string",
      "description": "Up to 64 letters, digits, dashes, dots or underscores."
    },
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
subscribe_topic annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
unsubscribe_topic — Unsubscribe a user from a topic
Advertised by the server during the last successful anonymous check.
Advertised destructive

Take a user off a topic.

unsubscribe_topic input schema
{
  "type": "object",
  "required": [
    "topic",
    "user_id"
  ],
  "properties": {
    "topic": {
      "type": "string",
      "description": "The topic name."
    },
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
unsubscribe_topic annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
list_templates — List templates
Advertised by the server during the last successful anonymous check.
Advertised read-only

Saved push templates with their fields.

list_templates input schema
{
  "type": "object",
  "required": [],
  "properties": {},
  "additionalProperties": false
}
list_templates annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
get_template — Get a template
Advertised by the server during the last successful anonymous check.
Advertised read-only

One template by name.

get_template input schema
{
  "type": "object",
  "required": [
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "The template name, like payment_received."
    }
  },
  "additionalProperties": false
}
get_template annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
save_template — Save a template
Advertised by the server during the last successful anonymous check.

Create or replace a template. Put {{field}} where a value goes, or {{field|default}} for one with a fallback.

save_template input schema
{
  "type": "object",
  "required": [
    "name"
  ],
  "properties": {
    "body": {
      "type": "string",
      "description": "Body, with {{fields}}."
    },
    "data": {
      "type": "object",
      "description": "Optional data, with {{fields}} in the values.",
      "additionalProperties": {
        "type": "string"
      }
    },
    "link": {
      "type": "string",
      "description": "Optional link."
    },
    "name": {
      "type": "string",
      "description": "Lowercase letters, digits and underscores."
    },
    "image": {
      "type": "string",
      "description": "Optional image URL."
    },
    "title": {
      "type": "string",
      "description": "Title, with {{fields}}."
    }
  },
  "additionalProperties": false
}
save_template annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
delete_template — Delete a template
Advertised by the server during the last successful anonymous check.
Advertised destructive

Delete a template by name. Pushes already made from it are not changed.

delete_template input schema
{
  "type": "object",
  "required": [
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "description": "The template name."
    }
  },
  "additionalProperties": false
}
delete_template annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
create_approval — Ask a user to approve
Advertised by the server during the last successful anonymous check.
Open-world

Send an approval request to the user's trusted phone, with number matching. The user must have a phone enrolled through the SignOps SDK.

create_approval input schema
{
  "type": "object",
  "required": [
    "user_id",
    "context"
  ],
  "properties": {
    "context": {
      "type": "string",
      "description": "What they are approving, up to 120 characters, like Sign in from Chrome on Windows."
    },
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
create_approval annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
get_approval — Get an approval
Advertised by the server during the last successful anonymous check.
Advertised read-only

An approval request's status: pending, approved, denied, expired or cancelled.

get_approval input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "The approval id, apr_..."
    }
  },
  "additionalProperties": false
}
get_approval annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
cancel_approval — Cancel an approval
Advertised by the server during the last successful anonymous check.
Advertised destructive

Cancel a pending approval request.

cancel_approval input schema
{
  "type": "object",
  "required": [
    "id"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "The approval id, apr_..."
    }
  },
  "additionalProperties": false
}
cancel_approval annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
list_passkeys — List a user's passkeys
Advertised by the server during the last successful anonymous check.
Advertised read-only

The passkeys registered for one user id.

list_passkeys input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
list_passkeys annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
get_authenticator — Get a user's authenticator
Advertised by the server during the last successful anonymous check.
Advertised read-only

Whether a user has an authenticator app (TOTP) confirmed, when it was last used, backup codes left, and whether wrong codes have locked them.

get_authenticator input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
get_authenticator annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
remove_authenticator — Remove a user's authenticator
Advertised by the server during the last successful anonymous check.
Advertised destructive

Remove a user's authenticator app and backup codes, for a lost phone. They can enrol again.

remove_authenticator input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
remove_authenticator annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}
unlock_user — Unlock a user
Advertised by the server during the last successful anonymous check.

Clear the lock that five wrong codes in 15 minutes put on a user, and their count of wrong codes.

unlock_user input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
unlock_user annotations
{
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
export_user — Export a user's data
Advertised by the server during the last successful anonymous check.
Advertised read-only

Everything SignOps holds on one user id as JSON: devices (tokens shortened), topics, passkeys, authenticator status, approvals of the last 90 days, consent history and pushes sent to them.

export_user input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
export_user annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}
get_consent — Get a user's consent
Advertised by the server during the last successful anonymous check.
Advertised read-only

The latest consent answer per purpose for one user, like marketing_push, and the history.

get_consent input schema
{
  "type": "object",
  "required": [
    "user_id"
  ],
  "properties": {
    "user_id": {
      "type": "string",
      "description": "Your own id for the user."
    }
  },
  "additionalProperties": false
}
get_consent annotations
{
  "readOnlyHint": true,
  "openWorldHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

Not advertised

No resource definitions available.

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
161 ms
95th percentile latency
161 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 161 ms · metadata changed · 23 tool(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http signops-mcp https://api.signops.dev/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add signops-mcp --url https://api.signops.dev/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable signops-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "signops-mcp": {
      "url": "https://api.signops.dev/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "signops-mcp": {
      "type": "streamableHttp",
      "url": "https://api.signops.dev/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start signops-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "signops-mcp": {
      "type": "http",
      "url": "https://api.signops.dev/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http signops-mcp https://api.signops.dev/mcp

Claude Desktop

Merge this into claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop.
Claude Desktop configuration
{
  "mcpServers": {
    "signops-mcp": {
      "url": "https://api.signops.dev/mcp"
    }
  }
}

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "signops-mcp": {
      "serverUrl": "https://api.signops.dev/mcp"
    }
  }
}

Let your agent find its tools

Find servers like SignOps MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run SignOps MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing