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

agencyhandy-mcp

v1.7.2

Published

Official Agency Handy MCP server — owner insights, context packs, API builder context

Readme

Agency Handy MCP

Official Model Context Protocol server for Agency Handy.

Connect Claude Desktop, Cursor, or any MCP host to your Agency Handy workspace: inspect proposals, projects, tickets, invoices, and create leads & clients — using your existing workspace API key.

| | | |---|---| | npm | agencyhandy-mcp (publish after this repo is set up) | | Node | ≥ 20 | | Auth | Workspace API key (x-api-key) from Agency Handy | | API | Your Agency Handy backend (AGENCY_BACKEND_URL) |


Quick start (Agency Handy users)

  1. In Agency Handy go to Workspace Config → API Key
  2. Generate a key (or use one you already saved)
  3. Copy MCP config from that page (or use the JSON below)
  4. Paste into:
    • Cursor: project or user .mcp.json
    • Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
  5. Restart the host. Requires Node.js 20+.
{
  "mcpServers": {
    "agency-handy": {
      "command": "npx",
      "args": ["-y", "agencyhandy-mcp@1"],
      "env": {
        "NODE_ENV": "production",
        "AGENCY_BACKEND_URL": "https://api.agencyhandy.com",
        "AGENCY_BACKEND_API_KEY": "YOUR_API_KEY"
      }
    }
  }
}

Prefer the in-app config: it fills the correct API base URL for your environment (production, staging, etc.).

Until the package is on npm, developers can run from this repo:

{
  "mcpServers": {
    "agency-handy": {
      "command": "node",
      "args": ["/absolute/path/to/agency-backend-mcp/src/server.js"],
      "env": {
        "AGENCY_BACKEND_URL": "https://api.agencyhandy.com",
        "AGENCY_BACKEND_API_KEY": "YOUR_API_KEY"
      }
    }
  }
}

What you can do

Product naming → API

| In Agency Handy | Backend | |-----------------|---------| | Proposal | Quotations | | Project | Orders (pid) | | Ticket | Tasks with type=issue | | Task | Tasks with type=task |

Write tools

| Tool | Purpose | |------|---------| | ah_lead_create | Create lead(s) — POST /api/v1/members/bulk-lead | | ah_client_create | Create client(s) — POST /api/v1/members/bulk-client | | ah_client_company_create | Create client company — POST /api/v1/client-companies | | ah_member_update | Update lead/client — PUT /api/v1/accounts/update | | ah_lead_convert | Convert lead → client — PUT /api/v1/accounts/update | | ah_client_invite | Send portal invite — POST /api/v1/members/send-client-invite | | ah_custom_field_create | Create lead/client/task field definition — POST /api/v1/custom-fields | | ah_custom_field_set_values | Fill values on a member — POST /api/v1/custom-fields/respond | | ah_custom_field_delete | Delete definitions — DELETE /api/v1/custom-fields | | ah_ticket_create / ah_ticket_update | Ticket (type=issue) — POST/PUT /api/v1/tasks | | ah_task_create / ah_task_update | Task (type=task) — POST/PUT /api/v1/tasks | | ah_comment_create | Comment on ticket/task — POST /api/v1/comments | | ah_invoice_create / ah_invoice_update | Invoice — POST/PUT /api/v1/invoices | | ah_proposal_create / ah_proposal_update | Proposal — POST/PUT /api/v1/quotations | | ah_proposal_send | Send proposal — PUT /api/v1/quotations/send/:id | | ah_order_update | Update order — PUT /api/v1/orders?pid= | | ah_order_create | Create order from service package — POST /api/v1/orders/create | | ah_order_assign | Set order PMs — PUT /orders?pid= | | ah_invoice_send | Send/resend invoice email — open status or /invoices/resend | | ah_invoice_set_status | Mark paid/void/open/… — PUT /invoices/:id | | ah_work_assign | Add/remove ticket or task assignees | | ah_work_set_status | Move ticket/task board status |

Owner digest (read)

| Tool | Purpose | |------|---------| | ah_dashboard_digest | Morning briefing: open invoices, overdue work, new leads + dashboard | | ah_cash_risk | Open invoice aging buckets + top clients by amount due | | ah_proposal_pipeline | Waiting / stale / expiring proposals | | ah_lead_segments | Lead counts by status, source, optional custom field | | ah_client_churn_risk | Heuristic churn score (overdue + quiet orders) | | ah_member_resolve | Name/email → DB memberId (unique / ambiguous / none) — never invent ids | | ah_status_resolve | Status label → DB statusId — required before ah_work_set_status | | ah_custom_field_list | Workspace custom field definitions (lead/client/task) | | ah_custom_field_seed_types | Platform seed types (usually auto-resolved by create) | | ah_member_custom_fields | Member profile + custom field values | | ah_task_context / ah_ticket_context | Work item + who to assign (ranked candidates, order team/PM, workload) | | ah_order_context / ah_project_context | Order pack: tasks, tickets, files, related invoices/subscriptions | | ah_proposal_context | Proposal summary + comments + public + linked service | | ah_invoice_context | Invoice summary + public + linked order + related invoices |

