Skip to main content

@adcp/client Bug Report: Auth Headers Not Forwarded for sync_creatives

Summary

Auth headers configured via auth_token_env are successfully forwarded for get_products but NOT forwarded for sync_creatives when using the MCP protocol with StreamableHTTP transport.

Environment

  • Package: @adcp/client (version from package.json)
  • Protocol: MCP (Model Context Protocol)
  • Transport: StreamableHTTP
  • Auth Method: auth_token_env (environment variable approach)
  • Sales Agent: Wonderstruck MCP server (https://wonderstruck.sales-agent.scope3.com/mcp)

Expected Behavior

When configuring an AgentConfig with auth_token_env pointing to an environment variable containing an auth token:
const agentConfig: AgentConfig = {
  agent_uri: "https://wonderstruck.sales-agent.scope3.com/mcp",
  auth_token_env: "ADCP_AUTH_PRINCIPAL_8AC9E391",
  id: "principal_8ac9e391",
  name: "Wonderstruck",
  protocol: "mcp",
  requiresAuth: true,
};

process.env.ADCP_AUTH_PRINCIPAL_8AC9E391 =
  "UhwoigyVKdd6GT8hS04cc51ckGfi8qXpZL6OvS2i2cU";
The x-adcp-auth header should be forwarded to the MCP server for ALL tool calls, including both read operations (get_products) and write operations (sync_creatives).

Actual Behavior

✅ Works: get_products

When calling get_products, the auth header IS successfully forwarded:
const client = new ADCPClient({ agentConfigs: [agentConfig], debug: true });
const result = await client.allAgents().getProducts({
  brief: "premium display advertising",
  promoted_offering: "premium display advertising",
});
Debug logs show:
"MCP: Auth token provided (UhwoigyVKd...) for tool get_products"
"MCP: Setting auth headers: {\"x-adcp-auth\":\"UhwoigyVKdd6GT8hS04cc51ckGfi8qXpZL6OvS2i2cU\"}"
"MCP: Transport configured with x-adcp-auth header for get_products"
Result: ✅ Success - Returns 5 products from Wonderstruck

❌ Fails: sync_creatives

When calling sync_creatives with the SAME auth configuration, the header is NOT forwarded:
const client = new ADCPClient({ agentConfigs: [agentConfig], debug: true });
const result = await client.syncCreatives({
  creatives: [
    {
      id: "creative_k0i02ddq5b",
      name: "Test Creative",
      format: "DISPLAY_300x250",
      type: "image",
      status: "active",
      snippet: '<a href="https://wonderstruck.org"><img src="..." /></a>',
      snippet_type: "html",
      dimensions: { width: 300, height: 250 },
    },
  ],
});
Debug logs show:
"MCP: Auth token provided (UhwoigyVKd...) for tool sync_creatives"
"MCP: Setting auth headers: {\"x-adcp-auth\":\"UhwoigyVKdd6GT8hS04cc51ckGfi8qXpZL6OvS2i2cU\"}"
"MCP: Transport configured with x-adcp-auth header for sync_creatives"
MCP Server Response:
"Missing or invalid x-adcp-auth header for authentication."
Result: ❌ Failed - Auth header not received by server despite being “configured”

Bug Analysis

Key Observations

  1. Same auth configuration used for both tools
  2. Debug logs identical - both show “Transport configured with x-adcp-auth header”
  3. Different outcomes - get_products succeeds, sync_creatives fails
  4. Server confirms missing header - Wonderstruck explicitly reports “Missing or invalid x-adcp-auth header”

Hypothesis

The StreamableHTTP transport may have different code paths for different tool types, or there’s a bug in how headers are forwarded for sync_creatives specifically. The debug logs show the header is being SET on the transport object but NOT actually included in the HTTP request.

Minimal Reproduction

import { ADCPClient, type AgentConfig } from "@adcp/client";

// Set up auth
const AUTH_TOKEN = "UhwoigyVKdd6GT8hS04cc51ckGfi8qXpZL6OvS2i2cU";
process.env.ADCP_AUTH_PRINCIPAL_8AC9E391 = AUTH_TOKEN;

const agentConfig: AgentConfig = {
  agent_uri: "https://wonderstruck.sales-agent.scope3.com/mcp",
  auth_token_env: "ADCP_AUTH_PRINCIPAL_8AC9E391",
  id: "principal_8ac9e391",
  name: "Wonderstruck",
  protocol: "mcp",
  requiresAuth: true,
};

const client = new ADCPClient({
  agentConfigs: [agentConfig],
  debug: true,
});

// TEST 1: get_products - ✅ WORKS
console.log("Testing get_products...");
const productsResult = await client.allAgents().getProducts({
  brief: "test",
  promoted_offering: "test",
});
console.log("get_products success:", productsResult.success);
// Expected: true, Actual: true ✅

// TEST 2: sync_creatives - ❌ FAILS
console.log("\nTesting sync_creatives...");
const syncResult = await client.syncCreatives({
  creatives: [
    {
      id: "test_creative",
      name: "Test",
      format: "DISPLAY_300x250",
      type: "image",
      status: "active",
      snippet: "<div>test</div>",
      snippet_type: "html",
      dimensions: { width: 300, height: 250 },
    },
  ],
});
console.log("sync_creatives success:", syncResult.success);
// Expected: true, Actual: false ❌
// Error: "Missing or invalid x-adcp-auth header"

Debug Logs Comparison

get_products (✅ Working)

{
  "type": "info",
  "message": "MCP: Auth token provided (UhwoigyVKd...) for tool get_products",
  "timestamp": "2025-10-01T02:49:11.951Z",
  "headers": {
    "Accept": "application/json, text/event-stream",
    "x-adcp-auth": "UhwoigyVKdd6GT8hS04cc51ckGfi8qXpZL6OvS2i2cU"
  }
}
Response: 200 OK with products

sync_creatives (❌ Failing)

{
  "type": "info",
  "message": "MCP: Auth token provided (UhwoigyVKd...) for tool sync_creatives",
  "timestamp": "2025-10-01T02:49:36.535Z",
  "headers": {
    "Accept": "application/json, text/event-stream",
    "x-adcp-auth": "UhwoigyVKdd6GT8hS04cc51ckGfi8qXpZL6OvS2i2cU"
  }
}
Response: Error: “Missing or invalid x-adcp-auth header for authentication”

Impact

This bug prevents using sync_creatives with any MCP server that requires authentication via custom headers. Since creative syncing is a core ADCP operation, this significantly limits the protocol’s usefulness for authenticated scenarios.

Workarounds Attempted

  1. Direct auth token in config - Not supported by AgentConfig type
  2. Manual header injection - StreamableHTTP transport doesn’t expose header API
  3. OAuth instead of API key - Not supported by Wonderstruck MCP server

Requested Fix

Ensure that custom auth headers (configured via auth_token_env) are consistently forwarded for ALL MCP tool calls, not just get_products. The StreamableHTTP transport should apply headers uniformly regardless of which tool is being invoked.

Additional Context

  • Other MCP operations that may be affected: get_brand_compliance_policy, custom tools
  • This appears to be a transport-layer issue rather than a tool-specific issue
  • The @modelcontextprotocol/sdk StreamableHTTP transport may be the root cause if @adcp/client relies on it for header forwarding

Test Environment Details

  • Node.js: v22.19.0
  • TypeScript: 5.6.3
  • OS: macOS (Darwin 24.6.0)
  • Package Manager: npm

Logs Available

Full debug logs with request/response cycles are available upon request. Both successful (get_products) and failing (sync_creatives) scenarios have been captured with debug: true enabled.