@agimon-ai/po-mcp 0.0.0-alpha.75 → 0.0.0-alpha.76

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 (33) hide show
  1. package/README.md +28 -20
  2. package/dist/extensions/server.cjs +117 -50
  3. package/dist/extensions/server.cjs.map +1 -1
  4. package/dist/extensions/server.mjs +118 -51
  5. package/dist/extensions/server.mjs.map +1 -1
  6. package/dist/{index-BTMfJ_om.d.mts → index-BcP-x1SE.d.mts} +3 -17
  7. package/dist/index-BcP-x1SE.d.mts.map +1 -0
  8. package/dist/index.cjs +15 -3
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.mts +4 -9
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +9 -1
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/localServers.cjs +1 -1
  15. package/dist/localServers.d.mts +1 -1
  16. package/dist/localServers.mjs +1 -1
  17. package/dist/{mcpCatalog-DiEGW4h8.mjs → mcpCatalog-BiSdyG0A.mjs} +4 -4
  18. package/dist/mcpCatalog-BiSdyG0A.mjs.map +1 -0
  19. package/dist/{mcpCatalog-BE6bOIBG.cjs → mcpCatalog-Domudw3m.cjs} +3 -4
  20. package/dist/mcpCatalog-Domudw3m.cjs.map +1 -0
  21. package/dist/{sessionServers-BajEiwhs.cjs → sessionServers-CJNAexGl.cjs} +145 -68
  22. package/dist/sessionServers-CJNAexGl.cjs.map +1 -0
  23. package/dist/{sessionServers-Dy1PaZ7d.mjs → sessionServers-LBfUXsdp.mjs} +145 -68
  24. package/dist/sessionServers-LBfUXsdp.mjs.map +1 -0
  25. package/dist/sessionServers.cjs +1 -1
  26. package/dist/sessionServers.d.mts +1 -1
  27. package/dist/sessionServers.mjs +1 -1
  28. package/package.json +9 -9
  29. package/dist/index-BTMfJ_om.d.mts.map +0 -1
  30. package/dist/mcpCatalog-BE6bOIBG.cjs.map +0 -1
  31. package/dist/mcpCatalog-DiEGW4h8.mjs.map +0 -1
  32. package/dist/sessionServers-BajEiwhs.cjs.map +0 -1
  33. package/dist/sessionServers-Dy1PaZ7d.mjs.map +0 -1
package/README.md CHANGED
@@ -78,13 +78,13 @@ session Cordis root.
78
78
  Downstream clients run in-process through `@agimon-ai/po-mcp-proxy`; this adapter does not start its
79
79
  Hono server.
80
80
 
81
- ## Temporary API-key connections for packages
81
+ ## Temporary connections for packages
82
82
 
83
- Trusted session plugins such as po-development can inject `PO_MCP_SESSION_SERVERS_SERVICE`
84
- from `@agimon-ai/po-mcp/sessionServers`, then call `readPoMcpSessionServers(scoped)` inside
85
- that injection on their session Cordis root. This is not a model-visible management API and
86
- not a package-identity boundary. The caller must authorize the destination, bind code-mode
87
- calls to the owning session, and pass the run's abort signal.
83
+ Trusted session plugins inject `PO_MCP_SERVICE` from `@agimon-ai/po-core/mcp` and call
84
+ `readPoMcp(scoped)` inside that injection on their session Cordis root. `po-mcp` provides
85
+ this portable contract through `PO_MCP_CONTRACT`. This is not a model-visible management
86
+ API or a package-identity boundary. The caller authorizes the destination, binds code-mode
87
+ calls to the owning session, and passes the run's abort signal for establishment.
88
88
 
89
89
  ```ts
90
90
  const connection = await servers.register(
@@ -96,31 +96,39 @@ const connection = await servers.register(
96
96
  signal,
97
97
  );
98
98
  try {
99
- // The connected tools join this session's normal MCP surface.
99
+ // Tools also join this session's normal MCP surface.
100
+ const tools = connection.snapshot().tools;
101
+ if (tools.includes('ping')) await connection.invoke('ping', {});
100
102
  } finally {
101
- await servers.deregister(connection.name);
103
+ await connection.dispose();
102
104
  }
103
105
  ```
