@ema.co/mcp-toolkit 1.5.1 → 1.6.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.

Potentially problematic release.


This version of @ema.co/mcp-toolkit might be problematic. Click here for more details.

@@ -100,80 +100,22 @@ export class EmaClient {
100
100
  const controller = new AbortController();
101
101
  const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
102
102
  const fullUrl = `${this.env.baseUrl.replace(/\/$/, "")}${path}`;
103
- // #region agent log
104
- // H3/H4: verify wire-level request shape + size (no secrets).
105
- try {
106
- if (process.env.EMA_MCP_DEBUG_LOGS !== "1") {
107
- // disabled
108
- }
109
- else {
110
- const isUpdatePersona = path.includes("/api/personas/update_persona");
111
- const jsonAny = opts?.json;
112
- const workflowAny = jsonAny?.workflow ?? jsonAny?.workflow_def;
113
- const actions = workflowAny?.actions ?? [];
114
- const actionNames = Array.isArray(actions)
115
- ? actions
116
- .slice(0, 50)
117
- .map((a) => a?.name)
118
- .filter((n) => typeof n === "string")
119
- : [];
120
- const containsHitl = actionNames.some((n) => n.toLowerCase().includes("hitl")) || JSON.stringify(actionNames).toLowerCase().includes("hitl");
121
- const jsonSize = opts?.json !== undefined ? JSON.stringify(opts.json).length : 0;
122
- fetch('http://127.0.0.1:7245/ingest/c9b6768a-494d-4365-bd46-bf6c43dc1e22', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'src/sdk/client.ts:requestWithRetries:pre', message: 'HTTP request', data: { env: this.env.name, codeDir: process.env.EMA_MCP_CODE_DIR ?? null, cwd: process.cwd(), method, path, isUpdatePersona, attempt, retries, hasJson: opts?.json !== undefined, jsonSize, hasWorkflow: !!workflowAny, actionCount: Array.isArray(actions) ? actions.length : 0, containsHitl }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'pre-fix', hypothesisId: 'H3' }) }).catch(() => { });
123
- }
103
+ // gRPC-Connect endpoints need Connect-Protocol-Version header
104
+ const isGrpcConnect = path.includes(".v1.") || path.includes(".v2.");
105
+ const headers = {
106
+ Authorization: `Bearer ${this.env.bearerToken}`,
107
+ "Content-Type": "application/json",
108
+ };
109
+ if (isGrpcConnect) {
110
+ headers["Connect-Protocol-Version"] = "1";
124
111
  }
125
- catch { }
126
- // #endregion agent log
127
112
  const response = await fetch(fullUrl, {
128
113
  method,
129
- headers: {
130
- Authorization: `Bearer ${this.env.bearerToken}`,
131
- "Content-Type": "application/json",
132
- },
114
+ headers,
133
115
  body: opts?.json !== undefined ? JSON.stringify(opts.json) : undefined,
134
116
  signal: controller.signal,
135
117
  });
136
118
  clearTimeout(timeoutId);
