@frontmcp/sdk 0.11.2 → 0.11.3

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 (57) hide show
  1. package/adapter/adapter.registry.d.ts.map +1 -1
  2. package/agent/flows/call-agent.flow.d.ts.map +1 -1
  3. package/app/app.registry.d.ts +1 -0
  4. package/app/app.registry.d.ts.map +1 -1
  5. package/app/instances/app.local.instance.d.ts +1 -0
  6. package/app/instances/app.local.instance.d.ts.map +1 -1
  7. package/app/instances/app.remote.instance.d.ts.map +1 -1
  8. package/auth/flows/session.verify.flow.d.ts +2 -0
  9. package/auth/flows/session.verify.flow.d.ts.map +1 -1
  10. package/common/decorators/skill.decorator.d.ts +13 -1
  11. package/common/decorators/skill.decorator.d.ts.map +1 -1
  12. package/common/entries/skill.entry.d.ts +21 -1
  13. package/common/entries/skill.entry.d.ts.map +1 -1
  14. package/common/interfaces/internal/registry.interface.d.ts +1 -0
  15. package/common/interfaces/internal/registry.interface.d.ts.map +1 -1
  16. package/common/interfaces/skill.interface.d.ts +21 -1
  17. package/common/interfaces/skill.interface.d.ts.map +1 -1
  18. package/common/metadata/skill.metadata.d.ts +56 -0
  19. package/common/metadata/skill.metadata.d.ts.map +1 -1
  20. package/common/tokens/skill.tokens.d.ts +5 -0
  21. package/common/tokens/skill.tokens.d.ts.map +1 -1
  22. package/esm/index.mjs +393 -70
  23. package/esm/package.json +6 -6
  24. package/flows/flow.instance.d.ts +1 -0
  25. package/flows/flow.instance.d.ts.map +1 -1
  26. package/front-mcp/front-mcp.d.ts +1 -0
  27. package/front-mcp/front-mcp.d.ts.map +1 -1
  28. package/index.js +522 -198
  29. package/package.json +6 -6
  30. package/plugin/plugin.registry.d.ts +7 -0
  31. package/plugin/plugin.registry.d.ts.map +1 -1
  32. package/scope/scope.instance.d.ts +1 -0
  33. package/scope/scope.instance.d.ts.map +1 -1
  34. package/scope/scope.registry.d.ts +1 -0
  35. package/scope/scope.registry.d.ts.map +1 -1
  36. package/skill/index.d.ts +16 -0
  37. package/skill/index.d.ts.map +1 -1
  38. package/skill/skill-directory-loader.d.ts +51 -0
  39. package/skill/skill-directory-loader.d.ts.map +1 -0
  40. package/skill/skill-http.utils.d.ts +6 -1
  41. package/skill/skill-http.utils.d.ts.map +1 -1
  42. package/skill/skill-md-parser.d.ts +60 -0
  43. package/skill/skill-md-parser.d.ts.map +1 -0
  44. package/skill/skill.instance.d.ts.map +1 -1
  45. package/skill/skill.utils.d.ts.map +1 -1
  46. package/tool/flows/call-tool.flow.d.ts.map +1 -1
  47. package/transport/flows/handle.stateless-http.flow.d.ts.map +1 -1
  48. package/transport/flows/handle.streamable-http.flow.d.ts.map +1 -1
  49. package/transport/mcp-handlers/call-tool-request.handler.d.ts.map +1 -1
  50. package/transport/mcp-handlers/complete-request.handler.d.ts.map +1 -1
  51. package/transport/mcp-handlers/get-prompt-request.handler.d.ts.map +1 -1
  52. package/transport/mcp-handlers/list-prompts-request.handler.d.ts.map +1 -1
  53. package/transport/mcp-handlers/list-resource-templates-request.handler.d.ts.map +1 -1
  54. package/transport/mcp-handlers/list-resources-request.handler.d.ts.map +1 -1
  55. package/transport/mcp-handlers/list-tools-request.handler.d.ts.map +1 -1
  56. package/transport/mcp-handlers/read-resource-request.handler.d.ts.map +1 -1
  57. package/transport/mcp-handlers/unsubscribe-request.handler.d.ts.map +1 -1
