@caplets/core 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,6 @@
1
- import { A as CompleteRequestSchema, At as string, B as InitializedNotificationSchema, C as assertToolsCallTaskCapability, Ct as resolveProjectConfigPath, D as toJsonSchemaCompat, Dt as ZodOptional, E as mergeCapabilities, Et as SERVER_ID_PATTERN, F as ElicitResultSchema, Ft as toSafeError, G as ListResourcesRequestSchema, H as LATEST_PROTOCOL_VERSION, I as EmptyResultSchema, It as __commonJSMin, J as LoggingLevelSchema, K as ListRootsResultSchema, L as ErrorCode, Lt as __require, M as CreateMessageResultWithToolsSchema, Mt as CAPLETS_ERROR_CODES, N as CreateTaskResultSchema, Nt as CapletsError, O as CallToolRequestSchema, Ot as literal, Pt as redactSecrets, Q as SetLevelRequestSchema, R as GetPromptRequestSchema, Rt as __toESM, S as assertClientRequestTaskCapability, St as resolveProjectCapletsRoot, T as Protocol, Tt as validateCapletFile, U as ListPromptsRequestSchema, V as JSONRPCMessageSchema, W as ListResourceTemplatesRequestSchema, X as ReadResourceRequestSchema, Y as McpError, Z as SUPPORTED_PROTOCOL_VERSIONS, _ as readTokenBundle, _t as loadConfigWithSources, a as resolveCapletsServer, at as isJSONRPCResultResponse, b as serializeMessage, bt as resolveCapletsRoot, c as handleServerTool, ct as getParseErrorMessage, d as runGenericOAuthFlow, dt as isZ4Schema, et as assertCompleteRequestPrompt, f as runOAuthFlow, ft as normalizeObjectSchema, g as isTokenBundleExpired, gt as loadConfig, h as deleteTokenBundle, ht as safeParseAsync, i as resolveCapletsMode, it as isJSONRPCRequest, j as CreateMessageResultSchema, jt as url, k as CallToolResultSchema, kt as object, l as ServerRegistry, lt as getSchemaDescription, m as startOAuthFlow, mt as safeParse, nt as isInitializeRequest, o as CapletsEngine, ot as getLiteralValue, p as startGenericOAuthFlow, pt as objectFromShape, q as ListToolsRequestSchema, r as parseServerBaseUrl, rt as isJSONRPCErrorResponse, s as generatedToolInputSchema, st as getObjectShape, t as controlUrlForBase, tt as assertCompleteRequestResourceTemplate, u as capabilityDescription, ut as isSchemaOptional, vt as parseConfig, w as AjvJsonSchemaValidator, wt as discoverCapletFiles, xt as resolveConfigPath, y as ReadBuffer, yt as DEFAULT_AUTH_DIR, z as InitializeRequestSchema } from "./options-CJEOqS87.js";
1
+ import { $ as assertCompleteRequestPrompt, A as CreateMessageResultSchema, At as toSafeError, B as JSONRPCMessageSchema, C as AjvJsonSchemaValidator, D as CallToolRequestSchema, Dt as CAPLETS_ERROR_CODES, E as toJsonSchemaCompat, Et as SERVER_ID_PATTERN, F as EmptyResultSchema, G as ListRootsResultSchema, H as ListPromptsRequestSchema, I as ErrorCode, J as McpError, K as ListToolsRequestSchema, L as GetPromptRequestSchema, M as CreateTaskResultSchema, Nt as __require, O as CallToolResultSchema, Ot as CapletsError, P as ElicitResultSchema, Pt as __toESM, R as InitializeRequestSchema, S as assertToolsCallTaskCapability, St as resolveProjectCapletsRoot, T as mergeCapabilities, Tt as validateCapletFile, U as ListResourceTemplatesRequestSchema, V as LATEST_PROTOCOL_VERSION, W as ListResourcesRequestSchema, X as SUPPORTED_PROTOCOL_VERSIONS, Y as ReadResourceRequestSchema, Z as SetLevelRequestSchema, _t as parseConfig, a as resolveCapletsServer, at as getLiteralValue, bt as resolveCapletsRoot, c as ServerRegistry, ct as getSchemaDescription, d as runOAuthFlow, dt as normalizeObjectSchema, et as assertCompleteRequestResourceTemplate, f as startGenericOAuthFlow, ft as objectFromShape, g as readTokenBundle, gt as loadConfigWithSources, h as isTokenBundleExpired, ht as loadConfig, i as resolveCapletsMode, it as isJSONRPCResultResponse, j as CreateMessageResultWithToolsSchema, jt as __commonJSMin, k as CompleteRequestSchema, kt as redactSecrets, l as capabilityDescription, lt as isSchemaOptional, m as deleteTokenBundle, mt as safeParseAsync, nt as isJSONRPCErrorResponse, o as CapletsEngine, ot as getObjectShape, p as startOAuthFlow, pt as safeParse, q as LoggingLevelSchema, r as parseServerBaseUrl, rt as isJSONRPCRequest, s as handleServerTool, st as getParseErrorMessage, t as controlUrlForBase, tt as isInitializeRequest, u as runGenericOAuthFlow, ut as isZ4Schema, v as ReadBuffer, w as Protocol, wt as discoverCapletFiles, x as assertClientRequestTaskCapability, xt as resolveConfigPath, y as serializeMessage, z as InitializedNotificationSchema } from "./options-DM1cMRcp.js";
2
+ import { A as url, C as object, D as string, b as literal, d as ZodOptional, o as generatedToolInputSchema, s as generatedToolInputSchemaForCaplet } from "./generated-tool-input-schema-B6rce396.js";
3
+ import { a as formatCapletList, c as resolveCliConfigPaths, l as cliCommands, n as completionScript, o as formatConfigPaths, s as listCaplets, t as completeCliWords, u as completionShells } from "./completion-CxGG6ae3.js";
2
4
  import { accessSync, chmodSync, closeSync, constants, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
3
5
  import { basename, dirname, join, parse, relative, resolve } from "node:path";
4
6
  import { execFileSync } from "node:child_process";
@@ -1319,7 +1321,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
1319
1321
  } };