104
106
 
105
- `register` connects immediately and returns only `{ name, status, tools }`. It accepts HTTP
106
- or SSE over HTTPS, or HTTP loopback with an explicit port. It rejects URL userinfo,
107
- fragments, environment interpolation in URLs, reserved names, and all existing names,
108
- including configured, Help, local-stack, and pending-removal entries. It never replaces
109
- an existing connection. It is not idempotent.
107
+ `register` connects immediately and returns an identity-owned handle with `name`, live
108
+ `snapshot()`, validated `invoke(tool, args?, signal?)`, and asynchronous idempotent `dispose()`.
109
+ HTTP/SSE no-auth connections require HTTP loopback with an explicit port and never start OAuth.
110
+ API-key connections also accept HTTPS. URL userinfo, fragments, URL environment interpolation,
111
+ reserved names, and all existing or pending-removal names are rejected. Registrations never
112
+ replace a connection. Snapshot and invocation cannot observe a same-name replacement.
110
113
 
111
114
  API keys use `{ mode: 'bearer', environmentVariable }` or
112
115
  `{ mode: 'header', name: 'X-Api-Key', environmentVariable }`. Trusted server code may
113
- instead supply `value`; raw keys must never enter code-mode arguments, prompts, results,
114
- or logs. Environment references read only the owning session's admitted environment.
116
+ instead supply `value` programmatically. Do not print keys or add credential-bearing call records.
117
+ Literal keys embedded in `exec` source still persist in saved scripts and transcripts. Environment
118
+ references read only the owning session's admitted environment.
115
119
  The key stays in the session overlay, outside proxy configuration, disk caches, and the
116
120
  vault. The existing proxy API-key transport pins credentials to the destination origin,
117
121
  refuses redirects, and never starts OAuth.
118
122
 
119
- `deregister(name)` removes only this service's exact overlay registration, not a configured,
120
- Help, local-stack, or same-name replacement. Cleanup remains callable after run cancellation
121
- or selection changes. Call it in a `finally` when development ends, including failed stop
122
- paths. Session teardown is a fallback, not dev-finish detection. Failed or cancelled
123
- registration removes its partial entry and connection; no saved MCP config is changed.
123
+ Establishment cancellation rolls back its partial entry and connection. Once connected, normal
124
+ `exec` completion does not dispose the registration. `dispose()` remains available after run
125
+ cancellation or selection changes. Call it in `finally` when development ends, including failed
126
+ stop paths. Provider shutdown retires handles and closes connections; it does not stop external
127
+ MCP server processes. No saved MCP config is changed.
128
+
129
+ The existing `@agimon-ai/po-mcp/localServers` and `/sessionServers` APIs remain compatibility
130
+ adapters with their original name-based result and cleanup methods. New consumers use the core
131
+ contract and owned handles.
124
132
 
125
133
  ## Direct tools and configured identity
126
134
 
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
5
  const require_rolldown_runtime = require("../rolldown-runtime-C0BPl7ul.cjs");
6
- const require_mcpCatalog = require("../mcpCatalog-BE6bOIBG.cjs");
7
- const require_sessionServers = require("../sessionServers-BajEiwhs.cjs");
6
+ const require_mcpCatalog = require("../mcpCatalog-Domudw3m.cjs");
7
+ const require_sessionServers = require("../sessionServers-CJNAexGl.cjs");
8
8
  const require_projection = require("../projection-DBpXsw0W.cjs");
9
9
  let node_crypto = require("node:crypto");
10
10
  let node_fs_promises = require("node:fs/promises");
@@ -14,6 +14,7 @@ node_path = require_rolldown_runtime.__toESM(node_path, 1);
14
14
  let _agimon_ai_po_config_agentPluginMcp = require("@agimon-ai/po-config/agentPluginMcp");