137
- // #region agent log
138
- // H1/H2/H4: capture response status + request id for correlation (no secrets).
139
- try {
140
- if (process.env.EMA_MCP_DEBUG_LOGS !== "1") {
141
- // disabled
142
- }
143
- else {
144
- const reqId = response.headers.get("x-request-id") ?? response.headers.get("x-correlation-id") ?? response.headers.get("x-amzn-trace-id");
145
- fetch('http://127.0.0.1:7245/ingest/c9b6768a-494d-4365-bd46-bf6c43dc1e22', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'src/sdk/client.ts:requestWithRetries:post', message: 'HTTP response', data: { env: this.env.name, method, path, status: response.status, ok: response.ok, attempt, durationMs: Date.now() - startedAt, reqId }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'pre-fix', hypothesisId: 'H1' }) }).catch(() => { });
146
- }
147
- }
148
- catch { }
149
- // #endregion agent log
150
- // #region agent log
151
- // H1/H2: for update_persona failures, log first part of error body (redacted/truncated).
152
- try {
153
- if (process.env.EMA_MCP_DEBUG_LOGS !== "1") {
154
- // disabled
155
- }
156
- else {
157
- const isUpdatePersona = path.includes("/api/personas/update_persona");
158
- if (isUpdatePersona && !response.ok) {
159
- const cloned = response.clone();
160
- const txt = await cloned.text();
161
- const snippet = txt.length > 1200 ? `${txt.slice(0, 1200)}…(truncated)` : txt;
162
- let parsedDetail;
163
- let hasGweIssues = false;
164
- try {
165
- const j = JSON.parse(txt);
166
- const detail = j.detail ?? j.message ?? j.error;
167
- parsedDetail = typeof detail === "string" ? detail : undefined;
168
- hasGweIssues = Array.isArray(j.gwe_issues);
169
- }
170
- catch { }
171
- fetch('http://127.0.0.1:7245/ingest/c9b6768a-494d-4365-bd46-bf6c43dc1e22', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'src/sdk/client.ts:requestWithRetries:errorBody', message: 'HTTP error body (update_persona)', data: { env: this.env.name, method, path, status: response.status, parsedDetail, hasGweIssues, bodySnippet: snippet }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'pre-fix', hypothesisId: 'H2' }) }).catch(() => { });
172
- }
173
- }
174
- }
175
- catch { }
176
- // #endregion agent log
177
119
  // Handle 401 - attempt token refresh once
178
120
  if (response.status === 401 && !hasAttemptedRefresh && this.tokenRefreshConfig?.refreshCallback) {
179
121
  hasAttemptedRefresh = true;
@@ -324,15 +266,6 @@ export class EmaClient {
324
266
  });
325
267
  if (!resp.ok) {
326
268
  const body = await resp.text();
327
- // #region agent log
328
- try {
329
- if (this.debugLogsEnabled) {
330
- const snippet = body.length > 2000 ? `${body.slice(0, 2000)}…(truncated)` : body;
331
- fetch('http://127.0.0.1:7245/ingest/c9b6768a-494d-4365-bd46-bf6c43dc1e22', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'src/sdk/client.ts:checkWorkflow:error', message: 'CheckWorkflow failed', data: { env: this.env.name, status: resp.status, bodySnippet: snippet }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'pre-fix', hypothesisId: 'H5' }) }).catch(() => { });
332
- }
333
- }
334
- catch { }
335
- // #endregion agent log
336
269
  throw new EmaApiError({
337
270
  statusCode: resp.status,
338
271
  body,
@@ -340,35 +273,70 @@ export class EmaClient {
340
273
  });
341
274
  }
342
275
  const data = (await resp.json());
343
- // #region agent log
344
- try {
345
- if (this.debugLogsEnabled) {
346
- const keys = Object.keys(data);
347
- fetch('http://127.0.0.1:7245/ingest/c9b6768a-494d-4365-bd46-bf6c43dc1e22', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ location: 'src/sdk/client.ts:checkWorkflow:ok', message: 'CheckWorkflow ok', data: { env: this.env.name, keys }, timestamp: Date.now(), sessionId: 'debug-session', runId: 'pre-fix', hypothesisId: 'H5' }) }).catch(() => { });
348
- }
349
- }
350
- catch { }
351
- // #endregion agent log
352
276
  return data;
353
277
  }