1320
1322
  //#endregion
1321
1323
  //#region package.json
1322
- var version = "0.17.0";
1324
+ var version = "0.18.0";
1323
1325
  //#endregion
1324
1326
  //#region src/serve/session.ts
1325
1327
  var CapletsMcpSession = class {
@@ -1363,6 +1365,7 @@ var CapletsMcpSession = class {
1363
1365
  if (!previousCaplet || serializeCaplet(previousCaplet) !== serializeCaplet(caplet)) tool.update({
1364
1366
  title: caplet.name,
1365
1367
  description: capabilityDescription(caplet),
1368
+ paramsSchema: generatedToolInputSchemaForCaplet(caplet).shape,
1366
1369
  callback: async (request) => this.handleTool(serverId, request),
1367
1370
  enabled: true
1368
1371
  });
@@ -1376,7 +1379,7 @@ var CapletsMcpSession = class {
1376
1379
  return this.server.registerTool(caplet.server, {
1377
1380
  title: caplet.name,
1378
1381
  description: capabilityDescription(caplet),
1379
- inputSchema: generatedToolInputSchema
1382
+ inputSchema: generatedToolInputSchemaForCaplet(caplet).shape
1380
1383
  }, async (request) => this.handleTool(caplet.server, request));
1381
1384
  }
1382
1385
  async handleTool(serverId, request) {
@@ -5042,126 +5045,6 @@ function starterConfig() {
5042
5045
  }, null, 2);
5043
5046
  }
5044
5047
  //#endregion
5045
- //#region src/cli/inspection.ts
5046
- function listCaplets(configWithSources, options) {
5047
- const { config, sources, shadows } = configWithSources;
5048
- return allCaplets(config).filter((server) => options.includeDisabled || !server.disabled).map((server) => ({
5049
- server: server.server,
5050
- backend: server.backend,
5051
- name: server.name,
5052
- description: server.description,
5053
- disabled: server.disabled,
5054
- status: initialServerStatus(server),
5055
- source: sources[server.server]?.kind ?? "unknown",
5056
- path: sources[server.server]?.path ?? null,
5057
- shadows: shadows[server.server] ?? []
5058
- })).sort((left, right) => left.server.localeCompare(right.server));
5059
- }
5060
- function initialServerStatus(server) {
5061
- return server.disabled ? "disabled" : "not_started";
5062
- }
5063
- function allCaplets(config) {
5064
- return [
5065
- ...Object.values(config.mcpServers),
5066
- ...Object.values(config.openapiEndpoints),
5067
- ...Object.values(config.graphqlEndpoints),
5068
- ...Object.values(config.httpApis),
5069
- ...Object.values(config.cliTools)
5070
- ];
5071
- }
5072
- function formatCapletList(rows, format = "plain") {
5073
- return format === "markdown" ? formatCapletListMarkdown(rows) : formatCapletListPlain(rows);
5074
- }
5075
- function formatCapletListMarkdown(rows) {
5076
- if (rows.length === 0) return "## Configured Caplets\n\nNo configured Caplets found.\n";
5077
- const heading = [
5078
- "## Configured Caplets",
5079
- "",
5080
- `${rows.length} ${rows.length === 1 ? "Caplet" : "Caplets"} shown.`,
5081
- ""
5082
- ];
5083
- const entries = rows.flatMap((row) => [
5084
- `- \`${row.server}\` — ${row.name}`,
5085
- ` - Backend: ${row.backend}`,
5086
- ` - Status: ${row.status}`,
5087
- ` - Source: ${row.source}`,
5088
- ...row.disabled ? [" - Disabled: true"] : [],
5089
- ...row.path ? [` - Path: ${row.path}`] : []
5090
- ]);
5091
- const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
5092
- if (warnings.length === 0) return `${[...heading, ...entries].join("\n")}\n`;
5093
- return `${[
5094
- ...heading,
5095
- ...entries,
5096
- "",
5097
- "Warnings:",
5098
- ...warnings.map((warning) => `- ${warning}`)
5099
- ].join("\n")}\n`;
5100
- }
5101
- function formatCapletListPlain(rows) {
5102
- if (rows.length === 0) return "No configured Caplets found.\n";
5103
- const entries = rows.map((row) => [
5104
- row.server,
5105
- ` Name: ${row.name}`,
5106
- ` Backend: ${row.backend}`,
5107
- ` Status: ${row.status}`,
5108
- ` Source: ${row.source}`,
5109
- ...row.disabled ? [" Disabled: true"] : [],
5110
- ...row.path ? [` Path: ${row.path}`] : []
5111
- ].join("\n")).join("\n\n");
5112
- const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
5113
- if (warnings.length === 0) return `Configured Caplets (${rows.length})\n\n${entries}\n`;
5114
- return `Configured Caplets (${rows.length})\n\n${entries}\n\n${warnings.join("\n")}\n`;
5115
- }
5116
- function formatSourceKind(kind) {
5117
- if (kind.startsWith("project")) return "project";
5118
- if (kind.startsWith("global")) return "global";
5119
- return kind;
5120
- }
5121
- function resolveCliConfigPaths(envConfigPath, authDir) {
5122
- const configPath = resolveConfigPath(envConfigPath);
5123
- const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
5124
- return {
5125
- userConfig: configPath,
5126
- projectConfig: resolveProjectConfigPath(),
5127
- userRoot: resolveCapletsRoot(configPath),
5128
- stateRoot: dirname(effectiveAuthDir),
5129
- projectRoot: resolveProjectCapletsRoot(),
5130
- authDir: effectiveAuthDir,
5131
- envConfig: envConfigPath ?? null
5132
- };
5133
- }
5134
- function formatConfigPaths(paths, format = "plain") {
5135
- if (format === "markdown") return formatConfigPathsMarkdown(paths);
5136
- return formatConfigPathsPlain(paths);
5137
- }
5138
- function formatConfigPathsMarkdown(paths) {
5139
- return [
5140
- "## Caplets paths",
5141
- "",
5142
- `- User config: ${paths.userConfig}`,
5143
- `- Project config: ${paths.projectConfig}`,
5144
- `- User Caplets root: ${paths.userRoot}`,
5145
- `- State root: ${paths.stateRoot}`,
5146
- `- Project Caplets root: ${paths.projectRoot}`,
5147
- `- Auth directory: ${paths.authDir}`,
5148
- `- CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
5149
- ].join("\n") + "\n";
5150
- }
5151
- function formatConfigPathsPlain(paths) {
5152
- return [
5153
- "Caplets paths",
5154
- "",
5155
- `User config: ${paths.userConfig}`,
5156
- `Project config: ${paths.projectConfig}`,
5157
- `User root: ${paths.userRoot}`,
5158
- `State root: ${paths.stateRoot}`,
5159
- `Project root: ${paths.projectRoot}`,
5160
- `Auth directory: ${paths.authDir}`,
5161
- `CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
5162
- ].join("\n") + "\n";
5163
- }
5164
- //#endregion
5165
5048
  //#region src/cli/install.ts
5166
5049
  function installCaplets(repo, options = {}) {
5167
5050
  const source = resolveInstallSource(repo);
@@ -8413,7 +8296,15 @@ const ENGINE_COMMANDS = new Set([
8413
8296
  "list_tools",
8414
8297
  "search_tools",
8415
8298
  "get_tool",
8416
- "call_tool"
8299
+ "call_tool",
8300
+ "list_resources",
8301
+ "search_resources",
8302
+ "list_resource_templates",
8303
+ "read_resource",
8304
+ "list_prompts",
8305
+ "search_prompts",
8306
+ "get_prompt",
8307
+ "complete"
8417
8308
  ]);
8418
8309
  async function dispatchRemoteCliRequest(request, context) {
8419
8310
  try {
@@ -8464,6 +8355,16 @@ async function dispatch(request, context) {
8464
8355
  ...optionalProp("force", optionalBoolean(request.arguments, "force"))
8465
8356
  })
8466
8357
  };
8358
+ if (request.command === "complete_cli") {
8359
+ const shell = optionalString(request.arguments, "shell") ?? "bash";
8360
+ if (!completionShells.includes(shell)) return [];
8361
+ const engine = new CapletsEngine(context);
8362
+ try {
8363
+ return await engine.completeCliWords(optionalStringArray(request.arguments, "words") ?? [""]);
8364
+ } finally {
8365
+ await engine.close();
8366
+ }
8367
+ }
8467
8368
  if (request.command === "auth_list") return listAuthRows({
8468
8369
  ...optionalProp("configPath", context.configPath),
8469
8370
  ...optionalProp("authDir", context.authDir)
@@ -8580,6 +8481,12 @@ function requiredString(args, key) {
8580
8481
  if (typeof value !== "string" || value.length === 0) throw new CapletsError("REQUEST_INVALID", `${key} must be a non-empty string`);
8581
8482
  return value;
8582
8483
  }
8484
+ function optionalString(args, key) {
8485
+ const value = args[key];
8486
+ if (value === void 0) return;
8487
+ if (typeof value !== "string") throw new CapletsError("REQUEST_INVALID", `${key} must be a string`);
8488
+ return value;
8489
+ }
8583
8490
  function optionalObject(args, key) {
8584
8491
  const value = args[key];
8585
8492
  if (value === void 0) return {};
@@ -9159,6 +9066,9 @@ async function runCli(args, io = {}) {
9159
9066
  throw error;
9160
9067
  }
9161
9068
  }
9069
+ function normalizeCompletionWords(words) {
9070
+ return words.map((word) => word === "__CAPLETS_TRAILING_SPACE__" ? "" : word);
9071
+ }
9162
9072
  function createProgram(io = {}) {
9163
9073
  const writeOut = io.writeOut ?? ((value) => process.stdout.write(value));
9164
9074
  const writeErr = io.writeErr ?? ((value) => process.stderr.write(value));
@@ -9173,7 +9083,27 @@ function createProgram(io = {}) {
9173
9083
  writeErr,
9174
9084
  outputError: (value, write) => write(value)
9175
9085
  });
9176
- program.command("serve").description("Serve configured Caplets as an MCP server.").option("--transport <transport>", "server transport: stdio or http").option("--host <host>", "HTTP bind host").option("--port <port>", "HTTP bind port").option("--path <path>", "HTTP service base path").option("--user <user>", "HTTP Basic Auth username").option("--password <password>", "HTTP Basic Auth password").option("--allow-unauthenticated-http", "allow unauthenticated HTTP serving on non-loopback hosts").option("--trust-proxy", "trust X-Forwarded-* headers from a reverse proxy").action(async (options) => {
9086
+ program.command(cliCommands.completion).description("Print a shell completion script.").argument("<shell>", "completion shell: bash, zsh, fish, powershell, or cmd").action((shell) => {
9087
+ if (!completionShells.includes(shell)) throw new CapletsError("REQUEST_INVALID", "completion shell must be bash, zsh, fish, powershell, or cmd");
9088
+ writeOut(completionScript(shell));
9089
+ });
9090
+ program.command(cliCommands.completeHidden, { hidden: true }).description("Internal shell completion endpoint.").option("--shell <shell>", "completion shell").allowUnknownOption(true).argument("[words...]", "words to complete").action(async (words, options) => {
9091
+ const shell = completionShells.includes(options.shell) ? options.shell : "bash";
9092
+ const remote = remoteClientForCli(io);
9093
+ const configPath = currentConfigPath();
9094
+ const completionWords = normalizeCompletionWords(words);
9095
+ let suggestions = [];
9096
+ try {
9097
+ suggestions = remote ? await remote.request("complete_cli", {
9098
+ shell,
9099
+ words: completionWords
9100
+ }) : await completeCliWords(completionWords, configPath ? { configPath } : {});
9101
+ } catch {
9102
+ suggestions = [];
9103
+ }
9104
+ if (suggestions.length > 0) writeOut(`${suggestions.join("\n")}\n`);
9105
+ });
9106
+ program.command(cliCommands.serve).description("Serve configured Caplets as an MCP server.").option("--transport <transport>", "server transport: stdio or http").option("--host <host>", "HTTP bind host").option("--port <port>", "HTTP bind port").option("--path <path>", "HTTP service base path").option("--user <user>", "HTTP Basic Auth username").option("--password <password>", "HTTP Basic Auth password").option("--allow-unauthenticated-http", "allow unauthenticated HTTP serving on non-loopback hosts").option("--trust-proxy", "trust X-Forwarded-* headers from a reverse proxy").action(async (options) => {
9177
9107
  const resolved = resolveServeOptions(options);
9178
9108
  const configPath = currentConfigPath();
9179
9109
  await (io.serve ?? ((serveOptions) => serveResolvedCaplets(serveOptions, {
@@ -9181,7 +9111,7 @@ function createProgram(io = {}) {
9181
9111
  ...io.authDir ? { authDir: io.authDir } : {}
9182
9112
  }, writeErr)))(resolved);
9183
9113
  });
9184
- program.command("init").description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
9114
+ program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
9185
9115
  const remote = remoteClientForCli(io);
9186
9116
  if (remote) {
9187
9117
  writeOut(`Created remote Caplets config at ${(await remote.request("init", { force: Boolean(options.force) })).path}\n`);
@@ -9193,7 +9123,7 @@ function createProgram(io = {}) {
9193
9123
  force: Boolean(options.force)
9194
9124
  })}\n`);
9195
9125
  });
9196
- program.command("list").description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action(async (options) => {
9126
+ program.command(cliCommands.list).description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action(async (options) => {
9197
9127
  const includeDisabled = Boolean(options.all);
9198
9128
  const remote = remoteClientForCli(io);
9199
9129
  if (remote) {
@@ -9212,7 +9142,7 @@ function createProgram(io = {}) {
9212
9142
  }
9213
9143
  writeOut(formatCapletList(rows, options.format ?? "plain"));
9214
9144
  });
9215
- program.command("install").description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("-g, --global", "install to the user Caplets root").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
9145
+ program.command(cliCommands.install).description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("-g, --global", "install to the user Caplets root").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
9216
9146
  const remote = remoteClientForCli(io);
9217
9147
  if (remote) {
9218
9148
  if (options.global) writeErr("Warning: --global is not supported in remote mode; the server controls the installation destination.\n");
@@ -9231,7 +9161,7 @@ function createProgram(io = {}) {
9231
9161
  });
9232
9162
  for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${caplet.destination}\n`);
9233
9163
  });
9234
- const add = program.command("add").description("Add generated Caplet files.");
9164
+ const add = program.command(cliCommands.add).description("Add generated Caplet files.");
9235
9165
  add.command("cli").description("Add a CLI tools Caplet.").argument("<id>", "Caplet ID/display seed").option("--repo <path>", "repository path to inspect").option("--include <items>", "comma-separated generators to include: git,gh,package").option("--command <name>", "single CLI command template to generate").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
9236
9166
  const remote = remoteClientForCli(io);
9237
9167
  if (remote) {
@@ -9312,7 +9242,7 @@ function createProgram(io = {}) {
9312
9242
  destinationRoot: addDestinationRoot(options, currentConfigPath())
9313
9243
  }));
9314
9244
  });
