@loopops/mcp-server 2.0.0 → 2.0.1

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 (2) hide show
  1. package/dist/api-client.js +36 -22
  2. package/package.json +1 -1
@@ -153,34 +153,48 @@ function isRetryable(err) {
153
153
  return false;
154
154
  }
155
155
  /**
156
- * Persist a rotated refresh token back to ~/.mcp.json. Best-effort if
157
- * the write fails, we still keep the new token in-memory so the current
158
- * subprocess keeps working. Claude Desktop's next spawn will need the
159
- * disk value though.
156
+ * Persist a rotated refresh token across every config location we know
157
+ * users store MCP settings in:
158
+ * - ~/.mcp.json (Claude Desktop)
159
+ * - ~/.claude/settings.json (Claude Code)
160
+ *
161
+ * We update whichever files have the loop-operations stanza. Missing
162
+ * files are skipped silently. This mirrors @loopops/mcp-cli's
163
+ * `updateRefreshToken` helper — keep the two in sync.
164
+ *
165
+ * Best-effort: if all writes fail, we still keep the new token
166
+ * in-memory so the current subprocess keeps working. The next cold
167
+ * spawn is the one that breaks.
160
168
  */
161
169
  function persistRotatedRefreshToken(newToken) {
162
- try {
163
- const path = join(homedir(), ".mcp.json");
164
- if (!existsSync(path))
165
- return;
166
- const raw = readFileSync(path, "utf-8");
167
- const data = JSON.parse(raw);
168
- const stanza = data.mcpServers?.[SERVER_NAME];
169
- if (!stanza?.env)
170
- return;
171
- stanza.env.OKTA_REFRESH_TOKEN = newToken;
172
- writeFileSync(path, JSON.stringify(data, null, 2) + "\n");
170
+ const paths = [
171
+ join(homedir(), ".mcp.json"),
172
+ join(homedir(), ".claude", "settings.json"),
173
+ ];
174
+ for (const path of paths) {
173
175
  try {
174
- chmodSync(path, 0o600);
176
+ if (!existsSync(path))
177
+ continue;
178
+ const raw = readFileSync(path, "utf-8");
179
+ const data = JSON.parse(raw);
180
+ const stanza = data.mcpServers?.[SERVER_NAME];
181
+ if (!stanza?.env)
182
+ continue;
183
+ stanza.env.OKTA_REFRESH_TOKEN = newToken;
184
+ writeFileSync(path, JSON.stringify(data, null, 2) + "\n");
185
+ try {
186
+ chmodSync(path, 0o600);
187
+ }
188
+ catch {
189
+ // ok on platforms where this is a no-op
190
+ }
175
191
  }
176
- catch {
177
- // ok on platforms where this is a no-op
192
+ catch (err) {
193
+ // Log to stderr (visible in Claude Desktop/Code logs) but don't
194
+ // fail the request.
195
+ console.error(`[MCP] Could not persist rotated refresh token to ${path}:`, err instanceof Error ? err.message : String(err));
178
196
  }
179
197
  }
180
- catch (err) {
181
- // Log to stderr (visible in Claude Desktop logs) but don't fail the request.
182
- console.error("[MCP] Could not persist rotated refresh token to ~/.mcp.json:", err instanceof Error ? err.message : String(err));
183
- }
184
198
  }
185
199
  /**
186
200
  * Mint a fresh access token via Okta's /token endpoint. Updates the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loopops/mcp-server",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Loop Operations MCP Server — AI skills for RevOps",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",