loopctl-mcp-server 2.31.1 → 2.33.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.
Files changed (2) hide show
  1. package/index.js +41 -11
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1182,12 +1182,21 @@ async function llmConfig() {
1182
1182
  return toContent(result);
1183
1183
  }
1184
1184
 
1185
- async function setLlmConfig({ api_key, extraction_model, classification_model, merge_model }) {
1185
+ async function setLlmConfig({
1186
+ api_key,
1187
+ extraction_model,
1188
+ classification_model,
1189
+ merge_model,
1190
+ embedding_api_key,
1191
+ embedding_model,
1192
+ }) {
1186
1193
  const body = {};
1187
1194
  if (api_key != null) body.api_key = api_key;
1188
1195
  if (extraction_model !== undefined) body.extraction_model = extraction_model;
1189
1196
  if (classification_model !== undefined) body.classification_model = classification_model;
1190
1197
  if (merge_model !== undefined) body.merge_model = merge_model;
1198
+ if (embedding_api_key != null) body.embedding_api_key = embedding_api_key;
1199
+ if (embedding_model !== undefined) body.embedding_model = embedding_model;
1191
1200
  // PATCH (partial-merge) + EXACT user key (review #12, #13).
1192
1201
  const result = await apiCall(
1193
1202
  "PATCH",
@@ -2576,7 +2585,11 @@ const TOOLS = [
2576
2585
  "list mode or knowledge_stats. " +
2577
2586
  "Pass story_id when working on a loopctl story so reads attribute correctly. " +
2578
2587
  "When you knowledge_get a result and it carries `potential_conflicts`, resolve it if it's " +
2579
- "material to your task (see knowledge_get / the conflict-resolution wiki playbook).",
2588
+ "material to your task (see knowledge_get / the conflict-resolution wiki playbook). " +
2589
+ "If semantic ranking is unavailable the search transparently degrades to keyword-only " +
2590
+ "(meta.fallback: true, meta.search_mode: 'keyword_only') and now reports meta.fallback_reason " +
2591
+ "— a stable tag naming WHY (e.g. no_embedding_key, embedding_circuit_open, " +
2592
+ "embedding_provider_error_<status>, embedding_timeout).",
2580
2593
  inputSchema: {
2581
2594
  type: "object",
2582
2595
  properties: {
@@ -2665,7 +2678,10 @@ const TOOLS = [
2665
2678
  "memory, scope to a memory_type/agent/conversation via the memory_types/agents/" +
2666
2679
  "conversation_id filters (articles whose metadata carries those keys). NOTE (#163): for " +
2667
2680
  "an agent key, another agent's private/owner memories are never returned (results AND " +
2668
- "linked refs) regardless of the agents= filter — visibility is enforced, not advisory.",
2681
+ "linked refs) regardless of the agents= filter — visibility is enforced, not advisory. " +
2682
+ "If semantic ranking is unavailable this degrades to keyword-only (meta.fallback: true) and " +
2683
+ "now reports meta.fallback_reason — a stable tag naming WHY (e.g. no_embedding_key, " +
2684
+ "embedding_circuit_open, embedding_provider_error_<status>, embedding_timeout).",
2669
2685
  inputSchema: {
2670
2686
  type: "object",
2671
2687
  properties: {
@@ -3364,19 +3380,23 @@ const TOOLS = [
3364
3380
  {
3365
3381
  name: "llm_config",
3366
3382
  description:
3367
- "Get the tenant's BYO Anthropic LLM configuration: the per-operation model " +
3368
- "choices, whether a key is configured (has_api_key), and a masked last-4 hint. " +
3369
- "NEVER returns the key itself. Requires user role (LOOPCTL_USER_KEY).",
3383
+ "Get the tenant's BYO Anthropic + embedding configuration: the per-operation " +
3384
+ "model choices, whether each key is configured (has_api_key / has_embedding_key), " +
3385
+ "and masked last-4 hints. NEVER returns a key itself. Requires user role " +
3386
+ "(LOOPCTL_USER_KEY).",
3370
3387
  inputSchema: { type: "object", properties: {}, required: [] },
3371
3388
  },
3372
3389
  {
3373
3390
  name: "set_llm_config",
3374
3391
  description:
3375
- "Set/rotate the tenant's OWN Anthropic API key (stored encrypted, never returned) " +
3376
- "and the three per-operation models (extraction/classification/merge). loopctl " +
3377
- "fronts no LLM cost — the tenant's key bills the tenant. Any subset of fields may " +
3378
- "be sent; omitting api_key leaves the existing key untouched. Model ids are " +
3379
- "free-form (any model the key permits). Requires user role (LOOPCTL_USER_KEY).",
3392
+ "Set/rotate the tenant's OWN Anthropic API key AND OpenAI embedding key (both " +
3393
+ "stored encrypted, never returned) and the per-operation models " +
3394
+ "(extraction/classification/merge/embedding). loopctl fronts no cost — the " +
3395
+ "tenant's keys bill the tenant. Mandatory BYO for embeddings: without an " +
3396
+ "embedding_api_key the tenant's articles are not vector-searchable. Any subset " +
3397
+ "of fields may be sent; omitting a key leaves the existing key untouched. Model " +
3398
+ "ids are free-form (any model the key permits). Requires user role " +
3399
+ "(LOOPCTL_USER_KEY).",
3380
3400
  inputSchema: {
3381
3401
  type: "object",
3382
3402
  properties: {
@@ -3396,6 +3416,16 @@ const TOOLS = [
3396
3416
  type: "string",
3397
3417
  description: "Model id for article merge synthesis (null → server default).",
3398
3418
  },
3419
+ embedding_api_key: {
3420
+ type: "string",
3421
+ description:
3422
+ "OpenAI-compatible embedding API key (write-only; stored encrypted, never returned).",
3423
+ },
3424
+ embedding_model: {
3425
+ type: "string",
3426
+ description:
3427
+ "Embedding model id (null → server default text-embedding-3-small).",
3428
+ },
3399
3429
  },
3400
3430
  required: [],
3401
3431
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loopctl-mcp-server",
3
- "version": "2.31.1",
3
+ "version": "2.33.0",
4
4
  "description": "MCP server for loopctl — structural trust for AI development loops",
5
5
  "type": "module",
6
6
  "main": "index.js",