npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@signal4/s4

v2.6.1

Published

Signal4 media intelligence — CLI and MCP server for AI agents

Readme

@signal4/s4

Media intelligence platform — CLI, MCP server, and TypeScript client.

Search quotes, analyze discourse, track trends, and explore speakers across thousands of hours of audiovisual content.

Architecture

This package contains three surfaces backed by one HTTP client:

@signal4/s4
├── client.ts      ← Typed HTTP client (38 functions wrapping the REST API)
├── types.ts       ← TypeScript types for all API responses
├── config.ts      ← Config loader (~/.signal4/config)
├── cli.ts         ← Terminal interface (s4 search, s4 speaker, ...)
├── index.ts       ← MCP server for Claude Desktop / Cursor
└── handlers/      ← Human-readable formatters (shared by CLI + MCP)

Client is the core — everything else is a consumer. Use it directly for programmatic access; use the CLI or MCP server for interactive use.

| Surface | Entry point | Reads from | Formats with | |---------|-------------|------------|-------------| | TypeScript client | import from '@signal4/s4/client' | client.ts | — (raw typed responses) | | CLI | npx @signal4/s4 search ... | client.ts | handlers/ → text | | MCP server | s4 --mcp | client.ts | handlers/ → text |

TypeScript Client

For applications that need typed access to the Signal4 API (frontends, agents, pipelines, scripts):

import { searchQuotes, getSpeaker, analyze } from '@signal4/s4/client';
import type { QuoteSearchResult, SpeakerProfile } from '@signal4/s4/types';

// Search for quotes about a topic
const results = await searchQuotes({
  topic: 'AI regulation',
  speaker_name: 'Tucker Carlson',
  limit: 10,
  start_date: '2026-05-01',
});

// Get a speaker profile
const speaker = await getSpeaker(12345);

// Run an AI analysis
const analysis = await analyze({
  query: 'How are podcasters talking about tariffs?',
  workflow: 'deep_analysis',
  days: 30,
});

Sub-path exports

import { searchQuotes, detectTrend, ... } from '@signal4/s4/client';  // HTTP client
import type { Quote, SpeakerProfile, ... } from '@signal4/s4/types';   // TypeScript types
import { applyConfig } from '@signal4/s4/config';                      // Config loader

Configuration

The client reads from environment variables:

| Variable | Purpose | Default | |----------|---------|---------| | SIGNAL4_API_KEY | API key (required) | — | | SIGNAL4_API_URL | API base URL | https://api.signal4.ca | | SIGNAL4_CLIENT_ID | Client identifier for analytics | — |

applyConfig() loads these from ~/.signal4/config if not already set in the environment. The CLI and MCP server call this automatically; programmatic consumers should call it explicitly if they want the file-based fallback.

Client functions

Search

  • searchQuotes(params) — Semantic/keyword search across transcripts
  • searchClaims(params) — Search extracted claims with stance and observation counts
  • detectTrend(params) — Compare recent vs baseline mention volume
  • getTimeline(params) — Topic mention volume over time

Entities

  • searchSpeakers(query, limit?) — Autocomplete speaker search
  • getSpeaker(id) / getSpeakerByName(name) — Speaker profile
  • getSpeakerSegments(params) — Recent segments by speaker
  • searchSpeakerSegments(params) — Semantic search within a speaker's segments
  • getChannel(id) / getChannelByName(name) — Channel profile
  • getEpisode(contentId) — Episode details
  • getTranscript(contentId) — Full episode transcript
  • getSegment(segmentId) — Single segment with audio clip URL
  • getSegmentThread(segmentId, n?) — Conversation context around a segment

Analysis (SSE streaming, handled internally)

  • analyze(params) — AI-powered analysis (workflows: simple_rag, deep_analysis, speaker_compare, speaker_dossier, contradiction_check)