9315
- program.command("get-caplet").description("Print a configured Caplet card.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9245
+ program.command(cliCommands.getCaplet).description("Print a configured Caplet card.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9316
9246
  await executeOperation(caplet, { operation: "get_caplet" }, {
9317
9247
  writeOut,
9318
9248
  writeErr,
@@ -9323,7 +9253,7 @@ function createProgram(io = {}) {
9323
9253
  format: options.format
9324
9254
  });
9325
9255
  });
9326
- program.command("check-backend").description("Check backend availability for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9256
+ program.command(cliCommands.checkBackend).description("Check backend availability for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9327
9257
  await executeOperation(caplet, { operation: "check_backend" }, {
9328
9258
  writeOut,
9329
9259
  writeErr,
@@ -9334,7 +9264,7 @@ function createProgram(io = {}) {
9334
9264
  format: options.format
9335
9265
  });
9336
9266
  });
9337
- program.command("list-tools").description("List downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9267
+ program.command(cliCommands.listTools).description("List downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
9338
9268
  await executeOperation(caplet, { operation: "list_tools" }, {
9339
9269
  writeOut,
9340
9270
  writeErr,
@@ -9345,7 +9275,7 @@ function createProgram(io = {}) {
9345
9275
  format: options.format
9346
9276
  });
9347
9277
  });
9348
- program.command("search-tools").description("Search downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").argument("<query>", "search query").option("--limit <n>", "maximum number of tools to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => {
9278
+ program.command(cliCommands.searchTools).description("Search downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").argument("<query>", "search query").option("--limit <n>", "maximum number of tools to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => {
9349
9279
  await executeOperation(caplet, options.limit === void 0 ? {
9350
9280
  operation: "search_tools",
9351
9281
  query
@@ -9363,7 +9293,7 @@ function createProgram(io = {}) {
9363
9293
  format: options.format
9364
9294
  });
9365
9295
  });
9366
- program.command("get-tool").description("Print one downstream tool schema.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
9296
+ program.command(cliCommands.getTool).description("Print one downstream tool schema.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
9367
9297
  const { caplet, tool } = parseQualifiedTarget(target);
9368
9298
  await executeOperation(caplet, {
9369
9299
  operation: "get_tool",
@@ -9378,7 +9308,7 @@ function createProgram(io = {}) {
9378
9308
  format: options.format
9379
9309
  });
9380
9310
  });
9381
- program.command("call-tool").description("Call one downstream tool.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
9311
+ program.command(cliCommands.callTool).description("Call one downstream tool.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
9382
9312
  const { caplet, tool } = parseQualifiedTarget(target);
9383
9313
  await executeOperation(caplet, {
9384
9314
  operation: "call_tool",
@@ -9395,7 +9325,119 @@ function createProgram(io = {}) {
9395
9325
  format: options.format
9396
9326
  });
9397
9327
  });
9398
- const config = program.command("config").description("Inspect Caplets config locations.");
9328
+ program.command(cliCommands.listResources).description("List MCP resources for a configured MCP Caplet.").argument("<caplet>").option("--limit <n>", "maximum number of resources to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, options.limit === void 0 ? { operation: "list_resources" } : {
9329
+ operation: "list_resources",
9330
+ limit: options.limit
9331
+ }, {
9332
+ writeOut,
9333
+ writeErr,
9334
+ setExitCode,
9335
+ authDir: io.authDir,
9336
+ env,
9337
+ remote: remoteClientForCli(io),
9338
+ format: options.format
9339
+ }));
9340
+ program.command(cliCommands.searchResources).description("Search MCP resources and resource templates for a configured MCP Caplet.").argument("<caplet>").argument("<query>").option("--limit <n>", "maximum number of matches to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => executeOperation(caplet, options.limit === void 0 ? {
9341
+ operation: "search_resources",
9342
+ query
9343
+ } : {
9344
+ operation: "search_resources",
9345
+ query,
9346
+ limit: options.limit
9347
+ }, {
9348
+ writeOut,
9349
+ writeErr,
9350
+ setExitCode,
9351
+ authDir: io.authDir,
9352
+ env,
9353
+ remote: remoteClientForCli(io),
9354
+ format: options.format
9355
+ }));
9356
+ program.command(cliCommands.listResourceTemplates).description("List MCP resource templates for a configured MCP Caplet.").argument("<caplet>").option("--limit <n>", "maximum number of templates to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, options.limit === void 0 ? { operation: "list_resource_templates" } : {
9357
+ operation: "list_resource_templates",
9358
+ limit: options.limit
9359
+ }, {
9360
+ writeOut,
9361
+ writeErr,
9362
+ setExitCode,
9363
+ authDir: io.authDir,
9364
+ env,
9365
+ remote: remoteClientForCli(io),
9366
+ format: options.format
9367
+ }));
9368
+ program.command(cliCommands.readResource).description("Read one MCP resource by URI.").argument("<caplet>").argument("<uri>").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, uri, options) => executeOperation(caplet, {
9369
+ operation: "read_resource",
9370
+ uri
9371
+ }, {
9372
+ writeOut,
9373
+ writeErr,
9374
+ setExitCode,
9375
+ authDir: io.authDir,
9376
+ env,
9377
+ remote: remoteClientForCli(io),
9378
+ format: options.format
9379
+ }));
9380
+ program.command(cliCommands.listPrompts).description("List MCP prompts for a configured MCP Caplet.").argument("<caplet>").option("--limit <n>", "maximum number of prompts to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, options.limit === void 0 ? { operation: "list_prompts" } : {
9381
+ operation: "list_prompts",
9382
+ limit: options.limit
9383
+ }, {
9384
+ writeOut,
9385
+ writeErr,
9386
+ setExitCode,
9387
+ authDir: io.authDir,
9388
+ env,
9389
+ remote: remoteClientForCli(io),
9390
+ format: options.format
9391
+ }));
9392
+ program.command(cliCommands.searchPrompts).description("Search MCP prompts for a configured MCP Caplet.").argument("<caplet>").argument("<query>").option("--limit <n>", "maximum number of prompts to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => executeOperation(caplet, options.limit === void 0 ? {
9393
+ operation: "search_prompts",
9394
+ query
9395
+ } : {
9396
+ operation: "search_prompts",
9397
+ query,
9398
+ limit: options.limit
9399
+ }, {
9400
+ writeOut,
9401
+ writeErr,
9402
+ setExitCode,
9403
+ authDir: io.authDir,
9404
+ env,
9405
+ remote: remoteClientForCli(io),
9406
+ format: options.format
9407
+ }));
9408
+ program.command(cliCommands.getPrompt).description("Get one MCP prompt by name.").argument("<caplet.prompt>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of prompt arguments").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
9409
+ const { caplet, tool: prompt } = parseQualifiedTarget(target);
9410
+ await executeOperation(caplet, {
9411
+ operation: "get_prompt",
9412
+ prompt,
9413
+ arguments: parseJsonObjectOption(options.args, "get-prompt --args")
9414
+ }, {
9415
+ writeOut,
9416
+ writeErr,
9417
+ setExitCode,
9418
+ authDir: io.authDir,
9419
+ env,
9420
+ remote: remoteClientForCli(io),
9421
+ format: options.format
9422
+ });
9423
+ });
9424
+ program.command(cliCommands.complete).description("Complete an MCP prompt or resource-template argument.").argument("<caplet>").requiredOption("--argument <name>", "argument name").option("--value <value>", "argument prefix", "").option("--prompt <name>", "prompt name to complete").option("--resource-template <uri-template>", "resource template URI to complete").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => executeOperation(caplet, {
9425
+ operation: "complete",
9426
+ ref: completionRefFromOptions(options),
9427
+ argument: {
9428
+ name: options.argument,
9429
+ value: options.value
9430
+ }
9431
+ }, {
9432
+ writeOut,
9433
+ writeErr,
9434
+ setExitCode,
9435
+ authDir: io.authDir,
9436
+ env,
9437
+ remote: remoteClientForCli(io),
9438
+ format: options.format
9439
+ }));
9440
+ const config = program.command(cliCommands.config).description("Inspect Caplets config locations.");
9399
9441
  config.command("path").description("Print the effective user config path.").action(() => {
9400
9442
  writeOut(`${resolveConfigPath(currentConfigPath())}\n`);
9401
9443
  });
