@kivimedia/kmhub 2.9.1 → 2.10.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.
Files changed (57) hide show
  1. package/README.md +170 -170
  2. package/bin/kmhub.mjs +896 -896
  3. package/coach-book-output-guard.mjs +760 -760
  4. package/index.mjs +57 -57
  5. package/package.json +56 -56
  6. package/prompts/briefing.md +29 -29
  7. package/prompts/luxury.md +70 -70
  8. package/prompts/play.md +49 -49
  9. package/prompts/run.md +36 -36
  10. package/prompts/setup.md +33 -33
  11. package/prompts/vs-booked.md +46 -46
  12. package/prompts/what-can-you-do.md +40 -40
  13. package/prompts.mjs +110 -110
  14. package/read-only-tools.json +143 -142
  15. package/remote.mjs +929 -929
  16. package/tools/balloon-costing.mjs +80 -80
  17. package/tools/booking-equipment.mjs +110 -110
  18. package/tools/bridges.mjs +54 -54
  19. package/tools/briefing.mjs +91 -91
  20. package/tools/calendar.mjs +170 -170
  21. package/tools/capabilities.mjs +155 -155
  22. package/tools/catalog.mjs +288 -288
  23. package/tools/clubs.mjs +176 -176
  24. package/tools/coach.mjs +771 -771
  25. package/tools/compare.mjs +76 -76
  26. package/tools/core.mjs +244 -244
  27. package/tools/crm.mjs +209 -209
  28. package/tools/dubsado.mjs +137 -137
  29. package/tools/exports.mjs +128 -128
  30. package/tools/fact-review.mjs +125 -125
  31. package/tools/flows.mjs +261 -261
  32. package/tools/forms.mjs +158 -158
  33. package/tools/gols.mjs +134 -134
  34. package/tools/hr.mjs +162 -162
  35. package/tools/knowledge.mjs +125 -125
  36. package/tools/marketing.mjs +396 -396
  37. package/tools/meta.mjs +245 -245
  38. package/tools/military.mjs +244 -244
  39. package/tools/money.mjs +235 -197
  40. package/tools/outreach.mjs +238 -238
  41. package/tools/pending.mjs +122 -122
  42. package/tools/photos.mjs +140 -140
  43. package/tools/plays.mjs +244 -244
  44. package/tools/profile.mjs +118 -118
  45. package/tools/radar.mjs +173 -173
  46. package/tools/recurring-invoices.mjs +149 -149
  47. package/tools/reengage.mjs +434 -434
  48. package/tools/schedules.mjs +55 -55
  49. package/tools/setup.mjs +168 -168
  50. package/tools/sops-bridges.mjs +86 -86
  51. package/tools/sops.mjs +314 -314
  52. package/tools/sourcing.mjs +268 -268
  53. package/tools/strategy.mjs +146 -146
  54. package/tools/studio.mjs +132 -132
  55. package/tools/venueradar.mjs +151 -151
  56. package/tools/voice.mjs +134 -134
  57. package/tools.mjs +407 -407