Reports

  • getTopSpeakers(params) / getTopChannels(params) — Leaderboards
  • getSpeakerNetwork(params) — Co-appearance network graph
  • getTopics(params) — Trending topic clusters
  • getReportStats(days?) / getProjectStats() — Platform statistics
  • getDiscourseSummary(params) — AI discourse briefing

Claims

  • getClaim(claimId) — Full claim detail
  • getClaimObservations(params) — Observations supporting a claim
  • getRelatedClaims(claimId) — Similar/related claims

Ads

  • getAdStats(days?) / getAdvertisers(params) / getAdvertiser(id) — Ad intelligence
  • getAdsByChannel(channelId, days?) / getAdTrends(days?) — Channel-level and trending ads

Bookmarks

  • createBookmark(params) / listBookmarks(params) / deleteBookmark(id)

Auth

  • whoami() — Verify key and see access scope

Error handling

All functions throw on error. HTTP 502/503 are retried automatically (3 attempts with backoff). Wrap calls in try/catch:

try {
  const result = await searchQuotes({ topic: 'tariffs' });
} catch (err) {
  console.error((err as Error).message); // "HTTP 401: ..."
}

Installing as a dependency

For projects within the signal4 monorepo:

pnpm add @signal4/s4@file:../mcp

For external projects (once published):

npm install @signal4/s4

CLI

npm install -g @signal4/s4

s4 setup          # Save your API key to ~/.signal4/config
s4 whoami         # Verify access and see available commands

Commands

# Search
s4 search "immigration" --speaker "Tucker Carlson"
s4 claims "AI regulation" --entity "OpenAI"
s4 trend "tariffs"
s4 timeline "carbon tax" --days 90

# Explore
s4 speaker "Joe Rogan"
s4 speaker "Tucker Carlson" "economy"   # discourse search
s4 channel "Power & Politics"
s4 episode pod_8f1e55513f70 --transcript
s4 segment 28553756
s4 thread 28553756

# Analyze (AI-powered, slower)
s4 analyze "carbon tax" --days 14
s4 frames "midterm elections" --days 30
s4 compare "tariffs" --speakers "Trump,Biden"
s4 dossier "immigration" --speaker "Carlson"
s4 contradictions "vaccines" --speaker "Trump"
s4 briefing

# Reports
s4 stats
s4 top-speakers --ranking talkative
s4 top-channels
s4 network
s4 topics

# Ads
s4 ads --trending

# Bookmarks
s4 bookmarks
s4 bookmarks add segment 12345 --note "key quote"

All commands support --json for raw JSON output (bypasses the handler formatting layer and calls the client directly).

MCP Server

For Claude Desktop, Cursor, or other MCP clients:

{
  "mcpServers": {
    "signal4": {
      "command": "npx",
      "args": ["-y", "@signal4/s4", "--mcp"],
      "env": {
        "SIGNAL4_API_KEY": "your-api-key"  # pragma: allowlist secret
      }
    }
  }
}

Tool definitions are loaded dynamically from the API based on your key's access level. The MCP server uses the same handlers as the CLI for formatting responses.

Remote server (streamable-http)

The same server is also deployable as a remote streamable-http service (this replaced the retired Python MCP server in core/src/mcp/):

node dist/http.js --host 127.0.0.1 --port 7998
  • Env: SIGNAL4_API_URL — backend base URL (default https://api.signal4.ca; PM2 deployments set http://localhost:7999)
  • MCP endpoint: POST /mcp
  • Auth: the client's own Signal4 API key (sk_...), sent as X-API-Key: <key> or Authorization: Bearer <key>. The server needs no service key and no database access — the key passes through to the backend, which validates it, enforces scopes/projects, rate-limits, and records usage.
  • Health check: GET /health{"status": "ok", "service": "signal4-mcp", "transport": "http"}

In production it runs under PM2 as signal4-mcp (on-prem: core/ecosystem.config.js, bound 0.0.0.0:7998; VPS: ~/signal4/start-mcp.sh synced from the parent repo's scripts/start-mcp.vps.sh, bound 127.0.0.1:7998).

Requirements