agencyhandy-mcp 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example ADDED
@@ -0,0 +1,13 @@
1
+ # Production MCP — copy to .env and fill from Agency Handy UI
2
+ # Settings → API tokens (member API key / x-api-key JWT)
3
+
4
+ AGENCY_BACKEND_URL=https://api.agencyhandy.com
5
+ AGENCY_BACKEND_API_KEY=
6
+
7
+ # Optional overrides
8
+ # AGENCY_COMPANY_ID= # normally decoded from API key JWT
9
+ # AGENCY_WORKSPACE_ID=
10
+ # AGENCY_BACKEND_TIMEOUT_MS=45000
11
+ # AGENCY_MCP_MAX_RPM=120 # in-process tool call rate limit
12
+ # AGENCY_MCP_STRICT_API_KEY=1 # require JWT exp (default on when NODE_ENV=production)
13
+ # NODE_ENV=production
package/PRODUCTION.md ADDED
@@ -0,0 +1,31 @@
1
+ # Production checklist — Agency Handy MCP
2
+
3
+ npm package name: **`agencyhandy-mcp`**
4
+ Repo: https://github.com/AgencyHandy/agency-backend-mcp
5
+
6
+ ## End-user flow
7
+
8
+ 1. Agency Handy → **Workspace Config → API Key** → Generate
9
+ 2. Copy MCP config (key filled in once)
10
+ 3. Paste into Cursor `.mcp.json` or Claude Desktop config
11
+ 4. Restart host (Node.js 20+)
12
+
13
+ ## Ship checklist
14
+
15
+ 1. Push this repo to GitHub
16
+ 2. `npm publish --access public` (so `npx -y agencyhandy-mcp@1` works)
17
+ 3. Merge/deploy ah-client PR that shows the MCP copy UI on the API Key tab
18
+
19
+ ## Runtime guarantees
20
+
21
+ - Fail fast on missing / placeholder / expired API keys
22
+ - Stderr JSON audit logs (stdout = MCP protocol only)
23
+ - Secret redaction, rate limit (120 RPM), one retry on 502/503
24
+ - `companyid` from JWT; `ah_health` probes backend
25
+ - Writes allowlisted: CRM, work assign/status, invoices (+send), proposals, orders (create/update/assign)
26
+ - Owner digest: `ah_dashboard_digest`
27
+ - Resolve-only ids: `ah_member_resolve`, `ah_status_resolve` (no invented ObjectIds)
28
+
29
+ ## Version
30
+
31
+ `1.4.0` — DB-backed member/status resolve; assign/status writes require real ids.
package/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # Agency Handy MCP
2
+
3
+ Official [Model Context Protocol](https://modelcontextprotocol.io) server for **Agency Handy**.
4
+
5
+ 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.
6
+
7
+ | | |
8
+ |---|---|
9
+ | **npm** | `agencyhandy-mcp` (publish after this repo is set up) |
10
+ | **Node** | ≥ 20 |
11
+ | **Auth** | Workspace API key (`x-api-key`) from Agency Handy |
12
+ | **API** | Your Agency Handy backend (`AGENCY_BACKEND_URL`) |
13
+
14
+ ---
15
+
16
+ ## Quick start (Agency Handy users)
17
+
18
+ 1. In Agency Handy go to **Workspace Config → API Key**
19
+ 2. **Generate** a key (or use one you already saved)
20
+ 3. **Copy MCP config** from that page (or use the JSON below)
21
+ 4. Paste into:
22
+ - **Cursor:** project or user `.mcp.json`
23
+ - **Claude Desktop:** `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
24
+ 5. Restart the host. Requires **Node.js 20+**.
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "agency-handy": {
30
+ "command": "npx",
31
+ "args": ["-y", "agencyhandy-mcp@1"],
32
+ "env": {
33
+ "NODE_ENV": "production",
34
+ "AGENCY_BACKEND_URL": "https://api.agencyhandy.com",
35
+ "AGENCY_BACKEND_API_KEY": "YOUR_API_KEY"
36
+ }
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ > Prefer the in-app config: it fills the correct API base URL for your environment (production, staging, etc.).
43
+
44
+ Until the package is on npm, developers can run from this repo:
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "agency-handy": {
50
+ "command": "node",
51
+ "args": ["/absolute/path/to/agency-backend-mcp/src/server.js"],
52
+ "env": {
53
+ "AGENCY_BACKEND_URL": "https://api.agencyhandy.com",
54
+ "AGENCY_BACKEND_API_KEY": "YOUR_API_KEY"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ---
62
+
63
+ ## What you can do
64
+
65
+ ### Product naming → API
66
+
67
+ | In Agency Handy | Backend |
68
+ |-----------------|---------|
69
+ | Proposal | Quotations |
70
+ | Project | Orders (`pid`) |
71
+ | Ticket | Tasks with `type=issue` |
72
+ | Task | Tasks with `type=task` |
73
+
74
+ ### Write tools
75
+
76
+ | Tool | Purpose |
77
+ |------|---------|
78
+ | `ah_lead_create` | Create lead(s) — `POST /api/v1/members/bulk-lead` |
79
+ | `ah_client_create` | Create client(s) — `POST /api/v1/members/bulk-client` |
80
+ | `ah_client_company_create` | Create client company — `POST /api/v1/client-companies` |
81
+ | `ah_member_update` | Update lead/client — `PUT /api/v1/accounts/update` |
82
+ | `ah_lead_convert` | Convert lead → client — `PUT /api/v1/accounts/update` |
83
+ | `ah_client_invite` | Send portal invite — `POST /api/v1/members/send-client-invite` |
84
+ | `ah_ticket_create` / `ah_ticket_update` | Ticket (`type=issue`) — `POST/PUT /api/v1/tasks` |
85
+ | `ah_task_create` / `ah_task_update` | Task (`type=task`) — `POST/PUT /api/v1/tasks` |
86
+ | `ah_comment_create` | Comment on ticket/task — `POST /api/v1/comments` |
87
+ | `ah_invoice_create` / `ah_invoice_update` | Invoice — `POST/PUT /api/v1/invoices` |
88
+ | `ah_proposal_create` / `ah_proposal_update` | Proposal — `POST/PUT /api/v1/quotations` |
89
+ | `ah_proposal_send` | Send proposal — `PUT /api/v1/quotations/send/:id` |
90
+ | `ah_order_update` | Update order — `PUT /api/v1/orders?pid=` |
91
+ | `ah_order_create` | Create order from service package — `POST /api/v1/orders/create` |
92
+ | `ah_order_assign` | Set order PMs — `PUT /orders?pid=` |
93
+ | `ah_invoice_send` | Send/resend invoice email — open status or `/invoices/resend` |
94
+ | `ah_invoice_set_status` | Mark paid/void/open/… — `PUT /invoices/:id` |
95
+ | `ah_work_assign` | Add/remove ticket or task assignees |
96
+ | `ah_work_set_status` | Move ticket/task board status |
97
+
98
+ **Owner digest (read)**
99
+
100
+ | Tool | Purpose |
101
+ |------|---------|
102
+ | `ah_dashboard_digest` | Morning briefing: open invoices, overdue work, new leads + dashboard |
103
+ | `ah_member_resolve` | Name/email → DB memberId (`unique` / `ambiguous` / `none`) — never invent ids |
104
+ | `ah_status_resolve` | Status label → DB statusId — required before `ah_work_set_status` |
105
+
106
+ **Resolve rule:** If `ambiguous` or `none`, ask the user. Only assign/update with an id returned from these tools (or a user-confirmed match).
107
+
108
+ **Lead example**
109
+
110
+ ```json
111
+ {
112
+ "email": "lead@acme.com",
113
+ "firstName": "Ada",
114
+ "lastName": "Lovelace",
115
+ "status": "New",
116
+ "sendInvitationEmail": false
117
+ }
118
+ ```
119
+
120
+ **Client example**
121
+
122
+ ```json
123
+ {
124
+ "email": "client@acme.com",
125
+ "firstName": "Ada",
126
+ "sendInvitationEmail": false
127
+ }
128
+ ```
129
+
130
+ **Client company example**
131
+
132
+ ```json
133
+ {
134
+ "name": "Acme Inc",
135
+ "ownerId": "<existing-member-id>",
136
+ "city": "Dhaka"
137
+ }
138
+ ```
139
+
140
+ **Ticket example**
141
+
142
+ ```json
143
+ {
144
+ "name": "Portal login broken",
145
+ "priority": "high",
146
+ "labels": [],
147
+ "client": "<client-member-id>",
148
+ "visibility": "client"
149
+ }
150
+ ```
151
+
152
+ **Invoice example**
153
+
154
+ ```json
155
+ {
156
+ "currency": "usd",
157
+ "client": "<client-member-id>",
158
+ "amount": 500,
159
+ "additionalFields": [{ "name": "Design", "quantity": 1, "value": 500 }]
160
+ }
161
+ ```
162
+
163
+ Order create is intentionally omitted (multipart / service-package heavy). Use `ah_order_update` for existing orders.
164
+
165
+ ### Read tools (highlights)
166
+
167
+ - **Health:** `ah_ping`, `ah_health`
168
+ - **Context packs:** `ah_proposal_context`, `ah_project_context`, `ah_ticket_context`, `ah_task_context`, `ah_invoice_context`, `ah_chat_context`, `ah_webhook_context`
169
+ - **Lists / gets:** proposals, projects, tickets, tasks, invoices, members, client companies, services, forms, dashboard
170
+ - **Platform:** chat, email-to-ticket settings, webhooks, order & platform subscriptions
171
+
172
+ Prefer `*_context` tools and the `ah://full-context` resource before inventing ObjectIds.
173
+
174
+ ### Resources & prompts
175
+
176
+ Resources: `ah://full-context`, `ah://glossary`, `ah://models`, `ah://fields`, `ah://workflows`, `ah://workflows-platform`, `ah://usage`, …
177
+
178
+ Prompts: `agency_handy_orientation`, `investigate_ticket`, `investigate_project`, `investigate_proposal`, `investigate_task`
179
+
180
+ ---
181
+
182
+ ## Environment
183
+
184
+ | Variable | Required | Description |
185
+ |----------|----------|-------------|
186
+ | `AGENCY_BACKEND_URL` | yes | API origin, e.g. `https://api.agencyhandy.com` (no `/api/v1` suffix) |
187
+ | `AGENCY_BACKEND_API_KEY` | yes | Member API JWT from Workspace Config → API Key |
188
+ | `AGENCY_COMPANY_ID` | no | Override; normally taken from the JWT `company` claim |
189
+ | `AGENCY_WORKSPACE_ID` | no | Optional workspace hint for tools that accept it |
190
+ | `AGENCY_BACKEND_TIMEOUT_MS` | no | Default `45000` |
191
+ | `AGENCY_MCP_MAX_RPM` | no | Tool rate limit per process (default `120`) |
192
+ | `AGENCY_MCP_STRICT_API_KEY` | no | `1` to require JWT `exp`; on by default when `NODE_ENV=production` |
193
+ | `NODE_ENV` | no | Set `production` for hosts |
194
+
195
+ Copy `.env.example` → `.env` for local development.
196
+
197
+ ---
198
+
199
+ ## Develop
200
+
201
+ ```bash
202
+ git clone https://github.com/AgencyHandy/agency-backend-mcp.git
203
+ cd agency-backend-mcp
204
+ npm ci
205
+ cp .env.example .env # fill URL + API key
206
+ npm start # stdio MCP server
207
+ npm test # offline smoke / production gate
208
+ npm run test:live # strict live calls (backend must be reachable)
209
+ ```
210
+
211
+ ### CI
212
+
213
+ GitHub Actions runs offline smoke on Node 20 (`.github/workflows/ci.yml`).
214
+
215
+ ### Publish to npm
216
+
217
+ ```bash
218
+ npm ci
219
+ npm test
220
+ npm publish --access public
221
+ ```
222
+
223
+ See [PRODUCTION.md](./PRODUCTION.md) for the operator checklist.
224
+
225
+ ---
226
+
227
+ ## Security
228
+
229
+ - The API key is a **full workspace credential** — treat it like a password
230
+ - Never commit `.env` or paste keys into public chats
231
+ - Rotate keys in Agency Handy if leaked
232
+ - MCP is **stdio / local-trust**; do not expose it on a public network without extra auth
233
+ - Allowed writes are limited to lead / client / client-company create
234
+
235
+ ---
236
+
237
+ ## License
238
+
239
+ UNLICENSED — Agency Handy proprietary.
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "agencyhandy-mcp",
3
+ "version": "1.4.0",
4
+ "description": "Official Agency Handy MCP server — DB-backed resolve + owner ops (no invented ids)",
5
+ "type": "module",
6
+ "main": "src/server.js",
7
+ "bin": {
8
+ "agencyhandy-mcp": "src/server.js"
9
+ },
10
+ "engines": {
11
+ "node": ">=20"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "README.md",
16
+ "PRODUCTION.md",
17
+ ".env.example"
18
+ ],
19
+ "scripts": {
20
+ "start": "node src/server.js",
21
+ "dev": "node --watch src/server.js",
22
+ "test": "node scripts/smoke.mjs",
23
+ "test:live": "SMOKE_LIVE=1 node scripts/smoke.mjs",
24
+ "prepublishOnly": "npm test"
25
+ },
26
+ "keywords": [
27
+ "agencyhandy",
28
+ "mcp",
29
+ "claude",
30
+ "cursor",
31
+ "model-context-protocol"
32
+ ],
33
+ "license": "UNLICENSED",
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.12.3",
36
+ "axios": "^1.9.0",
37
+ "dotenv": "^16.5.0",
38
+ "zod": "^3.24.4"
39
+ }
40
+ }