package/esm/index.mjs CHANGED
@@ -406,6 +406,11 @@ var init_skill_tokens = __esm({
406
406
  hideFromDiscovery: tokenFactory.meta("skill:hideFromDiscovery"),
407
407
  toolValidation: tokenFactory.meta("skill:toolValidation"),
408
408
  visibility: tokenFactory.meta("skill:visibility"),
409
+ license: tokenFactory.meta("skill:license"),
410
+ compatibility: tokenFactory.meta("skill:compatibility"),
411
+ specMetadata: tokenFactory.meta("skill:specMetadata"),
412
+ allowedTools: tokenFactory.meta("skill:allowedTools"),
413
+ resources: tokenFactory.meta("skill:resources"),
409
414
  metadata: tokenFactory.meta("skill:metadata")
410
415
  // used in skill({}) construction
411
416
  };
@@ -2645,7 +2650,7 @@ function isFileInstructions(source) {
2645
2650
  function isUrlInstructions(source) {
2646
2651
  return typeof source === "object" && "url" in source;
2647
2652
  }
2648
- var skillToolRefSchema, skillToolRefWithClassSchema, skillToolInputSchema, skillParameterSchema, skillExampleSchema, skillInstructionSourceSchema, skillMetadataSchema;
2653
+ var skillToolRefSchema, skillToolRefWithClassSchema, skillToolInputSchema, skillParameterSchema, skillExampleSchema, skillInstructionSourceSchema, skillResourcesSchema, skillMetadataSchema;
2649
2654
  var init_skill_metadata = __esm({
2650
2655
  "libs/sdk/src/common/metadata/skill.metadata.ts"() {
2651
2656
  "use strict";
@@ -2696,10 +2701,21 @@ var init_skill_metadata = __esm({
2696
2701
  }).strict()
2697
2702
  // URL
2698
2703
  ]);
2704
+ skillResourcesSchema = z29.object({
2705
+ scripts: z29.string().optional(),
2706
+ references: z29.string().optional(),
2707
+ assets: z29.string().optional()
2708
+ });
2699
2709
  skillMetadataSchema = z29.object({
2700
2710
  id: z29.string().optional(),
2701
- name: z29.string().min(1),
2702
- description: z29.string().min(1),
2711
+ name: z29.string().min(1).max(64).regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/, {
2712
+ message: "Skill name must be kebab-case: lowercase letters, numbers, and hyphens only. Must not start/end with a hyphen."
2713
+ }).refine((n) => !n.includes("--"), {
2714
+ message: "Skill name must not contain consecutive hyphens."
2715
+ }),
2716
+ description: z29.string().min(1).max(1024).refine((d) => !/<[a-zA-Z][^>]*>/.test(d), {
2717
+ message: "Skill description must not contain XML/HTML tags (per Agent Skills spec)."
2718
+ }),
2703
2719
  instructions: skillInstructionSourceSchema,
2704
2720
  tools: z29.array(skillToolInputSchema).optional(),
2705
2721
  tags: z29.array(z29.string().min(1)).optional(),
@@ -2708,7 +2724,12 @@ var init_skill_metadata = __esm({
2708
2724
  priority: z29.number().optional().default(0),
2709
2725
  hideFromDiscovery: z29.boolean().optional().default(false),
2710
2726
  toolValidation: z29.enum(["strict", "warn", "ignore"]).optional().default("warn"),
2711
- visibility: z29.enum(["mcp", "http", "both"]).optional().default("both")
2727
+ visibility: z29.enum(["mcp", "http", "both"]).optional().default("both"),
2728
+ license: z29.string().optional(),
2729
+ compatibility: z29.string().max(500).optional(),
2730
+ specMetadata: z29.record(z29.string(), z29.string()).optional(),
2731
+ allowedTools: z29.string().optional(),
2732
+ resources: skillResourcesSchema.optional()
2712
2733
  }).passthrough();
2713
2734
  }
2714
2735
  });
@@ -9333,7 +9354,11 @@ ${JSON.stringify(error.schema, null, 2)}
9333
9354
  this.logger.info("finalize: sending response", {
9334
9355
  tool: tool.metadata.name,
9335
9356
  hasContent: Array.isArray(result.content) && result.content.length > 0,
9336
- contentLength: Array.isArray(result.content) ? result.content.length : 0,
9357
+ contentParts: Array.isArray(result.content) ? result.content.length : 0,
9358
+ contentBytes: Array.isArray(result.content) ? result.content.reduce((sum, part) => {
9359
+ const str = JSON.stringify(part);
9360
+ return sum + (typeof Buffer !== "undefined" ? Buffer.byteLength(str, "utf8") : new TextEncoder().encode(str).byteLength);
9361
+ }, 0) : 0,
9337
9362
  hasStructuredContent: result.structuredContent !== void 0,
9338
9363
  hasMeta: result._meta !== void 0,
9339
9364
  metaKeys: result._meta ? Object.keys(result._meta) : [],
@@ -13078,9 +13103,10 @@ var init_adapter_registry = __esm({
13078
13103
  const instance = new AdapterInstance(rec, deps, this.providers);
13079
13104
  this.instances.set(token, instance);
13080
13105
  readyArr.push(instance.ready);
13106
+ this.logger?.verbose(`AdapterRegistry: initialized adapter '${rec.metadata.name}'`);
13081
13107
  }
13082
13108
  await Promise.all(readyArr);
13083
- this.logger?.debug("AdapterRegistry: initialization complete");
13109
+ this.logger?.verbose(`AdapterRegistry: initialization complete (${this.instances.size} adapter(s))`);
13084
13110
  }
13085
13111
  getAdapters() {
13086
13112
  return [...this.instances.values()];
@@ -13217,9 +13243,46 @@ var init_skill_events = __esm({
13217
13243
  }
13218
13244
  });
13219
13245
 
13246
+ // libs/sdk/src/skill/skill-md-parser.ts
13247
+ import * as yaml from "js-yaml";
13248
+ import { readFile } from "@frontmcp/utils";
13249
+ function parseSkillMdFrontmatter(content) {
13250
+ const trimmed = content.trimStart();
13251
+ if (!trimmed.startsWith("---")) {
13252
+ return { frontmatter: {}, body: content };
13253
+ }
13254
+ const closingIndex = trimmed.indexOf("\n---", 3);
13255
+ if (closingIndex === -1) {
13256
+ return { frontmatter: {}, body: content };
13257
+ }
13258
+ const yamlBlock = trimmed.substring(3, closingIndex).trim();
13259
+ const afterClose = closingIndex + 4;
13260
+ const bodyStart = trimmed[afterClose] === "\n" ? afterClose + 1 : afterClose;
13261
+ const body = trimmed.substring(bodyStart);
13262
+ let frontmatter = {};
13263
+ try {
13264
+ const parsed = yaml.load(yamlBlock);
13265
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
13266
+ frontmatter = parsed;
13267
+ }
13268
+ } catch {
13269
+ return { frontmatter: {}, body: content };
13270
+ }
13271
+ return { frontmatter, body };
13272
+ }
13273
+ function stripFrontmatter(content) {
13274
+ const { body } = parseSkillMdFrontmatter(content);
13275
+ return body;
13276
+ }
13277
+ var init_skill_md_parser = __esm({
13278
+ "libs/sdk/src/skill/skill-md-parser.ts"() {
13279
+ "use strict";
13280
+ }
13281
+ });
13282
+
13220
13283
  // libs/sdk/src/skill/skill.utils.ts
13221
13284
  import { isClass as isClass11, getMetadata as getMetadata13, depsOfClass as depsOfClass8 } from "@frontmcp/di";
13222
- import { readFile } from "@frontmcp/utils";
13285
+ import { readFile as readFile2 } from "@frontmcp/utils";
13223
13286
  function collectSkillMetadata(cls) {
13224
13287
  const extended = getMetadata13(extendedSkillMetadata, cls);
13225
13288
  const seed = extended ? { ...extended } : {};
@@ -13285,7 +13348,8 @@ async function loadInstructions(source, basePath) {
13285
13348
  }
13286
13349
  if (isFileInstructions(source)) {
13287
13350
  const filePath = basePath ? `${basePath}/${source.file}` : source.file;
13288
- return readFile(filePath, "utf-8");
13351
+ const content = await readFile2(filePath, "utf-8");
13352
+ return stripFrontmatter(content);
13289
13353
  }
13290
13354
  if (isUrlInstructions(source)) {
13291
13355
  const response = await fetch(source.url);
@@ -13304,7 +13368,12 @@ function buildSkillContent(metadata, instructions) {
13304
13368
  instructions,
13305
13369
  tools: normalizeToolRefs(metadata.tools),
13306
13370
  parameters: metadata.parameters,
13307
- examples: metadata.examples
13371
+ examples: metadata.examples,
13372
+ license: metadata.license,
13373
+ compatibility: metadata.compatibility,
13374
+ specMetadata: metadata.specMetadata,
13375
+ allowedTools: metadata.allowedTools,
13376
+ resources: metadata.resources
13308
13377
  };
13309
13378
  }
13310
13379
  function normalizeToolRefs(tools) {
@@ -13338,6 +13407,14 @@ function formatSkillForLLM(skill, availableTools, missingTools) {
13338
13407
  parts.push("");
13339
13408
  parts.push(skill.description);
13340
13409
  parts.push("");
13410
+ if (skill.license) {
13411
+ parts.push(`**License:** ${skill.license}`);
13412
+ parts.push("");
13413
+ }
13414
+ if (skill.compatibility) {
13415
+ parts.push(`**Compatibility:** ${skill.compatibility}`);
13416
+ parts.push("");
13417
+ }
13341
13418
  if (missingTools.length > 0) {
13342
13419
  parts.push("> **Warning:** Some tools referenced by this skill are not available:");
13343
13420
  parts.push(`> Missing: ${missingTools.join(", ")}`);
@@ -13412,6 +13489,7 @@ var init_skill_utils = __esm({
13412
13489
  "use strict";
13413
13490
  init_common();
13414
13491
  init_errors();
13492
+ init_skill_md_parser();
13415
13493
  }
13416
13494
  });
13417
13495
 
@@ -14697,6 +14775,7 @@ var init_plugin_registry = __esm({
14697
14775
  init_hooks_utils();
14698
14776
  init_errors();
14699
14777
  init_context();
14778
+ init_common();
14700
14779
  PluginRegistry = class _PluginRegistry extends RegistryAbstract {
14701
14780
  /** providers by token */
14702
14781
  pProviders = /* @__PURE__ */ new Map();
@@ -14715,15 +14794,29 @@ var init_plugin_registry = __esm({
14715
14794
  scope;
14716
14795
  scopeInfo;
14717
14796
  owner;
14797
+ logger;
14718
14798
  constructor(providers, list, owner, scopeInfo) {
14719
14799
  super("PluginRegistry", providers, list);
14720
14800
  this.scope = providers.getActiveScope();
14721
14801
  this.scopeInfo = scopeInfo;
14722
14802
  this.owner = owner;
14803
+ try {
14804
+ this.logger = providers.get(FrontMcpLogger)?.child("PluginRegistry");
14805
+ } catch (e) {
14806
+ console.debug("PluginRegistry: logger initialization failed", e);
14807
+ }
14723
14808
  }
14724
14809
  getPlugins() {
14725
14810
  return [...this.instances.values()];
14726
14811
  }
14812
+ /**
14813
+ * Returns the names of all registered plugins from their definition records.
14814
+ * Unlike getPlugins().map(p => p.metadata.name), this is safe because
14815
+ * raw plugin instances (e.g. DynamicPlugin subclasses) may not carry a .metadata property.
14816
+ */
14817
+ getPluginNames() {
14818
+ return [...this.defs.values()].map((rec) => rec.metadata.name);
14819
+ }
14727
14820
  buildMap(list) {
14728
14821
  const tokens = /* @__PURE__ */ new Set();
14729
14822
  const defs = /* @__PURE__ */ new Map();
@@ -14750,6 +14843,7 @@ var init_plugin_registry = __esm({
14750
14843
  }
14751
14844
  }
14752
14845
  async initialize() {
14846
+ this.logger?.verbose(`PluginRegistry: initializing ${this.tokens.size} plugin(s)`);
14753
14847
  for (const token of this.tokens) {
14754
14848
  const rec = this.defs.get(token);
14755
14849
  const deps = this.graph.get(token);
@@ -14857,6 +14951,9 @@ var init_plugin_registry = __esm({
14857
14951
  }
14858
14952
  }
14859
14953
  this.instances.set(token, pluginInstance);
14954
+ this.logger?.verbose(
14955
+ `PluginRegistry: registered plugin '${rec.metadata.name}' (${hooks.length} hook(s), ${contextExtensions?.length ?? 0} context extension(s))`
14956
+ );
14860
14957
  }
14861
14958
  }
14862
14959
  };
@@ -15990,7 +16087,7 @@ var init_config_symbols = __esm({
15990
16087
  });
15991
16088
 
15992
16089
  // libs/sdk/src/builtin/config/providers/env-loader.ts
15993
- import { readFile as readFile2, fileExists } from "@frontmcp/utils";
16090
+ import { readFile as readFile3, fileExists } from "@frontmcp/utils";
15994
16091
  import * as path from "path";
15995
16092
  function parseEnvContent(content) {
15996
16093
  const result = {};
@@ -16021,12 +16118,12 @@ async function loadEnvFiles(basePath = process.cwd(), envPath = ".env", localEnv
16021
16118
  const result = {};
16022
16119
  const envFile = path.resolve(basePath, envPath);
16023
16120
  if (await fileExists(envFile)) {
16024
- const content = await readFile2(envFile);
16121
+ const content = await readFile3(envFile);
16025
16122
  Object.assign(result, parseEnvContent(content));
16026
16123
  }
16027
16124
  const localFile = path.resolve(basePath, localEnvPath);
16028
16125
  if (await fileExists(localFile)) {
16029
- const content = await readFile2(localFile);
16126
+ const content = await readFile3(localFile);
16030
16127
  Object.assign(result, parseEnvContent(content));
16031
16128
  }
16032
16129
  return result;
@@ -16145,9 +16242,9 @@ var init_env_loader = __esm({
16145
16242
  });
16146
16243
 
16147
16244
  // libs/sdk/src/builtin/config/providers/config-loader.ts
16148
- import * as yaml from "js-yaml";
16245
+ import * as yaml2 from "js-yaml";
16149
16246
  import * as path2 from "path";
16150
- import { readFile as readFile3, fileExists as fileExists2 } from "@frontmcp/utils";
16247
+ import { readFile as readFile4, fileExists as fileExists2 } from "@frontmcp/utils";
16151
16248
  async function loadConfig(schema, options = {}) {
16152
16249
  const {
16153
16250
  basePath = process.cwd(),
@@ -16190,8 +16287,8 @@ async function loadYamlConfig(basePath, configPath) {
16190
16287
  for (const ext of extensions) {
16191
16288
  const fullPath = path2.resolve(basePath, baseName + ext);
16192
16289
  if (await fileExists2(fullPath)) {
16193
- const content = await readFile3(fullPath);
16194
- const parsed = yaml.load(content);
16290
+ const content = await readFile4(fullPath);
16291
+ const parsed = yaml2.load(content);
16195
16292
  if (parsed && typeof parsed === "object") {
16196
16293
  return parsed;
16197
16294
  }
@@ -16657,6 +16754,7 @@ var init_flow_instance = __esm({
16657
16754
  FlowClass;
16658
16755
  stages;
16659
16756
  hooks;
16757
+ logger;
16660
16758
  constructor(scope, record, deps, globalProviders) {
16661
16759
  super(scope, record);
16662
16760
  this.deps = [...deps];
@@ -16665,6 +16763,7 @@ var init_flow_instance = __esm({
16665
16763
  this.ready = this.initialize();
16666
16764
  this.plan = this.record.metadata.plan;
16667
16765
  this.hooks = scope.providers.getHooksRegistry();
16766
+ this.logger = scope.logger.child("FlowInstance");
16668
16767
  }
16669
16768
  async initialize() {
16670
16769
  const server = this.globalProviders.getActiveServer();
@@ -16699,7 +16798,8 @@ var init_flow_instance = __esm({
16699
16798
  return writeHttpResponse(response, e.output);
16700
16799
  }
16701
16800
  }
16702
- console.error("[FlowInstance] Unhandled error:", {
16801
+ this.logger.error("Unhandled error in flow", {
16802
+ flow: this.name,
16703
16803
  name: e instanceof Error ? e.name : "UnknownError",
16704
16804
  message: e instanceof Error ? e.message : String(e)
16705
16805
  });
@@ -16732,6 +16832,7 @@ var init_flow_instance = __esm({
16732
16832
  try {
16733
16833
  return this.globalProviders.get(FrontMcpContextStorage);
16734
16834
  } catch {
16835
+ this.logger.verbose("getContextStorage: FrontMcpContextStorage not available");
16735
16836
  return void 0;
16736
16837
  }
16737
16838
  }
@@ -16765,6 +16866,7 @@ var init_flow_instance = __esm({
16765
16866
  );
16766
16867
  }
16767
16868
  async run(input, deps) {
16869
+ this.logger.verbose(`run: starting flow '${this.name}'`);
16768
16870
  const scope = this.globalProviders.getActiveScope();
16769
16871
  const { FlowClass, plan: plan32, name: name33 } = this;
16770
16872
  const contextStorage = this.getContextStorage();
@@ -16800,10 +16902,10 @@ var init_flow_instance = __esm({
16800
16902
  try {
16801
16903
  metas.push(h2.metadata);
16802
16904
  } catch (e) {
16803
- console.warn(
16804
- "[flow] Ignoring injected hook that failed to materialize:",
16805
- e instanceof Error ? e.message : "Unknown error"
16806
- );
16905
+ this.logger.warn("Ignoring injected hook that failed to materialize", {
16906
+ flow: this.name,
16907
+ error: e instanceof Error ? e.message : "Unknown error"
16908
+ });
16807
16909
  }
16808
16910
  }
16809
16911
  if (metas.length) {
@@ -16911,6 +17013,7 @@ var init_flow_instance = __esm({
16911
17013
  };
16912
17014
  {
16913
17015
  const pre = await runStageGroup(plan32.pre, true);
17016
+ this.logger.verbose(`run: PRE completed, outcome=${pre.outcome}`);
16914
17017
  if (pre.outcome === "respond") {
16915
17018
  const post = await runStageGroup(plan32.post, false);
16916
17019
  if (post.outcome === "unknown_error" || post.outcome === "fail") {
@@ -16949,6 +17052,7 @@ var init_flow_instance = __esm({
16949
17052
  }
16950
17053
  if (!responded) {
16951
17054
  const exec = await runStageGroup(plan32.execute, true);
17055
+ this.logger.verbose(`run: EXECUTE completed, outcome=${exec.outcome}`);
16952
17056
  if (exec.outcome === "respond") {
16953
17057
  } else if (exec.outcome === "unknown_error" || exec.outcome === "fail") {
16954
17058
  try {
@@ -16967,6 +17071,7 @@ var init_flow_instance = __esm({
16967
17071
  }
16968
17072
  {
16969
17073
  const post = await runStageGroup(plan32.post, false);
17074
+ this.logger.verbose(`run: POST completed, outcome=${post.outcome}`);
16970
17075
  if (post.outcome === "unknown_error" || post.outcome === "fail") {
16971
17076
  try {
16972
17077
  await runErrorStage();
@@ -18456,13 +18561,19 @@ var init_app_local_instance = __esm({
18456
18561
  appPrompts;
18457
18562
  appAgents;
18458
18563
  appSkills;
18564
+ logger;
18459
18565
  constructor(record, scopeProviders) {
18460
18566
  super(record);
18461
18567
  this.scopeProviders = scopeProviders;
18462
18568
  this.id = this.metadata.id ?? idFromString(this.metadata.name);
18569
+ try {
18570
+ this.logger = scopeProviders.get(FrontMcpLogger)?.child("AppLocalInstance");
18571
+ } catch {
18572
+ }
18463
18573
  this.ready = this.initialize();
18464
18574
  }
18465
18575
  async initialize() {
18576
+ this.logger?.verbose(`Initializing app: ${this.metadata.name} (id: ${this.id})`);
18466
18577
  this.appProviders = new ProviderRegistry(this.metadata.providers ?? [], this.scopeProviders);
18467
18578
  await this.appProviders.ready;
18468
18579
  const appOwner = {
@@ -18478,15 +18589,37 @@ var init_app_local_instance = __esm({
18478
18589
  };
18479
18590
  this.appPlugins = new PluginRegistry(this.appProviders, this.metadata.plugins ?? [], appOwner, scopeInfo);
18480
18591
  await this.appPlugins.ready;
18592
+ this.logger?.verbose(`App ${this.metadata.name}: ${this.appPlugins.getPlugins().length} plugin(s) registered`);
18481
18593
  this.appAdapters = new AdapterRegistry(this.appProviders, this.metadata.adapters ?? []);
18482
18594
  await this.appAdapters.ready;
18595
+ this.logger?.verbose(`App ${this.metadata.name}: ${this.appAdapters.getAdapters().length} adapter(s) found`);
18483
18596
  this.appTools = new ToolRegistry(this.appProviders, this.metadata.tools ?? [], appOwner);
18484
18597
  await this.appTools.ready;
18598
+ const toolNames = this.appTools.getTools(true).map((t) => t.metadata.name);
18599
+ this.logger?.verbose(
18600
+ `App ${this.metadata.name}: ${toolNames.length} tool(s) registered: [${toolNames.join(", ")}]`
18601
+ );
18485
18602
  this.appResources = new ResourceRegistry(this.appProviders, this.metadata.resources ?? [], appOwner);
18486
18603
  this.appPrompts = new PromptRegistry(this.appProviders, this.metadata.prompts ?? [], appOwner);
18487
18604
  this.appAgents = new AgentRegistry(this.appProviders, this.metadata.agents ?? [], appOwner);
18488
18605
  this.appSkills = new SkillRegistry(this.appProviders, this.metadata.skills ?? [], appOwner);
18489
18606
  await Promise.all([this.appResources.ready, this.appPrompts.ready, this.appAgents.ready, this.appSkills.ready]);
18607
+ this.logger?.verbose(
18608
+ `App ${this.metadata.name}: ${this.appResources.getResources().length} resource(s) registered`
18609
+ );
18610
+ this.logger?.verbose(`App ${this.metadata.name}: ${this.appPrompts.getPrompts().length} prompt(s) registered`);
18611
+ const parts = [];
18612
+ const toolCount = this.appTools.getTools(true).length;
18613
+ const resourceCount = this.appResources.getResources().length;
18614
+ const promptCount = this.appPrompts.getPrompts().length;
18615
+ const adapterCount = this.appAdapters.getAdapters().length;
18616
+ const pluginCount = this.appPlugins.getPlugins().length;
18617
+ if (toolCount > 0) parts.push(`${toolCount} tool${toolCount !== 1 ? "s" : ""}`);
18618
+ if (resourceCount > 0) parts.push(`${resourceCount} resource${resourceCount !== 1 ? "s" : ""}`);
18619
+ if (promptCount > 0) parts.push(`${promptCount} prompt${promptCount !== 1 ? "s" : ""}`);
18620
+ if (adapterCount > 0) parts.push(`${adapterCount} adapter${adapterCount !== 1 ? "s" : ""}`);
18621
+ if (pluginCount > 0) parts.push(`${pluginCount} plugin${pluginCount !== 1 ? "s" : ""}`);
18622
+ this.logger?.info(`${this.metadata.name}: ${parts.length > 0 ? parts.join(", ") : "no entries"}`);
18490
18623
  }
18491
18624
  get providers() {
18492
18625
  return this.appProviders;
@@ -20152,6 +20285,9 @@ var init_app_remote_instance = __esm({
20152
20285
  getPlugins() {
20153
20286
  return [];
20154
20287
  }
20288
+ getPluginNames() {
20289
+ return [];
20290
+ }
20155
20291
  };
20156
20292
  EmptyAdapterRegistry = class {
20157
20293
  getAdapters() {
@@ -20532,15 +20668,21 @@ var AppRegistry;
20532
20668
  var init_app_registry = __esm({
20533
20669
  "libs/sdk/src/app/app.registry.ts"() {
20534
20670
  "use strict";
20671
+ init_common();
20535
20672
  init_app_utils();
20536
20673
  init_regsitry();
20537
20674
  init_instances();
20538
20675
  init_errors();
20539
20676
  AppRegistry = class extends RegistryAbstract {
20540
20677
  owner;
20678
+ logger;
20541
20679
  constructor(globalProviders, list, owner) {
20542
20680
  super("AppRegistry", globalProviders, list);
20543
20681
  this.owner = owner;
20682
+ try {
20683
+ this.logger = globalProviders.get(FrontMcpLogger)?.child("AppRegistry");
20684
+ } catch {
20685
+ }
20544
20686
  }
20545
20687
  buildMap(list) {
20546
20688
  const tokens = /* @__PURE__ */ new Set();
@@ -20569,6 +20711,7 @@ var init_app_registry = __esm({
20569
20711
  }
20570
20712
  /** Instantiate adapters, run fetch/transform, and populate registries. */
20571
20713
  async initialize() {
20714
+ this.logger?.verbose(`AppRegistry: initializing ${this.tokens.size} app(s)`);
20572
20715
  const readyArr = [];
20573
20716
  for (const token of this.tokens) {
20574
20717
  const rec = this.defs.get(token);
@@ -20582,8 +20725,10 @@ var init_app_registry = __esm({
20582
20725
  }
20583
20726
  this.instances.set(token, app);
20584
20727
  readyArr.push(app.ready);
20728
+ this.logger?.verbose(`AppRegistry: registered ${rec.kind} app '${rec.metadata.name}'`);
20585
20729
  }
20586
20730
  await Promise.all(readyArr);
20731
+ this.logger?.debug(`AppRegistry: initialization complete (${this.instances.size} app(s))`);
20587
20732
  }
20588
20733
  getApps() {
20589
20734
  return [...this.instances.values()];
@@ -21123,12 +21268,19 @@ var init_session_verify_flow = __esm({
21123
21268
  name13 = "session:verify";
21124
21269
  Stage13 = StageHookOf(name13);
21125
21270
  SessionVerifyFlow = class extends FlowBase {
21271
+ logger = this.scopeLogger.child("SessionVerifyFlow");
21272
+ maskSub(sub) {
21273
+ if (!sub) return "***";
21274
+ if (sub.length <= 10) return "***" + sub.slice(-4);
21275
+ return sub.slice(0, 6) + "***" + sub.slice(-4);
21276
+ }
21126
21277
  /**
21127
21278
  * Create an anonymous session with consistent structure for both public and transparent-anon modes.
21128
21279
  * Encapsulates the shared logic for session creation, payload encryption, and user derivation.
21129
21280
  */
21130
21281
  createAnonymousSession(options) {
21131
21282
  const { authMode, issuer, scopes = ["anonymous"], sessionIdHeader } = options;
21283
+ this.logger.verbose("createAnonymousSession", { authMode, hasExistingSession: !!sessionIdHeader });
21132
21284
  const machineId = getMachineId2();
21133
21285
  if (sessionIdHeader) {
21134
21286
  const existingPayload = decryptPublicSession(sessionIdHeader);
@@ -21191,6 +21343,12 @@ var init_session_verify_flow = __esm({
21191
21343
  const userAgent = request.headers?.["user-agent"] ?? void 0;
21192
21344
  const prmMetadataPath = `/.well-known/oauth-protected-resource${entryPath}${routeBase}`;
21193
21345
  const prmMetadataHeader = `Bearer resource_metadata="${baseUrl}${prmMetadataPath}"`;
21346
+ this.logger.verbose("parseInput", {
21347
+ hasAuthHeader: !!authorizationHeader,
21348
+ hasToken: !!token,
21349
+ sessionProtocol,
21350
+ hasSessionId: !!sessionIdHeader
21351
+ });
21194
21352
  this.state.set({
21195
21353
  baseUrl,
21196
21354
  authorizationHeader,
@@ -21210,6 +21368,7 @@ var init_session_verify_flow = __esm({
21210
21368
  if (this.state.token) {
21211
21369
  return;
21212
21370
  }
21371
+ this.logger.info("handlePublicMode: allowing anonymous access (public mode)");
21213
21372
  this.createAnonymousSession({
21214
21373
  authMode: "public",
21215
21374
  issuer: "public",
@@ -21218,6 +21377,7 @@ var init_session_verify_flow = __esm({
21218
21377
  });
21219
21378
  }
21220
21379
  async handleAnonymousFallback() {
21380
+ this.logger.verbose("handleAnonymousFallback: creating anonymous session (transparent-anon)");
21221
21381
  const authOptions = this.scope.auth?.options;
21222
21382
  const scopes = authOptions?.anonymousScopes ?? ["anonymous"];
21223
21383
  this.createAnonymousSession({
@@ -21228,6 +21388,7 @@ var init_session_verify_flow = __esm({
21228
21388
  });
21229
21389
  }
21230
21390
  async requireAuthorizationOrChallenge() {
21391
+ this.logger.verbose("requireAuthorizationOrChallenge: returning 401");
21231
21392
  this.respond({
21232
21393
  kind: "unauthorized",
21233
21394
  prmMetadataHeader: this.state.required.prmMetadataHeader
@@ -21237,6 +21398,7 @@ var init_session_verify_flow = __esm({
21237
21398
  const jwks = this.get(JwksService2);
21238
21399
  const token = this.state.token;
21239
21400
  if (!token) {
21401
+ this.logger.warn("verifyIfJwt: missing or empty bearer token, returning 401");
21240
21402
  this.respond({
21241
21403
  kind: "unauthorized",
21242
21404
  prmMetadataHeader: this.state.required.prmMetadataHeader
@@ -21244,6 +21406,7 @@ var init_session_verify_flow = __esm({
21244
21406
  return;
21245
21407
  }
21246
21408
  if (!isJwt(token)) {
21409
+ this.logger.warn("verifyIfJwt: token is not a JWT, returning 401");
21247
21410
  this.respond({
21248
21411
  kind: "unauthorized",
21249
21412
  prmMetadataHeader: this.state.required.prmMetadataHeader
@@ -21252,6 +21415,7 @@ var init_session_verify_flow = __esm({
21252
21415
  }
21253
21416
  const auth = this.scope.auth;
21254
21417
  if (!auth) {
21418
+ this.logger.warn("verifyIfJwt: auth registry not available, returning 401");
21255
21419
  this.respond({
21256
21420
  kind: "unauthorized",
21257
21421
  prmMetadataHeader: this.state.required.prmMetadataHeader
@@ -21260,6 +21424,8 @@ var init_session_verify_flow = __esm({
21260
21424
  }
21261
21425
  let verify;
21262
21426
  const authOptions = auth.options;
21427
+ const mode = isTransparentMode(authOptions) ? "transparent" : "gateway";
21428
+ this.logger.verbose(`verifyIfJwt: verifying using ${mode} mode`);
21263
21429
  if (isTransparentMode(authOptions)) {
21264
21430
  const primary = authOptions;
21265
21431
  const issuer = auth.issuer;
@@ -21280,6 +21446,7 @@ var init_session_verify_flow = __esm({
21280
21446
  this.state.set({ jwtPayload: result.payload });
21281
21447
  return;
21282
21448
  }
21449
+ this.logger.warn("verifyIfJwt: JWT verification failed", { error: result.error });
21283
21450
  this.respond({
21284
21451
  kind: "unauthorized",
21285
21452
  prmMetadataHeader: this.state.required.prmMetadataHeader
@@ -21294,6 +21461,7 @@ var init_session_verify_flow = __esm({
21294
21461
  required: { token }
21295
21462
  } = this.state;
21296
21463
  const session = parseSessionHeader(sessionIdHeader, token);
21464
+ this.logger.verbose("parseSessionHeader", { hasSessionId: !!sessionIdHeader, parsed: !!session });
21297
21465
  if (session) {
21298
21466
  this.state.set("session", session);
21299
21467
  }
@@ -21303,6 +21471,10 @@ var init_session_verify_flow = __esm({
21303
21471
  required: { token, user },
21304
21472
  session
21305
21473
  } = this.state;
21474
+ this.logger.info("Session verified successfully", {
21475
+ sub: this.maskSub(user.sub),
21476
+ hasSession: !!session
21477
+ });
21306
21478
  this.respond({
21307
21479
  kind: "authorized",
21308
21480
  authorization: {
@@ -25178,9 +25350,12 @@ function listToolsRequestHandler({
25178
25350
  return {
25179
25351
  requestSchema: ListToolsRequestSchema2,
25180
25352
  handler: async (request, ctx) => {
25181
- logger.verbose("tools/list: listing tools");
25353
+ logger.verbose("tools/list requested");
25354
+ const start = Date.now();
25182
25355
  try {
25183
- return await scope.runFlowForOutput("tools:list-tools", { request, ctx });
25356
+ const result = await scope.runFlowForOutput("tools:list-tools", { request, ctx });
25357
+ logger.verbose("tools/list completed", { durationMs: Date.now() - start });
25358
+ return result;
25184
25359
  } catch (e) {
25185
25360
  logger.error("tools/list failed", {
25186
25361
  error: e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e
@@ -25209,9 +25384,12 @@ function callToolRequestHandler({
25209
25384
  requestSchema: CallToolRequestSchema2,
25210
25385
  handler: async (request, ctx) => {
25211
25386
  const toolName = request.params?.name || "unknown";
25212
- logger.verbose(`tools/call: ${toolName}`);
25387
+ logger.info(`tools/call: ${toolName}`);
25388
+ const start = Date.now();
25213
25389
  try {
25214
- return await scope.runFlowForOutput("tools:call-tool", { request, ctx });
25390
+ const result = await scope.runFlowForOutput("tools:call-tool", { request, ctx });
25391
+ logger.verbose("tools/call completed", { tool: toolName, durationMs: Date.now() - start });
25392
+ return result;
25215
25393
  } catch (e) {
25216
25394
  if (e instanceof FlowControl) {
25217
25395
  if (e.type === "respond") {
@@ -25256,9 +25434,12 @@ function listResourcesRequestHandler({
25256
25434
  return {
25257
25435
  requestSchema: ListResourcesRequestSchema2,
25258
25436
  handler: async (request, ctx) => {
25259
- logger.verbose("resources/list: listing resources");
25437
+ logger.verbose("resources/list requested");
25438
+ const start = Date.now();
25260
25439
  try {
25261
- return await scope.runFlowForOutput("resources:list-resources", { request, ctx });
25440
+ const result = await scope.runFlowForOutput("resources:list-resources", { request, ctx });
25441
+ logger.verbose("resources/list completed", { durationMs: Date.now() - start });
25442
+ return result;
25262
25443
  } catch (e) {
25263
25444
  logger.error("resources/list failed", {
25264
25445
  error: e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e
@@ -25285,9 +25466,12 @@ function listResourceTemplatesRequestHandler({
25285
25466
  return {
25286
25467
  requestSchema: ListResourceTemplatesRequestSchema2,
25287
25468
  handler: async (request, ctx) => {
25288
- logger.verbose("resources/listTemplates: listing resource templates");
25469
+ logger.verbose("resources/listTemplates requested");
25470
+ const start = Date.now();
25289
25471
  try {
25290
- return await scope.runFlowForOutput("resources:list-resource-templates", { request, ctx });
25472
+ const result = await scope.runFlowForOutput("resources:list-resource-templates", { request, ctx });
25473
+ logger.verbose("resources/listTemplates completed", { durationMs: Date.now() - start });
25474
+ return result;
25291
25475
  } catch (e) {
25292
25476
  logger.error("resources/listTemplates failed", {
25293
25477
  error: e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e
@@ -25313,9 +25497,12 @@ function readResourceRequestHandler({
25313
25497
  requestSchema: ReadResourceRequestSchema2,
25314
25498
  handler: async (request, ctx) => {
25315
25499
  const uri = request.params?.uri || "unknown";
25316
- logger.verbose(`resources/read: ${uri}`);
25500
+ logger.info(`resources/read: ${uri}`);
25501
+ const start = Date.now();
25317
25502
  try {
25318
- return await scope.runFlowForOutput("resources:read-resource", { request, ctx });
25503
+ const result = await scope.runFlowForOutput("resources:read-resource", { request, ctx });
25504
+ logger.verbose("resources/read completed", { uri, durationMs: Date.now() - start });
25505
+ return result;
25319
25506
  } catch (e) {
25320
25507
  logger.error("resources/read failed", {
25321
25508
  uri,
@@ -25346,9 +25533,9 @@ function SubscribeRequestHandler({ scope }) {
25346
25533
  }
25347
25534
  const isNew = scope.notifications.subscribeResource(sessionId, uri);
25348
25535
  if (isNew) {
25349
- scope.logger.verbose(`resources/subscribe: Session ${sessionId.slice(0, 20)}... subscribed to ${uri}`);
25536
+ scope.logger.info(`resources/subscribe: Session ${sessionId.slice(0, 20)}... subscribed to ${uri}`);
25350
25537
  } else {
25351
- scope.logger.verbose(`resources/subscribe: Session ${sessionId.slice(0, 20)}... already subscribed to ${uri}`);
25538
+ scope.logger.debug(`resources/subscribe: Session ${sessionId.slice(0, 20)}... already subscribed to ${uri}`);
25352
25539
  }
25353
25540
  return {};
25354
25541
  }
@@ -25374,11 +25561,9 @@ function UnsubscribeRequestHandler({ scope }) {
25374
25561
  }
25375
25562
  const wasSubscribed = scope.notifications.unsubscribeResource(sessionId, uri);
25376
25563
  if (wasSubscribed) {
25377
- scope.logger.verbose(`resources/unsubscribe: Session ${sessionId.slice(0, 20)}... unsubscribed from ${uri}`);
25564
+ scope.logger.info(`resources/unsubscribe: Session ${sessionId.slice(0, 20)}... unsubscribed from ${uri}`);
25378
25565
  } else {
25379
- scope.logger.verbose(
25380
- `resources/unsubscribe: Session ${sessionId.slice(0, 20)}... was not subscribed to ${uri}`
25381
- );
25566
+ scope.logger.debug(`resources/unsubscribe: Session ${sessionId.slice(0, 20)}... was not subscribed to ${uri}`);
25382
25567
  }
25383
25568
  return {};
25384
25569
  }
@@ -25399,9 +25584,12 @@ function listPromptsRequestHandler({
25399
25584
  return {
25400
25585
  requestSchema: ListPromptsRequestSchema2,
25401
25586
  handler: async (request, ctx) => {
25402
- logger.verbose("prompts/list: listing prompts");
25587
+ logger.verbose("prompts/list requested");
25588
+ const start = Date.now();
25403
25589
  try {
25404
- return await scope.runFlowForOutput("prompts:list-prompts", { request, ctx });
25590
+ const result = await scope.runFlowForOutput("prompts:list-prompts", { request, ctx });
25591
+ logger.verbose("prompts/list completed", { durationMs: Date.now() - start });
25592
+ return result;
25405
25593
  } catch (e) {
25406
25594
  logger.error("prompts/list failed", {
25407
25595
  error: e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e
@@ -25427,9 +25615,12 @@ function getPromptRequestHandler({
25427
25615
  requestSchema: GetPromptRequestSchema2,
25428
25616
  handler: async (request, ctx) => {
25429
25617
  const promptName = request.params?.name || "unknown";
25430
- logger.verbose(`prompts/get: ${promptName}`);
25618
+ logger.info(`prompts/get: ${promptName}`);
25619
+ const start = Date.now();
25431
25620
  try {
25432
- return await scope.runFlowForOutput("prompts:get-prompt", { request, ctx });
25621
+ const result = await scope.runFlowForOutput("prompts:get-prompt", { request, ctx });
25622
+ logger.verbose("prompts/get completed", { prompt: promptName, durationMs: Date.now() - start });
25623
+ return result;
25433
25624
  } catch (e) {
25434
25625
  logger.error("prompts/get failed", {
25435
25626
  prompt: promptName,
@@ -25455,9 +25646,12 @@ function completeRequestHandler({
25455
25646
  return {
25456
25647
  requestSchema: CompleteRequestSchema,
25457
25648
  handler: async (request, ctx) => {
25458
- logger.verbose("completion/complete: completing");
25649
+ logger.verbose("completion/complete requested");
25650
+ const start = Date.now();
25459
25651
  try {
25460
- return await scope.runFlowForOutput("completion:complete", { request, ctx });
25652
+ const result = await scope.runFlowForOutput("completion:complete", { request, ctx });
25653
+ logger.verbose("completion/complete completed", { durationMs: Date.now() - start });
25654
+ return result;
25461
25655
  } catch (e) {
25462
25656
  logger.error("completion/complete failed", {
25463
25657
  error: e instanceof Error ? { name: e.name, message: e.message, stack: e.stack } : e
@@ -25708,6 +25902,9 @@ function formatSkillsForLlmCompact(skills) {
25708
25902
  if (tags && tags.length > 0) {
25709
25903
  lines.push(`Tags: ${tags.join(", ")}`);
25710
25904
  }
25905
+ if (skill.metadata.license) {
25906
+ lines.push(`License: ${skill.metadata.license}`);
25907
+ }
25711
25908
  parts.push(lines.join("\n"));
25712
25909
  }
25713
25910
  return parts.join("\n\n---\n\n");
@@ -25734,6 +25931,14 @@ function formatSkillForLLMWithSchemas(skill, availableTools, missingTools, toolR
25734
25931
  parts.push("");
25735
25932
  parts.push(skill.description);
25736
25933
  parts.push("");
25934
+ if (skill.license) {
25935
+ parts.push(`**License:** ${skill.license}`);
25936
+ parts.push("");
25937
+ }
25938
+ if (skill.compatibility) {
25939
+ parts.push(`**Compatibility:** ${skill.compatibility}`);
25940
+ parts.push("");
25941
+ }
25737
25942
  if (missingTools.length > 0) {
25738
25943
  parts.push("> **Warning:** Some tools are not available:");
25739
25944
  parts.push(`> Missing: ${missingTools.join(", ")}`);
@@ -25818,7 +26023,12 @@ function skillToApiResponse(skill, loadResult) {
25818
26023
  type: p.type ?? "string"
25819
26024
  })),
25820
26025
  priority: skill.metadata.priority ?? 0,
25821
- visibility: skill.metadata.visibility ?? "both"
26026
+ visibility: skill.metadata.visibility ?? "both",
26027
+ license: skill.metadata.license,
26028
+ compatibility: skill.metadata.compatibility,
26029
+ specMetadata: skill.metadata.specMetadata,
26030
+ allowedTools: skill.metadata.allowedTools,
26031
+ resources: skill.metadata.resources
25822
26032
  };
25823
26033
  if (loadResult) {
25824
26034
  result.availableTools = loadResult.availableTools;
@@ -28435,10 +28645,12 @@ var init_handle_streamable_http_flow = __esm({
28435
28645
  const { request } = this.rawInput;
28436
28646
  const authorization = request[ServerRequestTokens.auth];
28437
28647
  const { token } = authorization;
28648
+ const logger = this.scopeLogger.child("handle:streamable-http:parseInput");
28438
28649
  const raw = request.headers?.["mcp-session-id"];
28439
28650
  const rawMcpSessionHeader = typeof raw === "string" ? raw : void 0;
28440
28651
  const mcpSessionHeader = validateMcpSessionHeader(rawMcpSessionHeader);
28441
28652
  if (raw !== void 0 && !mcpSessionHeader) {
28653
+ logger.warn("parseInput: invalid mcp-session-id header");
28442
28654
  this.respond(httpRespond.sessionNotFound("invalid session id"));
28443
28655
  return;
28444
28656
  }
@@ -28461,24 +28673,32 @@ var init_handle_streamable_http_flow = __esm({
28461
28673
  });
28462
28674
  }
28463
28675
  this.state.set(stateSchema18.parse({ token, session }));
28676
+ logger.info("parseInput: session resolved", { sessionId: session.id?.slice(0, 20) });
28464
28677
  }
28465
28678
  async router() {
28466
28679
  const { request } = this.rawInput;
28680
+ const logger = this.scopeLogger.child("handle:streamable-http:router");
28467
28681
  if (request.method.toUpperCase() === "GET") {
28468
28682
  this.state.set("requestType", "sseListener");
28683
+ logger.info("router: requestType=sseListener, method=GET");
28469
28684
  return;
28470
28685
  }
28471
28686
  const body = request.body;
28472
28687
  const method = body?.method;
28473
28688
  if (method === "initialize") {
28474
28689
  this.state.set("requestType", "initialize");
28690
+ logger.info("router: requestType=initialize, method=POST");
28475
28691
  } else if (typeof method === "string" && method.startsWith("ui/")) {
28476
28692
  this.state.set("requestType", "extApps");
28693
+ logger.info(`router: requestType=extApps, method=${method}`);
28477
28694
  } else if (ElicitResultSchema2.safeParse(request.body?.result).success) {
28478
28695
  this.state.set("requestType", "elicitResult");
28696
+ logger.info("router: requestType=elicitResult, method=POST");
28479
28697
  } else if (method && RequestSchema.safeParse(request.body).success) {
28480
28698
  this.state.set("requestType", "message");
28699
+ logger.info(`router: requestType=message, method=${method}`);
28481
28700
  } else {
28701
+ logger.warn("router: invalid request, no valid method");
28482
28702
  this.respond(httpRespond.rpcError("Invalid Request"));
28483
28703
  }
28484
28704
  }
@@ -28488,7 +28708,7 @@ var init_handle_streamable_http_flow = __esm({
28488
28708
  const { request, response } = this.rawInput;
28489
28709
  const { token, session } = this.state.required;
28490
28710
  logger.info("onInitialize: creating transport", {
28491
- sessionId: session.id.slice(0, 30),
28711
+ sessionId: session.id?.slice(0, 20),
28492
28712
  hasToken: !!token,
28493
28713
  tokenPrefix: token?.slice(0, 10)
28494
28714
  });
@@ -28521,12 +28741,12 @@ var init_handle_streamable_http_flow = __esm({
28521
28741
  let transport = await transportService.getTransporter("streamable-http", token, session.id);
28522
28742
  if (!transport) {
28523
28743
  try {
28524
- logger.info("onElicitResult: transport not in memory, checking stored session", {
28744
+ logger.verbose("onElicitResult: transport not in memory, checking stored session", {
28525
28745
  sessionId: session.id?.slice(0, 20)
28526
28746
  });
28527
28747
  const storedSession = await transportService.getStoredSession("streamable-http", token, session.id);
28528
28748
  if (storedSession) {
28529
- logger.info("onElicitResult: recreating transport from stored session", {
28749
+ logger.verbose("onElicitResult: recreating transport from stored session", {
28530
28750
  sessionId: session.id?.slice(0, 20),
28531
28751
  createdAt: storedSession.createdAt,
28532
28752
  initialized: storedSession.initialized
@@ -28569,19 +28789,19 @@ var init_handle_streamable_http_flow = __esm({
28569
28789
  hasToken: !!token
28570
28790
  });
28571
28791
  let transport = await transportService.getTransporter("streamable-http", token, session.id);
28572
- logger.info("onMessage: getTransporter result", { found: !!transport });
28792
+ logger.verbose("onMessage: getTransporter result", { found: !!transport });
28573
28793
  if (!transport) {
28574
28794
  try {
28575
- logger.info("onMessage: transport not in memory, checking Redis", {
28795
+ logger.verbose("onMessage: transport not in memory, checking Redis", {
28576
28796
  sessionId: session.id?.slice(0, 20)
28577
28797
  });
28578
28798
  const storedSession = await transportService.getStoredSession("streamable-http", token, session.id);
28579
- logger.info("onMessage: getStoredSession result", {
28799
+ logger.verbose("onMessage: getStoredSession result", {
28580
28800
  found: !!storedSession,
28581
28801
  initialized: storedSession?.initialized
28582
28802
  });
28583
28803
  if (storedSession) {
28584
- logger.info("Recreating transport from Redis session", {
28804
+ logger.verbose("onMessage: recreating transport from stored session", {
28585
28805
  sessionId: session.id?.slice(0, 20),
28586
28806
  createdAt: storedSession.createdAt,
28587
28807
  initialized: storedSession.initialized
@@ -28593,7 +28813,7 @@ var init_handle_streamable_http_flow = __esm({
28593
28813
  storedSession,
28594
28814
  response
28595
28815
  );
28596
- logger.info("onMessage: transport recreated successfully");
28816
+ logger.verbose("onMessage: transport recreated successfully");
28597
28817
  }
28598
28818
  } catch (error) {
28599
28819
  logger.warn("Failed to recreate transport from stored session", {
@@ -28673,6 +28893,7 @@ var init_handle_streamable_http_flow = __esm({
28673
28893
  }
28674
28894
  }
28675
28895
  if (!transport) {
28896
+ logger.warn("onSseListener: transport not found", { sessionId: session.id?.slice(0, 20) });
28676
28897
  this.respond(httpRespond.notFound("Session not found"));
28677
28898
  return;
28678
28899
  }
@@ -28691,12 +28912,12 @@ var init_handle_streamable_http_flow = __esm({
28691
28912
  let transport = await transportService.getTransporter("streamable-http", token, session.id);
28692
28913
  if (!transport) {
28693
28914
  try {
28694
- logger.info("onExtApps: transport not in memory, checking stored session", {
28915
+ logger.verbose("onExtApps: transport not in memory, checking stored session", {
28695
28916
  sessionId: session.id?.slice(0, 20)
28696
28917
  });
28697
28918
  const storedSession = await transportService.getStoredSession("streamable-http", token, session.id);
28698
28919
  if (storedSession) {
28699
- logger.info("onExtApps: recreating transport from stored session", {
28920
+ logger.verbose("onExtApps: recreating transport from stored session", {
28700
28921
  sessionId: session.id?.slice(0, 20),
28701
28922
  createdAt: storedSession.createdAt,
28702
28923
  initialized: storedSession.initialized
@@ -28719,8 +28940,14 @@ var init_handle_streamable_http_flow = __esm({
28719
28940
  if (!transport) {
28720
28941
  const wasCreated = await transportService.wasSessionCreatedAsync("streamable-http", token, session.id);
28721
28942
  if (wasCreated) {
28943
+ logger.info("onExtApps: session expired - client should re-initialize", {
28944
+ sessionId: session.id?.slice(0, 20)
28945
+ });
28722
28946
  this.respond(httpRespond.sessionExpired("session expired"));
28723
28947
  } else {
28948
+ logger.warn("onExtApps: session not initialized - client attempted request without initializing", {
28949
+ sessionId: session.id?.slice(0, 20)
28950
+ });
28724
28951
  this.respond(httpRespond.sessionNotFound("session not initialized"));
28725
28952
  }
28726
28953
  return;
@@ -29005,9 +29232,11 @@ var init_handle_stateless_http_flow = __esm({
29005
29232
  name = name22;
29006
29233
  async parseInput() {
29007
29234
  const { request } = this.rawInput;
29235
+ const logger = this.scope.logger.child("HandleStatelessHttpFlow");
29008
29236
  const auth = request[ServerRequestTokens.auth];
29009
29237
  const token = auth?.token;
29010
29238
  const isAuthenticated = !!token && token.length > 0;
29239
+ logger.verbose("parseInput", { isAuthenticated, hasToken: !!token });
29011
29240
  this.state.set(
29012
29241
  stateSchema20.parse({
29013
29242
  token: token || void 0,
@@ -29017,28 +29246,44 @@ var init_handle_stateless_http_flow = __esm({
29017
29246
  }
29018
29247
  async router() {
29019
29248
  const { request } = this.rawInput;
29249
+ const logger = this.scope.logger.child("HandleStatelessHttpFlow");
29020
29250
  const body = request.body;
29021
29251
  const method = body?.method;
29022
29252
  if (method === "initialize") {
29023
29253
  this.state.set("requestType", "initialize");
29254
+ logger.info("router: requestType=initialize, method=POST");
29024
29255
  } else if (method && RequestSchema2.safeParse(request.body).success) {
29025
29256
  this.state.set("requestType", "message");
29257
+ logger.info(`router: requestType=message, method=${method}`);
29026
29258
  } else {
29259
+ logger.warn("router: invalid request, no valid method");
29027
29260
  this.respond(httpRespond.rpcError("Invalid Request"));
29028
29261
  }
29029
29262
  }
29030
29263
  async handleRequest() {
29031
29264
  const transportService = this.scope.transportService;
29265
+ const logger = this.scope.logger.child("HandleStatelessHttpFlow");
29032
29266
  const { request, response } = this.rawInput;
29033
29267
  const { token, isAuthenticated, requestType } = this.state;
29268
+ logger.info(`handleRequest: using ${isAuthenticated ? "authenticated" : "anonymous"} stateless transport`);
29034
29269
  const transport = isAuthenticated && token ? await transportService.getOrCreateAuthenticatedStatelessTransport("stateless-http", token, response) : await transportService.getOrCreateAnonymousStatelessTransport("stateless-http", response);
29035
29270
  if (!request.headers["mcp-session-id"]) {
29036
29271
  request.headers["mcp-session-id"] = "__stateless__";
29272
+ logger.verbose("handleRequest: injected __stateless__ session ID");
29037
29273
  }
29038
- if (requestType === "initialize") {
29039
- await transport.initialize(request, response);
29040
- } else {
29041
- await transport.handleRequest(request, response);
29274
+ logger.verbose(`handleRequest: requestType=${requestType}, forwarding to transport`);
29275
+ try {
29276
+ if (requestType === "initialize") {
29277
+ await transport.initialize(request, response);
29278
+ } else {
29279
+ await transport.handleRequest(request, response);
29280
+ }
29281
+ } catch (error) {
29282
+ logger.error("handleRequest: transport failed", {
29283
+ requestType,
29284
+ error: error instanceof Error ? { name: error.name, message: error.message } : String(error)
29285
+ });
29286
+ throw error;
29042
29287
  }
29043
29288
  this.handled();
29044
29289
  }
@@ -32877,7 +33122,11 @@ var init_call_agent_flow = __esm({
32877
33122
  this.logger.info("finalize: sending response", {
32878
33123
  agent: agent.metadata.name,
32879
33124
  hasContent: Array.isArray(result.content) && result.content.length > 0,
32880
- contentLength: Array.isArray(result.content) ? result.content.length : 0,
33125
+ contentParts: Array.isArray(result.content) ? result.content.length : 0,
33126
+ contentBytes: Array.isArray(result.content) ? result.content.reduce((sum, part) => {
33127
+ const str = JSON.stringify(part);
33128
+ return sum + (typeof Buffer !== "undefined" ? Buffer.byteLength(str, "utf8") : new TextEncoder().encode(str).byteLength);
33129
+ }, 0) : 0,
32881
33130
  hasStructuredContent: result.structuredContent !== void 0,
32882
33131
  hasMeta: result._meta !== void 0,
32883
33132
  metaKeys: result._meta ? Object.keys(result._meta) : [],
@@ -33326,30 +33575,30 @@ var require_dist = __commonJS({
33326
33575
  sqliteStorageOptionsSchema: () => sqliteStorageOptionsSchema
33327
33576
  });
33328
33577
  module.exports = __toCommonJS2(index_exports);
33329
- var import_utils55 = __require("@frontmcp/utils");
33578
+ var import_utils56 = __require("@frontmcp/utils");
33330
33579
  var HKDF_SALT = new TextEncoder().encode("frontmcp-sqlite-storage-v1");
33331
33580
  var HKDF_INFO = new TextEncoder().encode("aes-256-gcm-value-encryption");
33332
33581
  var KEY_LENGTH = 32;
33333
33582
  function deriveEncryptionKey(secret) {
33334
33583
  const ikm = new TextEncoder().encode(secret);
33335
- return (0, import_utils55.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
33584
+ return (0, import_utils56.hkdfSha256)(ikm, HKDF_SALT, HKDF_INFO, KEY_LENGTH);
33336
33585
  }
33337
33586
  var SEPARATOR = ":";
33338
33587
  function encryptValue(key, plaintext) {
33339
- const iv = (0, import_utils55.randomBytes)(12);
33588
+ const iv = (0, import_utils56.randomBytes)(12);
33340
33589
  const plaintextBytes = new TextEncoder().encode(plaintext);
33341
- const { ciphertext, tag } = (0, import_utils55.encryptAesGcm)(key, plaintextBytes, iv);
33342
- return [(0, import_utils55.base64urlEncode)(iv), (0, import_utils55.base64urlEncode)(tag), (0, import_utils55.base64urlEncode)(ciphertext)].join(SEPARATOR);
33590
+ const { ciphertext, tag } = (0, import_utils56.encryptAesGcm)(key, plaintextBytes, iv);
33591
+ return [(0, import_utils56.base64urlEncode)(iv), (0, import_utils56.base64urlEncode)(tag), (0, import_utils56.base64urlEncode)(ciphertext)].join(SEPARATOR);
33343
33592
  }
33344
33593
  function decryptValue(key, encrypted) {
33345
33594
  const parts = encrypted.split(SEPARATOR);
33346
33595
  if (parts.length !== 3) {
33347
33596
  throw new Error("Invalid encrypted value format");
33348
33597
  }
33349
- const iv = (0, import_utils55.base64urlDecode)(parts[0]);
33350
- const tag = (0, import_utils55.base64urlDecode)(parts[1]);
33351
- const ciphertext = (0, import_utils55.base64urlDecode)(parts[2]);
33352
- const plaintext = (0, import_utils55.decryptAesGcm)(key, ciphertext, iv, tag);
33598
+ const iv = (0, import_utils56.base64urlDecode)(parts[0]);
33599
+ const tag = (0, import_utils56.base64urlDecode)(parts[1]);
33600
+ const ciphertext = (0, import_utils56.base64urlDecode)(parts[2]);
33601
+ const plaintext = (0, import_utils56.decryptAesGcm)(key, ciphertext, iv, tag);
33353
33602
  return new TextDecoder().decode(plaintext);
33354
33603
  }
33355
33604
  var SqliteKvStore = class {
@@ -34227,10 +34476,13 @@ var init_scope_instance = __esm({
34227
34476
  const scopeProviders = this.scopeProviders;
34228
34477
  this.scopeHooks = new HookRegistry(scopeProviders, []);
34229
34478
  await this.scopeHooks.ready;
34479
+ this.logger.verbose("HookRegistry initialized");
34230
34480
  this.scopeFlows = new FlowRegistry(scopeProviders, [HttpRequestFlow]);
34231
34481
  await this.scopeFlows.ready;
34482
+ this.logger.verbose("FlowRegistry initialized");
34232
34483
  const transportConfig = this.metadata.transport;
34233
34484
  this.transportService = new TransportService(this, transportConfig?.persistence);
34485
+ this.logger.verbose("TransportService initialized");
34234
34486
  const eventStoreConfig = transportConfig?.eventStore;
34235
34487
  if (eventStoreConfig?.enabled) {
34236
34488
  const { eventStore } = createEventStore(eventStoreConfig, this.logger);
@@ -34252,7 +34504,10 @@ var init_scope_instance = __esm({
34252
34504
  }
34253
34505
  this.scopeAuth = new AuthRegistry(this, scopeProviders, [], scopeRef, this.metadata.auth);
34254
34506
  await this.scopeAuth.ready;
34507
+ this.logger.verbose("AuthRegistry initialized");
34255
34508
  this.scopeApps = new AppRegistry(this.scopeProviders, this.metadata.apps, scopeRef);
34509
+ const appCount = this.metadata.apps.length;
34510
+ this.logger.info(`Initializing ${appCount} app(s)...`);
34256
34511
  await this.scopeApps.ready;
34257
34512
  const serverPlugins = this.metadata.plugins ?? [];
34258
34513
  if (serverPlugins.length > 0) {
@@ -34264,15 +34519,20 @@ var init_scope_instance = __esm({
34264
34519
  };
34265
34520
  this.scopePlugins = new PluginRegistry(this.scopeProviders, serverPlugins, scopeRef, serverPluginScopeInfo);
34266
34521
  await this.scopePlugins.ready;
34522
+ const pluginNames = this.scopePlugins.getPluginNames();
34523
+ this.logger.verbose(`PluginRegistry initialized (${pluginNames.length} plugin(s): [${pluginNames.join(", ")}])`);
34267
34524
  }
34268
34525
  this.scopeTools = new ToolRegistry(this.scopeProviders, [], scopeRef);
34269
34526
  await this.scopeTools.ready;
34527
+ const toolNames = this.scopeTools.getTools(true).map((t) => t.metadata.name);
34528
+ this.logger.verbose(`ToolRegistry initialized with initial ${toolNames.length} tool(s): [${toolNames.join(", ")}]`);
34270
34529
  if (elicitationEnabled) {
34271
34530
  this.registerSendElicitationResultTool(scopeRef);
34272
34531
  }
34273
34532
  this.toolUIRegistry = new ToolUIRegistry();
34274
34533
  this.scopeResources = new ResourceRegistry(this.scopeProviders, [], scopeRef);
34275
34534
  await this.scopeResources.ready;
34535
+ this.logger.verbose(`ResourceRegistry initialized (${this.scopeResources.getResources().length} resource(s))`);
34276
34536
  const toolsWithUI = this.scopeTools.getTools(true).filter((t) => hasUIConfig(t.metadata));
34277
34537
  if (toolsWithUI.length > 0) {
34278
34538
  this.scopeResources.registerDynamicResource(StaticWidgetResourceTemplate);
@@ -34378,10 +34638,13 @@ var init_scope_instance = __esm({
34378
34638
  }
34379
34639
  this.scopePrompts = new PromptRegistry(this.scopeProviders, [], scopeRef);
34380
34640
  await this.scopePrompts.ready;
34641
+ this.logger.verbose(`PromptRegistry initialized (${this.scopePrompts.getPrompts().length} prompt(s))`);
34381
34642
  this.scopeAgents = new AgentRegistry(this.scopeProviders, [], scopeRef);
34382
34643
  await this.scopeAgents.ready;
34644
+ this.logger.verbose(`AgentRegistry initialized (${this.scopeAgents.getAgents().length} agent(s))`);
34383
34645
  this.scopeSkills = new SkillRegistry(this.scopeProviders, this.metadata.skills ?? [], scopeRef);
34384
34646
  await this.scopeSkills.ready;
34647
+ this.logger.verbose(`SkillRegistry initialized (${this.scopeSkills.getSkills().length} skill(s))`);
34385
34648
  if (this.scopeSkills.hasAny()) {
34386
34649
  const store = createSkillSessionStore({ type: "memory" });
34387
34650
  this._skillSession = new SkillSessionManager(
@@ -34438,6 +34701,7 @@ var init_scope_instance = __esm({
34438
34701
  });
34439
34702
  this.notificationService = new NotificationService(this);
34440
34703
  await this.notificationService.initialize();
34704
+ this.logger.verbose("NotificationService initialized");
34441
34705
  await this.scopeFlows.registryFlows([
34442
34706
  SetLevelFlow,
34443
34707
  CompleteFlow,
@@ -34446,7 +34710,20 @@ var init_scope_instance = __esm({
34446
34710
  ElicitationResultFlow
34447
34711
  ]);
34448
34712
  await this.auth.ready;
34449
- this.logger.info("Initializing multi-app scope", this.metadata);
34713
+ this.logger.info(`Scope ready \u2014 ${this.formatScopeSummary()}`);
34714
+ }
34715
+ formatScopeSummary() {
34716
+ const entries = [];
34717
+ const add = (count, label) => {
34718
+ if (count > 0) entries.push(`${count} ${label}${count !== 1 ? "s" : ""}`);
34719
+ };
34720
+ add(this.scopeApps.getApps().length, "app");
34721
+ add(this.scopeTools.getTools(true).length, "tool");
34722
+ add(this.scopeResources.getResources().length, "resource");
34723
+ add(this.scopePrompts.getPrompts().length, "prompt");
34724
+ add(this.scopeAgents.getAgents().length, "agent");
34725
+ add(this.scopeSkills.getSkills().length, "skill");
34726
+ return entries.length > 0 ? entries.join(", ") : "empty";
34450
34727
  }
34451
34728
  get defaultScopeProviders() {
34452
34729
  return [
@@ -34685,6 +34962,7 @@ var ScopeRegistry;
34685
34962
  var init_scope_registry = __esm({
34686
34963
  "libs/sdk/src/scope/scope.registry.ts"() {
34687
34964
  "use strict";
34965
+ init_common();
34688
34966
  init_regsitry();
34689
34967
  init_front_mcp_tokens2();
34690
34968
  init_app_utils();
@@ -34692,9 +34970,11 @@ var init_scope_registry = __esm({
34692
34970
  init_scope_instance();
34693
34971
  init_errors();
34694
34972
  ScopeRegistry = class extends RegistryAbstract {
34973
+ logger;
34695
34974
  constructor(globalProviders) {
34696
34975
  const metadata = globalProviders.get(FrontMcpConfig);
34697
34976
  super("ScopeRegistry", globalProviders, metadata);
34977
+ this.logger = globalProviders.get(FrontMcpLogger)?.child("ScopeRegistry");
34698
34978
  }
34699
34979
  buildMap(metadata) {
34700
34980
  const tokens = /* @__PURE__ */ new Set();
@@ -34751,6 +35031,7 @@ var init_scope_registry = __esm({
34751
35031
  }
34752
35032
  }
34753
35033
  async initialize() {
35034
+ this.logger?.verbose(`ScopeRegistry: initializing ${this.tokens.size} scope(s)`);
34754
35035
  for (const token of this.tokens) {
34755
35036
  const rec = this.defs.get(token);
34756
35037
  let scope;
@@ -34766,7 +35047,9 @@ var init_scope_registry = __esm({
34766
35047
  }
34767
35048
  await scope.ready;
34768
35049
  this.instances.set(token, scope);
35050
+ this.logger?.verbose(`ScopeRegistry: initialized scope '${tokenName16(token)}'`);
34769
35051
  }
35052
+ this.logger?.verbose(`ScopeRegistry: initialization complete (${this.instances.size} scope(s))`);
34770
35053
  }
34771
35054
  /**
34772
35055
  * Get all initialized scope instances.
@@ -36201,6 +36484,7 @@ var init_front_mcp = __esm({
36201
36484
  logger;
36202
36485
  providers;
36203
36486
  scopes;
36487
+ log;
36204
36488
  constructor(config) {
36205
36489
  this.config = config;
36206
36490
  this.ready = this.initialize();
@@ -36210,10 +36494,16 @@ var init_front_mcp = __esm({
36210
36494
  await this.providers.ready;
36211
36495
  this.logger = new LoggerRegistry(this.providers);
36212
36496
  await this.logger.ready;
36497
+ this.log = this.providers.get(FrontMcpLogger);
36498
+ const name33 = this.config.info?.name;
36499
+ const version = this.config.info?.version;
36500
+ const tag = [name33, version].filter(Boolean).join(" v");
36501
+ this.log?.info(`Initializing FrontMCP${tag ? ` "${tag}"` : ""}...`);
36213
36502
  this.scopes = new ScopeRegistry(this.providers);
36214
36503
  await this.scopes.ready;
36215
36504
  }
36216
36505
  async start() {
36506
+ this.log?.info("Starting FrontMCP server...");
36217
36507
  const server = this.providers.get(FrontMcpServer);
36218
36508
  if (!server) {
36219
36509
  throw new ServerNotFoundError();
@@ -36237,6 +36527,7 @@ var init_front_mcp = __esm({
36237
36527
  const frontMcp = new _FrontMcpInstance2(options);
36238
36528
  await frontMcp.ready;
36239
36529
  await frontMcp.start();
36530
+ frontMcp.log?.info("FrontMCP bootstrap complete");
36240
36531
  }
36241
36532
  /**
36242
36533
  * Creates and initializes a FrontMCP instance without starting the HTTP server.
@@ -36257,6 +36548,7 @@ var init_front_mcp = __esm({
36257
36548
  throw new ServerNotFoundError();
36258
36549
  }
36259
36550
  server.prepare();
36551
+ frontMcp.log?.info("FrontMCP handler created (serverless mode)");
36260
36552
  return server.getHandler();
36261
36553
  }
36262
36554
  /**
@@ -36316,6 +36608,7 @@ var init_front_mcp = __esm({
36316
36608
  if (scopes.length === 0) {
36317
36609
  throw new InternalMcpError("No scopes initialized. Ensure at least one app is configured.");
36318
36610
  }
36611
+ frontMcp.log?.info("FrontMCP direct server created");
36319
36612
  return new DirectMcpServerImpl(scopes[0]);
36320
36613
  }
36321
36614
  /**
@@ -36383,7 +36676,7 @@ var init_front_mcp = __esm({
36383
36676
  const frontMcp = new _FrontMcpInstance2(parsedConfig);
36384
36677
  await frontMcp.ready;
36385
36678
  await frontMcp.start();
36386
- console.log(`MCP server listening on unix://${socketPath}`);
36679
+ frontMcp.log?.info(`MCP server listening on unix://${socketPath}`);
36387
36680
  const cleanup = async () => {
36388
36681
  try {
36389
36682
  if (await fileExists4(socketPath)) {
@@ -39451,6 +39744,36 @@ var init_skill_entry = __esm({
39451
39744
  getPriority() {
39452
39745
  return this.metadata.priority ?? 0;
39453
39746
  }
39747
+ /**
39748
+ * Get the skill's license.
39749
+ */
39750
+ getLicense() {
39751
+ return this.metadata.license;
39752
+ }
39753
+ /**
39754
+ * Get the skill's compatibility notes.
39755
+ */
39756
+ getCompatibility() {
39757
+ return this.metadata.compatibility;
39758
+ }
39759
+ /**
39760
+ * Get the skill's spec metadata (arbitrary key-value pairs).
39761
+ */
39762
+ getSpecMetadata() {
39763
+ return this.metadata.specMetadata;
39764
+ }
39765
+ /**
39766
+ * Get the skill's allowed tools (space-delimited string).
39767
+ */
39768
+ getAllowedTools() {
39769
+ return this.metadata.allowedTools;
39770
+ }
39771
+ /**
39772
+ * Get the skill's bundled resource directories.
39773
+ */
39774
+ getResources() {
39775
+ return this.metadata.resources;
39776
+ }
39454
39777
  };
39455
39778
  }
39456
39779
  });