354
278
  async updateAiEmployee(req, opts) {
355
279
  // Use /api/personas/update_persona - same endpoint as Ema frontend
280
+ // Debug logging for troubleshooting
281
+ if (opts?.verbose || process.env.EMA_DEBUG) {
282
+ console.error("[EmaClient] updateAiEmployee request:", JSON.stringify({
283
+ persona_id: req.persona_id,
284
+ has_workflow: !!req.workflow,
285
+ workflow_actions: req.workflow ? req.workflow.actions : undefined,
286
+ has_proto_config: !!req.proto_config,
287
+ }, null, 2));
288
+ }
356
289
  const resp = await this.requestWithRetries("POST", "/api/personas/update_persona", {
357
290
  json: req,
358
291
  });
359
292
  if (!resp.ok) {
360
293
  const body = await resp.text();
294
+ // Debug logging for errors
295
+ if (opts?.verbose || process.env.EMA_DEBUG) {
296
+ console.error("[EmaClient] updateAiEmployee FAILED:", resp.status, body);
297
+ console.error("[EmaClient] Request that failed:", JSON.stringify(req, null, 2).slice(0, 5000));
298
+ }
361
299
  // Try to parse error body for better error messages
362
300
  let errorDetail = "";
363
301
  try {
364
302
  const errorJson = JSON.parse(body);
365
303
  // Ema API returns InvalidPersonaResponse with 'detail' field
366
304
  errorDetail = errorJson.detail ?? errorJson.message ?? errorJson.error ?? "";
367
- // Also check for GWE (workflow) issues
368
- if (errorJson.gwe_issues) {
369
- const issues = errorJson.gwe_issues;
370
- if (Array.isArray(issues)) {
371
- errorDetail += ` Workflow issues: ${issues.map((i) => i.message ?? i.detail ?? JSON.stringify(i)).join("; ")}`;
305
+ // Parse GWE (workflow) issues - it's an object, not an array
306
+ // See WorkflowIssues schema in OpenAPI spec
307
+ if (errorJson.gwe_issues && typeof errorJson.gwe_issues === "object") {
308
+ const gwe = errorJson.gwe_issues;
309
+ const issuesParts = [];
310
+ if (gwe.detail) {
311
+ issuesParts.push(`Detail: ${gwe.detail}`);
312
+ }
313
+ if (Array.isArray(gwe.missing_widgets) && gwe.missing_widgets.length > 0) {
314
+ issuesParts.push(`Missing widgets: ${gwe.missing_widgets.join(", ")}`);
315
+ }
316
+ if (Array.isArray(gwe.unready_widgets) && gwe.unready_widgets.length > 0) {
317
+ const unready = gwe.unready_widgets.map((w) => `${w.widget_name}: ${w.message}`);
318
+ issuesParts.push(`Unready widgets: ${unready.join("; ")}`);
319
+ }
320
+ if (Array.isArray(gwe.missing_inputs) && gwe.missing_inputs.length > 0) {
321
+ const missing = gwe.missing_inputs.map((i) => `${i.action_name}.${i.input_name}`);
322
+ issuesParts.push(`Missing inputs: ${missing.join(", ")}`);
323
+ }
324
+ if (Array.isArray(gwe.mismatched_inputs) && gwe.mismatched_inputs.length > 0) {
325
+ const mismatched = gwe.mismatched_inputs.map((i) => `${i.action_name}.${i.input_name}`);
326
+ issuesParts.push(`Mismatched inputs: ${mismatched.join(", ")}`);
327
+ }
328
+ if (Array.isArray(gwe.named_result_errors) && gwe.named_result_errors.length > 0) {
329
+ const resultErrs = gwe.named_result_errors.map((e) => `${e.named_result_key}: ${e.error_description}`);
330
+ issuesParts.push(`Result errors: ${resultErrs.join("; ")}`);
331
+ }
332
+ if (gwe.has_cycles) {
333
+ issuesParts.push("Workflow has cycles");
334
+ }
335
+ if (gwe.has_no_outputs) {
336
+ issuesParts.push("Workflow has no outputs");
337
+ }
338
+ if (issuesParts.length > 0) {
339
+ errorDetail += ` [GWE Issues: ${issuesParts.join(" | ")}]`;
372
340
  }
373
341
  }
374
342
  }