package/README.md CHANGED
@@ -1,170 +1,170 @@
1
- # kmhub-mcp
2
-
3
- A standalone [MCP](https://modelcontextprotocol.io) server for KM Hub. It exposes your
4
- workspace to any MCP client (Claude Desktop, Claude Code, IDEs, agents) using a KM Hub
5
- API key, by wrapping the public REST API (`kmhub-api`).
6
-
7
- It ships in two transports that share the exact same tool set (`tools.mjs` plus the
8
- family modules in `tools/`):
9
-
10
- - **Local stdio** (`index.mjs`) - the client spawns the process; the org key comes from
11
- the `KMHUB_API_KEY` env var. One process = one workspace. Best for a single power user
12
- on their own machine.
13
- - **Remote Streamable HTTP** (`remote.mjs`) - one long-running server (hosted on the VPS)
14
- serves many orgs with zero local install. Each request authenticates with its own KM Hub
15
- key sent as a `Authorization: Bearer kmh_live_...` header, and is scoped to that org only.
16
- Deploy runbook: [DEPLOY-VPS.md](./DEPLOY-VPS.md).
17
-
18
- ## Tools
19
-
20
- Tools are grouped into **families**, one file per family in [`tools/`](./tools/README.md).
21
- `tools.mjs` discovers them at load time, so a new family is a new file and nothing else.
22
-
23
- ### `core` - orientation and the CRM essentials
24
- - `km_me` - the connected workspace (id, name, plan) + the key's scopes
25
- - `km_waiting` - what needs you (approvals, enquiries, tasks, invoices, contracts)
26
- - `km_list_clients` - recent clients / leads (optional `limit`)
27
- - `km_create_lead` - create a lead (`first_name`, `last_name`, `company`, `email`, `phone`, `notes`)
28
- - `km_list_deals` - pipeline deals (optional `limit`, `stage`, `status`)
29
- - `km_list_events` - calendar events (optional `limit`, `from`/`to` start-date range)
30
- - `km_list_bookings` - recent bookings (optional `limit`, `status`, `from`/`to` event-date range)
31
- - `km_create_inquiry` - log an enquiry + its client (`client_name` required; `event_type`, `event_date`, `budget_cents`, `notes`, ...). Opens a pipeline deal automatically. Audited + undoable in the AI activity log.
32
- - `km_create_booking` - create a real booking + its client (`client_name` and `event_date` required; optional `status`: `pending` default or `confirmed`). Opens a pipeline deal at booked/won. Audited + undoable.
33
- - `km_create_outreach_draft` - queue an outreach message as a DRAFT (`body` required; optional `subject`, `channel` email/linkedin/ig/sms_whatsapp, `deal_id`, `contact_id`). It only QUEUES: a human approves the draft in the Approval Queue before anything can send. Audited.
34
-
35
- ### `meta` - keeping the connection current
36
- - `km_check_updates` - asks KM Hub what it publishes today (`GET /version` returns
37
- `api_version`, `rules_version`, `tools_version`, `min_client`, `changelog_url`) and answers
38
- in plain language. Two judgements: is this connector still above `min_client` (the build
39
- KM Hub refuses to serve below), and is the rules file on disk still the published
40
- `rules_version`? Pass the local one in as `rules_version`. The rules pack carries a content
41
- hash after a `+`, and the two endpoints do not always both publish it, so the semver base
42
- and the hash are judged separately rather than looping on a suffix that proves nothing.
43
- - `km_fetch_rules` - downloads the current KM Hub operating rules (`GET /rules`) and returns
44
- `{ version, markdown, sha256, bytes, instructions }`. The model is instructed to write that
45
- markdown verbatim over the user's global rules file (for Claude Code, their `CLAUDE.md`),
46
- replacing any older KM Hub block, and then to tell the user it did so.
47
-
48
- Both meta tools degrade gracefully: if your KM Hub has not shipped `/version` or `/rules` yet
49
- they say "your KM Hub does not support update checks yet" and report success, rather than
50
- failing. The checksum is computed locally from the bytes that actually arrived; if KM Hub also
51
- sends one and the two differ, the response carries a warning instead of a silent bad write.
52
-
53
- ## Profiles
54
-
55
- Every tool schema is loaded into every turn, so a big tool set is a real context tax. A
56
- profile loads only the families you want:
57
-
58
- | Profile | Loads |
59
- |---|---|
60
- | `core` | orientation + CRM essentials, plus `meta` |
61
- | `outreach` | `core` + the outreach families |
62
- | `money` | `core` + the billing families |
63
- | `content` | `core` + the content families |
64
- | `coach` | Fully Booked Coach operations, client delivery, acquisition, and content requests |
65
- | `full` | everything (**default**) |
66
-
67
- `full` is the default, so nothing changes for an existing connection. An unknown profile name
68
- falls back to `full` rather than erroring: a typo in a config file should never cost someone
69
- their tools.
70
-
71
- - **Remote**: per request, `POST /mcp?profile=money` or an `X-KMHub-Profile: money` header.
72
- The query string wins if both are present. The profile is read from the request and passed
73
- down by argument, so the server stays stateless and two tenants can hold two different
74
- profiles at the same moment.
75
- - **Local stdio**: the `KMHUB_PROFILE` env var.
76
-
77
- `GET /health` reports the families that loaded and the tool count for each profile.
78
-
79
- ## Setup - local stdio (`index.mjs`)
80
- 1. In KM Hub: **Settings > Developer & API** -> create an API key (`kmh_live_...`).
81
- Read tools need the `read` scope, create tools need `write` (a read-only key
82
- gets 403 on writes).
83
- 2. Install deps in this folder:
84
- ```
85
- npm install
86
- ```
87
- 3. Add to your MCP client.
88
-
89
- Claude Code (one command):
90
- ```
91
- claude mcp add kmhub -e KMHUB_API_KEY=kmh_live_xxxxxxxx -- node /absolute/path/to/kmhub/mcp-server/index.mjs
92
- ```
93
-
94
- Claude Desktop `claude_desktop_config.json`:
95
- ```json
96
- {
97
- "mcpServers": {
98
- "kmhub": {
99
- "command": "node",
100
- "args": ["/absolute/path/to/kmhub/mcp-server/index.mjs"],
101
- "env": { "KMHUB_API_KEY": "kmh_live_xxxxxxxx", "KMHUB_PROFILE": "full" }
102
- }
103
- }
104
- }
105
- ```
106
- (Override the API base with `KMHUB_API_BASE` if self-hosting. `KMHUB_PROFILE` is optional
107
- and defaults to `full`.)
108
-
109
- ## Setup - remote Streamable HTTP (`remote.mjs`)
110
-
111
- No local install for the user - they point their client at the hosted VPS endpoint and
112
- authenticate with their own KM Hub key as a header. One server process serves every org;
113
- each request is scoped to the token it carries. Operators: see
114
- [DEPLOY-VPS.md](./DEPLOY-VPS.md) (pm2 `kmhub-mcp`, port `8830`,
115
- `https://mcp.kivimedia.co/mcp`).
116
-
117
- Claude Code (one command):
118
-
119
- ```bash
120
- claude mcp add --transport http kmhub https://mcp.kivimedia.co/mcp \
121
- --header "Authorization: Bearer kmh_live_xxxxxxxx"
122
- ```
123
-
124
- Add `?profile=core` to the URL to load a smaller tool set:
125
-
126
- ```bash
127
- claude mcp add --transport http kmhub "https://mcp.kivimedia.co/mcp?profile=core" \
128
- --header "Authorization: Bearer kmh_live_xxxxxxxx"
129
- ```
130
-
131
- Claude Desktop / config-file clients:
132
-
133
- ```json
134
- {
135
- "mcpServers": {
136
- "kmhub": {
137
- "type": "streamable-http",
138
- "url": "https://mcp.kivimedia.co/mcp",
139
- "headers": {
140
- "Authorization": "Bearer kmh_live_xxxxxxxx",
141
- "X-KMHub-Profile": "full"
142
- }
143
- }
144
- }
145
- }
146
- ```
147
-
148
- Health check (no auth): `GET https://mcp.kivimedia.co/health`.
149
-
150
- ## Adding tools
151
-
152
- See [tools/README.md](./tools/README.md) for the family contract. Short version: drop a new
153
- `tools/<family>.mjs` exporting `FAMILY`, `TOOLS`, `register(server, call, helpers)` and an
154
- optional `PROFILES`, and it loads itself. You never edit `tools.mjs`, so parallel work on
155
- different families cannot collide. A family that fails to load, or claims a tool name another
156
- family already took, is skipped with a warning on stderr; the rest of the server carries on.
157
-
158
- ## Notes
159
- This is the same org-scoped, key-authed substrate the Telegram bot and Zapier use - one
160
- auth surface for all machine access. Everything is scoped to the key's workspace; a key
161
- can never reach another tenant's data. The API rate-limits each key to 60 reads and 20
162
- writes per minute (429 + `retry-after` beyond that). Writes land in the AI activity log;
163
- outreach drafts additionally wait for human approval in the Approval Queue before any send.
164
-
165
- **Lapsed subscription (402).** If the API answers `402 subscription_inactive`, every tool in
166
- every family returns a plain-English message instead of a raw JSON blob: the subscription is
167
- not active, nothing in the workspace changed, and here is where to restart it. That is handled
168
- once in the shared `out()` helper in `tools.mjs`, so it covers families that do not exist yet.
169
- Other statuses keep the raw JSON body, which is what the model needs to reason about validation
170
- errors.
1
+ # kmhub-mcp
2
+
3
+ A standalone [MCP](https://modelcontextprotocol.io) server for KM Hub. It exposes your
4
+ workspace to any MCP client (Claude Desktop, Claude Code, IDEs, agents) using a KM Hub
5
+ API key, by wrapping the public REST API (`kmhub-api`).
6
+
7
+ It ships in two transports that share the exact same tool set (`tools.mjs` plus the
8
+ family modules in `tools/`):
9
+
10
+ - **Local stdio** (`index.mjs`) - the client spawns the process; the org key comes from
11
+ the `KMHUB_API_KEY` env var. One process = one workspace. Best for a single power user
12
+ on their own machine.
13
+ - **Remote Streamable HTTP** (`remote.mjs`) - one long-running server (hosted on the VPS)
14
+ serves many orgs with zero local install. Each request authenticates with its own KM Hub
15
+ key sent as a `Authorization: Bearer kmh_live_...` header, and is scoped to that org only.
16
+ Deploy runbook: [DEPLOY-VPS.md](./DEPLOY-VPS.md).
17
+
18
+ ## Tools
19
+
20
+ Tools are grouped into **families**, one file per family in [`tools/`](./tools/README.md).
21
+ `tools.mjs` discovers them at load time, so a new family is a new file and nothing else.
22
+
23
+ ### `core` - orientation and the CRM essentials
24
+ - `km_me` - the connected workspace (id, name, plan) + the key's scopes
25
+ - `km_waiting` - what needs you (approvals, enquiries, tasks, invoices, contracts)
26
+ - `km_list_clients` - recent clients / leads (optional `limit`)
27
+ - `km_create_lead` - create a lead (`first_name`, `last_name`, `company`, `email`, `phone`, `notes`)
28
+ - `km_list_deals` - pipeline deals (optional `limit`, `stage`, `status`)
29
+ - `km_list_events` - calendar events (optional `limit`, `from`/`to` start-date range)
30
+ - `km_list_bookings` - recent bookings (optional `limit`, `status`, `from`/`to` event-date range)
31
+ - `km_create_inquiry` - log an enquiry + its client (`client_name` required; `event_type`, `event_date`, `budget_cents`, `notes`, ...). Opens a pipeline deal automatically. Audited + undoable in the AI activity log.
32
+ - `km_create_booking` - create a real booking + its client (`client_name` and `event_date` required; optional `status`: `pending` default or `confirmed`). Opens a pipeline deal at booked/won. Audited + undoable.
33
+ - `km_create_outreach_draft` - queue an outreach message as a DRAFT (`body` required; optional `subject`, `channel` email/linkedin/ig/sms_whatsapp, `deal_id`, `contact_id`). It only QUEUES: a human approves the draft in the Approval Queue before anything can send. Audited.
34
+
35
+ ### `meta` - keeping the connection current
36
+ - `km_check_updates` - asks KM Hub what it publishes today (`GET /version` returns
37
+ `api_version`, `rules_version`, `tools_version`, `min_client`, `changelog_url`) and answers
38
+ in plain language. Two judgements: is this connector still above `min_client` (the build
39
+ KM Hub refuses to serve below), and is the rules file on disk still the published
40
+ `rules_version`? Pass the local one in as `rules_version`. The rules pack carries a content
41
+ hash after a `+`, and the two endpoints do not always both publish it, so the semver base
42
+ and the hash are judged separately rather than looping on a suffix that proves nothing.
43
+ - `km_fetch_rules` - downloads the current KM Hub operating rules (`GET /rules`) and returns
44
+ `{ version, markdown, sha256, bytes, instructions }`. The model is instructed to write that
45
+ markdown verbatim over the user's global rules file (for Claude Code, their `CLAUDE.md`),
46
+ replacing any older KM Hub block, and then to tell the user it did so.
47
+
48
+ Both meta tools degrade gracefully: if your KM Hub has not shipped `/version` or `/rules` yet
49
+ they say "your KM Hub does not support update checks yet" and report success, rather than
50
+ failing. The checksum is computed locally from the bytes that actually arrived; if KM Hub also
51
+ sends one and the two differ, the response carries a warning instead of a silent bad write.
52
+
53
+ ## Profiles
54
+
55
+ Every tool schema is loaded into every turn, so a big tool set is a real context tax. A
56
+ profile loads only the families you want:
57
+
58
+ | Profile | Loads |
59
+ |---|---|
60
+ | `core` | orientation + CRM essentials, plus `meta` |
61
+ | `outreach` | `core` + the outreach families |
62
+ | `money` | `core` + the billing families |
63
+ | `content` | `core` + the content families |
64
+ | `coach` | Fully Booked Coach operations, client delivery, acquisition, and content requests |
65
+ | `full` | everything (**default**) |
66
+
67
+ `full` is the default, so nothing changes for an existing connection. An unknown profile name
68
+ falls back to `full` rather than erroring: a typo in a config file should never cost someone
69
+ their tools.
70
+
71
+ - **Remote**: per request, `POST /mcp?profile=money` or an `X-KMHub-Profile: money` header.
72
+ The query string wins if both are present. The profile is read from the request and passed
73
+ down by argument, so the server stays stateless and two tenants can hold two different
74
+ profiles at the same moment.
75
+ - **Local stdio**: the `KMHUB_PROFILE` env var.
76
+
77
+ `GET /health` reports the families that loaded and the tool count for each profile.
78
+
79
+ ## Setup - local stdio (`index.mjs`)
80
+ 1. In KM Hub: **Settings > Developer & API** -> create an API key (`kmh_live_...`).
81
+ Read tools need the `read` scope, create tools need `write` (a read-only key
82
+ gets 403 on writes).
83
+ 2. Install deps in this folder:
84
+ ```
85
+ npm install
86
+ ```
87
+ 3. Add to your MCP client.
88
+
89
+ Claude Code (one command):
90
+ ```
91
+ claude mcp add kmhub -e KMHUB_API_KEY=kmh_live_xxxxxxxx -- node /absolute/path/to/kmhub/mcp-server/index.mjs
92
+ ```
93
+
94
+ Claude Desktop `claude_desktop_config.json`:
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "kmhub": {
99
+ "command": "node",
100
+ "args": ["/absolute/path/to/kmhub/mcp-server/index.mjs"],
101
+ "env": { "KMHUB_API_KEY": "kmh_live_xxxxxxxx", "KMHUB_PROFILE": "full" }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+ (Override the API base with `KMHUB_API_BASE` if self-hosting. `KMHUB_PROFILE` is optional
107
+ and defaults to `full`.)
108
+
109
+ ## Setup - remote Streamable HTTP (`remote.mjs`)
110
+
111
+ No local install for the user - they point their client at the hosted VPS endpoint and
112
+ authenticate with their own KM Hub key as a header. One server process serves every org;
113
+ each request is scoped to the token it carries. Operators: see
114
+ [DEPLOY-VPS.md](./DEPLOY-VPS.md) (pm2 `kmhub-mcp`, port `8830`,
115
+ `https://mcp.kivimedia.co/mcp`).
116
+
117
+ Claude Code (one command):
118
+
119
+ ```bash
120
+ claude mcp add --transport http kmhub https://mcp.kivimedia.co/mcp \
121
+ --header "Authorization: Bearer kmh_live_xxxxxxxx"
122
+ ```
123
+
124
+ Add `?profile=core` to the URL to load a smaller tool set:
125
+
126
+ ```bash
127
+ claude mcp add --transport http kmhub "https://mcp.kivimedia.co/mcp?profile=core" \
128
+ --header "Authorization: Bearer kmh_live_xxxxxxxx"
129
+ ```
130
+
131
+ Claude Desktop / config-file clients:
132
+
133
+ ```json
134
+ {
135
+ "mcpServers": {
136
+ "kmhub": {
137
+ "type": "streamable-http",
138
+ "url": "https://mcp.kivimedia.co/mcp",
139
+ "headers": {
140
+ "Authorization": "Bearer kmh_live_xxxxxxxx",
141
+ "X-KMHub-Profile": "full"
142
+ }
143
+ }
144
+ }
145
+ }
146
+ ```
147
+
148
+ Health check (no auth): `GET https://mcp.kivimedia.co/health`.
149
+
150
+ ## Adding tools
151
+
152
+ See [tools/README.md](./tools/README.md) for the family contract. Short version: drop a new
153
+ `tools/<family>.mjs` exporting `FAMILY`, `TOOLS`, `register(server, call, helpers)` and an
154
+ optional `PROFILES`, and it loads itself. You never edit `tools.mjs`, so parallel work on
155
+ different families cannot collide. A family that fails to load, or claims a tool name another
156
+ family already took, is skipped with a warning on stderr; the rest of the server carries on.
157
+
158
+ ## Notes
159
+ This is the same org-scoped, key-authed substrate the Telegram bot and Zapier use - one
160
+ auth surface for all machine access. Everything is scoped to the key's workspace; a key
161
+ can never reach another tenant's data. The API rate-limits each key to 60 reads and 20
162
+ writes per minute (429 + `retry-after` beyond that). Writes land in the AI activity log;
163
+ outreach drafts additionally wait for human approval in the Approval Queue before any send.
164
+
165
+ **Lapsed subscription (402).** If the API answers `402 subscription_inactive`, every tool in
166
+ every family returns a plain-English message instead of a raw JSON blob: the subscription is
167
+ not active, nothing in the workspace changed, and here is where to restart it. That is handled
168
+ once in the shared `out()` helper in `tools.mjs`, so it covers families that do not exist yet.
169
+ Other statuses keep the raw JSON body, which is what the model needs to reason about validation
170
+ errors.