caplets 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +54 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19847,7 +19847,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
19847
19847
  } };
19848
19848
  //#endregion
19849
19849
  //#region package.json
19850
- var version = "0.2.0";
19850
+ var version = "0.2.1";
19851
19851
  //#endregion
19852
19852
  //#region node_modules/.pnpm/@modelcontextprotocol+sdk@1.29.0_zod@4.4.3/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
19853
19853
  /**
@@ -20001,6 +20001,7 @@ const FORBIDDEN_HEADERS = new Set([
20001
20001
  ]);
20002
20002
  join(homedir(), ".caplets", "config.json");
20003
20003
  join(homedir(), ".caplets", "auth");
20004
+ const PROJECT_CONFIG_FILE = join(".caplets", "config.json");
20004
20005
  const remoteAuthSchema = discriminatedUnion("type", [
20005
20006
  object({ type: literal("none") }).strict(),
20006
20007
  object({
@@ -20111,15 +20112,43 @@ const configFileSchema = object({
20111
20112
  function resolveConfigPath(path) {
20112
20113
  return path ?? join(homedir(), ".caplets", "config.json");
20113
20114
  }
20114
- function loadConfig(path = resolveConfigPath()) {
20115
- if (!existsSync(path)) throw new CapletsError("CONFIG_NOT_FOUND", `Caplets config not found at ${path}`);
20115
+ function resolveProjectConfigPath(cwd = process.cwd()) {
20116
+ return join(cwd, PROJECT_CONFIG_FILE);
20117
+ }
20118
+ function loadConfig(path = resolveConfigPath(), projectPath = resolveProjectConfigPath()) {
20119
+ const hasUserConfig = existsSync(path);
20120
+ const hasProjectConfig = existsSync(projectPath);
20121
+ if (!hasUserConfig && !hasProjectConfig) throw new CapletsError("CONFIG_NOT_FOUND", `Caplets config not found at ${path} or ${projectPath}`);
20116
20122
  try {
20117
- return parseConfig(JSON.parse(readFileSync(path, "utf8")));
20123
+ return parseConfig(mergeConfigInputs(hasProjectConfig ? readConfigFile(projectPath) : void 0, hasUserConfig ? readConfigFile(path) : void 0));
20118
20124
  } catch (error) {
20119
20125
  if (error instanceof CapletsError) throw error;
20120
20126
  throw new CapletsError("CONFIG_INVALID", "Caplets config is not valid JSON", redactSecrets(error));
20121
20127
  }
20122
20128
  }
20129
+ function readConfigFile(path) {
20130
+ try {
20131
+ return JSON.parse(readFileSync(path, "utf8"));
20132
+ } catch (error) {
20133
+ throw new CapletsError("CONFIG_INVALID", `Caplets config at ${path} is not valid JSON`, redactSecrets(error));
20134
+ }
20135
+ }
20136
+ function mergeConfigInputs(projectConfig, userConfig) {
20137
+ if (projectConfig === void 0) return userConfig;
20138
+ if (userConfig === void 0) return projectConfig;
20139
+ if (!isPlainConfigObject(projectConfig) || !isPlainConfigObject(userConfig)) return userConfig;
20140
+ return {
20141
+ ...userConfig,
20142
+ ...projectConfig,
20143
+ mcpServers: {
20144
+ ...userConfig.mcpServers,
20145
+ ...projectConfig.mcpServers
20146
+ }
20147
+ };
20148
+ }
20149
+ function isPlainConfigObject(value) {
20150
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
20151
+ }
20123
20152
  function parseConfig(input) {
20124
20153
  const parsed = configFileSchema.safeParse(interpolateServer(input));
20125
20154
  if (!parsed.success) throw new CapletsError("CONFIG_INVALID", "Caplets config is invalid", parsed.error.issues);
@@ -23477,11 +23506,11 @@ var FileOAuthProvider = class {
23477
23506
  codeVerifier() {
23478
23507
  return this.verifier;
23479
23508
  }
23480
- async addClientAuthentication(headers, params) {
23509
+ addClientAuthentication = async (headers, params) => {
23481
23510
  if (this.server.auth?.type !== "oauth2" || !this.server.auth.clientSecret) return;
23482
23511
  params.set("client_secret", this.server.auth.clientSecret);
23483
23512
  headers.set("content-type", "application/x-www-form-urlencoded");
23484
- }
23513
+ };
23485
23514
  };
23486
23515
  async function runOAuthFlow(server, options = {}) {
23487
23516
  if (server.transport === "stdio" || !server.url || server.auth?.type !== "oauth2") throw new CapletsError("REQUEST_INVALID", `${server.server} is not a configured OAuth remote server`);
@@ -23815,7 +23844,16 @@ var ServerRegistry = class {
23815
23844
  }
23816
23845
  };
23817
23846
  function capabilityDescription(server) {
23818
- const hint = `Use this tool to inspect and call tools from ${server.server}. Start with search_tools or list_tools; use get_tool for schema; use call_tool to invoke.`;
23847
+ const hint = [
23848
+ `Use this Caplets wrapper to inspect and call tools from ${server.server}.`,
23849
+ "",
23850
+ "Recommended flow:",
23851
+ "- Discover tools: {\"operation\":\"list_tools\"} or {\"operation\":\"search_tools\",\"query\":\"<what you need>\"}",
23852
+ "- Read one tool schema: {\"operation\":\"get_tool\",\"tool\":\"<tool name>\"}",
23853
+ "- Invoke one downstream tool: {\"operation\":\"call_tool\",\"tool\":\"<tool name>\",\"arguments\":{...}}",
23854
+ "",
23855
+ "Important: call_tool requires a top-level \"arguments\" JSON object containing the downstream tool inputs. Do not put downstream arguments at the top level of this wrapper request."
23856
+ ].join("\n");
23819
23857
  return `${server.name}\n\n${server.description}\n\n${hint}`;
23820
23858
  }
23821
23859
  //#endregion
@@ -23829,11 +23867,15 @@ const operations = [
23829
23867
  "call_tool"
23830
23868
  ];
23831
23869
  const generatedToolInputSchema = object({
23832
- operation: _enum(operations).describe("Operation to perform for this configured MCP server."),
23833
- query: string().optional().describe("Required for search_tools."),
23834
- limit: number$1().int().positive().optional().describe("Optional for search_tools; defaults to configured limit."),
23835
- tool: string().optional().describe("Exact downstream tool name for get_tool or call_tool."),
23836
- arguments: record(string(), unknown()).optional().describe("JSON object arguments for call_tool.")
23870
+ operation: _enum(operations).describe([
23871
+ "Caplets wrapper operation to perform for this configured MCP server.",
23872
+ "Use list_tools or search_tools to discover downstream tools, get_tool to read a downstream input schema, and call_tool to run one downstream tool.",
23873
+ "For call_tool, pass downstream inputs only inside the top-level \"arguments\" object."
23874
+ ].join(" ")),
23875
+ query: string().optional().describe("Required only for search_tools. Example: {\"operation\":\"search_tools\",\"query\":\"web search\",\"limit\":5}. Do not use query for call_tool; put downstream query values under arguments.query."),
23876
+ limit: number$1().int().positive().optional().describe("Optional only for search_tools; defaults to the configured search limit. For downstream result limits, use call_tool.arguments with the downstream schema field name."),
23877
+ tool: string().optional().describe("Exact downstream tool name for get_tool or call_tool. Example: {\"operation\":\"get_tool\",\"tool\":\"web_search_exa\"} before calling it."),
23878
+ arguments: record(string(), unknown()).optional().describe("Required JSON object only for call_tool. Put every downstream tool input inside this object. Example: {\"operation\":\"call_tool\",\"tool\":\"web_search_exa\",\"arguments\":{\"query\":\"latest MCP docs\",\"numResults\":3}}. Do not send downstream inputs as top-level query, limit, url, path, or other fields.")
23837
23879
  }).strict();
23838
23880
  async function handleServerTool(server, request, registry, downstream) {
23839
23881
  const parsed = validateOperationRequest(request, registry.config.options.maxSearchLimit);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caplets",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Progressive disclosure gateway for MCP servers.",
5
5
  "keywords": [
6
6
  "caplets",