Resolve rule: If ambiguous or none, ask the user. Only assign/update with an id returned from these tools (or a user-confirmed match).

Assigning work

  1. ah_task_context / ah_ticket_context (pass pid when known)
  2. Read assignment.assignmentCandidates + assignment.advice
  3. ah_work_assign with a real memberId from candidates (or ah_member_resolve if the user named someone)

Owner insights

| Ask | Tool | |---|---| | Top AR clients + past 30/60/90 — who to chase today | ah_cash_risk → then ah_invoice_context / send | | Stale or expiring proposals — bump vs write off | ah_proposal_pipelineah_proposal_context | | Lead mix by source / Industry — volume vs converting | ah_lead_segments (customFieldName) | | Quiet + overdue clients — watchlist & one next action | ah_client_churn_risk → order/invoice context | | Monday pulse: cash + cold proposals + slipping work | ah_dashboard_digest + the tools above |

Custom fields

Lead and client custom fields are separate catalogs (same display name may exist once per owner).

  1. ah_custom_field_list (type=lead or client) → use returned definition _id (never invent ids)
  2. Fill with ah_custom_field_set_values, or pass customFields on ah_lead_create / ah_client_create
  3. Updates: ah_member_custom_fields first; prefer an existing filled-value row id when present
  4. Admins can create definitions with ah_custom_field_create (name + type; options required for selects)
  5. Duplicates: creating a field whose name already exists for that owner (case/spacing ignored) returns notCreatedCustomFields with reason Field already exists — reuse the existing id instead

Lead example

{
  "email": "[email protected]",
  "firstName": "Ada",
  "lastName": "Lovelace",
  "status": "New",
  "sendInvitationEmail": false
}

Client example

{
  "email": "[email protected]",
  "firstName": "Ada",
  "sendInvitationEmail": false
}

Client company example

{
  "name": "Acme Inc",
  "ownerId": "<existing-member-id>",
  "city": "Dhaka"
}

Ticket example

{
  "name": "Portal login broken",
  "priority": "high",
  "labels": [],
  "client": "<client-member-id>",
  "visibility": "client"
}

Invoice example

{
  "currency": "usd",
  "client": "<client-member-id>",
  "amount": 500,
  "additionalFields": [{ "name": "Design", "quantity": 1, "value": 500 }]
}

Order create is intentionally omitted (multipart / service-package heavy). Use ah_order_update for existing orders.

Read tools (highlights)

  • Health: ah_ping, ah_health
  • Context packs: ah_proposal_context, ah_project_context, ah_ticket_context, ah_task_context, ah_invoice_context, ah_chat_context, ah_webhook_context
  • Lists / gets: proposals, projects, tickets, tasks, invoices, members, client companies, services, forms, dashboard
  • Platform: chat, email-to-ticket settings, webhooks, order & platform subscriptions

Prefer *_context tools and the ah://full-context resource before inventing ObjectIds. For custom API tooling, also read ah://api-context (leads/orders/tasks/comments/labels/clients/invoices/vouchers/forms gotchas).

Resources & prompts

Resources: ah://full-context, ah://glossary, ah://models, ah://fields, ah://workflows, ah://workflows-platform, ah://api-context, ah://usage, …

Prompts: agency_handy_orientation, investigate_ticket, investigate_project, investigate_proposal, investigate_task


Environment

| Variable | Required | Description | |----------|----------|-------------| | AGENCY_BACKEND_URL | yes | API origin, e.g. https://api.agencyhandy.com (no /api/v1 suffix) | | AGENCY_BACKEND_API_KEY | yes | Member API JWT from Workspace Config → API Key | | AGENCY_COMPANY_ID | no | Override; normally taken from the JWT company claim | | AGENCY_WORKSPACE_ID | no | Optional workspace hint for tools that accept it | | AGENCY_BACKEND_TIMEOUT_MS | no | Default 45000 | | AGENCY_MCP_MAX_RPM | no | Tool rate limit per process (default 120) | | AGENCY_MCP_STRICT_API_KEY | no | 1 to require JWT exp; on by default when NODE_ENV=production | | NODE_ENV | no | Set production for hosts |

Copy .env.example.env for local development.


Develop

git clone https://github.com/AgencyHandy/agency-backend-mcp.git
cd agency-backend-mcp
npm ci
cp .env.example .env   # fill URL + API key
npm start              # stdio MCP server
npm test               # offline smoke / production gate
npm run test:live      # strict live calls (backend must be reachable)

CI

GitHub Actions runs offline smoke on Node 20 (.github/workflows/ci.yml).

Publish to npm

npm ci
npm test
npm publish --access public

See PRODUCTION.md for the operator checklist.


Security

  • The API key is a full workspace credential — treat it like a password
  • Never commit .env or paste keys into public chats
  • Rotate keys in Agency Handy if leaked
  • MCP is stdio / local-trust; do not expose it on a public network without extra auth
  • Allowed writes are limited to lead / client / client-company create

License

UNLICENSED — Agency Handy proprietary.