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

@noeva/crm-mcp

v1.10.0

Published

MCP server for the Noeva CRM — protocol adapter over the noeva-server-api CRM REST API. Ships an HTTP service (central deploy) and a stdio package (client-distributable).

Readme

@my-ginkgo/noeva-crm-mcp

An MCP (Model Context Protocol) server for the Noeva CRM. It is a thin protocol adapter: it translates MCP tools/call requests into HTTP calls against the existing noeva-server-api CRM REST API, applying a policy/confirmation layer in between. It holds no domain logic, no database access, and no Noeva secrets.

Public install (npm)

Installazione pubblica senza credenziali GitHub:

npx -y @noeva/crm-mcp

Config MCP (es. Claude Desktop):

{
  "mcpServers": {
    "noeva-crm": {
      "command": "npx",
      "args": ["-y", "@noeva/crm-mcp"],
      "env": {
        "NOEVA_API_BASE_URL": "https://api.noeva.ai",
        "NOEVA_API_KEY": "noeva_sk_..."
      }
    }
  }
}

Il canale @my-ginkgo/noeva-crm-mcp su GitHub Packages resta disponibile per uso interno (richiede un PAT read:packages).

Two artifacts are built from this one codebase:

| Transport | Who runs it | Who consumes it | Auth source | | ------------------------------------------ | ---------------------------- | ----------------------------------------- | ---------------------------------------- | | HTTP (StreamableHTTPServerTransport) | Noeva (central deploy) | the Mastra agent platform | per-request bearer token | | stdio (StdioServerTransport) | the customer (local process) | their MCP client (Claude Desktop, IDE, …) | NOEVA_API_KEY (a noeva_sk_… API key) |

Both share the exact same MCP core, the same 18 tools, and the same CRM client.


Security model (read this)

  • noeva-server-api is the only trust boundary. It verifies the token, the workspace, and membership. This server forwards Authorization: Bearer <token> + x-noeva-workspace: <id> and propagates whatever it gets back.
  • The token is opaque. It is never decoded or verified locally. A 401/403 from the API is surfaced as an authorization error.
  • No Noeva secrets in the build. No SUPABASE_JWT_SECRET, no service key — not even in the HTTP image. The stdio package ships to customer machines, so anything in it is considered public.
  • No escalation. Because the server is pure pass-through, a customer inspecting or modifying it gains nothing beyond what their own token already permits.
  • Writes require confirmation. Either via MCP elicitation (primary) or a dry-run + signed confirm_token (fallback). The token is bound to the exact arguments, so a preview cannot be turned into a different write.

Tools

One consolidated tool per CRM domain; pick the operation with the action field. Every tool requires workspace_id (UUID).

crm_leads, crm_companies, crm_offers, crm_activities, crm_templates, crm_quotes, crm_quote_templates, crm_entity_templates, crm_lookups, crm_locations, crm_assets, crm_vocab, crm_punches, crm_notifications, crm_dashboard, crm_explore, crm_search, crm_members.

Read actions run immediately. Write actions go through the confirmation layer. notifications.mark_read / mark_all_read are soft-writes (no confirmation by default; set MCP_CONFIRM_SOFT_WRITES=true to require it).

Two things do not behave like plain CRUD:

  • crm_quotes.generate starts an async document build and returns a processId. Progress lives outside the /crm route category, so this server cannot report completion — poll it through the Noeva core tools.
  • Template-driven records. crm_leads and crm_companies accept template_id plus custom_fields in data; the available models come from crm_entity_templates.

What this server deliberately does not expose, and why, is listed in docs/SCOPE.md.


Customer installation guide (stdio)

For non-technical users. You will paste a small block of config into your MCP client.

1. Generate a NOEVA API key

In the Noeva app, go to Profile → API Keys and create a key. Copy it — you will not be able to see it again. The key looks like noeva_sk_…, is personal and revocable, acts with your own permissions, and only grants access to the workspaces you are a member of.

An API key is required because a normal login session expires after ~1 hour, which would stop the local server from working. The key must start with noeva_sk_.

2. Add it to your MCP client

