mcp-bing-ads 1.0.7 → 1.0.9

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.
@@ -1 +1 @@
1
- {"sha":"26e5811","builtAt":"2026-04-09T21:28:13.723Z"}
1
+ {"sha":"9c3433f","builtAt":"2026-04-09T21:47:25.221Z"}
package/dist/errors.js CHANGED
@@ -12,7 +12,7 @@ export class BingAdsAuthError extends Error {
12
12
  export class BingAdsRateLimitError extends Error {
13
13
  retryAfterMs;
14
14
  constructor(retryAfterMs, cause) {
15
- super(`Rate limited, retry after ${retryAfterMs}ms`);
15
+ super(`Bing Ads rate limited, retry after ${retryAfterMs}ms`);
16
16
  this.retryAfterMs = retryAfterMs;
17
17
  this.name = "BingAdsRateLimitError";
18
18
  this.cause = cause;
@@ -47,7 +47,7 @@ export function classifyError(error) {
47
47
  message.includes("OAuth token refresh failed") ||
48
48
  message.includes("AuthenticationTokenExpired") ||
49
49
  message.includes("InvalidCredentials")) {
50
- return new BingAdsAuthError(`Auth failed: ${message}. Refresh token may be expired. Re-authenticate and update Keychain.`, error);
50
+ return new BingAdsAuthError(`Bing Ads auth failed: ${message}. Refresh token may be expired. Re-authenticate and update Keychain.`, error);
51
51
  }
52
52
  if (status === 429 || message.includes("RateLimit") || message.includes("CallRateExceeded")) {
53
53
  const retryMs = 60_000;
package/dist/index.js CHANGED
@@ -33,6 +33,10 @@ if (process.argv.includes("--version") || process.argv.includes("-v")) {
33
33
  console.error(__cliPkg.version);
34
34
  process.exit(0);
35
35
  }
36
+ // ============================================
37
+ // ENV VAR TRIMMING
38
+ // ============================================
39
+ const envTrimmed = (key) => (process.env[key] || "").trim().replace(/^["']|["']$/g, "");
36
40
  function loadConfig() {
37
41
  const configPath = join(dirname(new URL(import.meta.url).pathname), "..", "config.json");
38
42
  if (!existsSync(configPath)) {
@@ -69,14 +73,14 @@ class BingAdsManager {
69
73
  throw new BingAdsAuthError(msg);
70
74
  }
71
75
  console.error("[startup] Credentials validated: all required env vars present");
72
- this.developerToken = process.env.BING_ADS_DEVELOPER_TOKEN;
73
- this.refreshToken = process.env.BING_ADS_REFRESH_TOKEN;
76
+ this.developerToken = envTrimmed("BING_ADS_DEVELOPER_TOKEN");
77
+ this.refreshToken = envTrimmed("BING_ADS_REFRESH_TOKEN");
74
78
  // Allow env vars to override config for OAuth
75
79
  if (process.env.BING_ADS_CLIENT_ID) {
76
- this.config.oauth.client_id = process.env.BING_ADS_CLIENT_ID;
80
+ this.config.oauth.client_id = envTrimmed("BING_ADS_CLIENT_ID");
77
81
  }
78
82
  if (process.env.BING_ADS_CLIENT_SECRET) {
79
- this.config.oauth.client_secret = process.env.BING_ADS_CLIENT_SECRET;
83
+ this.config.oauth.client_secret = envTrimmed("BING_ADS_CLIENT_SECRET");
80
84
  }
81
85
  }
82
86
  async getAccessToken() {
@@ -738,6 +742,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
738
742
  error: true,
739
743
  error_type: error.name,
740
744
  message: error.message,
745
+ server: __cliPkg.name,
741
746
  };
742
747
  if (error instanceof BingAdsAuthError) {
743
748
  response.action_required = "Re-authenticate: refresh token may be expired. Update Keychain entry BING_ADS_REFRESH_TOKEN.";
@@ -753,11 +758,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
753
758
  response.details = rawError.stack;
754
759
  }
755
760
  return {
761
+ isError: true,
756
762
  content: [{
757
763
  type: "text",
758
764
  text: JSON.stringify(response, null, 2),
759
765
  }],
760
- isError: true,
761
766
  };
762
767
  }
763
768
  });
@@ -788,4 +793,7 @@ process.on("SIGINT", () => {
788
793
  process.on("SIGPIPE", () => {
789
794
  // Client disconnected -- expected during shutdown
790
795
  });
796
+ process.on("unhandledRejection", (reason) => {
797
+ console.error("[error] Unhandled promise rejection:", reason);
798
+ });
791
799
  main().catch(console.error);
@@ -5,7 +5,7 @@ import pino from "pino";
5
5
  // ============================================
6
6
  export const logger = pino({
7
7
  level: process.env.LOG_LEVEL || "info",
8
- ...(process.env.NODE_ENV !== "test" && {
8
+ ...(process.env.NODE_ENV !== "test" && process.stderr.isTTY && {
9
9
  transport: {
10
10
  target: "pino-pretty",
11
11
  options: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mcp-bing-ads",
3
3
  "mcpName": "io.github.mharnett/bing-ads",
4
- "version": "1.0.7",
4
+ "version": "1.0.9",
5
5
  "description": "MCP server for Microsoft Advertising (Bing Ads) API with campaign, ad group, keyword, and performance reporting. First comprehensive open-source Bing Ads MCP.",
6
6
  "main": "dist/index.js",
7
7
  "bin": {
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "homepage": "https://github.com/mharnett/mcp-bing-ads#readme",
50
50
  "engines": {
51
- "node": ">=18.0.0"
51
+ "node": ">=18.18.0"
52
52
  },
53
53
  "dependencies": {
54
54
  "@modelcontextprotocol/sdk": "^0.5.0",