15
15
  let node_os = require("node:os");
16
16
  node_os = require_rolldown_runtime.__toESM(node_os, 1);
17
+ let _agimon_ai_po_core_mcpSession = require("@agimon-ai/po-core/mcpSession");
17
18
  let _agimon_ai_po_core_help = require("@agimon-ai/po-core/help");
18
19
  let _agimon_ai_po_mcp_proxy = require("@agimon-ai/po-mcp-proxy");
19
20
  let typebox_value = require("typebox/value");
@@ -27,8 +28,10 @@ let _agimon_ai_po_core_piSettings = require("@agimon-ai/po-core/piSettings");
27
28
  let _agimon_ai_po_core_childSession = require("@agimon-ai/po-core/childSession");
28
29
  let _agimon_ai_po_core_codemode = require("@agimon-ai/po-core/codemode");
29
30
  let _agimon_ai_po_core_headless = require("@agimon-ai/po-core/headless");
31
+ let _agimon_ai_po_core_mcp = require("@agimon-ai/po-core/mcp");
30
32
  let _agimon_ai_po_core_mcpStatus = require("@agimon-ai/po-core/mcpStatus");
31
33
  let _agimon_ai_po_core_mcpToolResolver = require("@agimon-ai/po-core/mcpToolResolver");
34
+ let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
32
35
  let node_dns_promises = require("node:dns/promises");
33
36
  node_dns_promises = require_rolldown_runtime.__toESM(node_dns_promises, 1);
34
37
  let node_https = require("node:https");
