harn-stdlib 0.8.163

Embedded Harn standard library source catalog
Documentation
/**
 * agent_mcp_bootstrap_if_needed.
 *
 * @effects: [host, mcp]
 * @errors: []
 * @api_stability: experimental
 */
pub fn agent_mcp_bootstrap_if_needed(session, opts) {
  let specs = opts?.mcp_servers
  if specs == nil || len(specs) == 0 {
    return opts
  }
  let result = __host_mcp_bootstrap(session.session_id, specs)
  let out = opts + {_mcp_bootstrap: result, _mcp_server_info: result?.server_info ?? []}
  if len(result.tools_added) == 0 {
    return out
  }
  let existing = opts?.tools
  let existing_tools = if existing?._type == "tool_registry" {
    existing?.tools ?? []
  } else {
    []
  }
  let reg = {_type: "tool_registry", tools: existing_tools + result.tools_added}
  return __with_mcp_tool_ceiling(out + {tools: reg}, result.tools_added)
}

/**
 * Admit the just-bootstrapped MCP tools into the execution-policy tool
 * ceiling so the agent that can SEE them in its catalog can also CALL them.
 *
 * The catalog merge above adds the `server__tool` entries to `opts.tools`,
 * which is what makes the model aware of them; without a matching entry in
 * `opts.policy.tools` (the ceiling enforced by
 * `enforce_current_policy_for_tool`) every dispatch is denied with
 * "exceeds tool ceiling". An MCP tool is a runtime projection — its name is
 * not known until `tools/list` returns — so the ceiling can only learn it
 * here, at boot time, not from the host's static surface declaration.
 *
 * An EMPTY `policy.tools` means "no ceiling" (allow any tool), so we only
 * extend a non-empty ceiling: adding names to an empty list would flip an
 * open policy into a closed one and silently forbid the host's own tools.
 * Idempotent: never double-adds a name already present.
 */
fn __with_mcp_tool_ceiling(opts, tools_added) {
  let policy = opts?.policy
  if type_of(policy) != "dict" {
    return opts
  }
  let ceiling = policy?.tools
  if type_of(ceiling) != "list" || len(ceiling) == 0 {
    return opts
  }
  var names = []
  for entry in tools_added {
    let name = __mcp_tool_ceiling_name(entry)
    if name != "" && !ceiling.contains(name) && !names.contains(name) {
      names = names + [name]
    }
  }
  if len(names) == 0 {
    return opts
  }
  return opts + {policy: policy + {tools: ceiling + names}}
}

/** Resolve a bootstrapped tool entry's dispatch name (flat or OpenAI-shape). */
fn __mcp_tool_ceiling_name(entry) {
  if type_of(entry) != "dict" {
    return ""
  }
  let flat = to_string(entry?.name ?? "")
  if flat != "" {
    return flat
  }
  return to_string(entry?.function?.name ?? "")
}