Open your client's MCP server configuration (e.g. Claude Desktop's config file) and add:

{
  "mcpServers": {
    "noeva-crm": {
      "command": "npx",
      "args": ["-y", "@my-ginkgo/noeva-crm-mcp"],
      "env": {
        "NOEVA_API_KEY": "noeva_sk_…",
        "NOEVA_API_BASE_URL": "https://api.noeva.ai"
      }
    }
  }
}

Package registry. Published to GitHub Packages under the private @my-ginkgo scope, so npx needs read access. Add to your ~/.npmrc:

@my-ginkgo:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=<GitHub PAT with read:packages>

The PAT must belong to an account granted access to the my-ginkgo org.

3. Verify it works

Restart your MCP client. Ask it to "list my Noeva CRM workspace members" — it should call crm_members. If you see results, you are connected.

4. Revoke access

Revoke the API key in the Noeva app (Profile → API Keys). The local server stops working immediately on its next call. You can also just remove the noeva-crm block from your config.


Central HTTP deployment

Container image built from the included Dockerfile (node:20-slim). Stateless, so it scales horizontally. Configure via env (see .env.example):

  • NOEVA_API_BASE_URL (https) — the CRM API.
  • MCP_CONFIRMATION_SECRET — 32+ random chars, shared across instances (dry-run and execute may hit different pods). If unset, a per-process secret is generated and a warning is logged (only safe for a single instance).
  • MCP_RESOURCE_URL, MCP_OAUTH_AUTHORIZATION_SERVER — advertised at /.well-known/oauth-protected-resource.
  • SENTRY_DSN — optional; error tracking is only wired in the HTTP build.

Health check: GET /health. MCP endpoint: POST /mcp.


Development

pnpm install
pnpm dev:http      # HTTP transport with reload
pnpm dev:stdio     # stdio transport
pnpm build         # tsc -> dist/
pnpm test          # vitest (unit + integration)
pnpm lint

Try the tools with MCP Inspector

The Inspector gives a browser UI to list and call the tools. It inherits the process env, so pass the credentials inline:

# source (tsx, no build needed)
NOEVA_API_KEY="noeva_sk_…" NOEVA_API_BASE_URL="http://localhost:3002" pnpm inspect

# built dist/ (the artifact Claude Desktop runs)
NOEVA_API_KEY="noeva_sk_…" NOEVA_API_BASE_URL="http://localhost:3002" pnpm inspect:dist

Then Connect → pick a tool (e.g. crm_members, set workspace_id + action: list) → Run. You can also set the env vars in the Inspector's Environment Variables fields instead of inline.

The Inspector does not support elicitation, so writes use the fallback: the first call returns a dry-run preview + confirm_token; call again with the identical arguments plus that token to execute. (Claude Desktop, which supports elicitation, shows a confirmation popup instead.)

For the HTTP transport, start the server and point the Inspector at the URL:

# terminal 1
NOEVA_API_BASE_URL=http://localhost:3002 MCP_CONFIRMATION_SECRET=$(openssl rand -hex 32) pnpm start:http
# terminal 2
npx -y @modelcontextprotocol/inspector
# UI: Transport = "Streamable HTTP", URL = http://localhost:8080/mcp,
#     header Authorization: Bearer <token>

Prerequisites & open questions

  • P1 — durable customer credential — resolved. noeva-server-api now accepts long-lived personal API keys (noeva_sk_…): the auth middleware detects the noeva_sk_ prefix, looks the key up in user_api_keys, and authenticates as the owning user. The stdio build uses such a key via NOEVA_API_KEY.
  • P2 — server-side rate limiting. The in-process limit here is a courtesy guard, not a security control. Authoritative per-token rate limiting must live in noeva-server-api.
  • Mastra token acquisition for the HTTP transport, and whether Mastra's MCP client supports elicitation (if not, the HTTP transport always uses the token fallback).
  • OAuth audience. This server uses token pass-through (it cannot do a token exchange without a secret). A full OAuth Resource Server form with its own audience remains a possible evolution for the HTTP transport only.
  • crm/timbrature. A separate router exists alongside crm/punches; whether to expose both is open.