@@ -2718,6 +2721,11 @@ var McpSession = class {
2718
2721
  toolRestriction;
2719
2722
  enabled = true;
2720
2723
  startup;
2724
+ initialConfiguration() {
2725
+ const configuration = (0, _agimon_ai_po_core_mcpSession.readPoMcpSessionConfig)(this.options.environment ?? {});
2726
+ if (!configuration) throw new Error("MCP session configuration must be supplied by the host.");
2727
+ return configuration;
2728
+ }
2721
2729
  /** Resolved per tool call, so a registration outlives the container it was made under. */
2722
2730
  getClientManager = () => this.runtime?.getServices()?.clientManager;
2723
2731
  constructor(options) {
@@ -2754,7 +2762,7 @@ var McpSession = class {
2754
2762
  * Returns the servers it seeded, so a caller can report what the session started
2755
2763
  * with before anything connected.
2756
2764
  */
2757
- async install(configuration = require_mcpCatalog.readSessionConfig(this.options.environment)) {
2765
+ async install(configuration = this.initialConfiguration()) {
2758
2766
  const generation = ++this.lifecycleGeneration;
2759
2767
  await this.bindConfiguration(configuration);
2760
2768
  if (generation !== this.lifecycleGeneration) return this.catalog.toSnapshot();
@@ -2929,7 +2937,7 @@ var McpSession = class {
2929
2937
  if (!this.enabled || this.configuredServerNames().length === 0) return;
2930
2938
  const [{ MemoryTokenStore }, { McpRuntimeOwner }, { VaultTokenStore }] = await Promise.all([
2931
2939
  import("@agimon-ai/po-mcp-proxy"),
2932
- Promise.resolve().then(() => require("../mcpCatalog-BE6bOIBG.cjs")).then((n) => n.mcpRuntime_exports),
2940
+ Promise.resolve().then(() => require("../mcpCatalog-Domudw3m.cjs")).then((n) => n.mcpRuntime_exports),
2933
2941
  Promise.resolve().then(() => vaultTokenStore_exports)
2934
2942
  ]);
2935
2943
  if (generation !== this.lifecycleGeneration) return;
@@ -3340,6 +3348,7 @@ var McpSession = class {
3340
3348
  if (change.state !== "connecting" && change.state !== "needs-auth") this.authorizationUrls.delete(change.serverName);
3341
3349
  const runtime = this.runtime;
3342
3350
  const services = runtime?.getServices();
3351
+ const entry = this.options.sessionServers?.().get(change.serverName);
3343
3352
  (change.state === "connected" && services ? services.clientManager.ensureConnected(change.serverName).then((connection) => connection.listTools()) : Promise.resolve([])).then((tools) => ({
3344
3353
  tools,
3345
3354
  error: void 0
@@ -3347,7 +3356,7 @@ var McpSession = class {
3347
3356
  tools: [],
3348
3357
  error: `Could not discover tools for MCP server "${change.serverName}".`
3349
3358
  })).then(({ tools, error }) => {
3350
- if (generation !== this.lifecycleGeneration || !runtime?.isCurrent(services) || this.disconnectedServers.has(change.serverName)) return;
3359
+ if (generation !== this.lifecycleGeneration || !runtime?.isCurrent(services) || this.disconnectedServers.has(change.serverName) || this.options.sessionServers?.().get(change.serverName) !== entry) return;
3351
3360
  if (error) this.catalog.addDiagnostic(error);
3352
3361
  this.catalog.applyStateChange(error ? {
3353
3362
  ...change,
@@ -3448,11 +3457,10 @@ function createMcpSessionApi(source, countTokens) {
3448
3457
  }
3449
3458
  //#endregion
3450
3459
  //#region src/services/serverRuntime/index.ts
3451
- async function sessionConfiguration(execution, workspaceRoot) {
3460
+ async function sessionConfiguration(execution, workspaceRoot, loaded) {
3452
3461
  if (workspaceRoot !== void 0) {
3453
- const loaded = (0, _agimon_ai_po_config_harnessStore.loadHarnessState)({ ...execution.environment });
3454
- const projection = loaded.state.mcpProjection;
3455
- if (loaded.filePath && loaded.state.root === workspaceRoot && execution.repoRoot === workspaceRoot && loaded.state.mcp && loaded.state.majorMode === execution.selection.majorMode && JSON.stringify(loaded.state.domains) === JSON.stringify(execution.selection.domains) && JSON.stringify(loaded.state.layers) === JSON.stringify(execution.selection.activeLayers) && (0, _agimon_ai_po_core_mcpProjection.isPoMcpProjection)(projection) && projection.repoRoot === workspaceRoot) return require_projection.mcpSessionConfigFromProjection(projection, execution.cwd);
3462
+ const projection = loaded?.state.mcpProjection;
3463
+ if (loaded?.filePath && loaded.state.root === workspaceRoot && execution.repoRoot === workspaceRoot && loaded.state.mcp && loaded.state.majorMode === execution.selection.majorMode && JSON.stringify(loaded.state.domains) === JSON.stringify(execution.selection.domains) && JSON.stringify(loaded.state.layers) === JSON.stringify(execution.selection.activeLayers) && (0, _agimon_ai_po_core_mcpProjection.isPoMcpProjection)(projection) && projection.repoRoot === workspaceRoot) return require_projection.mcpSessionConfigFromProjection(projection, execution.cwd);
3456
3464
  return {
3457
3465
  enabled: false,
3458
3466
  repoRoot: execution.cwd,
@@ -3462,8 +3470,11 @@ async function sessionConfiguration(execution, workspaceRoot) {
3462
3470
  }
3463
3471
  return require_mcpCatalog.readSessionConfig(execution.environment, execution.cwd);
3464
3472
  }
3465
- function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, publishFile, assertPackageActive, getVault) {
3473
+ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, publishFile, assertPackageActive, getVault, getFs) {
3466
3474
  let active;
3475
+ let stopActive;
3476
+ let disposed = false;
3477
+ let disposal;
3467
3478
  let currentSelection;
3468
3479
  let staleSelection = false;
3469
3480
  let cleanup;
@@ -3486,6 +3497,7 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3486
3497
  sessionServers: () => sessionServers
3487
3498
  });
3488
3499
  const assertAvailable = () => {
3500
+ if (disposed) throw new Error("The MCP runtime has been disposed.");
3489
3501
  if (!active) throw new Error("The MCP runtime has not started yet.");
3490
3502
  if (staleSelection) throw new Error("The MCP projection is stale for the current selection.");
3491
3503
  };
@@ -3494,6 +3506,11 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3494
3506
  session,
3495
3507
  entries: sessionServers,
3496
3508
  environment,
3509
+ invoke: (server, tool, args, signal) => invoke({
3510
+ server,
3511
+ tool,
3512
+ arguments: args
3513
+ }, signal),
3497
3514
  assertAdmitted(sessionId, signal) {
3498
3515
  assertPackageActive?.();
3499
3516
  assertAvailable();
@@ -3533,11 +3550,13 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3533
3550
  }
3534
3551
  if (active !== execution) return;
3535
3552
  const resolver = getResolver?.();
3536
- const loaded = workspaceRoot ? (0, _agimon_ai_po_config_harnessStore.loadHarnessState)({ ...execution.environment }) : void 0;
3553
+ const fs = getFs?.();
3554
+ if (workspaceRoot && !fs) throw new Error("MCP session configuration requires the host filesystem.");
3555
+ const loaded = workspaceRoot && fs ? await (0, _agimon_ai_po_config_harnessStore.loadHarnessStateAsync)(fs, { ...execution.environment }, (0, _agimon_ai_po_core_platform.withAbortSignal)(lifetime.signal, _agimon_ai_po_core_platform.BACKGROUND_CONTEXT)) : void 0;
3537
3556
  const authorized = workspaceRoot && loaded?.filePath && loaded.state.root === workspaceRoot && execution.repoRoot === workspaceRoot && loaded.state.mcp && (0, _agimon_ai_po_core_mcpProjection.isPoMcpProjection)(loaded.state.mcpProjection) && loaded.state.mcpProjection.repoRoot === workspaceRoot && loaded.state.mcpProjection.enabled;
3538
3557
  if (!resolver || !authorized) {
3539
3558
  if (active === execution && selection === currentSelection) {
3540
- if (workspaceRoot === void 0 || JSON.stringify(execution.selection.domains) === JSON.stringify(selection.domains)) await session.reconfigure(await sessionConfiguration(execution, workspaceRoot), execution.cwd, execution.repoRoot);
3559
+ if (workspaceRoot === void 0 || JSON.stringify(execution.selection.domains) === JSON.stringify(selection.domains)) await session.reconfigure(await sessionConfiguration(execution, workspaceRoot, loaded), execution.cwd, execution.repoRoot);
3541
3560
  staleSelection = workspaceRoot !== void 0 && JSON.stringify(execution.selection.domains) !== JSON.stringify(selection.domains);
3542
3561
  }
3543
3562
  return;
@@ -3556,8 +3575,13 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3556
3575
  await candidate.cleanup();
3557
3576
  throw error;
3558
3577
  }
3559
- }).then(() => {
3560
- for (const name of sessionServers.keys()) if (session.hasConfiguredServer(name)) sessionServers.delete(name);
3578
+ }).then(async () => {
3579
+ for (const [name, entry] of sessionServers) {
3580
+ if (!session.hasConfiguredServer(name)) continue;
3581
+ sessionServers.delete(name);
3582
+ delete entry.apiKey;
3583
+ await entry.tokenStore.clear(name);
3584
+ }
3561
3585
  sessionTools.refresh();
3562
3586
  }).catch(async (error) => {
3563
3587
  if (active !== execution || selection !== currentSelection) return;
@@ -3589,6 +3613,7 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3589
3613
  const activity = {
3590
3614
  name: "po-mcp-runtime",
3591
3615
  async start(execution) {
3616
+ if (disposed) throw new Error("The MCP runtime has been disposed.");
3592
3617
  active = execution;
3593
3618
  lifetime = new AbortController();
3594
3619
  currentSelection = execution.selection;
@@ -3628,45 +3653,53 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3628
3653
  loadTokenizer().then(() => {
3629
3654
  if (active === execution) publish();
3630
3655
  });
3656
+ let stopping;
3657
+ const stop = () => {
3658
+ stopping ??= (async () => {
3659
+ stopPublishing();
3660
+ if (active !== execution) return;
3661
+ lifetime.abort();
3662
+ setHelp();
3663
+ testServers.clear();
3664
+ active = void 0;
3665
+ currentSelection = void 0;
3666
+ staleSelection = true;
3667
+ sessionTools.refresh();
3668
+ authorizing.clear();
3669
+ await transition;
3670
+ const retiredCleanup = cleanup;
3671
+ cleanup = void 0;
3672
+ try {
3673
+ await session.dispose();
3674
+ } finally {
3675
+ await session.install({
3676
+ enabled: false,
3677
+ repoRoot: execution.cwd,
3678
+ stagingDirectory: execution.cwd
3679
+ });
3680
+ await retiredCleanup?.();
3681
+ execution.client.setStatus(MCP_STATUS_KEY, void 0);
3682
+ execution.client.setStatus(MCP_SESSION_AUTH_STATUS_KEY, void 0);
3683
+ execution.client.setStatus(_agimon_ai_po_core_contextApi.CONTEXT_TOOL_WARNINGS_STATUS_KEY, void 0);
3684
+ }
3685
+ })().finally(async () => {
3686
+ if (stopActive === stop) stopActive = void 0;
3687
+ await testServers.settleRemovals();
3688
+ });
3689
+ return stopping;
3690
+ };
3691
+ stopActive = stop;
3631
3692
  try {
3632
3693
  await refresh(execution, execution.selection);
3633
- publish();
3694
+ if (active === execution) publish();
3634
3695
  } catch (error) {
3635
- await execution.client.notify({
3696
+ if (active === execution) await execution.client.notify({
3636
3697
  title: "Po MCP unavailable",
3637
3698
  body: error instanceof Error ? error.message : String(error),
3638
3699
  level: "warning"
3639
3700
  });
3640
3701
  }
3641
- return async () => {
3642
- stopPublishing();
3643
- if (active !== execution) return;
3644
- lifetime.abort();
3645
- setHelp();
3646
- sessionServers.clear();
3647
- testServers.clear();
3648
- active = void 0;
3649
- currentSelection = void 0;
3650
- staleSelection = true;
3651
- sessionTools.refresh();
3652
- authorizing.clear();
3653
- await transition;
3654
- const retiredCleanup = cleanup;
3655
- cleanup = void 0;
3656
- try {
3657
- await session.dispose();
3658
- } finally {
3659
- await session.install({
3660
- enabled: false,
3661
- repoRoot: execution.cwd,
3662
- stagingDirectory: execution.cwd
3663
- });
3664
- await retiredCleanup?.();
3665
- execution.client.setStatus(MCP_STATUS_KEY, void 0);
3666
- execution.client.setStatus(MCP_SESSION_AUTH_STATUS_KEY, void 0);
3667
- execution.client.setStatus(_agimon_ai_po_core_contextApi.CONTEXT_TOOL_WARNINGS_STATUS_KEY, void 0);
3668
- }
3669
- };
3702
+ return stop;
3670
3703
  }
3671
3704
  };
3672
3705
  const invoke = async (parameters, signal) => {
@@ -3769,6 +3802,27 @@ function createMcpServerRuntime(environment = {}, workspaceRoot, getResolver, pu
3769
3802
  testServerNamespace: testServers.namespace,
3770
3803
  localServers: testServers.localServers,
3771
3804
  sessionServers: testServers.sessionServers,
3805
+ mcp: testServers.mcp,
3806
+ dispose() {
3807
+ if (disposal) return disposal;
3808
+ disposed = true;
3809
+ lifetime.abort();
3810
+ testServers.retire();
3811
+ const stop = stopActive;
3812
+ disposal = (async () => {
3813
+ try {
3814
+ if (stop) await stop();
3815
+ else {
3816
+ await transition;
3817
+ await session.dispose();
3818
+ }
3819
+ } finally {
3820
+ sessionTools.dispose();
3821
+ await testServers.settleRemovals();
3822
+ }
3823
+ })();
3824
+ return disposal;
3825
+ },
3772
3826
  isHelpActive: () => helpActive,
3773
3827
  onHelpChange(listener) {
3774
3828
  helpListeners.add(listener);
@@ -3797,17 +3851,24 @@ const createMcpServerRoot = (context) => {
3797
3851
  host: () => appHost,
3798
3852
  signal: context?.signal
3799
3853
  });
3800
- const runtime = createMcpServerRuntime(context?.agent?.context?.environment, context?.host.context.workspaceRoot, () => resolver, publishFile, () => appHost?.assertActive("@agimon-ai/po-mcp"), () => serverScope?.resolve(_agimon_ai_po_vault.PO_VAULT_CONTRACT));
3854
+ const runtime = createMcpServerRuntime(context?.agent?.context?.environment, context?.host.context.workspaceRoot, () => resolver, publishFile, () => appHost?.assertActive("@agimon-ai/po-mcp"), () => serverScope?.resolve(_agimon_ai_po_vault.PO_VAULT_CONTRACT), () => context && (0, _agimon_ai_po_core_platform.readPoFs)(context.context));
3801
3855
  const generation = `${context?.agent?.context?.sessionId ?? crypto.randomUUID()}:mcp-server`;
3802
3856
  const { session } = runtime;
3803
3857
  const tools = [...runtime.tools, ...createFileTransferTools(context)];
3804
3858
  const apps = createMcpAppsService(runtime.sessionTools, () => appHost, context?.signal);
3805
3859
  const namespace = createMcpNamespace(runtime.sessionTools, hostContext?.sessionId);
3806
3860
  const mountSession = (cordis) => {
3807
- cordis.inject([_agimon_ai_po_core_serverPlugin.PO_SERVER_SCOPE_SERVICE], (scoped) => {
3861
+ cordis.inject([_agimon_ai_po_core_serverPlugin.PO_SERVER_SCOPE_SERVICE], async (scoped) => {
3808
3862
  serverScope = (0, _agimon_ai_po_core_serverPlugin.requirePoServerScope)(scoped);
3809
- return () => {
3863
+ const withdraw = await serverScope.provide(_agimon_ai_po_core_mcp.PO_MCP_CONTRACT, runtime.mcp);
3864
+ return async () => {
3810
3865
  serverScope = void 0;
3866
+ const closing = runtime.dispose();
3867
+ try {
3868
+ await withdraw();
3869
+ } finally {
3870
+ await closing;
3871
+ }
3811
3872
  };
3812
3873
  });
3813
3874
  cordis.inject([_agimon_ai_po_core_codemode.PO_CODEMODE_SERVICE], (scoped) => {
@@ -3899,7 +3960,7 @@ const createMcpServerRoot = (context) => {
3899
3960
  provider.provide(_agimon_ai_po_core_childSession.PO_CHILD_SESSION_MCP_TOOL_SERVICE, runtime.childTool);
3900
3961
  provider.provide(require_sessionServers.PO_MCP_LOCAL_SERVERS_SERVICE, runtime.localServers);
3901
3962
  provider.provide(require_sessionServers.PO_MCP_SESSION_SERVERS_SERVICE, runtime.sessionServers);
3902
- return () => runtime.sessionTools.dispose();
3963
+ return () => runtime.dispose();
3903
3964
  });
3904
3965
  };
3905
3966
  return {
@@ -3909,7 +3970,13 @@ const createMcpServerRoot = (context) => {
3909
3970
  },
3910
3971
  activities: runtime.activities,
3911
3972
  services: [mountMcpHeadlessTools(tools), mountSession],
3912
- onDispose: apps.dispose
3973
+ onDispose: async () => {
3974
+ try {
3975
+ await runtime.dispose();
3976
+ } finally {
3977
+ apps.dispose();
3978
+ }
3979
+ }
3913
3980
  };
3914
3981
  };
3915
3982
  //#endregion