@@ -9407,7 +9449,7 @@ function createProgram(io = {}) {
9407
9449
  }
9408
9450
  writeOut(formatConfigPaths(paths, options.format ?? "plain"));
9409
9451
  });
9410
- const auth = program.command("auth").description("Manage OAuth credentials for remote servers.");
9452
+ const auth = program.command(cliCommands.auth).description("Manage OAuth credentials for remote servers.");
9411
9453
  auth.command("login").description("Authenticate a configured remote OAuth server.").argument("<server>", "configured server ID").option("--no-open", "print the authorization URL without opening a browser").action(async (serverId, options) => {
9412
9454
  const remote = remoteClientForCli(io);
9413
9455
  if (remote) {
@@ -9492,7 +9534,15 @@ function remoteCommandForOperation(operation) {
9492
9534
  case "list_tools":
9493
9535
  case "search_tools":
9494
9536
  case "get_tool":
9495
- case "call_tool": return operation;
9537
+ case "call_tool":
9538
+ case "list_resources":
9539
+ case "search_resources":
9540
+ case "list_resource_templates":
9541
+ case "read_resource":
9542
+ case "list_prompts":
9543
+ case "search_prompts":
9544
+ case "get_prompt":
9545
+ case "complete": return operation;
9496
9546
  default: return;
9497
9547
  }
9498
9548
  }
@@ -9540,6 +9590,29 @@ function parseCallToolArgs(value) {
9540
9590
  if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", "call-tool --args must be a JSON object");
9541
9591
  return parsed;
9542
9592
  }
9593
+ function parseJsonObjectOption(value, label) {
9594
+ if (value === void 0) return {};
9595
+ let parsed;
9596
+ try {
9597
+ parsed = JSON.parse(value);
9598
+ } catch (error) {
9599
+ throw new CapletsError("REQUEST_INVALID", `${label} must be valid JSON`, error);
9600
+ }
9601
+ if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", `${label} must be a JSON object`);
9602
+ return parsed;
9603
+ }
9604
+ function completionRefFromOptions(options) {
9605
+ if (options.prompt && options.resourceTemplate) throw new CapletsError("REQUEST_INVALID", "complete accepts either --prompt or --resource-template, not both");
9606
+ if (options.prompt) return {
9607
+ type: "prompt",
9608
+ name: options.prompt
9609
+ };
9610
+ if (options.resourceTemplate) return {
9611
+ type: "resourceTemplate",
9612
+ uri: options.resourceTemplate
9613
+ };
9614
+ throw new CapletsError("REQUEST_INVALID", "complete requires --prompt or --resource-template");
9615
+ }
9543
9616
  function isPlainObject(value) {
9544
9617
  return value !== null && typeof value === "object" && !Array.isArray(value);
9545
9618
  }
@@ -9670,6 +9743,55 @@ function markdownSummaryForOperation(result, request) {
9670
9743
  "",
9671
9744
  "Use `--format json` to inspect the full structured result."
9672
9745
  ].filter((line) => line !== void 0).join("\n");
9746
+ case "list_resources":
9747
+ case "search_resources": {
9748
+ const resources = Array.isArray(payload.resources) ? payload.resources : [];
9749
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
9750
+ const matches = Array.isArray(payload.matches) ? payload.matches : [...resources, ...templates];
9751
+ return [
9752
+ `## MCP resources for \`${id}\``,
9753
+ "",
9754
+ `${matches.length} item${matches.length === 1 ? "" : "s"} found.`,
9755
+ "",
9756
+ ...formatResourceLines(matches, "markdown")
9757
+ ].join("\n");
9758
+ }
9759
+ case "list_resource_templates": {
9760
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
9761
+ return [
9762
+ `## MCP resource templates for \`${id}\``,
9763
+ "",
9764
+ ...formatResourceLines(templates, "markdown")
9765
+ ].join("\n");
9766
+ }
9767
+ case "read_resource": return [
9768
+ `## Resource \`${String(request.uri ?? "")}\``,
9769
+ "",
9770
+ summarizeResourceRead(payload),
9771
+ "",
9772
+ "Use `--format json` to inspect all contents."
9773
+ ].join("\n");
9774
+ case "list_prompts":
9775
+ case "search_prompts": {
9776
+ const prompts = Array.isArray(payload.prompts) ? payload.prompts : [];
9777
+ return [
9778
+ `## MCP prompts for \`${id}\``,
9779
+ "",
9780
+ ...formatPromptLines(prompts, "markdown")
9781
+ ].join("\n");
9782
+ }
9783
+ case "get_prompt": return [
9784
+ `## Prompt \`${String(request.caplet)}.${String(request.prompt)}\``,
9785
+ "",
9786
+ summarizePromptResult(payload),
9787
+ "",
9788
+ "Use `--format json` to inspect all messages."
9789
+ ].join("\n");
9790
+ case "complete": return [
9791
+ `## Completion for \`${id}\``,
9792
+ "",
9793
+ summarizeCompletionResult(payload)
9794
+ ].join("\n");
9673
9795
  default: return JSON.stringify(payload, null, 2);
9674
9796
  }
9675
9797
  }
