@pilot-status/mcp-server 0.1.0 → 0.1.1
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/README.md +34 -81
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,24 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that
|
|
4
4
|
exposes the **Pilot Status public `/v1` API** as MCP tools, so any MCP-capable
|
|
5
|
-
client (Claude Desktop, Cursor, custom agents, …) can
|
|
6
|
-
manage numbers/templates, read conversations, and more —
|
|
7
|
-
API key.
|
|
5
|
+
client (Claude Desktop, Cursor, the claude.ai connector, custom agents, …) can
|
|
6
|
+
send WhatsApp messages, manage numbers/templates, read conversations, and more —
|
|
7
|
+
using a Pilot Status API key.
|
|
8
8
|
|
|
9
9
|
It speaks two transports:
|
|
10
10
|
|
|
11
11
|
- **stdio** — for local clients that spawn the server as a child process. The
|
|
12
12
|
API key is read once from `PILOT_STATUS_API_KEY`.
|
|
13
|
-
- **streamable HTTP** —
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
stateless (a fresh MCP session per request), so it scales horizontally behind
|
|
17
|
-
a load balancer.
|
|
13
|
+
- **streamable HTTP** — clients connect over HTTP and authenticate either with an
|
|
14
|
+
`x-api-key` header **or** with an OAuth 2.1 bearer token (for the
|
|
15
|
+
[claude.ai custom connector](#remote-oauth--claudeai-connector)).
|
|
18
16
|
|
|
19
17
|
## Install
|
|
20
18
|
|
|
21
19
|
```bash
|
|
22
|
-
# Run straight from npm (no
|
|
20
|
+
# Run straight from npm (no install needed):
|
|
23
21
|
npx @pilot-status/mcp-server stdio # stdio transport (default)
|
|
24
22
|
npx @pilot-status/mcp-server http # streamable HTTP transport
|
|
25
23
|
|
|
@@ -42,8 +40,8 @@ There are two ways to authenticate against the public `/v1` API:
|
|
|
42
40
|
1. **API key** (`x-api-key`) — a `ps_*` key, used by stdio and by HTTP clients
|
|
43
41
|
that send the header themselves.
|
|
44
42
|
2. **OAuth 2.1 bearer token** — used by the claude.ai custom connector
|
|
45
|
-
(HTTP transport).
|
|
46
|
-
|
|
43
|
+
(HTTP transport). claude.ai handles the login, so no API key is shared with
|
|
44
|
+
the client. See [Remote (OAuth)](#remote-oauth--claudeai-connector).
|
|
47
45
|
|
|
48
46
|
Scope matters (same rules as the REST API):
|
|
49
47
|
|
|
@@ -55,9 +53,9 @@ Scope matters (same rules as the REST API):
|
|
|
55
53
|
surfaced as a tool error.)
|
|
56
54
|
|
|
57
55
|
Under an OAuth/tenant token there is no number scope, so number-scoped tools
|
|
58
|
-
accept an optional `whatsappNumberId` argument
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
accept an optional `whatsappNumberId` argument so the backend can resolve the
|
|
57
|
+
target number. It is ignored when the API key is already scoped to a single
|
|
58
|
+
number.
|
|
61
59
|
|
|
62
60
|
Token-based pairing/connect routes (interactive browser flows) are intentionally
|
|
63
61
|
**not** exposed as tools.
|
|
@@ -103,39 +101,24 @@ See [`.env.example`](./.env.example). Key variables:
|
|
|
103
101
|
| `PILOT_STATUS_API_URL` | `https://pilotstatuss.com` | Public API base URL (no trailing slash). |
|
|
104
102
|
| `PILOT_STATUS_API_KEY` | — | `ps_*` key. Required for stdio; optional fallback for HTTP. |
|
|
105
103
|
| `PILOT_STATUS_API_KEY_ID` | — | Optional `x-api-key-id` companion. |
|
|
106
|
-
| `MCP_RESOURCE_URL` | `https://mcp.pilotstatuss.com` | Public URL of
|
|
104
|
+
| `MCP_RESOURCE_URL` | `https://mcp.pilotstatuss.com` | Public URL of this server (OAuth `resource`). |
|
|
107
105
|
| `PILOT_STATUS_AUTH_SERVER_URL` | `https://pilotstatuss.com` | OAuth authorization server (the backend). |
|
|
108
106
|
| `MCP_TRANSPORT` | `stdio` | `stdio` or `http`. |
|
|
109
107
|
| `PORT` | `8787` | HTTP transport port. |
|
|
110
108
|
| `HOST` | `0.0.0.0` | HTTP transport bind host. |
|
|
111
109
|
|
|
112
|
-
##
|
|
110
|
+
## HTTP endpoint
|
|
113
111
|
|
|
114
|
-
|
|
115
|
-
npm install # from the repo root (workspaces)
|
|
116
|
-
npm --workspace @pilot-status/mcp-server run build
|
|
117
|
-
|
|
118
|
-
# stdio (default)
|
|
119
|
-
PILOT_STATUS_API_KEY=ps_xxx node apps/mcp-server/dist/index.js
|
|
120
|
-
|
|
121
|
-
# streamable HTTP
|
|
122
|
-
MCP_TRANSPORT=http PORT=8787 node apps/mcp-server/dist/index.js
|
|
123
|
-
# or: node apps/mcp-server/dist/index.js http
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
Dev mode (no build): `npm --workspace @pilot-status/mcp-server run dev`.
|
|
127
|
-
|
|
128
|
-
### HTTP endpoint
|
|
112
|
+
When running the HTTP transport, the server exposes:
|
|
129
113
|
|
|
130
114
|
- `POST /mcp` — JSON-RPC over Streamable HTTP. Authenticate with `x-api-key:
|
|
131
115
|
ps_xxx` **or** `Authorization: Bearer <oauth-token>`. With no credentials it
|
|
132
116
|
replies `401` + `WWW-Authenticate`, which starts the OAuth flow.
|
|
133
117
|
- `GET /.well-known/oauth-protected-resource` — OAuth 2.1 protected-resource
|
|
134
118
|
metadata (RFC 9728); points discovery at the authorization server.
|
|
135
|
-
- `GET /health` — liveness probe.
|
|
136
119
|
|
|
137
120
|
```bash
|
|
138
|
-
curl -s
|
|
121
|
+
curl -s https://mcp.pilotstatuss.com/mcp \
|
|
139
122
|
-H "content-type: application/json" \
|
|
140
123
|
-H "accept: application/json, text/event-stream" \
|
|
141
124
|
-H "x-api-key: ps_xxx" \
|
|
@@ -146,8 +129,8 @@ curl -s http://localhost:8787/mcp \
|
|
|
146
129
|
|
|
147
130
|
### Claude Desktop / Cursor (stdio)
|
|
148
131
|
|
|
149
|
-
Use the published binary via `npx`
|
|
150
|
-
|
|
132
|
+
Use the published binary via `npx` — add to the client's MCP config (e.g.
|
|
133
|
+
`claude_desktop_config.json`):
|
|
151
134
|
|
|
152
135
|
```json
|
|
153
136
|
{
|
|
@@ -164,12 +147,9 @@ config (e.g. `claude_desktop_config.json`):
|
|
|
164
147
|
}
|
|
165
148
|
```
|
|
166
149
|
|
|
167
|
-
Or point `command`/`args` at a local build
|
|
168
|
-
(`node /absolute/path/to/apps/mcp-server/dist/index.js`).
|
|
169
|
-
|
|
170
150
|
### Remote / HTTP clients (API key)
|
|
171
151
|
|
|
172
|
-
Point the client at the
|
|
152
|
+
Point the client at the hosted URL and supply the API key as a header:
|
|
173
153
|
|
|
174
154
|
```json
|
|
175
155
|
{
|
|
@@ -185,46 +165,19 @@ Point the client at the deployed URL and supply the API key as a header:
|
|
|
185
165
|
|
|
186
166
|
### Remote (OAuth) — claude.ai connector
|
|
187
167
|
|
|
188
|
-
For the [claude.ai](https://claude.ai) **Custom Connector**,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
1. Deploy with `MCP_TRANSPORT=http` and set:
|
|
193
|
-
- `MCP_RESOURCE_URL` — the public URL of this server, e.g.
|
|
194
|
-
`https://mcp.pilotstatuss.com`.
|
|
195
|
-
- `PILOT_STATUS_AUTH_SERVER_URL` — the Pilot Status backend, e.g.
|
|
196
|
-
`https://pilotstatuss.com` (the default).
|
|
197
|
-
- Leave `PILOT_STATUS_API_KEY` **unset** so unauthenticated requests return a
|
|
198
|
-
`401` challenge (otherwise the env key would short-circuit OAuth).
|
|
199
|
-
2. In claude.ai → **Settings → Connectors → Add custom connector**, set the URL
|
|
200
|
-
to `https://mcp.pilotstatuss.com/mcp`.
|
|
201
|
-
3. claude.ai fetches `GET /.well-known/oauth-protected-resource`, discovers the
|
|
202
|
-
authorization server (`PILOT_STATUS_AUTH_SERVER_URL`), and runs the OAuth
|
|
203
|
-
2.1 login (Pilot Status SSO). The resulting access token is sent on every
|
|
204
|
-
`POST /mcp` as `Authorization: Bearer <token>`.
|
|
205
|
-
|
|
206
|
-
This server is a **dumb forwarder**: it does not verify the token. It forwards
|
|
207
|
-
the bearer token to the public `/v1` API, which validates it. If `/v1` rejects
|
|
208
|
-
the token (`401`), the response is relayed as `401` + `WWW-Authenticate` so the
|
|
209
|
-
client re-authenticates. The authorization server itself (`/api/oauth/*` and
|
|
210
|
-
`/.well-known/oauth-authorization-server`) lives in the Pilot Status backend.
|
|
211
|
-
|
|
212
|
-
## Deployment
|
|
213
|
-
|
|
214
|
-
`MCP_TRANSPORT=http` behind HTTPS at `MCP_RESOURCE_URL`. A container image +
|
|
215
|
-
generator entry + Traefik host (`mcp.pilotstatuss.com`) and the backend
|
|
216
|
-
authorization-server endpoints are tracked as follow-up tasks. The server is
|
|
217
|
-
stateless, so it can run with multiple replicas behind the load balancer.
|
|
218
|
-
|
|
219
|
-
## Tests
|
|
168
|
+
For the [claude.ai](https://claude.ai) **Custom Connector**, point claude.ai at
|
|
169
|
+
the hosted HTTPS URL and let it run the OAuth login — no API key is shared with
|
|
170
|
+
the client.
|
|
220
171
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
`
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
172
|
+
1. In claude.ai → **Settings → Connectors → Add custom connector**, set the URL
|
|
173
|
+
to `https://mcp.pilotstatuss.com/mcp`.
|
|
174
|
+
2. claude.ai fetches `GET /.well-known/oauth-protected-resource`, discovers the
|
|
175
|
+
authorization server, and runs the OAuth 2.1 login (Pilot Status SSO). The
|
|
176
|
+
resulting access token is sent on every `POST /mcp` as
|
|
177
|
+
`Authorization: Bearer <token>`.
|
|
178
|
+
|
|
179
|
+
If you run your own instance, serve the HTTP transport at a public HTTPS URL and
|
|
180
|
+
set `MCP_RESOURCE_URL` to that URL and `PILOT_STATUS_AUTH_SERVER_URL` to the
|
|
181
|
+
Pilot Status backend (`https://pilotstatuss.com`). Leave `PILOT_STATUS_API_KEY`
|
|
182
|
+
unset so unauthenticated requests return the `401` challenge that starts the
|
|
183
|
+
OAuth flow.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pilot-status/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Model Context Protocol (MCP) server exposing the Pilot Status public /v1 API as tools. Supports stdio and streamable HTTP transports (with OAuth 2.1 for the claude.ai custom connector).",
|
|
6
6
|
"license": "MIT",
|