@apicircle/mcp-server 1.0.7 → 1.0.8

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.cjs CHANGED
@@ -41,7 +41,7 @@ var import_zod = require("zod");
41
41
  // package.json
42
42
  var package_default = {
43
43
  name: "@apicircle/mcp-server",
44
- version: "1.0.7",
44
+ version: "1.0.8",
45
45
  private: false,
46
46
  type: "module",
47
47
  description: "Model Context Protocol server exposing API Circle Studio's workspace as a tool catalog. Used by Claude Desktop, ChatGPT, Cursor, GitHub Copilot, and any other MCP-compatible AI client.",
@@ -2851,17 +2851,58 @@ var FileBackedWorkspaceProvider = class {
2851
2851
 
2852
2852
  // src/providers/MultiWorkspaceProvider.ts
2853
2853
  var import_registry = require("@apicircle/core/workspace/registry");
2854
+ var LazyActiveWorkspaceProvider = class {
2855
+ constructor(registryRoot, onActiveResolved) {
2856
+ this.registryRoot = registryRoot;
2857
+ this.onActiveResolved = onActiveResolved;
2858
+ }
2859
+ registryRoot;
2860
+ onActiveResolved;
2861
+ async resolveActive() {
2862
+ const registry = await (0, import_registry.loadRegistry)(this.registryRoot);
2863
+ const activeId = registry?.activeWorkspaceId ?? null;
2864
+ if (!activeId) {
2865
+ throw new Error(
2866
+ "No active workspace. Open the desktop app at least once, or run `apicircle workspaces create <name>`."
2867
+ );
2868
+ }
2869
+ this.onActiveResolved(activeId);
2870
+ return new FileBackedWorkspaceProvider((0, import_registry.workspaceDirFor)(this.registryRoot, activeId));
2871
+ }
2872
+ async read() {
2873
+ const provider = await this.resolveActive();
2874
+ return provider.read();
2875
+ }
2876
+ async apply(patch) {
2877
+ const provider = await this.resolveActive();
2878
+ return provider.apply(patch);
2879
+ }
2880
+ async write(next) {
2881
+ const provider = await this.resolveActive();
2882
+ return provider.write(next);
2883
+ }
2884
+ };
2854
2885
  var MultiWorkspaceProvider = class {
2855
2886
  constructor(registryRoot) {
2856
2887
  this.registryRoot = registryRoot;
2888
+ this.lazyProvider = new LazyActiveWorkspaceProvider(this.registryRoot, (id) => {
2889
+ this.activeWorkspaceId = id;
2890
+ });
2857
2891
  }
2858
2892
  registryRoot;
2859
- active = null;
2893
+ /** Last-known active workspace id. Refreshed every time the lazy
2894
+ * provider resolves; reflects what the most recent operation saw on
2895
+ * disk, not a stale boot-time snapshot. */
2860
2896
  activeWorkspaceId = null;
2897
+ /** The lazy provider tool handlers consume as `ctx.workspace`. Holds a
2898
+ * reference back to this instance so each call updates
2899
+ * `activeWorkspaceId` for `activeId()` callers + diagnostic logs. */
2900
+ lazyProvider;
2861
2901
  /**
2862
- * Hydrate the active provider from disk. Must be called once before the
2863
- * MCP host boots so `ctx.workspace.read()` doesn't race the first
2864
- * registry-load. Returns the registry the boot can log.
2902
+ * Read the registry from disk so the host can log a boot banner. Does
2903
+ * NOT cache a per-id provider — each `activeProvider()` call re-reads
2904
+ * the registry, so a workspace switch in the desktop is picked up by
2905
+ * the next tool call without restarting the MCP server.
2865
2906
  */
2866
2907
  async init() {
2867
2908
  const registry = await (0, import_registry.loadRegistry)(this.registryRoot) ?? {
@@ -2869,22 +2910,18 @@ var MultiWorkspaceProvider = class {
2869
2910
  activeWorkspaceId: null,
2870
2911
  workspaces: []
2871
2912
  };
2872
- if (registry.activeWorkspaceId) {
2873
- this.activeWorkspaceId = registry.activeWorkspaceId;
2874
- this.active = new FileBackedWorkspaceProvider(
2875
- (0, import_registry.workspaceDirFor)(this.registryRoot, registry.activeWorkspaceId)
2876
- );
2877
- }
2913
+ this.activeWorkspaceId = registry.activeWorkspaceId;
2878
2914
  return registry;
2879
2915
  }
2880
- /** The provider tool handlers see as `ctx.workspace`. */
2916
+ /**
2917
+ * The provider tool handlers see as `ctx.workspace`. Returns a lazy
2918
+ * provider whose `read` / `apply` / `write` calls re-read
2919
+ * `registry.json` so the right active workspace is always targeted
2920
+ * even if the desktop switched workspaces since this MCP process
2921
+ * started.
2922
+ */
2881
2923
  activeProvider() {
2882
- if (!this.active) {
2883
- throw new Error(
2884
- "No active workspace. Open the desktop app at least once, or run `apicircle workspaces create <name>`."
2885
- );
2886
- }
2887
- return this.active;
2924
+ return this.lazyProvider;
2888
2925
  }
2889
2926
  // ─── Workspaces interface ──────────────────────────────────────────────────
2890
2927
  async list() {
@@ -2932,23 +2969,17 @@ var MultiWorkspaceProvider = class {
2932
2969
  if (!registry || !registry.workspaces.some((w) => w.id === workspaceId)) {
2933
2970
  throw new WorkspaceNotFoundError(workspaceId);
2934
2971
  }
2935
- const next = await (0, import_registry.setActiveWorkspace)(this.registryRoot, workspaceId);
2936
- void next;
2972
+ await (0, import_registry.setActiveWorkspace)(this.registryRoot, workspaceId);
2937
2973
  this.activeWorkspaceId = workspaceId;
2938
- this.active = new FileBackedWorkspaceProvider((0, import_registry.workspaceDirFor)(this.registryRoot, workspaceId));
2939
2974
  }
2940
2975
  /**
2941
2976
  * Idempotent registry write — used by tests / tools that need to
2942
- * persist registry updates that didn't go through `setActive`.
2977
+ * persist registry updates that didn't go through `setActive`. The
2978
+ * lazy active provider picks the new id up on its next operation.
2943
2979
  */
2944
2980
  async writeRegistry(registry) {
2945
2981
  await (0, import_registry.saveRegistry)(this.registryRoot, registry);
2946
2982
  this.activeWorkspaceId = registry.activeWorkspaceId;
2947
- if (registry.activeWorkspaceId) {
2948
- this.active = new FileBackedWorkspaceProvider(
2949
- (0, import_registry.workspaceDirFor)(this.registryRoot, registry.activeWorkspaceId)
2950
- );
2951
- }
2952
2983
  }
2953
2984
  };
2954
2985