maiday-mcp 0.1.0 → 0.1.2
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 +89 -0
- package/dist/bin.js +46 -20
- package/dist/index.d.ts +7 -4
- package/dist/index.js +47 -20
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# maiday-mcp
|
|
2
|
+
|
|
3
|
+
**The distress signal for AI agents.** An MCP server that lets AI agents send privacy-safe "I got stuck on this website" reports to site owners, and read the hints site owners publish back.
|
|
4
|
+
|
|
5
|
+
When an agent fails on a website, nobody learns from it: a form rejects it, a login wall stops it, a validation error loops, a button can't be found. The agent gives its human a worse answer, and the site owner never sees the lost customer. Maiday closes that loop.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
### Claude Code
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
claude mcp add -s user maiday -e MAIDAY_HARNESS=claude-code -- npx -y maiday-mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Codex
|
|
16
|
+
|
|
17
|
+
Add to `~/.codex/config.toml`:
|
|
18
|
+
|
|
19
|
+
```toml
|
|
20
|
+
[mcp_servers.maiday]
|
|
21
|
+
command = "npx"
|
|
22
|
+
args = ["-y", "maiday-mcp"]
|
|
23
|
+
env = { MAIDAY_HARNESS = "codex" }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Any MCP client
|
|
27
|
+
|
|
28
|
+
Run `npx -y maiday-mcp` as a stdio server and set `MAIDAY_HARNESS` to your client's name.
|
|
29
|
+
|
|
30
|
+
Maiday only does something when the agent can use websites, through a browser tool such as Playwright MCP, Chrome DevTools MCP or Claude in Chrome.
|
|
31
|
+
|
|
32
|
+
## Tools
|
|
33
|
+
|
|
34
|
+
### `send_maiday`
|
|
35
|
+
|
|
36
|
+
Report that the agent got stuck on a step.
|
|
37
|
+
|
|
38
|
+
| Field | Required | Notes |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `url` | yes | The page URL. Only origin and path are sent; query strings and fragments are removed. |
|
|
41
|
+
| `task` | yes | `signup`, `login`, `checkout`, `booking`, `search`, `contact_form`, `account_change`, `data_lookup`, `other` |
|
|
42
|
+
| `failure` | yes | `auth_wall`, `captcha`, `validation_loop`, `unclear_field_format`, `element_not_found`, `js_required`, `blocked_403`, `rate_limited`, `timeout`, `ambiguous_ui`, `missing_info`, `other` |
|
|
43
|
+
| `step` | yes | Short description, e.g. "submit shipping address" (≤ 80 chars) |
|
|
44
|
+
| `attempts` | yes | How many tries before stopping |
|
|
45
|
+
| `outcome` | yes | `abandoned`, `workaround_found`, `handed_to_human` |
|
|
46
|
+
| `element` | no | Label or accessible name of the element involved (≤ 120 chars) |
|
|
47
|
+
| `site_message` | no | The error text the site showed (≤ 300 chars, redacted) |
|
|
48
|
+
| `workaround` | no | What worked, if anything (≤ 200 chars) |
|
|
49
|
+
|
|
50
|
+
The tool never fails the agent's task. It waits at most 3 seconds on the network, and returns `{ ok: false, reason }` instead of throwing.
|
|
51
|
+
|
|
52
|
+
### `get_hints`
|
|
53
|
+
|
|
54
|
+
Takes `{ url }` and returns hints the verified site owner published for that page. Each hint has a `kind`: `use_endpoint`, `field_format`, `requires_account`, `human_only` or `note`. Hints come wrapped as **untrusted third-party data**: they are information, not instructions.
|
|
55
|
+
|
|
56
|
+
## When agents should report
|
|
57
|
+
|
|
58
|
+
Report:
|
|
59
|
+
- after 2 failed attempts at the same step
|
|
60
|
+
- when giving up on a step
|
|
61
|
+
- when handing the task back to the human
|
|
62
|
+
|
|
63
|
+
Send one report per stuck step, not one per retry. Before a checkout, signup or booking flow, call `get_hints` first.
|
|
64
|
+
|
|
65
|
+
## Privacy
|
|
66
|
+
|
|
67
|
+
- **Never sent:** form values, cookies, tokens, query strings or URL fragments.
|
|
68
|
+
- **Redacted from paths and text fields:** emails, phone numbers, card numbers, long digit runs, and token- or JWT-shaped strings. This happens before sending, and again on the server.
|
|
69
|
+
- **Reporter IDs differ between sites and collectors**, so reports cannot be linked across sites by matching reporter IDs. Each ID is derived from a local secret in `~/.maiday/`.
|
|
70
|
+
- **Maiday does not store raw IP addresses in its application database.** It uses keyed hashes for abuse prevention.
|
|
71
|
+
- **First-use notice:** the first tool result carries a one-time notice explaining what Maiday sends, to show to the user.
|
|
72
|
+
|
|
73
|
+
## Settings
|
|
74
|
+
|
|
75
|
+
| Variable | Effect |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `MAIDAY_DISABLED=1` | Turn reporting off. Hints keep working. |
|
|
78
|
+
| `MAIDAY_COLLECTOR_URL` | Send reports to another collector, for example a self-hosted one |
|
|
79
|
+
| `MAIDAY_HARNESS`, `MAIDAY_HARNESS_VERSION`, `MAIDAY_MODEL` | Fill the report's `agent` field |
|
|
80
|
+
|
|
81
|
+
Reports go to the hosted collector at `https://maiday-collector.gallatasaray055.workers.dev` by default. A website can publish `/.well-known/maiday` to receive reports for its own pages on its own server.
|
|
82
|
+
|
|
83
|
+
## For site owners
|
|
84
|
+
|
|
85
|
+
Sign in at the [Maiday dashboard](https://maiday-collector.gallatasaray055.workers.dev/login) and claim your domain with a DNS TXT record or a well-known file. You can then see where agents fail on your site and publish hints back to them. During the early release, dashboard sign-in is limited to the maintainer.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/dist/bin.js
CHANGED
|
@@ -210,6 +210,9 @@ function matchHint(pattern, path) {
|
|
|
210
210
|
return false;
|
|
211
211
|
return true;
|
|
212
212
|
}
|
|
213
|
+
function isValidPathPattern(pp) {
|
|
214
|
+
return pp.startsWith("/") && pp.length <= HINT_PATH_PATTERN_MAX && !/[?#]/.test(pp) && !hasControlChars(pp) && !pp.split("/").some((seg) => seg.includes("*") && seg !== "*");
|
|
215
|
+
}
|
|
213
216
|
function isSameSiteEndpoint(endpoint, domain) {
|
|
214
217
|
let u;
|
|
215
218
|
try {
|
|
@@ -240,7 +243,7 @@ function validateHint(input, domain) {
|
|
|
240
243
|
return { ok: false, error: "Hints may not contain control characters or line breaks." };
|
|
241
244
|
}
|
|
242
245
|
const pp = h.path_pattern;
|
|
243
|
-
if (!
|
|
246
|
+
if (!isValidPathPattern(pp)) {
|
|
244
247
|
return { ok: false, error: `Path pattern must start with "/", be at most ${HINT_PATH_PATTERN_MAX} characters, contain no "?" or "#", and use "*" only as a whole segment.` };
|
|
245
248
|
}
|
|
246
249
|
if (h.kind === "use_endpoint") {
|
|
@@ -353,26 +356,45 @@ async function fetchSite(origin, fetchFn, fallback, parent) {
|
|
|
353
356
|
|
|
354
357
|
// src/install.ts
|
|
355
358
|
import { createHmac, randomBytes } from "crypto";
|
|
356
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
359
|
+
import { link, mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
|
|
357
360
|
import { join } from "path";
|
|
358
361
|
var newSecret = () => randomBytes(32).toString("base64url");
|
|
362
|
+
async function claim(target) {
|
|
363
|
+
const tmp = `${target}.${randomBytes(8).toString("hex")}.tmp`;
|
|
364
|
+
await writeFile(tmp, JSON.stringify({ secret: newSecret() }) + "\n", { mode: 384 });
|
|
365
|
+
let created = true;
|
|
366
|
+
try {
|
|
367
|
+
await link(tmp, target);
|
|
368
|
+
} catch (e) {
|
|
369
|
+
if (e.code !== "EEXIST") throw e;
|
|
370
|
+
created = false;
|
|
371
|
+
} finally {
|
|
372
|
+
await unlink(tmp).catch(() => {
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
return { secret: await readSecret(target), created };
|
|
376
|
+
}
|
|
377
|
+
async function replaceWith(file, secret) {
|
|
378
|
+
const tmp = `${file}.${randomBytes(8).toString("hex")}.tmp`;
|
|
379
|
+
await writeFile(tmp, JSON.stringify({ secret }) + "\n", { mode: 384 });
|
|
380
|
+
await rename(tmp, file);
|
|
381
|
+
}
|
|
359
382
|
async function getInstall(home) {
|
|
360
383
|
const dir = join(home, ".maiday");
|
|
361
384
|
const file = join(dir, "install.json");
|
|
362
385
|
await mkdir(dir, { recursive: true });
|
|
363
|
-
|
|
364
|
-
if (existing) return { secret: existing, firstRun: false };
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return { secret, firstRun:
|
|
369
|
-
|
|
370
|
-
if (e.code !== "EEXIST") throw e;
|
|
371
|
-
const raced = await readSecret(file);
|
|
372
|
-
if (raced) return { secret: raced, firstRun: false };
|
|
373
|
-
await writeFile(file, JSON.stringify({ secret }) + "\n", { mode: 384 });
|
|
374
|
-
return { secret, firstRun: true };
|
|
386
|
+
let existing = await readSecret(file);
|
|
387
|
+
if (typeof existing === "string") return { secret: existing, firstRun: false };
|
|
388
|
+
if (existing === null) {
|
|
389
|
+
const c = await claim(file);
|
|
390
|
+
if (c.created) return { secret: c.secret, firstRun: true };
|
|
391
|
+
if (typeof c.secret === "string") return { secret: c.secret, firstRun: false };
|
|
392
|
+
existing = c.secret;
|
|
375
393
|
}
|
|
394
|
+
const replacement = await claim(join(dir, "install.v2.json"));
|
|
395
|
+
if (typeof replacement.secret !== "string") throw new Error(`unreadable ${join(dir, "install.v2.json")}`);
|
|
396
|
+
await replaceWith(file, replacement.secret);
|
|
397
|
+
return { secret: replacement.secret, firstRun: existing === null && replacement.created };
|
|
376
398
|
}
|
|
377
399
|
function cachedInstall(home) {
|
|
378
400
|
let p;
|
|
@@ -384,14 +406,18 @@ function cachedInstall(home) {
|
|
|
384
406
|
return p;
|
|
385
407
|
};
|
|
386
408
|
}
|
|
387
|
-
|
|
388
|
-
|
|
409
|
+
var INSTALL_ID_VERSION = "v2";
|
|
410
|
+
function installIdFor(secret, reportEndpoint, siteOrigin) {
|
|
411
|
+
const input = JSON.stringify(["maiday-install-id", INSTALL_ID_VERSION, new URL(reportEndpoint).origin, new URL(siteOrigin).origin]);
|
|
412
|
+
return `${INSTALL_ID_VERSION}.${createHmac("sha256", secret).update(input).digest("base64url")}`;
|
|
389
413
|
}
|
|
414
|
+
var LEGACY = /* @__PURE__ */ Symbol("legacy install file");
|
|
390
415
|
async function readSecret(file) {
|
|
391
416
|
try {
|
|
392
417
|
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
393
|
-
const v = parsed.secret
|
|
394
|
-
|
|
418
|
+
const v = parsed.secret;
|
|
419
|
+
if (typeof v === "string" && v.length > 0 && v.length <= 128) return v;
|
|
420
|
+
return typeof parsed.id === "string" && parsed.id.length > 0 ? LEGACY : null;
|
|
395
421
|
} catch {
|
|
396
422
|
return null;
|
|
397
423
|
}
|
|
@@ -481,7 +507,7 @@ async function sendMaiday(input, deps) {
|
|
|
481
507
|
return await withDeadline(
|
|
482
508
|
async (signal) => {
|
|
483
509
|
const site = await discover(report.origin, deps.fetch, discoverOpts(deps, signal));
|
|
484
|
-
const body = { ...checked.data, install_id: installIdFor(secret, site.reportEndpoint) };
|
|
510
|
+
const body = { ...checked.data, install_id: installIdFor(secret, site.reportEndpoint, checked.data.origin) };
|
|
485
511
|
const res = await deps.fetch(site.reportEndpoint, {
|
|
486
512
|
method: "POST",
|
|
487
513
|
redirect: "manual",
|
|
@@ -570,7 +596,7 @@ var sendShape = {
|
|
|
570
596
|
};
|
|
571
597
|
var asText = (payload) => ({ content: [{ type: "text", text: JSON.stringify(payload) }] });
|
|
572
598
|
function createServer(baseDeps) {
|
|
573
|
-
const server2 = new McpServer({ name: "maiday-mcp", version: "0.1.
|
|
599
|
+
const server2 = new McpServer({ name: "maiday-mcp", version: "0.1.2" });
|
|
574
600
|
const deps = { ...baseDeps, install: baseDeps.install ?? cachedInstall(baseDeps.config.home) };
|
|
575
601
|
let noticeClaimed = false;
|
|
576
602
|
const takeNotice = async () => {
|
package/dist/index.d.ts
CHANGED
|
@@ -21,11 +21,14 @@ declare function getInstall(home: string): Promise<Install>;
|
|
|
21
21
|
* firstRun and the first-run notice cannot be lost to a concurrent write. A failure is not cached (next call retries).
|
|
22
22
|
*/
|
|
23
23
|
declare function cachedInstall(home: string): () => Promise<Install>;
|
|
24
|
+
/** Prefix of the current reporter-ID scheme; collectors count IDs per scheme and never add schemes together. */
|
|
25
|
+
declare const INSTALL_ID_VERSION = "v2";
|
|
24
26
|
/**
|
|
25
|
-
* The install_id sent
|
|
26
|
-
*
|
|
27
|
+
* The install_id sent with a report: "v2." + base64url(HMAC-SHA256(secret, JSON ["maiday-install-id", "v2",
|
|
28
|
+
* collector origin, site origin])). Stable for one collector and one site; different for every other site or
|
|
29
|
+
* collector, so reports cannot be linked across sites by matching IDs. JSON keeps the inputs unambiguous.
|
|
27
30
|
*/
|
|
28
|
-
declare function installIdFor(secret: string, reportEndpoint: string): string;
|
|
31
|
+
declare function installIdFor(secret: string, reportEndpoint: string, siteOrigin: string): string;
|
|
29
32
|
|
|
30
33
|
interface Discovered {
|
|
31
34
|
reportEndpoint: string;
|
|
@@ -88,5 +91,5 @@ declare function getHints(url: string, deps: Deps): Promise<HintsResult>;
|
|
|
88
91
|
declare const FIRST_RUN_NOTICE = "Maiday sends anonymous reports when an agent gets stuck on a website (page path, failure type, the site's error message with personal data removed). No form values or personal data are sent. Set MAIDAY_DISABLED=1 to turn reporting off. Please tell the user this once.";
|
|
89
92
|
declare function createServer(baseDeps: Deps): McpServer;
|
|
90
93
|
|
|
91
|
-
export { DEFAULT_COLLECTOR_URL, FIRST_RUN_NOTICE, HINTS_INSTRUCTIONS, cachedInstall, createServer, defaultEndpoints, discover, getHints, getInstall, installIdFor, isSafeEndpoint, loadConfig, sendMaiday };
|
|
94
|
+
export { DEFAULT_COLLECTOR_URL, FIRST_RUN_NOTICE, HINTS_INSTRUCTIONS, INSTALL_ID_VERSION, cachedInstall, createServer, defaultEndpoints, discover, getHints, getInstall, installIdFor, isSafeEndpoint, loadConfig, sendMaiday };
|
|
92
95
|
export type { Config, Deps, DiscoverOptions, Discovered, Env, HintsResult, Install, SendResult };
|
package/dist/index.js
CHANGED
|
@@ -13,26 +13,45 @@ function loadConfig(env = process.env) {
|
|
|
13
13
|
|
|
14
14
|
// src/install.ts
|
|
15
15
|
import { createHmac, randomBytes } from "crypto";
|
|
16
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
16
|
+
import { link, mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
|
|
17
17
|
import { join } from "path";
|
|
18
18
|
var newSecret = () => randomBytes(32).toString("base64url");
|
|
19
|
+
async function claim(target) {
|
|
20
|
+
const tmp = `${target}.${randomBytes(8).toString("hex")}.tmp`;
|
|
21
|
+
await writeFile(tmp, JSON.stringify({ secret: newSecret() }) + "\n", { mode: 384 });
|
|
22
|
+
let created = true;
|
|
23
|
+
try {
|
|
24
|
+
await link(tmp, target);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
if (e.code !== "EEXIST") throw e;
|
|
27
|
+
created = false;
|
|
28
|
+
} finally {
|
|
29
|
+
await unlink(tmp).catch(() => {
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return { secret: await readSecret(target), created };
|
|
33
|
+
}
|
|
34
|
+
async function replaceWith(file, secret) {
|
|
35
|
+
const tmp = `${file}.${randomBytes(8).toString("hex")}.tmp`;
|
|
36
|
+
await writeFile(tmp, JSON.stringify({ secret }) + "\n", { mode: 384 });
|
|
37
|
+
await rename(tmp, file);
|
|
38
|
+
}
|
|
19
39
|
async function getInstall(home) {
|
|
20
40
|
const dir = join(home, ".maiday");
|
|
21
41
|
const file = join(dir, "install.json");
|
|
22
42
|
await mkdir(dir, { recursive: true });
|
|
23
|
-
|
|
24
|
-
if (existing) return { secret: existing, firstRun: false };
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return { secret, firstRun:
|
|
29
|
-
|
|
30
|
-
if (e.code !== "EEXIST") throw e;
|
|
31
|
-
const raced = await readSecret(file);
|
|
32
|
-
if (raced) return { secret: raced, firstRun: false };
|
|
33
|
-
await writeFile(file, JSON.stringify({ secret }) + "\n", { mode: 384 });
|
|
34
|
-
return { secret, firstRun: true };
|
|
43
|
+
let existing = await readSecret(file);
|
|
44
|
+
if (typeof existing === "string") return { secret: existing, firstRun: false };
|
|
45
|
+
if (existing === null) {
|
|
46
|
+
const c = await claim(file);
|
|
47
|
+
if (c.created) return { secret: c.secret, firstRun: true };
|
|
48
|
+
if (typeof c.secret === "string") return { secret: c.secret, firstRun: false };
|
|
49
|
+
existing = c.secret;
|
|
35
50
|
}
|
|
51
|
+
const replacement = await claim(join(dir, "install.v2.json"));
|
|
52
|
+
if (typeof replacement.secret !== "string") throw new Error(`unreadable ${join(dir, "install.v2.json")}`);
|
|
53
|
+
await replaceWith(file, replacement.secret);
|
|
54
|
+
return { secret: replacement.secret, firstRun: existing === null && replacement.created };
|
|
36
55
|
}
|
|
37
56
|
function cachedInstall(home) {
|
|
38
57
|
let p;
|
|
@@ -44,14 +63,18 @@ function cachedInstall(home) {
|
|
|
44
63
|
return p;
|
|
45
64
|
};
|
|
46
65
|
}
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
var INSTALL_ID_VERSION = "v2";
|
|
67
|
+
function installIdFor(secret, reportEndpoint, siteOrigin) {
|
|
68
|
+
const input = JSON.stringify(["maiday-install-id", INSTALL_ID_VERSION, new URL(reportEndpoint).origin, new URL(siteOrigin).origin]);
|
|
69
|
+
return `${INSTALL_ID_VERSION}.${createHmac("sha256", secret).update(input).digest("base64url")}`;
|
|
49
70
|
}
|
|
71
|
+
var LEGACY = /* @__PURE__ */ Symbol("legacy install file");
|
|
50
72
|
async function readSecret(file) {
|
|
51
73
|
try {
|
|
52
74
|
const parsed = JSON.parse(await readFile(file, "utf8"));
|
|
53
|
-
const v = parsed.secret
|
|
54
|
-
|
|
75
|
+
const v = parsed.secret;
|
|
76
|
+
if (typeof v === "string" && v.length > 0 && v.length <= 128) return v;
|
|
77
|
+
return typeof parsed.id === "string" && parsed.id.length > 0 ? LEGACY : null;
|
|
55
78
|
} catch {
|
|
56
79
|
return null;
|
|
57
80
|
}
|
|
@@ -247,6 +270,9 @@ function matchHint(pattern, path) {
|
|
|
247
270
|
return false;
|
|
248
271
|
return true;
|
|
249
272
|
}
|
|
273
|
+
function isValidPathPattern(pp) {
|
|
274
|
+
return pp.startsWith("/") && pp.length <= HINT_PATH_PATTERN_MAX && !/[?#]/.test(pp) && !hasControlChars(pp) && !pp.split("/").some((seg) => seg.includes("*") && seg !== "*");
|
|
275
|
+
}
|
|
250
276
|
function isSameSiteEndpoint(endpoint, domain) {
|
|
251
277
|
let u;
|
|
252
278
|
try {
|
|
@@ -277,7 +303,7 @@ function validateHint(input, domain) {
|
|
|
277
303
|
return { ok: false, error: "Hints may not contain control characters or line breaks." };
|
|
278
304
|
}
|
|
279
305
|
const pp = h.path_pattern;
|
|
280
|
-
if (!
|
|
306
|
+
if (!isValidPathPattern(pp)) {
|
|
281
307
|
return { ok: false, error: `Path pattern must start with "/", be at most ${HINT_PATH_PATTERN_MAX} characters, contain no "?" or "#", and use "*" only as a whole segment.` };
|
|
282
308
|
}
|
|
283
309
|
if (h.kind === "use_endpoint") {
|
|
@@ -472,7 +498,7 @@ async function sendMaiday(input, deps) {
|
|
|
472
498
|
return await withDeadline(
|
|
473
499
|
async (signal) => {
|
|
474
500
|
const site = await discover(report.origin, deps.fetch, discoverOpts(deps, signal));
|
|
475
|
-
const body = { ...checked.data, install_id: installIdFor(secret, site.reportEndpoint) };
|
|
501
|
+
const body = { ...checked.data, install_id: installIdFor(secret, site.reportEndpoint, checked.data.origin) };
|
|
476
502
|
const res = await deps.fetch(site.reportEndpoint, {
|
|
477
503
|
method: "POST",
|
|
478
504
|
redirect: "manual",
|
|
@@ -563,7 +589,7 @@ var sendShape = {
|
|
|
563
589
|
};
|
|
564
590
|
var asText = (payload) => ({ content: [{ type: "text", text: JSON.stringify(payload) }] });
|
|
565
591
|
function createServer(baseDeps) {
|
|
566
|
-
const server = new McpServer({ name: "maiday-mcp", version: "0.1.
|
|
592
|
+
const server = new McpServer({ name: "maiday-mcp", version: "0.1.2" });
|
|
567
593
|
const deps = { ...baseDeps, install: baseDeps.install ?? cachedInstall(baseDeps.config.home) };
|
|
568
594
|
let noticeClaimed = false;
|
|
569
595
|
const takeNotice = async () => {
|
|
@@ -596,6 +622,7 @@ export {
|
|
|
596
622
|
DEFAULT_COLLECTOR_URL,
|
|
597
623
|
FIRST_RUN_NOTICE,
|
|
598
624
|
HINTS_INSTRUCTIONS,
|
|
625
|
+
INSTALL_ID_VERSION,
|
|
599
626
|
cachedInstall,
|
|
600
627
|
createServer,
|
|
601
628
|
defaultEndpoints,
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "maiday-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Maiday MCP client: privacy-safe stuck reports and site-owner hints for AI agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"bin": {
|
|
10
|
-
"maiday-mcp": "
|
|
10
|
+
"maiday-mcp": "dist/bin.js"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"dist"
|