@@ -9726,6 +9848,33 @@ function plainSummaryForOperation(result, request) {
9726
9848
  `Result: ${summarizeCallResult(payload)}`,
9727
9849
  "Use --format json to inspect the full structured result."
9728
9850
  ].filter((line) => Boolean(line)).join("\n");
9851
+ case "list_resources":
9852
+ case "search_resources": {
9853
+ const resources = Array.isArray(payload.resources) ? payload.resources : [];
9854
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
9855
+ const matches = Array.isArray(payload.matches) ? payload.matches : [...resources, ...templates];
9856
+ return [`MCP resources for ${id} (${matches.length}):`, ...formatResourceLines(matches, "plain")].join("\n");
9857
+ }
9858
+ case "list_resource_templates": {
9859
+ const templates = Array.isArray(payload.resourceTemplates) ? payload.resourceTemplates : [];
9860
+ return [`MCP resource templates for ${id}:`, ...formatResourceLines(templates, "plain")].join("\n");
9861
+ }
9862
+ case "read_resource": return [
9863
+ `Resource ${String(request.uri ?? "")}`,
9864
+ summarizeResourceRead(payload),
9865
+ "Use --format json to inspect all contents."
9866
+ ].join("\n");
9867
+ case "list_prompts":
9868
+ case "search_prompts": {
9869
+ const prompts = Array.isArray(payload.prompts) ? payload.prompts : [];
9870
+ return [`MCP prompts for ${id}:`, ...formatPromptLines(prompts, "plain")].join("\n");
9871
+ }
9872
+ case "get_prompt": return [
9873
+ `Prompt ${String(request.caplet)}.${String(request.prompt)}`,
9874
+ summarizePromptResult(payload),
9875
+ "Use --format json to inspect all messages."
9876
+ ].join("\n");
9877
+ case "complete": return [`Completion for ${id}`, summarizeCompletionResult(payload)].join("\n");
9729
9878
  default: return JSON.stringify(payload, null, 2);
