Quick Takeaways
What you'll learn in this article
- 1
Push live progress updates to a web UI while performing a long-running task
- 2
Trigger deploy notifications to a team dashboard when a CI/CD pipeline completes
- 3
Send alerts to connected clients when it detects anomalies in monitored data
- 4
Coordinate with other agents through pub/sub channels โ agent A publishes a result, agent B picks it up
- 5
Implement human-in-the-loop workflows by checking presence channels to see if a human is online before escalating
Keep reading for detailed implementation, code examples, and real-world results
Most MCP servers give AI agents the ability to read things โ query a database, search files, fetch API data. But what if your agent could push real-time messages to live dashboards, trigger notifications to connected users, or coordinate with other agents through pub/sub channels?
That's exactly what we built. The Pusher Channels MCP Server gives any MCP-compatible AI client (Claude Desktop, Claude Code, Cursor, Windsurf) the ability to interact with Pusher Channels โ the real-time messaging platform used by over 200,000 developers.
And as of today, it's live on the official MCP Registry.
Why Real-Time Matters for AI Agents
The current MCP ecosystem is heavily skewed toward read operations. Agents query databases, search codebases, fetch web content. That's powerful, but it treats the agent as a passive observer.
Real-time messaging flips that model. An AI agent with Pusher access can:
- Push live progress updates to a web UI while performing a long-running task
- Trigger deploy notifications to a team dashboard when a CI/CD pipeline completes
- Send alerts to connected clients when it detects anomalies in monitored data
- Coordinate with other agents through pub/sub channels โ agent A publishes a result, agent B picks it up
- Implement human-in-the-loop workflows by checking presence channels to see if a human is online before escalating
This makes the agent an active participant in live systems, not just a tool that answers questions.
What the Server Does
The server exposes 7 tools that map to the Pusher Channels REST API:
| Tool | What It Does |
|---|---|
trigger_event | Send an event to one or more channels |
trigger_batch_events | Send up to 10 events in a single API call |
list_channels | List all active channels with optional prefix filtering |
get_channel_info | Get subscription count, user count, and occupancy status |
get_presence_users | List users connected to a presence channel |
authorize_channel | Generate auth tokens for private/presence channels |
terminate_user_connections | Disconnect a user from all channels (moderation) |
Each tool uses Zod schemas for input validation, returns human-readable text responses, and handles errors gracefully โ if Pusher's API is down, you get a clear error message instead of a crash.
The Tech Stack
The server is built with:
- TypeScript with ES2022 target and Node16 module resolution
- @modelcontextprotocol/sdk (^1.12.0) โ the official MCP SDK using the modern McpServer + server.tool() pattern
- pusher (^5.2.0) โ the official Pusher Node.js SDK
- zod (^3.24.0) โ runtime input validation with .describe() annotations that flow through to the MCP tool schema
The architecture follows a clean separation: each tool lives in its own file under src/tools/, a singleton factory in pusher-client.ts handles credential validation, and index.ts wires everything together with the stdio transport.
Publishing to the MCP Registry in 2026
If you've been following the MCP ecosystem, you might think publishing means submitting a PR to the modelcontextprotocol/servers repo. That's no longer the case. As of late 2025, the repo explicitly says:
We are no longer accepting PRs to add server links to the README. Please publish your server to the MCP Server Registry instead.
They even have a GitHub Actions workflow that auto-flags README-only PRs. The official path is now the MCP Registry.
How the Registry Works
The MCP Registry is a metaregistry โ it stores metadata about your server, not the actual code. Your package lives on npm (or PyPI, Docker Hub, etc.), and the registry points to it.
The publishing flow has three steps:
Step 1: Publish your package to npm
Your package.json needs an mcpName field that matches your registry namespace:
{
"name": "@crashbytes/pusher-mcp-server",
"mcpName": "io.github.CrashBytes/pusher-mcp-server"
}
Then publish normally:
npm publish --access public
Step 2: Create a server.json metadata file
This describes your server for the registry โ name, description, environment variables, transport type:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.CrashBytes/pusher-mcp-server",
"title": "Pusher Channels",
"description": "Trigger events, query channels, and manage realtime messaging on Pusher Channels.",
"repository": {
"url": "https://github.com/CrashBytes/pusher-mcp-server",
"source": "github"
},
"version": "1.0.3",
"packages": [
{
"registryType": "npm",
"identifier": "@crashbytes/pusher-mcp-server",
"version": "1.0.3",
"runtime": "node",
"transport": { "type": "stdio" },
"environmentVariables": [
{ "name": "PUSHER_APP_ID", "isRequired": true, "isSecret": false },
{ "name": "PUSHER_KEY", "isRequired": true, "isSecret": false },
{ "name": "PUSHER_SECRET", "isRequired": true, "isSecret": true },
{ "name": "PUSHER_CLUSTER", "isRequired": true, "isSecret": false }
]
}
]
}
Step 3: Authenticate and publish with mcp-publisher
Install the CLI (available via Homebrew), authenticate with GitHub, and publish:
brew install mcp-publisher mcp-publisher login github mcp-publisher publish
The login github command uses a device flow โ you get a code to enter at github.com/login/device. The registry validates that your GitHub identity matches the io.github.<username>/ namespace in your server name.
Gotchas We Hit
The namespace is case-sensitive. Our GitHub org is CrashBytes (capital C and B). We initially used io.github.crashbytes/ in our server.json. The registry rejected it with a 403:
You have permission to publish: io.github.CrashBytes/*. Attempting to publish: io.github.crashbytes/pusher-mcp-server
The fix was simple โ match the exact casing of the GitHub org.
The mcpName in package.json must match the registry name. When we published v1.0.1 to npm with the lowercase mcpName, then tried to publish to the registry with the corrected casing, we got:
NPM package ownership validation failed. Expected mcpName 'io.github.CrashBytes/pusher-mcp-server', got 'io.github.crashbytes/pusher-mcp-server'
We had to bump to 1.0.3 and republish to npm with the corrected mcpName before the registry would accept it.
Auth tokens expire quickly. Between mcp-publisher login and mcp-publisher publish, if you take too long (fixing issues, bumping versions), the JWT expires. Just run login github again โ it's fast.
You cannot overwrite npm versions. npm's immutability means every fix requires a version bump. We went through 1.0.0 โ 1.0.1 โ 1.0.2 โ 1.0.3 during the publishing process. Plan your versions accordingly, or get everything right locally before your first publish.
Testing the Server
We didn't just publish and hope for the best. The server has a comprehensive test suite with 52 tests across 9 test files, built with Vitest:
- Unit tests for all 7 tools โ mock the Pusher client, test success paths, error handling, edge cases
- Pusher client tests โ env var validation, singleton behavior, missing credential detection
- MCP protocol integration tests โ use the SDK's InMemoryTransport to connect a real McpServer and Client, call tools through the actual MCP protocol
The integration tests verify real workflows like "list presence users, then terminate a bad actor" and "authorize a channel, then trigger an event excluding the authorized socket."
We also tested all tools against the live Pusher API to confirm they work end-to-end.
How to Use It
Add this to your Claude Desktop config (claude_desktop_config.json) or Claude Code settings:
{
"mcpServers": {
"pusher": {
"command": "npx",
"args": ["-y", "@crashbytes/pusher-mcp-server"],
"env": {
"PUSHER_APP_ID": "your-app-id",
"PUSHER_KEY": "your-key",
"PUSHER_SECRET": "your-secret",
"PUSHER_CLUSTER": "us2"
}
}
}
}
You'll need a free Pusher account to get your credentials. The free tier includes 200,000 messages per day โ more than enough for development and small-scale production use.
Once configured, you can ask Claude things like:
- "Send a notification event to the alerts channel with a warning about high CPU usage"
- "List all active channels and show me their subscription counts"
- "Check if anyone is connected to the presence-support channel"
- "Generate an auth token for private-user-42"
What's Next
The full source code is available at CrashBytes/pusher-mcp-server and in our Byte Sized Examples monorepo. The companion tutorial walks through building it step by step: Building a Pusher Channels MCP Server.
If you're thinking about building your own MCP server for a service that doesn't have one yet, the registry makes it straightforward to share your work with the community. The ecosystem is growing fast โ over 500 official integrations and 900 community servers โ but there are still plenty of gaps to fill.
Real-time messaging was one of them. Now it's covered.
Links:

