@topolo/mcp 0.11.0 → 0.11.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.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // src/index.ts
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
 
6
- // ../../../public-platform-tooling-boundary-20260813/packages/topolo-sdk/dist/index.js
6
+ // node_modules/@topolo/sdk/dist/index.js
7
7
  function applyAuthHeaders(headers, credential) {
8
8
  if (credential.kind === "api_key") {
9
9
  headers.set("X-Api-Key", credential.apiKey);
@@ -2169,8 +2169,8 @@ function createTopolo(options) {
2169
2169
  };
2170
2170
  }
2171
2171
 
2172
- // ../../../public-platform-tooling-boundary-20260813/packages/topolo-sdk/dist/node/credential-store.js
2173
- import { mkdir, readFile, writeFile, chmod } from "fs/promises";
2172
+ // node_modules/@topolo/sdk/dist/node/credential-store.js
2173
+ import { mkdir, readFile, writeFile, chmod, rm, stat } from "fs/promises";
2174
2174
  import { existsSync } from "fs";
2175
2175
  import { homedir, platform } from "os";
2176
2176
  import { dirname, join } from "path";
@@ -2633,6 +2633,41 @@ async function resolveCredential(environment = selectedEnvironment()) {
2633
2633
  return profileForEnvironment(config, environment).credential ?? null;
2634
2634
  }
2635
2635
  var REFRESH_SKEW_SECONDS = 60;
2636
+ var CONFIG_LOCK_RETRY_MS = 25;
2637
+ var CONFIG_LOCK_TIMEOUT_MS = 5e3;
2638
+ var CONFIG_LOCK_STALE_MS = 12e4;
2639
+ async function withConfigWriteLock(operation) {
2640
+ const lockPath = `${configPath()}.lock`;
2641
+ await mkdir(dirname(lockPath), { recursive: true });
2642
+ const startedAt = Date.now();
2643
+ while (true) {
2644
+ try {
2645
+ await mkdir(lockPath);
2646
+ break;
2647
+ } catch (error) {
2648
+ if (error.code !== "EEXIST") throw error;
2649
+ try {
2650
+ const lock = await stat(lockPath);
2651
+ if (Date.now() - lock.mtimeMs > CONFIG_LOCK_STALE_MS) {
2652
+ await rm(lockPath, { recursive: true, force: true });
2653
+ continue;
2654
+ }
2655
+ } catch (inspectionError) {
2656
+ if (inspectionError.code !== "ENOENT") throw inspectionError;
2657
+ continue;
2658
+ }
2659
+ if (Date.now() - startedAt >= CONFIG_LOCK_TIMEOUT_MS) {
2660
+ throw new Error(`Timed out waiting for credential configuration lock at ${lockPath}.`);
2661
+ }
2662
+ await new Promise((resolve2) => setTimeout(resolve2, CONFIG_LOCK_RETRY_MS));
2663
+ }
2664
+ }
2665
+ try {
2666
+ return await operation();
2667
+ } finally {
2668
+ await rm(lockPath, { recursive: true, force: true });
2669
+ }
2670
+ }
2636
2671
  async function refreshCredentialIfNeeded(environment = selectedEnvironment(), options = {}) {
2637
2672
  const prefix = envVarPrefix(environment);
2638
2673
  if (process.env[`${prefix}_API_KEY`] || process.env[`${prefix}_ACCESS_TOKEN`] || environment === "production" && process.env.TOPOLO_API_KEY || environment === "production" && process.env.TOPOLO_ACCESS_TOKEN) {
@@ -2686,51 +2721,47 @@ async function refreshCredentialIfNeeded(environment = selectedEnvironment(), op
2686
2721
  }
2687
2722
  }
2688
2723
  async function refreshContextCredentialIfNeeded(environment, key, options = {}) {
2689
- const config = await readConfig();
2690
- const profile = profileForEnvironment(config, environment);
2691
- const context = profile.contexts?.[key];
2692
- const credential = context?.credential;
2693
- if (!credential || credential.kind !== "access_token") return credential ?? null;
2694
- const oauthClientId = context.oauthClientId ?? profile.oauthClientId;
2695
- if (!credential.refreshToken || !oauthClientId) return credential;
2696
- const now = Math.floor(Date.now() / 1e3);
2697
- if (!options.force && credential.expiresAt && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
2698
- const serviceUrls = resolveServiceUrls(profile.serviceUrls, environment);
2699
- if (environment === "local" && !serviceUrls?.auth) {
2700
- throw new TopoloSdkError2(
2701
- "environment_service_url_required",
2702
- "Local Topolo context refresh requires an explicit local Auth service origin."
2703
- );
2704
- }
2705
- try {
2706
- const oauth = new TopoloOAuth({
2707
- serviceUrls
2708
- });
2709
- const tokens = await oauth.refreshToken({
2710
- clientId: oauthClientId,
2711
- refreshToken: credential.refreshToken
2712
- });
2713
- const refreshed = {
2714
- kind: "access_token",
2715
- accessToken: tokens.access_token,
2716
- ...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : { refreshToken: credential.refreshToken },
2717
- expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
2718
- };
2719
- await writeConfig(writeProfileConfig(config, environment, {
2720
- ...profile.activeContext === key ? { credential: refreshed } : {},
2721
- contexts: {
2722
- ...profile.contexts ?? {},
2723
- [key]: {
2724
- ...context,
2725
- credential: refreshed,
2726
- oauthClientId
2724
+ return withConfigWriteLock(async () => {
2725
+ const config = await readConfig();
2726
+ const profile = profileForEnvironment(config, environment);
2727
+ const context = profile.contexts?.[key];
2728
+ const credential = context?.credential;
2729
+ if (!credential || credential.kind !== "access_token") return credential ?? null;
2730
+ const oauthClientId = context.oauthClientId ?? profile.oauthClientId;
2731
+ if (!credential.refreshToken || !oauthClientId) return credential;
2732
+ const now = Math.floor(Date.now() / 1e3);
2733
+ if (!options.force && credential.expiresAt && credential.expiresAt - REFRESH_SKEW_SECONDS > now) return credential;
2734
+ const serviceUrls = resolveServiceUrls(profile.serviceUrls, environment);
2735
+ if (environment === "local" && !serviceUrls?.auth) {
2736
+ throw new TopoloSdkError2(
2737
+ "environment_service_url_required",
2738
+ "Local Topolo context refresh requires an explicit local Auth service origin."
2739
+ );
2740
+ }
2741
+ try {
2742
+ const oauth = new TopoloOAuth({ serviceUrls });
2743
+ const tokens = await oauth.refreshToken({
2744
+ clientId: oauthClientId,
2745
+ refreshToken: credential.refreshToken
2746
+ });
2747
+ const refreshed = {
2748
+ kind: "access_token",
2749
+ accessToken: tokens.access_token,
2750
+ ...tokens.refresh_token ? { refreshToken: tokens.refresh_token } : { refreshToken: credential.refreshToken },
2751
+ expiresAt: Math.floor(Date.now() / 1e3) + tokens.expires_in
2752
+ };
2753
+ await writeConfig(writeProfileConfig(config, environment, {
2754
+ ...profile.activeContext === key ? { credential: refreshed } : {},
2755
+ contexts: {
2756
+ ...profile.contexts ?? {},
2757
+ [key]: { ...context, credential: refreshed, oauthClientId }
2727
2758
  }
2728
- }
2729
- }));
2730
- return refreshed;
2731
- } catch {
2732
- return credential;
2733
- }
2759
+ }));
2760
+ return refreshed;
2761
+ } catch {
2762
+ return credential;
2763
+ }
2764
+ });
2734
2765
  }
2735
2766
  function resolveAgentName(configAgentName) {
2736
2767
  return process.env.TOPOLO_AGENT_NAME ?? configAgentName;
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@topolo/mcp",
3
- "version": "0.11.0",
4
- "topoloPublishedVersion": "0.11.0",
3
+ "version": "0.11.1",
4
+ "topoloPublishedVersion": "0.11.1",
5
5
  "description": "Model Context Protocol server for the Topolo platform. Exposes scope-gated tools that third-party agents (Claude, Codex, etc.) can call natively.",
6
+ "license": "UNLICENSED",
7
+ "author": "Topolo",
8
+ "homepage": "https://docs.topolo.app/guides/agents-and-automation",
6
9
  "type": "module",
7
10
  "bin": {
8
11
  "topolo-mcp": "dist/index.js"
@@ -32,7 +35,7 @@
32
35
  },
33
36
  "dependencies": {
34
37
  "@modelcontextprotocol/sdk": "^1.0.0",
35
- "@topolo/sdk": "0.11.0"
38
+ "@topolo/sdk": "0.11.1"
36
39
  },
37
40
  "devDependencies": {
38
41
  "@types/node": "^20.12.0",