9730
9879
  }
9731
9880
  }
@@ -9742,6 +9891,44 @@ function formatToolLines(tools, format) {
9742
9891
  return `- ${displayName}${flags ? ` (${flags})` : ""}${tool.description ? ` — ${compactDescription(String(tool.description))}` : ""}`;
9743
9892
  });
9744
9893
  }
9894
+ function formatResourceLines(resources, format) {
9895
+ if (resources.length === 0) return ["- none"];
9896
+ return resources.map((resource) => {
9897
+ if (!isPlainObject(resource)) return `- ${String(resource)}`;
9898
+ const name = String(resource.uri ?? resource.uriTemplate ?? "unknown");
9899
+ const displayName = format === "markdown" ? `\`${name}\`` : name;
9900
+ const label = typeof resource.name === "string" ? ` (${resource.name})` : "";
9901
+ return `- ${typeof resource.kind === "string" ? `${resource.kind}: ` : ""}${displayName}${label}${resource.description ? ` — ${compactDescription(String(resource.description))}` : ""}`;
9902
+ });
9903
+ }
9904
+ function formatPromptLines(prompts, format) {
9905
+ if (prompts.length === 0) return ["- none"];
9906
+ return prompts.map((prompt) => {
9907
+ if (!isPlainObject(prompt)) return `- ${String(prompt)}`;
9908
+ const name = String(prompt.prompt ?? prompt.name ?? "unknown");
9909
+ return `- ${format === "markdown" ? `\`${name}\`` : name}${Array.isArray(prompt.arguments) ? ` (${prompt.arguments.length} args)` : ""}${prompt.description ? ` — ${compactDescription(String(prompt.description))}` : ""}`;
9910
+ });
9911
+ }
9912
+ function summarizeResourceRead(payload) {
9913
+ const contents = Array.isArray(payload.contents) ? payload.contents : [];
9914
+ if (contents.length === 0) return "No contents returned.";
9915
+ const first = contents.find(isPlainObject);
9916
+ if (!first) return `${contents.length} content item${contents.length === 1 ? "" : "s"} returned.`;
9917
+ return previewValue(typeof first.text === "string" ? first.text : first.blob) ?? `${contents.length} content item${contents.length === 1 ? "" : "s"} returned.`;
9918
+ }
9919
+ function summarizePromptResult(payload) {
9920
+ const messages = Array.isArray(payload.messages) ? payload.messages : [];
9921
+ if (messages.length === 0) return "No messages returned.";
9922
+ const first = messages.find(isPlainObject);
9923
+ if (!first) return `${messages.length} message${messages.length === 1 ? "" : "s"} returned.`;
9924
+ return previewValue((isPlainObject(first.content) ? first.content : void 0)?.text ?? first.content) ?? `${messages.length} message${messages.length === 1 ? "" : "s"} returned.`;
9925
+ }
9926
+ function summarizeCompletionResult(payload) {
9927
+ const completion = isPlainObject(payload.completion) ? payload.completion : void 0;
9928
+ const values = Array.isArray(completion?.values) ? completion.values : [];
9929
+ if (values.length > 0) return values.map((value) => `- ${String(value)}`).join("\n");
9930
+ return previewValue(payload) ?? "No completions returned.";
9931
+ }
9745
9932
  function compactDescription(value) {
9746
9933
  const firstParagraph = value.trim().split(/\n\s*\n/u)[0] ?? "";
9747
9934
  const collapsed = (firstParagraph.match(/^.*?(?:[.!?](?=\s|$)|$)/u)?.[0] ?? firstParagraph).replace(/\s+/gu, " ").trim();
@@ -4,6 +4,7 @@ export type RemoteCapletsTool = {
4
4
  name: string;
5
5
  title?: string | undefined;
6
6
  description?: string | undefined;
7
+ inputSchema?: unknown;
7
8
  };
8
9
  export type RemoteCapletsClient = {
9
10
  listTools(): Promise<RemoteCapletsTool[]>;