@attrkit/mcp 0.4.2 → 0.4.4
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/dist/cli.js +31 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ Install Node.js 18 or newer. The `npx -y @attrkit/mcp` command downloads and
|
|
|
33
33
|
starts the server automatically, so no global install is required.
|
|
34
34
|
|
|
35
35
|
Create the first workspace management key under
|
|
36
|
-
[Dashboard → Settings → API keys](https://attrikit.io/en/dashboard/settings/api-keys).
|
|
36
|
+
[Dashboard → Settings → API keys & MCP](https://attrikit.io/en/dashboard/settings/api-keys).
|
|
37
37
|
This one-time bootstrap requires the dashboard.
|
|
38
38
|
|
|
39
39
|
After that first key exists, a workspace-scoped read/write key can manage every
|
package/dist/cli.js
CHANGED
|
@@ -14059,7 +14059,12 @@ async function callApi(config, path, options = {}) {
|
|
|
14059
14059
|
return {
|
|
14060
14060
|
ok: false,
|
|
14061
14061
|
status: 0,
|
|
14062
|
-
json: {
|
|
14062
|
+
json: {
|
|
14063
|
+
error: error instanceof Error && error.name === "AbortError" ? {
|
|
14064
|
+
code: "timeout",
|
|
14065
|
+
message: `no response within ${REQUEST_TIMEOUT_MS / 1000}s. The request may still have been applied on the server; retry with the same idempotency_key rather than a new one.`
|
|
14066
|
+
} : { code: "network_error", message: error instanceof Error ? error.message : String(error) }
|
|
14067
|
+
}
|
|
14063
14068
|
};
|
|
14064
14069
|
} finally {
|
|
14065
14070
|
clearTimeout(timer);
|
|
@@ -14071,10 +14076,13 @@ function toToolResult(result) {
|
|
|
14071
14076
|
const code = envelope?.error?.code ?? `http_${result.status}`;
|
|
14072
14077
|
const message = envelope?.error?.message ? `: ${envelope.error.message}` : "";
|
|
14073
14078
|
const retryAfter = result.status === 429 && result.retryAfter ? ` (Retry-After: ${result.retryAfter})` : "";
|
|
14079
|
+
const redact = (text) => text.replace(/\b(?:mk|pk|sk|rk)_[A-Za-z0-9_-]{8,}/g, "[redacted-key]").replace(/\b[Bb]earer\s+[A-Za-z0-9._-]{8,}/g, "Bearer [redacted]").replace(/\bAttriKit-(?:Management|Publishable)\s+\S+/g, "AttriKit-$1 [redacted]").replace(/([?&](?:token|secret|key|password|code|signature)=)[^&\s]+/gi, "$1[redacted]");
|
|
14080
|
+
const excerpt = !envelope?.error?.message && result.rawBody ? ` — body: ${redact(result.rawBody.replace(/\s+/g, " ").trim()).slice(0, 300)}` : "";
|
|
14081
|
+
const hint = result.status === 401 ? " Check ATTRKIT_API_KEY: this is the same error for a missing, wrong, revoked or expired key." : "";
|
|
14074
14082
|
return {
|
|
14075
14083
|
content: [{
|
|
14076
14084
|
type: "text",
|
|
14077
|
-
text: `AttrKit API error (${result.status || "network"}): ${code}${message}${retryAfter}`
|
|
14085
|
+
text: `AttrKit API error (${result.status || "network"}): ${code}${message}${retryAfter}${excerpt}${hint}`
|
|
14078
14086
|
}],
|
|
14079
14087
|
isError: true
|
|
14080
14088
|
};
|
|
@@ -14083,7 +14091,8 @@ function toToolResult(result) {
|
|
|
14083
14091
|
const isEmptySuccess = result.status === 204 && (result.rawBody === undefined || result.rawBody === "");
|
|
14084
14092
|
const isJsonEnvelope = result.json !== null && typeof result.json === "object" && !Array.isArray(result.json) && Object.hasOwn(result.json, "data");
|
|
14085
14093
|
const contentType = (result.contentType ?? "").toLowerCase();
|
|
14086
|
-
const
|
|
14094
|
+
const looksLikeMarkup = typeof result.json === "string" && /^\s*<(?:!doctype|html|head|body)\b/i.test(result.json);
|
|
14095
|
+
const isExpectedText = expectedResponse === "text" && typeof result.json === "string" && !contentType.includes("text/html") && !looksLikeMarkup;
|
|
14087
14096
|
if (!isEmptySuccess && !isJsonEnvelope && !isExpectedText) {
|
|
14088
14097
|
const reportedContentType = result.contentType ?? "unknown content type";
|
|
14089
14098
|
const received = result.json === null ? "an empty body" : Array.isArray(result.json) ? "a JSON array" : typeof result.json === "object" ? "a JSON object without a data field" : `a ${typeof result.json} body`;
|
|
@@ -14103,16 +14112,16 @@ ${body}`
|
|
|
14103
14112
|
structuredContent: structured
|
|
14104
14113
|
};
|
|
14105
14114
|
}
|
|
14106
|
-
var SERVER_VERSION = "0.4.
|
|
14115
|
+
var SERVER_VERSION = "0.4.4";
|
|
14107
14116
|
var periodSchema = z4.enum(["7d", "30d", "90d", "all"]).describe("Reporting window. Defaults to 30d.").optional();
|
|
14108
14117
|
var appIdSchema = z4.string().describe("Optional app id to scope the result to one app.").optional();
|
|
14109
14118
|
var requiredAppIdSchema = z4.string().describe("The AttrKit app id.");
|
|
14110
14119
|
var idempotencyKeySchema = z4.string().max(255).describe("Stable retry key for this exact mutation.").optional();
|
|
14111
14120
|
var ownersSchema = z4.record(z4.string(), z4.enum(["attrkit", "revenuecat", "customer"]));
|
|
14112
14121
|
var spendRowSchema = z4.object({
|
|
14113
|
-
campaign_id: z4.string().optional().describe("
|
|
14122
|
+
campaign_id: z4.string().optional().describe("The AttrKit campaign UUID, NOT the ad network's own campaign id. It is the opposite of create_campaign_link.campaign_id and is the most common mistake here: read it from list_campaigns. The API rejects a network id by name. Preferred snake_case spelling."),
|
|
14114
14123
|
campaignId: z4.string().optional().describe("Accepted camelCase alias for campaign_id."),
|
|
14115
|
-
adset_id: z4.string().optional().nullable(),
|
|
14124
|
+
adset_id: z4.string().optional().nullable().describe("Ad set id. Must be sent together with ad_id; either one alone is rejected."),
|
|
14116
14125
|
adsetId: z4.string().optional().nullable(),
|
|
14117
14126
|
ad_id: z4.string().optional().nullable(),
|
|
14118
14127
|
adId: z4.string().optional().nullable(),
|
|
@@ -14397,24 +14406,24 @@ function createServer(config, fetchImpl) {
|
|
|
14397
14406
|
description: "Freeze a scale/cut/hold decision and its exact model inputs for later maturity evaluation.",
|
|
14398
14407
|
inputSchema: {
|
|
14399
14408
|
app_id: requiredAppIdSchema,
|
|
14400
|
-
campaign_id: z4.string(),
|
|
14401
|
-
call: z4.enum(["scale", "cut", "hold"]),
|
|
14402
|
-
actor: z4.enum(["dashboard", "auto_suggested"]).optional(),
|
|
14403
|
-
p05: z4.number(),
|
|
14404
|
-
p50: z4.number(),
|
|
14405
|
-
p95: z4.number(),
|
|
14406
|
-
spend_minor_units: z4.number().nonnegative(),
|
|
14407
|
-
currency: z4.string().length(3),
|
|
14408
|
-
band_width_pct: z4.number().nonnegative(),
|
|
14409
|
-
threshold: z4.number(),
|
|
14410
|
-
model_version: z4.string(),
|
|
14411
|
-
cost_model_version: z4.number().int().positive().nullable(),
|
|
14412
|
-
revenue_per_install_minor_units: z4.number().nonnegative().nullable(),
|
|
14409
|
+
campaign_id: z4.string().describe("The AttrKit campaign uuid, as returned by list_campaigns or get_campaign_decision. Not the ad network's own campaign id."),
|
|
14410
|
+
call: z4.enum(["scale", "cut", "hold"]).describe("The decision being frozen. Report get_campaign_decision's own call verbatim rather than forming your own."),
|
|
14411
|
+
actor: z4.enum(["dashboard", "auto_suggested"]).optional().describe("Who made the call. Use auto_suggested when an agent proposed it without a human confirming."),
|
|
14412
|
+
p05: z4.number().describe("Low end of the profit range from get_campaign_decision, in minor units. Pass through unchanged."),
|
|
14413
|
+
p50: z4.number().describe("Central profit estimate from get_campaign_decision, in minor units. Pass through unchanged."),
|
|
14414
|
+
p95: z4.number().describe("High end of the profit range from get_campaign_decision, in minor units. Pass through unchanged."),
|
|
14415
|
+
spend_minor_units: z4.number().nonnegative().describe("Spend the decision was taken against, in minor units of `currency`."),
|
|
14416
|
+
currency: z4.string().length(3).describe("ISO 4217 code for spend and revenue on this decision, e.g. USD. Three letters."),
|
|
14417
|
+
band_width_pct: z4.number().nonnegative().describe("Width of the profit band as a percentage, from get_campaign_decision. It is how the maturity check later judges whether the range was tight enough to act on."),
|
|
14418
|
+
threshold: z4.number().describe("The profit threshold the call was made against, in minor units."),
|
|
14419
|
+
model_version: z4.string().describe("Model version string from get_campaign_decision. Recorded so a later evaluation knows which model produced the range."),
|
|
14420
|
+
cost_model_version: z4.number().int().positive().nullable().describe("Cost model version from get_campaign_decision, or null when no cost model applied."),
|
|
14421
|
+
revenue_per_install_minor_units: z4.number().nonnegative().nullable().describe("Revenue per install used in the estimate, in minor units, or null when revenue was unavailable."),
|
|
14413
14422
|
revenue_per_install_quality: z4.enum([
|
|
14414
14423
|
"campaign_verified_cohort",
|
|
14415
14424
|
"app_verified_cohort_fallback",
|
|
14416
14425
|
"unavailable"
|
|
14417
|
-
]),
|
|
14426
|
+
]).describe("How that revenue figure was derived: from this campaign's own verified cohort, from the app-wide fallback, or not at all. Pass through from get_campaign_decision."),
|
|
14418
14427
|
idempotency_key: idempotencyKeySchema
|
|
14419
14428
|
}
|
|
14420
14429
|
}, async ({
|
|
@@ -14629,7 +14638,7 @@ function createServer(config, fetchImpl) {
|
|
|
14629
14638
|
network: z4.enum(["meta", "google", "tiktok"]),
|
|
14630
14639
|
account_ref: z4.string().min(1),
|
|
14631
14640
|
credential: z4.string().min(1),
|
|
14632
|
-
owners: ownersSchema,
|
|
14641
|
+
owners: ownersSchema.describe("Which destination owns each event family. Enabling a destination requires ALL eight families to be present, or the API rejects the call."),
|
|
14633
14642
|
enable: z4.boolean().optional(),
|
|
14634
14643
|
idempotency_key: idempotencyKeySchema
|
|
14635
14644
|
}
|
|
@@ -14676,7 +14685,7 @@ function createServer(config, fetchImpl) {
|
|
|
14676
14685
|
description: "Store the RevenueCat provider app id and encrypted authorization secret for an app.",
|
|
14677
14686
|
inputSchema: {
|
|
14678
14687
|
app_id: requiredAppIdSchema,
|
|
14679
|
-
provider_app_id: revenueCatProviderAppIdSchema,
|
|
14688
|
+
provider_app_id: revenueCatProviderAppIdSchema.describe("RevenueCat's PROJECT app id from their dashboard app settings, not the SDK key."),
|
|
14680
14689
|
authorization_secret: z4.string().min(16).max(1024),
|
|
14681
14690
|
idempotency_key: idempotencyKeySchema
|
|
14682
14691
|
}
|