@attrkit/mcp 0.4.3 → 0.4.5

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +20 -7
  3. 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
@@ -14076,7 +14076,8 @@ function toToolResult(result) {
14076
14076
  const code = envelope?.error?.code ?? `http_${result.status}`;
14077
14077
  const message = envelope?.error?.message ? `: ${envelope.error.message}` : "";
14078
14078
  const retryAfter = result.status === 429 && result.retryAfter ? ` (Retry-After: ${result.retryAfter})` : "";
14079
- const excerpt = !envelope?.error?.message && result.rawBody ? ` — body: ${result.rawBody.replace(/\s+/g, " ").trim().slice(0, 300)}` : "";
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)}` : "";
14080
14081
  const hint = result.status === 401 ? " Check ATTRKIT_API_KEY: this is the same error for a missing, wrong, revoked or expired key." : "";
14081
14082
  return {
14082
14083
  content: [{
@@ -14090,7 +14091,8 @@ function toToolResult(result) {
14090
14091
  const isEmptySuccess = result.status === 204 && (result.rawBody === undefined || result.rawBody === "");
14091
14092
  const isJsonEnvelope = result.json !== null && typeof result.json === "object" && !Array.isArray(result.json) && Object.hasOwn(result.json, "data");
14092
14093
  const contentType = (result.contentType ?? "").toLowerCase();
14093
- const isExpectedText = expectedResponse === "text" && typeof result.json === "string" && (contentType.includes("text/csv") || contentType.includes("application/csv"));
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;
14094
14096
  if (!isEmptySuccess && !isJsonEnvelope && !isExpectedText) {
14095
14097
  const reportedContentType = result.contentType ?? "unknown content type";
14096
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`;
@@ -14110,12 +14112,14 @@ ${body}`
14110
14112
  structuredContent: structured
14111
14113
  };
14112
14114
  }
14113
- var SERVER_VERSION = "0.4.3";
14115
+ var SERVER_VERSION = "0.4.5";
14114
14116
  var periodSchema = z4.enum(["7d", "30d", "90d", "all"]).describe("Reporting window. Defaults to 30d.").optional();
14115
14117
  var appIdSchema = z4.string().describe("Optional app id to scope the result to one app.").optional();
14116
14118
  var requiredAppIdSchema = z4.string().describe("The AttrKit app id.");
14117
14119
  var idempotencyKeySchema = z4.string().max(255).describe("Stable retry key for this exact mutation.").optional();
14118
14120
  var ownersSchema = z4.record(z4.string(), z4.enum(["attrkit", "revenuecat", "customer"]));
14121
+ var cursorSchema = z4.string().optional().describe("Pass the next_cursor from the previous response to fetch the following page. Omit for the first page.");
14122
+ var listLimitSchema = z4.number().int().min(1).max(200).optional().describe("Rows per page, 1-200. The API defaults to 50, so a workspace with more than that needs paging.");
14119
14123
  var spendRowSchema = z4.object({
14120
14124
  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."),
14121
14125
  campaignId: z4.string().optional().describe("Accepted camelCase alias for campaign_id."),
@@ -14212,8 +14216,10 @@ function createServer(config, fetchImpl) {
14212
14216
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
14213
14217
  title: "List apps",
14214
14218
  description: "List the iOS and Android apps in your AttrKit workspace (id, name, platform, bundle id, store id, status).",
14215
- inputSchema: {}
14216
- }, async () => toToolResult(await call("/api/v1/apps")));
14219
+ inputSchema: { cursor: cursorSchema, limit: listLimitSchema }
14220
+ }, async ({ cursor, limit }) => toToolResult(await call("/api/v1/apps", {
14221
+ query: { ...cursor ? { cursor } : {}, ...limit === undefined ? {} : { limit: String(limit) } }
14222
+ })));
14217
14223
  server.registerTool("create_app", {
14218
14224
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
14219
14225
  title: "Create an app",
@@ -14360,8 +14366,15 @@ function createServer(config, fetchImpl) {
14360
14366
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
14361
14367
  title: "List campaigns",
14362
14368
  description: "List ad campaigns with their honest profit surface: the scale/cut/hold call, profit p05/p50/p95, spend, retention, and payback. Use this to see how campaigns are performing.",
14363
- inputSchema: { app_id: appIdSchema, period: periodSchema }
14364
- }, async ({ app_id, period }) => toToolResult(await call("/api/v1/reports/campaigns", { query: { appId: app_id, period } })));
14369
+ inputSchema: { app_id: appIdSchema, period: periodSchema, cursor: cursorSchema, limit: listLimitSchema }
14370
+ }, async ({ app_id, period, cursor, limit }) => toToolResult(await call("/api/v1/reports/campaigns", {
14371
+ query: {
14372
+ appId: app_id,
14373
+ period,
14374
+ ...cursor ? { cursor } : {},
14375
+ ...limit === undefined ? {} : { limit: String(limit) }
14376
+ }
14377
+ })));
14365
14378
  server.registerTool("list_ads", {
14366
14379
  annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
14367
14380
  title: "List creative-level ad performance",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@attrkit/mcp",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "AttrKit's stdio MCP server for its public Management API",
5
5
  "keywords": [
6
6
  "attrkit",