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

@icubeswire/unified-mcp-server

v0.2.1

Published

MCP server exposing read-only APIs of the Unified Backend (influencer discovery, campaigns, plans).

Readme

unified-mcp-server

A Model Context Protocol server that exposes the read-only APIs of the Unified Backend (influencer-marketing platform) as MCP tools, so an MCP client (Claude Desktop, Claude Code, etc.) can query influencers, campaigns, and plans in natural language.

  • Transport: stdio
  • Access: read-only (every tool is an HTTP GET)
  • Auth: per-user Laravel Sanctum bearer token — the backend applies that user's own permissions/policies to each request. There is no elevated service account.

Tools (v1)

Influencer discovery

| Tool | Endpoint | | --------------------------------- | ------------------------------------------ | | discovery_search | GET /discovery-search | | get_influencer_by_handle | GET /discovery-search/influencer/details | | discovery_list | GET /get-discovery | | get_influencer_growth | GET /discovery/growth/{id} | | get_influencer_audience | GET /discovery/audience/{id} | | get_influencer_engagement | GET /discovery/engagement/{id} | | get_influencer_content | GET /discovery/content/{id} | | get_influencer_posts | GET /discovery/posts/{id} | | get_influencer_related_profiles | GET /discovery/related-profiles/{id} | | get_influencer_brand_mentions | GET /discovery/brand-mentions/{id} |

Campaigns

| Tool | Endpoint | | -------------------------- | -------------------------------------- | | list_campaigns | GET /campaign/all-new | | get_campaign_analytics | GET /campaign/analytics/{offer_id} | | get_campaign_influencers | GET /campaign/influencers/{offer_id} |

Plans

| Tool | Endpoint | | ------------------------------- | ------------------------------------------------------- | | get_plan_platform_statistics | GET /plan/platform/statistics/{plan_id} | | get_plan_platform_influencers | GET /plan/platform/influencer/{plan_id}/{platform_id} | | get_plan_audience_geo | GET /plan/audience/geo/{plan_id}/{platform_id} |

The per-influencer detail tools take an InfluencerDetail id (_id). Resolve a handle/name to an id first with discovery_search or get_influencer_by_handle.

All tools are annotated readOnlyHint + openWorldHint, so clients like Claude can treat them as safe reads.

Prompts

MCP Prompts appear in Claude as slash-commands. Each one steers the model through the correct tool chain:

| Prompt | Args | What it does | | --------------------- | ---------- | --------------------------------------------------------- | | influencer-brief | handle | Resolve handle → growth/audience/engagement/content brief | | compare-influencers | handles | Comma-separated handles → side-by-side comparison table | | campaign-recap | offer_id | Campaign analytics + influencers → performance recap |

Quick start

npx -y @icubeswire/unified-mcp-server login

Opens unified.icubeswire.co/mcp/authorize in your browser. You're already signed in to the dashboard, so you just click Approve — the CLI receives the token, registers itself with Claude Code, and bounces you back to the editor. No token to mint, nothing to paste.

Restart Claude Code and run /mcp to verify (16 tools + 3 prompts).

  1. Binds a one-shot listener on 127.0.0.1:<ephemeral port> (loopback only).
  2. Opens /mcp/authorize?port=…&state=…state is a CSRF nonce.
  3. On approval the dashboard redirects back with a short-lived one-time code — never the token itself, since redirect URLs land in browser history, referrer headers, and proxy logs.
  4. The code is exchanged over POST /mcp/token for the Sanctum token.
  5. claude mcp add … -s user is run for you; if the claude binary isn't on PATH, the equivalent command is printed instead.

