@honkio/mcp 1.4.0 → 1.5.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/README.md +133 -46
- package/dist/auth.d.ts +40 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +98 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +13 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +44 -18
- package/dist/client.js.map +1 -1
- package/dist/http.d.ts +51 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +248 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -46
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +10 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +10 -0
- package/dist/log.js.map +1 -0
- package/dist/prompts.d.ts +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +18 -18
- package/dist/prompts.js.map +1 -1
- package/dist/rateLimit.d.ts +50 -0
- package/dist/rateLimit.d.ts.map +1 -0
- package/dist/rateLimit.js +85 -0
- package/dist/rateLimit.js.map +1 -0
- package/dist/resources.d.ts +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +4 -4
- package/dist/resources.js.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +46 -0
- package/dist/server.js.map +1 -0
- package/dist/toolMeta.d.ts +20 -0
- package/dist/toolMeta.d.ts.map +1 -0
- package/dist/toolMeta.js +75 -0
- package/dist/toolMeta.js.map +1 -0
- package/dist/tools.d.ts +1 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +194 -204
- package/dist/tools.js.map +1 -1
- package/package.json +16 -7
package/dist/client.js
CHANGED
|
@@ -17,11 +17,36 @@ export class HonkioError extends Error {
|
|
|
17
17
|
export class HonkioClient {
|
|
18
18
|
apiKey;
|
|
19
19
|
baseUrl;
|
|
20
|
+
accountId;
|
|
21
|
+
serviceKey;
|
|
20
22
|
constructor(options) {
|
|
21
23
|
this.apiKey = options.apiKey;
|
|
22
24
|
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
|
|
25
|
+
this.accountId = options.accountId;
|
|
26
|
+
this.serviceKey = options.serviceKey;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The account this key belongs to, looked up once per client instance. A
|
|
30
|
+
* stdio process has one key for its whole life; an HTTP request builds a
|
|
31
|
+
* fresh client per call, seeded from the verifier's cache, so neither ever
|
|
32
|
+
* asks the API twice.
|
|
33
|
+
*/
|
|
34
|
+
async currentAccountId() {
|
|
35
|
+
if (this.accountId)
|
|
36
|
+
return this.accountId;
|
|
37
|
+
const me = await this.getCurrentAccount();
|
|
38
|
+
this.accountId = me.account.id;
|
|
39
|
+
return this.accountId;
|
|
23
40
|
}
|
|
24
41
|
async request(method, path, body, query, extraHeaders) {
|
|
42
|
+
// Every id in a path comes from a tool argument, i.e. from the model. Call
|
|
43
|
+
// sites encode each segment, which turns a crafted id into one harmless
|
|
44
|
+
// segment; this catches any call site that ever forgets, so the request
|
|
45
|
+
// fails here instead of quietly resolving somewhere else. An encoded dot
|
|
46
|
+
// segment ("..%2Fx") is one segment and passes; a bare ".." does not.
|
|
47
|
+
if (path.replace(/^\//, '').split('/').some((segment) => segment === '..' || segment === '.' || segment === '')) {
|
|
48
|
+
throw new HonkioError(400, 'INVALID_ID', 'An identifier contained path characters and was refused.');
|
|
49
|
+
}
|
|
25
50
|
let url = `${this.baseUrl}${path}`;
|
|
26
51
|
if (query) {
|
|
27
52
|
const params = new URLSearchParams();
|
|
@@ -39,6 +64,7 @@ export class HonkioClient {
|
|
|
39
64
|
'Authorization': `Bearer ${this.apiKey}`,
|
|
40
65
|
'Content-Type': 'application/json',
|
|
41
66
|
'Accept': 'application/json',
|
|
67
|
+
...(this.serviceKey ? { 'X-MCP-Service-Key': this.serviceKey } : {}),
|
|
42
68
|
...extraHeaders,
|
|
43
69
|
},
|
|
44
70
|
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
@@ -68,7 +94,7 @@ export class HonkioClient {
|
|
|
68
94
|
return this.request('GET', '/v1/messages', undefined, query);
|
|
69
95
|
}
|
|
70
96
|
getMessage(id) {
|
|
71
|
-
return this.request('GET', `/v1/messages/${id}`);
|
|
97
|
+
return this.request('GET', `/v1/messages/${encodeURIComponent(id)}`);
|
|
72
98
|
}
|
|
73
99
|
// ── Phone Numbers ─────────────────────────────────────────
|
|
74
100
|
searchPhoneNumbers(query) {
|
|
@@ -81,10 +107,10 @@ export class HonkioClient {
|
|
|
81
107
|
return this.request('GET', '/v1/phone-numbers');
|
|
82
108
|
}
|
|
83
109
|
getPhoneNumber(id) {
|
|
84
|
-
return this.request('GET', `/v1/phone-numbers/${id}`);
|
|
110
|
+
return this.request('GET', `/v1/phone-numbers/${encodeURIComponent(id)}`);
|
|
85
111
|
}
|
|
86
112
|
releasePhoneNumber(id) {
|
|
87
|
-
return this.request('DELETE', `/v1/phone-numbers/${id}`);
|
|
113
|
+
return this.request('DELETE', `/v1/phone-numbers/${encodeURIComponent(id)}`);
|
|
88
114
|
}
|
|
89
115
|
// ── Compliance: Consents ──────────────────────────────────
|
|
90
116
|
recordConsent(params) {
|
|
@@ -126,10 +152,10 @@ export class HonkioClient {
|
|
|
126
152
|
return this.request('POST', '/v1/verify', params);
|
|
127
153
|
}
|
|
128
154
|
checkVerification(verificationId, code) {
|
|
129
|
-
return this.request('POST', `/v1/verify/${verificationId}/check`, { code });
|
|
155
|
+
return this.request('POST', `/v1/verify/${encodeURIComponent(verificationId)}/check`, { code });
|
|
130
156
|
}
|
|
131
157
|
getVerification(verificationId) {
|
|
132
|
-
return this.request('GET', `/v1/verify/${verificationId}`);
|
|
158
|
+
return this.request('GET', `/v1/verify/${encodeURIComponent(verificationId)}`);
|
|
133
159
|
}
|
|
134
160
|
listVerifications(query) {
|
|
135
161
|
return this.request('GET', '/v1/verify', undefined, query);
|
|
@@ -142,28 +168,28 @@ export class HonkioClient {
|
|
|
142
168
|
return this.request('GET', '/v1/webhooks');
|
|
143
169
|
}
|
|
144
170
|
getWebhook(id) {
|
|
145
|
-
return this.request('GET', `/v1/webhooks/${id}`);
|
|
171
|
+
return this.request('GET', `/v1/webhooks/${encodeURIComponent(id)}`);
|
|
146
172
|
}
|
|
147
173
|
updateWebhook(id, params) {
|
|
148
|
-
return this.request('PATCH', `/v1/webhooks/${id}`, params);
|
|
174
|
+
return this.request('PATCH', `/v1/webhooks/${encodeURIComponent(id)}`, params);
|
|
149
175
|
}
|
|
150
176
|
deleteWebhook(id) {
|
|
151
|
-
return this.request('DELETE', `/v1/webhooks/${id}`);
|
|
177
|
+
return this.request('DELETE', `/v1/webhooks/${encodeURIComponent(id)}`);
|
|
152
178
|
}
|
|
153
179
|
listWebhookDeliveries(webhookId, query) {
|
|
154
|
-
return this.request('GET', `/v1/webhooks/${webhookId}/deliveries`, undefined, query);
|
|
180
|
+
return this.request('GET', `/v1/webhooks/${encodeURIComponent(webhookId)}/deliveries`, undefined, query);
|
|
155
181
|
}
|
|
156
182
|
reactivateWebhook(webhookId) {
|
|
157
|
-
return this.request('POST', `/v1/webhooks/${webhookId}/reactivate`);
|
|
183
|
+
return this.request('POST', `/v1/webhooks/${encodeURIComponent(webhookId)}/reactivate`);
|
|
158
184
|
}
|
|
159
185
|
listWebhookDeadLetters(webhookId, query) {
|
|
160
186
|
return this.request('GET', `/v1/webhooks/${webhookId}/dead-letters`, undefined, query);
|
|
161
187
|
}
|
|
162
188
|
replayWebhookDeadLetter(deadLetterId) {
|
|
163
|
-
return this.request('POST', `/v1/webhooks/dead-letters/${deadLetterId}/replay`);
|
|
189
|
+
return this.request('POST', `/v1/webhooks/dead-letters/${encodeURIComponent(deadLetterId)}/replay`);
|
|
164
190
|
}
|
|
165
191
|
discardWebhookDeadLetter(deadLetterId) {
|
|
166
|
-
return this.request('DELETE', `/v1/webhooks/dead-letters/${deadLetterId}`);
|
|
192
|
+
return this.request('DELETE', `/v1/webhooks/dead-letters/${encodeURIComponent(deadLetterId)}`);
|
|
167
193
|
}
|
|
168
194
|
// ── Account ───────────────────────────────────────────────
|
|
169
195
|
/**
|
|
@@ -177,13 +203,13 @@ export class HonkioClient {
|
|
|
177
203
|
return this.request('GET', '/v1/accounts/me');
|
|
178
204
|
}
|
|
179
205
|
getAccount(id) {
|
|
180
|
-
return this.request('GET', `/v1/accounts/${id}`);
|
|
206
|
+
return this.request('GET', `/v1/accounts/${encodeURIComponent(id)}`);
|
|
181
207
|
}
|
|
182
208
|
updateAccount(id, params) {
|
|
183
|
-
return this.request('PATCH', `/v1/accounts/${id}`, params);
|
|
209
|
+
return this.request('PATCH', `/v1/accounts/${encodeURIComponent(id)}`, params);
|
|
184
210
|
}
|
|
185
211
|
getUsage(id, query) {
|
|
186
|
-
return this.request('GET', `/v1/accounts/${id}/usage`, undefined, query);
|
|
212
|
+
return this.request('GET', `/v1/accounts/${encodeURIComponent(id)}/usage`, undefined, query);
|
|
187
213
|
}
|
|
188
214
|
// ── Sending limits ────────────────────────────────────────────
|
|
189
215
|
getSendLimit() {
|
|
@@ -193,13 +219,13 @@ export class HonkioClient {
|
|
|
193
219
|
return this.request('POST', '/v1/send-limit/requests', params);
|
|
194
220
|
}
|
|
195
221
|
getTopupAllowance(accountId) {
|
|
196
|
-
return this.request('GET', `/v1/accounts/${accountId}/topup-allowance`);
|
|
222
|
+
return this.request('GET', `/v1/accounts/${encodeURIComponent(accountId)}/topup-allowance`);
|
|
197
223
|
}
|
|
198
224
|
createApiKey(accountId, params) {
|
|
199
|
-
return this.request('POST', `/v1/accounts/${accountId}/api-keys`, params ?? {});
|
|
225
|
+
return this.request('POST', `/v1/accounts/${encodeURIComponent(accountId)}/api-keys`, params ?? {});
|
|
200
226
|
}
|
|
201
227
|
revokeApiKey(accountId, keyId) {
|
|
202
|
-
return this.request('DELETE', `/v1/accounts/${accountId}/api-keys/${keyId}`);
|
|
228
|
+
return this.request('DELETE', `/v1/accounts/${encodeURIComponent(accountId)}/api-keys/${encodeURIComponent(keyId)}`);
|
|
203
229
|
}
|
|
204
230
|
rotateApiKey(accountId, keyId) {
|
|
205
231
|
return this.request('POST', `/v1/accounts/${accountId}/api-keys/${keyId}/rotate`);
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AACjD,sEAAsE;AACtE,MAAM,kBAAkB,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* HonkIO MCP server, hosted Streamable HTTP transport: what mcp.honkio.ca runs.
|
|
4
|
+
*
|
|
5
|
+
* POST /mcp the MCP endpoint (Origin check, then API-key gate, then MCP)
|
|
6
|
+
* GET /healthz liveness for Railway
|
|
7
|
+
*
|
|
8
|
+
* Every request builds a fresh McpServer around a HonkioClient carrying the
|
|
9
|
+
* caller's key, so nothing is shared between callers and the process holds no
|
|
10
|
+
* session state. The verifier cache is the only thing that outlives a request.
|
|
11
|
+
*/
|
|
12
|
+
import { type Server } from 'node:http';
|
|
13
|
+
import { KeyVerifier } from './auth.js';
|
|
14
|
+
import { type Logger } from './log.js';
|
|
15
|
+
export declare const DEFAULT_REQUESTS_PER_MINUTE = 300;
|
|
16
|
+
export declare const DEFAULT_FAILURES_PER_MINUTE = 10;
|
|
17
|
+
export interface HttpServerOptions {
|
|
18
|
+
apiBaseUrl: string;
|
|
19
|
+
/** Origins allowed to call the endpoint from a browser. Any other Origin header is refused. */
|
|
20
|
+
allowedOrigins?: string[];
|
|
21
|
+
logger?: Logger;
|
|
22
|
+
verifier?: KeyVerifier;
|
|
23
|
+
/** Per-address caps, fixed one-minute windows. Defaults 300 requests and 10 failed requests. */
|
|
24
|
+
rateLimit?: {
|
|
25
|
+
requestsPerMinute?: number;
|
|
26
|
+
failuresPerMinute?: number;
|
|
27
|
+
};
|
|
28
|
+
/** Proxy hops that append to X-Forwarded-For in front of this process. Railway's edge is one. Default 1. */
|
|
29
|
+
trustedProxies?: number;
|
|
30
|
+
/** The URL access tokens are bound to (RFC 8707 resource). Default https://mcp.honkio.ca/mcp. */
|
|
31
|
+
publicUrl?: string;
|
|
32
|
+
/** This service's key at the API (MCP_SERVICE_KEY); enables OAuth access tokens. Unset means API keys only. */
|
|
33
|
+
serviceKey?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Keep in step with api/src/services/oauth/scopes.ts. */
|
|
36
|
+
export declare const SCOPES: readonly ["messages:read", "messages:send", "numbers:read", "numbers:manage", "compliance:read", "compliance:write", "verify", "webhooks:read", "webhooks:manage", "account:read", "account:manage"];
|
|
37
|
+
export declare const DEFAULT_PUBLIC_URL = "https://mcp.honkio.ca/mcp";
|
|
38
|
+
export interface HttpServerHandle {
|
|
39
|
+
server: Server;
|
|
40
|
+
close(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
export declare function createHttpServer(opts: HttpServerOptions): HttpServerHandle;
|
|
43
|
+
export declare function startHttpServer(opts: HttpServerOptions & {
|
|
44
|
+
port: number;
|
|
45
|
+
host?: string;
|
|
46
|
+
}): Promise<{
|
|
47
|
+
url: string;
|
|
48
|
+
port: number;
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
}>;
|
|
51
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AACH,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAOjG,OAAO,EAAiB,WAAW,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAIrD,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAC/C,eAAO,MAAM,2BAA2B,KAAK,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,gGAAgG;IAChG,SAAS,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,4GAA4G;IAC5G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iGAAiG;IACjG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+GAA+G;IAC/G,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0DAA0D;AAC1D,eAAO,MAAM,MAAM,sMAGT,CAAC;AAEX,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAqCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,gBAAgB,CAyL1E;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACxD,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CAOhE"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* HonkIO MCP server, hosted Streamable HTTP transport: what mcp.honkio.ca runs.
|
|
4
|
+
*
|
|
5
|
+
* POST /mcp the MCP endpoint (Origin check, then API-key gate, then MCP)
|
|
6
|
+
* GET /healthz liveness for Railway
|
|
7
|
+
*
|
|
8
|
+
* Every request builds a fresh McpServer around a HonkioClient carrying the
|
|
9
|
+
* caller's key, so nothing is shared between callers and the process holds no
|
|
10
|
+
* session state. The verifier cache is the only thing that outlives a request.
|
|
11
|
+
*/
|
|
12
|
+
import { createServer } from 'node:http';
|
|
13
|
+
import { pathToFileURL } from 'node:url';
|
|
14
|
+
import { createMcpHandler } from '@modelcontextprotocol/server';
|
|
15
|
+
import { toNodeHandler } from '@modelcontextprotocol/node';
|
|
16
|
+
import { HonkioClient } from './client.js';
|
|
17
|
+
import { buildServer, PACKAGE_VERSION } from './server.js';
|
|
18
|
+
import { extractApiKey, KeyVerifier } from './auth.js';
|
|
19
|
+
import { createLogger } from './log.js';
|
|
20
|
+
import { clientIp, RateLimiter } from './rateLimit.js';
|
|
21
|
+
const MAX_BODY_BYTES = 1_000_000;
|
|
22
|
+
export const DEFAULT_REQUESTS_PER_MINUTE = 300;
|
|
23
|
+
export const DEFAULT_FAILURES_PER_MINUTE = 10;
|
|
24
|
+
/** Keep in step with api/src/services/oauth/scopes.ts. */
|
|
25
|
+
export const SCOPES = [
|
|
26
|
+
'messages:read', 'messages:send', 'numbers:read', 'numbers:manage', 'compliance:read', 'compliance:write',
|
|
27
|
+
'verify', 'webhooks:read', 'webhooks:manage', 'account:read', 'account:manage',
|
|
28
|
+
];
|
|
29
|
+
const DEFAULT_SCOPE = SCOPES.filter((s) => s !== 'account:manage').join(' ');
|
|
30
|
+
export const DEFAULT_PUBLIC_URL = 'https://mcp.honkio.ca/mcp';
|
|
31
|
+
function sendJson(res, status, body, headers = {}) {
|
|
32
|
+
res.writeHead(status, { 'Content-Type': 'application/json', ...headers });
|
|
33
|
+
res.end(JSON.stringify(body));
|
|
34
|
+
}
|
|
35
|
+
class PayloadTooLarge extends Error {
|
|
36
|
+
}
|
|
37
|
+
function readBody(req, limit) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const chunks = [];
|
|
40
|
+
let size = 0;
|
|
41
|
+
req.on('data', (chunk) => {
|
|
42
|
+
size += chunk.length;
|
|
43
|
+
if (size > limit) {
|
|
44
|
+
reject(new PayloadTooLarge());
|
|
45
|
+
req.destroy();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
chunks.push(chunk);
|
|
49
|
+
});
|
|
50
|
+
req.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
|
|
51
|
+
req.on('error', reject);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function rpcShape(body) {
|
|
55
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
56
|
+
return {};
|
|
57
|
+
const { method, params } = body;
|
|
58
|
+
const name = params?.name ?? params?.uri;
|
|
59
|
+
return {
|
|
60
|
+
method: typeof method === 'string' ? method : undefined,
|
|
61
|
+
name: typeof name === 'string' ? name : undefined,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function createHttpServer(opts) {
|
|
65
|
+
const logger = opts.logger ?? createLogger();
|
|
66
|
+
const verifier = opts.verifier ?? new KeyVerifier({ apiBaseUrl: opts.apiBaseUrl, serviceKey: opts.serviceKey });
|
|
67
|
+
const publicUrl = opts.publicUrl ?? DEFAULT_PUBLIC_URL;
|
|
68
|
+
const resourceMetadata = {
|
|
69
|
+
resource: publicUrl,
|
|
70
|
+
authorization_servers: [opts.apiBaseUrl],
|
|
71
|
+
bearer_methods_supported: ['header'],
|
|
72
|
+
scopes_supported: [...SCOPES],
|
|
73
|
+
resource_documentation: 'https://honkio.ca/docs#mcp',
|
|
74
|
+
};
|
|
75
|
+
/** The metadata URL on the origin the caller actually used, so a test host and the public host both resolve. */
|
|
76
|
+
const metadataUrlFor = (req) => {
|
|
77
|
+
const proto = typeof req.headers['x-forwarded-proto'] === 'string' ? req.headers['x-forwarded-proto'] : 'http';
|
|
78
|
+
return `${proto}://${req.headers.host ?? 'localhost'}/.well-known/oauth-protected-resource/mcp`;
|
|
79
|
+
};
|
|
80
|
+
const challenge = (req, error) => `Bearer realm="honkio"${error ? `, error="${error}"` : ''}, resource_metadata="${metadataUrlFor(req)}", scope="${DEFAULT_SCOPE}"`;
|
|
81
|
+
const allowedOrigins = new Set(opts.allowedOrigins ?? []);
|
|
82
|
+
const requestsPerMinute = opts.rateLimit?.requestsPerMinute ?? DEFAULT_REQUESTS_PER_MINUTE;
|
|
83
|
+
const failuresPerMinute = opts.rateLimit?.failuresPerMinute ?? DEFAULT_FAILURES_PER_MINUTE;
|
|
84
|
+
const requests = new RateLimiter({ limit: requestsPerMinute });
|
|
85
|
+
const failures = new RateLimiter({ limit: failuresPerMinute });
|
|
86
|
+
const trustedProxies = opts.trustedProxies ?? 1;
|
|
87
|
+
const handler = createMcpHandler(({ authInfo }) => {
|
|
88
|
+
if (!authInfo)
|
|
89
|
+
throw new Error('MCP handler reached without authInfo; the gate must run first');
|
|
90
|
+
const extra = (authInfo.extra ?? {});
|
|
91
|
+
return buildServer(new HonkioClient({
|
|
92
|
+
apiKey: authInfo.token,
|
|
93
|
+
baseUrl: opts.apiBaseUrl,
|
|
94
|
+
accountId: extra.accountId,
|
|
95
|
+
serviceKey: extra.credential === 'token' ? opts.serviceKey : undefined,
|
|
96
|
+
}));
|
|
97
|
+
}, {
|
|
98
|
+
// Default responseMode ('auto'): a single JSON body unless a handler emits a
|
|
99
|
+
// notification first, which none of ours do. Forcing 'json' logs a warning on boot.
|
|
100
|
+
onerror: (err) => logger.error('mcp handler error', { error: err.message }),
|
|
101
|
+
});
|
|
102
|
+
const mcp = toNodeHandler(handler, {
|
|
103
|
+
onerror: (err) => logger.error('mcp adapter error', { error: err.message, stack: err.stack }),
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* A refusal before MCP is reached. Logged with its reason so abuse and
|
|
107
|
+
* misconfiguration are visible. When an address is given, the refusal also
|
|
108
|
+
* counts toward that address's failure budget.
|
|
109
|
+
*/
|
|
110
|
+
function reject(res, status, reason, message, headers = {}, ip) {
|
|
111
|
+
if (ip && status !== 429)
|
|
112
|
+
failures.hit(ip);
|
|
113
|
+
logger.info('mcp rejected', { status, reason, ...(ip ? { ip, forwardedFor: res.req.headers['x-forwarded-for'] } : {}) });
|
|
114
|
+
sendJson(res, status, { error: reason, message }, headers);
|
|
115
|
+
}
|
|
116
|
+
async function route(req, res) {
|
|
117
|
+
const started = Date.now();
|
|
118
|
+
const path = (req.url ?? '/').split('?')[0];
|
|
119
|
+
if (path === '/healthz' && req.method === 'GET') {
|
|
120
|
+
return sendJson(res, 200, { ok: true, version: PACKAGE_VERSION });
|
|
121
|
+
}
|
|
122
|
+
if ((path === '/.well-known/oauth-protected-resource' || path === '/.well-known/oauth-protected-resource/mcp') && req.method === 'GET') {
|
|
123
|
+
return sendJson(res, 200, resourceMetadata, { 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'public, max-age=300' });
|
|
124
|
+
}
|
|
125
|
+
if (path !== '/mcp') {
|
|
126
|
+
return sendJson(res, 404, { error: 'not_found', message: 'The MCP endpoint is POST /mcp.' });
|
|
127
|
+
}
|
|
128
|
+
if (req.method !== 'POST') {
|
|
129
|
+
return reject(res, 405, 'method_not_allowed', 'The MCP endpoint accepts POST only.', { Allow: 'POST' });
|
|
130
|
+
}
|
|
131
|
+
const ip = clientIp(req, trustedProxies);
|
|
132
|
+
const budget = requests.hit(ip);
|
|
133
|
+
if (!budget.allowed) {
|
|
134
|
+
return reject(res, 429, 'rate_limited', `More than ${requestsPerMinute} requests a minute from one address. Retry in ${budget.retryAfterSec} s.`, { 'Retry-After': String(budget.retryAfterSec) }, ip);
|
|
135
|
+
}
|
|
136
|
+
const lockout = failures.blocked(ip);
|
|
137
|
+
if (!lockout.allowed) {
|
|
138
|
+
return reject(res, 429, 'too_many_failures', `More than ${failuresPerMinute} refused requests a minute from one address. Retry in ${lockout.retryAfterSec} s.`, { 'Retry-After': String(lockout.retryAfterSec) }, ip);
|
|
139
|
+
}
|
|
140
|
+
const origin = req.headers.origin;
|
|
141
|
+
if (typeof origin === 'string' && !allowedOrigins.has(origin)) {
|
|
142
|
+
return reject(res, 403, 'origin_forbidden', `Origin ${origin} is not allowed to call this endpoint.`, {}, ip);
|
|
143
|
+
}
|
|
144
|
+
const key = extractApiKey(req.headers);
|
|
145
|
+
if (!key) {
|
|
146
|
+
return reject(res, 401, 'unauthorized', 'Send your HonkIO API key as "Authorization: Bearer mk_live_..." (or mk_test_...).', { 'WWW-Authenticate': challenge(req) }, ip);
|
|
147
|
+
}
|
|
148
|
+
const verdict = await verifier.verify(key);
|
|
149
|
+
if (verdict.status === 'invalid') {
|
|
150
|
+
return reject(res, 401, 'unauthorized', 'Invalid or revoked API key.', { 'WWW-Authenticate': challenge(req, 'invalid_token') }, ip);
|
|
151
|
+
}
|
|
152
|
+
if (verdict.status === 'unavailable') {
|
|
153
|
+
return reject(res, 503, 'api_unavailable', 'The HonkIO API could not verify the key. Retry shortly.');
|
|
154
|
+
}
|
|
155
|
+
let raw;
|
|
156
|
+
try {
|
|
157
|
+
raw = await readBody(req, MAX_BODY_BYTES);
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
if (err instanceof PayloadTooLarge) {
|
|
161
|
+
return reject(res, 413, 'payload_too_large', 'The request body exceeds 1 MB.', {}, ip);
|
|
162
|
+
}
|
|
163
|
+
throw err;
|
|
164
|
+
}
|
|
165
|
+
let body;
|
|
166
|
+
try {
|
|
167
|
+
body = JSON.parse(raw);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return reject(res, 400, 'invalid_json', 'The request body must be a JSON-RPC message.', {}, ip);
|
|
171
|
+
}
|
|
172
|
+
const { method: mcpMethod, name: mcpName } = rpcShape(body);
|
|
173
|
+
res.on('finish', () => {
|
|
174
|
+
logger.info('mcp request', {
|
|
175
|
+
mcpMethod,
|
|
176
|
+
mcpName,
|
|
177
|
+
protocolVersion: req.headers['mcp-protocol-version'],
|
|
178
|
+
account: verdict.accountId,
|
|
179
|
+
mode: verdict.isTestMode ? 'test' : 'live',
|
|
180
|
+
status: res.statusCode,
|
|
181
|
+
ms: Date.now() - started,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
req.auth = verdict.authInfo;
|
|
185
|
+
await mcp(req, res, body);
|
|
186
|
+
}
|
|
187
|
+
const server = createServer((req, res) => {
|
|
188
|
+
route(req, res).catch((err) => {
|
|
189
|
+
logger.error('unhandled request error', { error: err instanceof Error ? err.message : String(err) });
|
|
190
|
+
if (!res.headersSent)
|
|
191
|
+
sendJson(res, 500, { error: 'internal_error' });
|
|
192
|
+
else
|
|
193
|
+
res.end();
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
server.requestTimeout = 30_000;
|
|
197
|
+
return {
|
|
198
|
+
server,
|
|
199
|
+
close: async () => {
|
|
200
|
+
await handler.close();
|
|
201
|
+
await new Promise((resolve, reject) => server.close((err) => (err ? reject(err) : resolve())));
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export async function startHttpServer(opts) {
|
|
206
|
+
const handle = createHttpServer(opts);
|
|
207
|
+
const host = opts.host ?? '0.0.0.0';
|
|
208
|
+
await new Promise((resolve) => handle.server.listen(opts.port, host, resolve));
|
|
209
|
+
const { port } = handle.server.address();
|
|
210
|
+
const urlHost = host === '0.0.0.0' ? '127.0.0.1' : host;
|
|
211
|
+
return { url: `http://${urlHost}:${port}`, port, close: handle.close };
|
|
212
|
+
}
|
|
213
|
+
function main() {
|
|
214
|
+
const logger = createLogger();
|
|
215
|
+
const port = Number(process.env['PORT'] ?? 8080);
|
|
216
|
+
const apiBaseUrl = process.env['API_URL'] ?? process.env['HONKIO_API_URL'] ?? 'https://api.honkio.ca';
|
|
217
|
+
const allowedOrigins = (process.env['MCP_ALLOWED_ORIGINS'] ?? '')
|
|
218
|
+
.split(',')
|
|
219
|
+
.map((s) => s.trim())
|
|
220
|
+
.filter(Boolean);
|
|
221
|
+
const positive = (raw, fallback) => {
|
|
222
|
+
const n = Number(raw);
|
|
223
|
+
return Number.isInteger(n) && n > 0 ? n : fallback;
|
|
224
|
+
};
|
|
225
|
+
const rateLimit = {
|
|
226
|
+
requestsPerMinute: positive(process.env['MCP_RATE_LIMIT_PER_MINUTE'], DEFAULT_REQUESTS_PER_MINUTE),
|
|
227
|
+
failuresPerMinute: positive(process.env['MCP_AUTH_FAILURES_PER_MINUTE'], DEFAULT_FAILURES_PER_MINUTE),
|
|
228
|
+
};
|
|
229
|
+
const trustedEnv = Number(process.env['MCP_TRUSTED_PROXIES']);
|
|
230
|
+
const trustedProxies = Number.isInteger(trustedEnv) && trustedEnv >= 0 ? trustedEnv : 1;
|
|
231
|
+
const publicUrl = process.env['MCP_PUBLIC_URL'] ?? DEFAULT_PUBLIC_URL;
|
|
232
|
+
const serviceKey = process.env['MCP_SERVICE_KEY'] || undefined;
|
|
233
|
+
void startHttpServer({ apiBaseUrl, allowedOrigins, logger, port, rateLimit, trustedProxies, publicUrl, serviceKey }).then((running) => {
|
|
234
|
+
logger.info('listening', { port: running.port, apiBaseUrl, allowedOrigins, rateLimit, trustedProxies, publicUrl, oauth: Boolean(serviceKey), version: PACKAGE_VERSION });
|
|
235
|
+
const shutdown = (signal) => {
|
|
236
|
+
logger.info('shutting down', { signal });
|
|
237
|
+
const force = setTimeout(() => process.exit(1), 10_000);
|
|
238
|
+
force.unref();
|
|
239
|
+
void running.close().then(() => process.exit(0));
|
|
240
|
+
};
|
|
241
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
242
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
246
|
+
main();
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* HonkIO MCP Server
|
|
4
|
-
*
|
|
5
|
-
* Exposes the HonkIO SMS API as an MCP server for AI coding agents.
|
|
6
|
-
* Supports stdio transport (Claude Desktop, Cursor, VS Code, etc.)
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* HONKIO_API_KEY=mk_live_... node dist/index.js
|
|
10
|
-
*/
|
|
11
2
|
export {};
|
|
12
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
CHANGED
|
@@ -1,56 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* HonkIO MCP
|
|
3
|
+
* HonkIO MCP server, stdio transport: what `npx -y @honkio/mcp` runs inside
|
|
4
|
+
* Claude Code, Claude Desktop, Cursor and VS Code.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
* Supports stdio transport (Claude Desktop, Cursor, VS Code, etc.)
|
|
6
|
+
* HONKIO_API_KEY=mk_test_... node dist/index.js
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* HONKIO_API_KEY=mk_live_... node dist/index.js
|
|
8
|
+
* Diagnostics go to stderr; stdout is the protocol channel and must stay clean.
|
|
10
9
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import { fileURLToPath } from 'node:url';
|
|
13
|
-
import { dirname, resolve } from 'node:path';
|
|
14
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
15
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { serveStdio } from '@modelcontextprotocol/server/stdio';
|
|
16
11
|
import { HonkioClient } from './client.js';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const pkg = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf8'));
|
|
24
|
-
return pkg.version ?? 'unknown';
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return 'unknown';
|
|
28
|
-
}
|
|
29
|
-
})();
|
|
30
|
-
function getEnv(key) {
|
|
31
|
-
const val = process.env[key];
|
|
32
|
-
if (!val) {
|
|
33
|
-
console.error(`[honkio-mcp] Missing required environment variable: ${key}`);
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
return val;
|
|
12
|
+
import { buildServer } from './server.js';
|
|
13
|
+
const apiKey = process.env['HONKIO_API_KEY'];
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
console.error('[honkio-mcp] Missing required environment variable: HONKIO_API_KEY');
|
|
16
|
+
process.exit(1);
|
|
37
17
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
18
|
+
// HONKIO_API_URL is the pre-1.5 name; still honoured so existing local overrides keep working.
|
|
19
|
+
const baseUrl = process.env['API_URL'] ?? process.env['HONKIO_API_URL'] ?? 'https://api.honkio.ca';
|
|
20
|
+
const client = new HonkioClient({ apiKey, baseUrl });
|
|
21
|
+
const handle = serveStdio(() => buildServer(client), {
|
|
22
|
+
onerror: (err) => console.error('[honkio-mcp]', err.message),
|
|
23
|
+
});
|
|
24
|
+
for (const signal of ['SIGINT', 'SIGTERM']) {
|
|
25
|
+
process.on(signal, () => {
|
|
26
|
+
void handle.close().finally(() => process.exit(0));
|
|
45
27
|
});
|
|
46
|
-
registerTools(server, client);
|
|
47
|
-
registerResources(server, client);
|
|
48
|
-
registerPrompts(server);
|
|
49
|
-
const transport = new StdioServerTransport();
|
|
50
|
-
await server.connect(transport);
|
|
51
28
|
}
|
|
52
|
-
main().catch((err) => {
|
|
53
|
-
console.error('[honkio-mcp] Fatal error:', err);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
});
|
|
56
29
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAC7C,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AACD,+FAA+F;AAC/F,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,uBAAuB,CAAC;AACnG,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;AAErD,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE;IACnD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC;CAC7D,CAAC,CAAC;AAEH,KAAK,MAAM,MAAM,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAU,EAAE,CAAC;IACpD,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACtB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** One JSON object per line on stdout. Used by the HTTP entry only; stdio must keep stdout for the protocol. */
|
|
2
|
+
export type LogFields = Record<string, unknown>;
|
|
3
|
+
export interface Logger {
|
|
4
|
+
info(msg: string, fields?: LogFields): void;
|
|
5
|
+
error(msg: string, fields?: LogFields): void;
|
|
6
|
+
}
|
|
7
|
+
export declare function createLogger(stream?: {
|
|
8
|
+
write(chunk: string): unknown;
|
|
9
|
+
}): Logger;
|
|
10
|
+
//# sourceMappingURL=log.d.ts.map
|