@togglhq/mcp 1.11.82 → 1.11.83
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 +1 -1
- package/build/cli.js +14 -17
- package/build/index.js +1 -1
- package/build/{src-CuNUrEWK.js → src-LMB5VU2N.js} +118 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,7 +104,7 @@ Disable product analytics:
|
|
|
104
104
|
TOGGL_PRODUCT_ANALYTICS=off
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
Error reporting is on by default. It sends the tool name, a redacted error category, the stack trace with package-relative file paths, the MCP, Node and OS versions, and sampled request timings without query strings. It never sends tool arguments, results, exception text, console output, your hostname, local paths, or your project's dependency list. Disable it with `TOGGL_SENTRY=off`, or send it to your own Sentry project with `TOGGL_SENTRY_DSN`.
|
|
108
108
|
|
|
109
109
|
## License
|
|
110
110
|
|
package/build/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as getProductAnalyticsDistinctId, c as resolvePublicSentryDsn, i as captureToolInvocation, l as shutdownProductAnalytics, n as runMcpCli, o as initProductAnalytics, r as PUBLIC_SENTRY_PRIVACY_OPTIONS, s as resolveProductAnalyticsDistinctId } from "./src-LMB5VU2N.js";
|
|
3
3
|
import * as Sentry from "@sentry/node";
|
|
4
4
|
//#region src/analytics-tool-metadata.ts
|
|
5
5
|
/**
|
|
@@ -66,25 +66,22 @@ function classifyToolResult(result) {
|
|
|
66
66
|
}
|
|
67
67
|
//#endregion
|
|
68
68
|
//#region src/public-analytics.ts
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const dsn =
|
|
77
|
-
if (!dsn
|
|
78
|
-
console.error("[Analytics] TOGGL_SENTRY is set but SENTRY_DSN is missing; Sentry left disabled");
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
69
|
+
/**
|
|
70
|
+
* Public client DSN for the `toggl-mcp` Sentry project. Safe to ship: it only
|
|
71
|
+
* accepts events. The pack audit allowlists this exact value and still rejects
|
|
72
|
+
* any other `ingest.sentry.io` DSN.
|
|
73
|
+
*/
|
|
74
|
+
const PUBLIC_SENTRY_DSN = "https://c37820699688a7c0393aa257dbe7a99e@o43910.ingest.us.sentry.io/4512156592046081";
|
|
75
|
+
function initPublicSentry(environment, release) {
|
|
76
|
+
const dsn = resolvePublicSentryDsn(PUBLIC_SENTRY_DSN);
|
|
77
|
+
if (!dsn) return false;
|
|
81
78
|
Sentry.init({
|
|
82
79
|
dsn,
|
|
83
80
|
environment: environment ?? "production",
|
|
81
|
+
release: release ? `@togglhq/mcp@${release}` : void 0,
|
|
84
82
|
tracesSampleRate: .2,
|
|
85
83
|
enableLogs: false,
|
|
86
|
-
|
|
87
|
-
beforeSend: (event) => redactUnsafeSentryMessages(event)
|
|
84
|
+
...PUBLIC_SENTRY_PRIVACY_OPTIONS
|
|
88
85
|
});
|
|
89
86
|
return true;
|
|
90
87
|
}
|
|
@@ -165,13 +162,13 @@ function wrapServerWithProductAnalytics(server) {
|
|
|
165
162
|
}
|
|
166
163
|
//#endregion
|
|
167
164
|
//#region src/cli.ts
|
|
168
|
-
const packageVersion = "1.11.
|
|
165
|
+
const packageVersion = "1.11.83";
|
|
169
166
|
let sentryEnabled = false;
|
|
170
167
|
let productAnalyticsEnabled = false;
|
|
171
168
|
runMcpCli({
|
|
172
169
|
beforeRegister(server) {
|
|
173
170
|
productAnalyticsEnabled = initMcpProductAnalytics({ packageVersion });
|
|
174
|
-
sentryEnabled = initPublicSentry(process.env.NODE_ENV);
|
|
171
|
+
sentryEnabled = initPublicSentry(process.env.NODE_ENV, packageVersion);
|
|
175
172
|
let next = server;
|
|
176
173
|
if (sentryEnabled) next = wrapPublicServerWithSentry(next);
|
|
177
174
|
if (productAnalyticsEnabled) wrapServerWithProductAnalytics(next);
|
package/build/index.js
CHANGED
|
@@ -40012,6 +40012,120 @@ function redactUnsafeSentryMessages(event) {
|
|
|
40012
40012
|
for (const value of event.exception?.values ?? []) if (!isSafeSentryMessage(value.value)) value.value = REDACTED_SENTRY_MESSAGE;
|
|
40013
40013
|
return event;
|
|
40014
40014
|
}
|
|
40015
|
+
/**
|
|
40016
|
+
* Shared Sentry setup for the public CLI and MCP packages. Reporting is on by
|
|
40017
|
+
* default there, so everything the SDK attaches on its own has to be safe to
|
|
40018
|
+
* send from any user's machine, not only the exception message. Both packages
|
|
40019
|
+
* build their `Sentry.init` options from here so the two cannot drift.
|
|
40020
|
+
*/
|
|
40021
|
+
function normalized(raw) {
|
|
40022
|
+
const value = raw?.trim();
|
|
40023
|
+
return value ? value.toLowerCase() : void 0;
|
|
40024
|
+
}
|
|
40025
|
+
function isOff(raw) {
|
|
40026
|
+
const value = normalized(raw);
|
|
40027
|
+
return value === "0" || value === "false" || value === "off" || value === "no";
|
|
40028
|
+
}
|
|
40029
|
+
function isOn(raw) {
|
|
40030
|
+
const value = normalized(raw);
|
|
40031
|
+
return value === "1" || value === "true" || value === "on" || value === "yes";
|
|
40032
|
+
}
|
|
40033
|
+
/**
|
|
40034
|
+
* Picks the DSN the public build reports to, or `undefined` when reporting is
|
|
40035
|
+
* off.
|
|
40036
|
+
*
|
|
40037
|
+
* `TOGGL_SENTRY_DSN` is the override. The generic `SENTRY_DSN` is what most Node
|
|
40038
|
+
* apps set, and the MCP loads the working directory's `.env`, so on its own it
|
|
40039
|
+
* must not redirect Toggl's errors into the user's project. It is still honoured
|
|
40040
|
+
* with an explicit `TOGGL_SENTRY=1`, the old opt-in, and `SENTRY_DSN=off` still
|
|
40041
|
+
* switches reporting off.
|
|
40042
|
+
*/
|
|
40043
|
+
function resolvePublicSentryDsn(builtIn, env = process.env) {
|
|
40044
|
+
if (isOff(env.TOGGL_SENTRY) || normalized(env.SENTRY_DSN) === "off") return void 0;
|
|
40045
|
+
const override = env.TOGGL_SENTRY_DSN?.trim();
|
|
40046
|
+
if (override) return override.toLowerCase() === "off" ? void 0 : override;
|
|
40047
|
+
const legacy = env.SENTRY_DSN?.trim();
|
|
40048
|
+
if (legacy && isOn(env.TOGGL_SENTRY)) return legacy;
|
|
40049
|
+
return builtIn;
|
|
40050
|
+
}
|
|
40051
|
+
/**
|
|
40052
|
+
* `/Users/jane/.npm/_npx/…/node_modules/@togglhq/mcp/build/cli.js` becomes
|
|
40053
|
+
* `@togglhq/mcp/build/cli.js`. A path outside `node_modules` keeps only its file
|
|
40054
|
+
* name, so no home directory or login leaves the machine.
|
|
40055
|
+
*/
|
|
40056
|
+
function toPackageRelativePath(path) {
|
|
40057
|
+
const unified = path.replace(/^file:\/\//, "").replaceAll("\\", "/");
|
|
40058
|
+
const at = unified.lastIndexOf("/node_modules/");
|
|
40059
|
+
if (at !== -1) return unified.slice(at + 14);
|
|
40060
|
+
if (!unified.includes("/")) return unified;
|
|
40061
|
+
return unified.slice(unified.lastIndexOf("/") + 1);
|
|
40062
|
+
}
|
|
40063
|
+
function scrubStacktrace(stacktrace) {
|
|
40064
|
+
for (const frame of stacktrace?.frames ?? []) {
|
|
40065
|
+
if (typeof frame.filename === "string") frame.filename = toPackageRelativePath(frame.filename);
|
|
40066
|
+
if (typeof frame.abs_path === "string") frame.abs_path = toPackageRelativePath(frame.abs_path);
|
|
40067
|
+
}
|
|
40068
|
+
}
|
|
40069
|
+
const QUERY_ATTRIBUTES = [
|
|
40070
|
+
"http.query",
|
|
40071
|
+
"url.query",
|
|
40072
|
+
"http.fragment",
|
|
40073
|
+
"url.fragment"
|
|
40074
|
+
];
|
|
40075
|
+
const URL_ATTRIBUTES = [
|
|
40076
|
+
"url.full",
|
|
40077
|
+
"http.url",
|
|
40078
|
+
"http.target",
|
|
40079
|
+
"url"
|
|
40080
|
+
];
|
|
40081
|
+
function stripQuery(value) {
|
|
40082
|
+
return value.replace(/[?#]\S*/, "");
|
|
40083
|
+
}
|
|
40084
|
+
function scrubSpan(span) {
|
|
40085
|
+
if (!span) return;
|
|
40086
|
+
if (typeof span.description === "string") span.description = stripQuery(span.description);
|
|
40087
|
+
const data = span.data;
|
|
40088
|
+
if (!data) return;
|
|
40089
|
+
for (const key of QUERY_ATTRIBUTES) delete data[key];
|
|
40090
|
+
for (const key of URL_ATTRIBUTES) {
|
|
40091
|
+
const value = data[key];
|
|
40092
|
+
if (typeof value === "string") data[key] = stripQuery(value);
|
|
40093
|
+
}
|
|
40094
|
+
}
|
|
40095
|
+
/**
|
|
40096
|
+
* Last word on every event the public build sends: messages reduced to fixed
|
|
40097
|
+
* categories, no hostname, no breadcrumbs, no dependency list, no request data,
|
|
40098
|
+
* package-relative stack paths, and no query strings on spans.
|
|
40099
|
+
*/
|
|
40100
|
+
function scrubPublicSentryEvent(event) {
|
|
40101
|
+
redactUnsafeSentryMessages(event);
|
|
40102
|
+
delete event.server_name;
|
|
40103
|
+
delete event.breadcrumbs;
|
|
40104
|
+
delete event.modules;
|
|
40105
|
+
delete event.request;
|
|
40106
|
+
for (const value of event.exception?.values ?? []) scrubStacktrace(value.stacktrace);
|
|
40107
|
+
for (const thread of event.threads?.values ?? []) scrubStacktrace(thread.stacktrace);
|
|
40108
|
+
for (const span of event.spans ?? []) scrubSpan(span);
|
|
40109
|
+
scrubSpan(event.contexts?.trace);
|
|
40110
|
+
return event;
|
|
40111
|
+
}
|
|
40112
|
+
/**
|
|
40113
|
+
* Privacy options shared by `initCliTelemetry` and `initPublicSentry`.
|
|
40114
|
+
*
|
|
40115
|
+
* `sendDefaultPii: false` leaves the hostname (`server_name`), console and fetch
|
|
40116
|
+
* breadcrumbs, absolute stack paths, the working directory's package.json
|
|
40117
|
+
* dependencies (`Modules`) and incoming request data in place. Console
|
|
40118
|
+
* breadcrumbs in the MCP include the workspace name it logs at startup.
|
|
40119
|
+
*/
|
|
40120
|
+
const PUBLIC_SENTRY_PRIVACY_OPTIONS = {
|
|
40121
|
+
sendDefaultPii: false,
|
|
40122
|
+
includeServerName: false,
|
|
40123
|
+
maxBreadcrumbs: 0,
|
|
40124
|
+
integrations: (defaults) => defaults.filter((integration) => integration.name !== "Modules"),
|
|
40125
|
+
beforeBreadcrumb: () => null,
|
|
40126
|
+
beforeSend: (event) => scrubPublicSentryEvent(event),
|
|
40127
|
+
beforeSendTransaction: (event) => scrubPublicSentryEvent(event)
|
|
40128
|
+
};
|
|
40015
40129
|
const DEFAULT_POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
40016
40130
|
/**
|
|
40017
40131
|
* The shared Toggl **production** PostHog project — the same token the Track
|
|
@@ -54723,7 +54837,7 @@ function registerWorkspaceTools(server) {
|
|
|
54723
54837
|
//#region src/package-version.ts
|
|
54724
54838
|
function mcpPackageVersion() {
|
|
54725
54839
|
try {
|
|
54726
|
-
return "1.11.
|
|
54840
|
+
return "1.11.83";
|
|
54727
54841
|
} catch {
|
|
54728
54842
|
return "unknown";
|
|
54729
54843
|
}
|
|
@@ -54898,7 +55012,7 @@ import_main.default.config({
|
|
|
54898
55012
|
quiet: true,
|
|
54899
55013
|
ignore: ["MISSING_ENV_FILE"]
|
|
54900
55014
|
});
|
|
54901
|
-
const packageVersion = "1.11.
|
|
55015
|
+
const packageVersion = "1.11.83";
|
|
54902
55016
|
function resolvePublicUrls() {
|
|
54903
55017
|
return {
|
|
54904
55018
|
focusApiUrl: process.env.TOGGL_FOCUS_API_URL ?? "https://focus.toggl.com",
|
|
@@ -54961,6 +55075,6 @@ function bootstrapServer(options = {}) {
|
|
|
54961
55075
|
if (options.beforeExit) process.on("beforeExit", async () => await options.beforeExit?.());
|
|
54962
55076
|
}
|
|
54963
55077
|
//#endregion
|
|
54964
|
-
export {
|
|
55078
|
+
export { getProductAnalyticsDistinctId as a, resolvePublicSentryDsn as c, captureToolInvocation as i, shutdownProductAnalytics as l, runMcpCli as n, initProductAnalytics as o, PUBLIC_SENTRY_PRIVACY_OPTIONS as r, resolveProductAnalyticsDistinctId as s, bootstrapServer as t };
|
|
54965
55079
|
|
|
54966
|
-
//# sourceMappingURL=src-
|
|
55080
|
+
//# sourceMappingURL=src-LMB5VU2N.js.map
|