| Var | Purpose | | ------------------------ | ------------------------------------------------------------- | | UNIFIED_WEB_BASE_URL | Dashboard origin (default https://unified.icubeswire.co) | | UNIFIED_API_BASE_URL | API base used for the code exchange | | UNIFIED_MCP_NO_BROWSER | Set to 1 over SSH/CI — prints the URL instead of opening it |

Manual setup

If you'd rather configure it by hand, or login isn't available to you.

The package is public on npm, so npx fetches it with no registry auth. You still need your own Sanctum token — the package ships no credentials, and every request is made as you.

Claude Code

claude mcp add unified-backend -s user \
  --env UNIFIED_API_BASE_URL=https://apis.icubeswire.co/api/v1 \
  --env UNIFIED_API_TOKEN=<your-sanctum-token> \
  -- npx -y @icubeswire/unified-mcp-server

Claude Desktop / Cursor / other clients

Add to the client's MCP config (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json):

{
  "mcpServers": {
    "unified-backend": {
      "command": "npx",
      "args": ["-y", "@icubeswire/unified-mcp-server"],
      "env": {
        "UNIFIED_API_BASE_URL": "https://apis.icubeswire.co/api/v1",
        "UNIFIED_API_TOKEN": "<your-sanctum-token>"
      }
    }
  }
}

Restart the client, then verify (Claude Code: /mcpunified-backend, 16 tools + 3 prompts).

Getting a Sanctum token

Issued by the Laravel app for a real user (the server acts as that user). From the backend (tinker):

$user = App\Models\User::find(<id>);
$user->createToken('mcp')->plainTextToken; // paste into UNIFIED_API_TOKEN

Configuration

Configure via environment variables (see .env.example):

| Var | Required | Default | Description | | -------------------------------- | -------- | ---------------------- | ------------------------------------------------------------------ | | UNIFIED_API_BASE_URL | yes | — | API base incl. /api/v1, e.g. https://apis.icubeswire.co/api/v1 | | UNIFIED_API_TOKEN | yes | — | A Sanctum personal access token for the acting user | | UNIFIED_API_TIMEOUT_MS | no | 30000 | Per-request timeout | | UNIFIED_API_MAX_RETRIES | no | 2 | Retries on 429 / 5xx / network (honours Retry-After) | | UNIFIED_API_RETRY_BASE_MS | no | 500 | Base for exponential backoff + jitter | | UNIFIED_API_MAX_CONCURRENCY | no | 4 | Max simultaneous in-flight requests | | UNIFIED_API_MAX_RESPONSE_BYTES | no | 5000000 | Reject responses larger than this (0 disables) | | UNIFIED_API_USER_AGENT | no | unified-mcp-server/… | User-Agent sent on every request | | LOG_LEVEL | no | info | error | warn | info | debug (JSON logs to stderr) |

Getting a Sanctum token

The token is issued by the Laravel app for a real user. From the backend (tinker):

$user = App\Models\User::find(<id>);
$user->createToken('mcp')->plainTextToken; // paste into UNIFIED_API_TOKEN

Run from source (contributors)

git clone https://bitbucket.org/prawezicw/unified-mcp-server.git
cd unified-mcp-server
npm install                       # builds automatically via "prepare"
cp .env.example .env              # fill in UNIFIED_API_BASE_URL + UNIFIED_API_TOKEN
npm run dev                       # watch mode (loads .env)

To point an MCP client at a local checkout instead of npm, use "command": "node", "args": ["<abs-path>/dist/index.js"].

Publishing (maintainers)

The package is public on npmjs.org under the @icubeswire scope (publishConfig.access: "public"). You must be an org member to publish.

It contains no credentials — every request is authenticated with the token the end user supplies, so a public package grants no access to anything.

npm login                        # once, per machine
npm version patch|minor|major    # bump package.json + create the git tag
npm publish                      # runs `npm run check` + build first
git push --follow-tags           # the version commit + tag are local until this

prepublishOnly runs the full check (typecheck + lint + format + tests) and prepare builds dist/, so a broken build can't be published. With 2FA on the account, add --otp=<code> to npm publish.

When bumping, update the version in three placespackage.json (via npm version), SERVER_VERSION in src/index.ts, and the userAgent default in src/config.ts. test/version.test.ts fails the build if they disagree, so a drifted release can't be published rather than silently reporting the wrong version to Claude and in request logs.

Production behaviours

  • Config validationsrc/config.ts validates the whole environment up front (zod) and fails with a single, human-readable list of problems.
  • Resilience — bounded concurrency, per-request timeout, and retries with exponential backoff + jitter on transient failures (429 / 5xx / network), honouring Retry-After. A response-size guard prevents a huge payload from blowing up the model context.
  • Structured logging — JSON log lines on stderr only (stdout is the JSON-RPC transport). Bearer tokens and token=/api_key= query params are redacted everywhere.
  • Graceful shutdownSIGINT / SIGTERM / stdin-close close the server cleanly; uncaughtException / unhandledRejection are logged and exit non-zero.

Development

npm run dev          # watch mode (loads .env)
npm test             # unit tests (node:test, no network)
npm run check        # typecheck + lint + format:check + test
npm run smoke        # boot the built server and list tools (loads .env)
npm run smoke -- discovery_search '{"q":"virat"}'   # call one tool end-to-end

CI (bitbucket-pipelines.yml) runs typecheck → lint → format:check → test → build on every PR and on main.

Design notes

  • The server is a thin HTTP proxy: it forwards each tool call to the existing API and returns the raw JSON. It does not touch Mongo/Postgres/OpenSearch directly, so all existing auth, validation, and business logic still apply.
  • Array params are sent Laravel-style (key[]=), and nested objects (e.g. discovery_list's filter) are JSON-encoded.
  • Errors (non-2xx, timeouts, network) are returned as isError tool results with the backend's message/body, never as a transport crash.

Extending

Add a tool by calling server.registerTool(...) in the relevant src/tools/*.ts module (or a new one wired up in src/index.ts). Keep this server read-only — writes belong behind a separate, explicitly-scoped surface.