diff --git a/plugins/askrene/askrene.c b/plugins/askrene/askrene.c
index 3429391084a2..59d8eea79856 100644
--- a/plugins/askrene/askrene.c
+++ b/plugins/askrene/askrene.c
@@ -9,6 +9,7 @@
 #include "config.h"
 #include <ccan/array_size/array_size.h>
 #include <ccan/tal/str/str.h>
+#include <ccan/time/time.h>
 #include <common/dijkstra.h>
 #include <common/gossmap.h>
 #include <common/gossmods_listpeerchannels.h>
@@ -18,11 +19,9 @@
 #include <errno.h>
 #include <math.h>
 #include <plugins/askrene/askrene.h>
-#include <plugins/askrene/explain_failure.h>
 #include <plugins/askrene/flow.h>
 #include <plugins/askrene/layer.h>
 #include <plugins/askrene/mcf.h>
-#include <plugins/askrene/refine.h>
 #include <plugins/askrene/reserve.h>
 
 /* "spendable" for a channel assumes a single HTLC: for additional HTLCs,
@@ -332,76 +331,55 @@ const char *fmt_flow_full(const tal_t *ctx,
 	return str;
 }
 
-static struct amount_msat linear_flows_cost(struct flow **flows,
-					    struct amount_msat total_amount,
-					    double delay_feefactor)
-{
-	struct amount_msat total = AMOUNT_MSAT(0);
-
-	for (size_t i = 0; i < tal_count(flows); i++) {
-		if (!amount_msat_accumulate(&total,
-					    linear_flow_cost(flows[i],
-							     total_amount,
-							     delay_feefactor)))
-			abort();
-	}
-	return total;
-}
+enum algorithm {
+	ALGO_DEFAULT,
+};
 
-/* Returns an error message, or sets *routes */
-static const char *get_routes(const tal_t *ctx,
-			      struct command *cmd,
-			      const struct node_id *source,
-			      const struct node_id *dest,
-			      struct amount_msat amount,
-			      struct amount_msat maxfee,
-			      u32 finalcltv,
-			      u32 maxdelay,
-			      const char **layers,
-			      struct gossmap_localmods *localmods,
-			      const struct layer *local_layer,
-			      bool single_path,
-			      struct route ***routes,
-			      struct amount_msat **amounts,
-			      const struct additional_cost_htable *additional_costs,
-			      double *probability)
+static struct command_result *
+param_algorithm(struct command *cmd, const char *name, const char *buffer,
+		const jsmntok_t *tok, enum algorithm **algo)
 {
-	struct askrene *askrene = get_askrene(cmd->plugin);
-	struct route_query *rq = tal(ctx, struct route_query);
-	struct flow **flows;
-	const struct gossmap_node *srcnode, *dstnode;
-	double delay_feefactor;
-	u32 mu;
-	const char *ret;
-
-	if (gossmap_refresh(askrene->gossmap)) {
-		/* FIXME: gossmap_refresh callbacks to we can update in place */
-		tal_free(askrene->capacities);
-		askrene->capacities = get_capacities(askrene, askrene->plugin, askrene->gossmap);
-	}
+	const char *algo_str = json_strdup(cmd, buffer, tok);
+	*algo = tal(cmd, enum algorithm);
+	if (streq(algo_str, "default"))
+		**algo = ALGO_DEFAULT;
+	else
+		return command_fail_badparam(cmd, name, buffer, tok,
+					     "unknown algorithm");
+	return NULL;
+}
 
-	rq->cmd = cmd;
-	rq->plugin = cmd->plugin;
-	rq->gossmap = askrene->gossmap;
-	rq->reserved = askrene->reserved;
-	rq->layers = tal_arr(rq, const struct layer *, 0);
-	rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
-	rq->additional_costs = additional_costs;
+struct getroutes_info {
+	struct command *cmd;
+	struct node_id *source, *dest;
+	struct amount_msat *amount, *maxfee;
+	u32 *finalcltv, *maxdelay;
+	const char **layers;
+	struct additional_cost_htable *additional_costs;
+	/* Non-NULL if we are told to use "auto.localchans" */
+	struct layer *local_layer;
+	/* algorithm selection, only dev */
+	enum algorithm *dev_algo;
+};
 
+static void apply_layers(struct askrene *askrene, struct route_query *rq,
+			 struct gossmap_localmods *localmods,
+			 const struct getroutes_info *info)
+{
 	/* Layers must exist, but might be special ones! */
-	for (size_t i = 0; i < tal_count(layers); i++) {
-		const struct layer *l = find_layer(askrene, layers[i]);
+	for (size_t i = 0; i < tal_count(info->layers); i++) {
+		const struct layer *l = find_layer(askrene, info->layers[i]);
 		if (!l) {
-			if (streq(layers[i], "auto.localchans")) {
+			if (streq(info->layers[i], "auto.localchans")) {
 				plugin_log(rq->plugin, LOG_DBG, "Adding auto.localchans");
-				l = local_layer;
-			} else if (streq(layers[i], "auto.no_mpp_support")) {
+				l = info->local_layer;
+			} else if (streq(info->layers[i], "auto.no_mpp_support")) {
 				plugin_log(rq->plugin, LOG_DBG, "Adding auto.no_mpp_support, sorry");
-				l = remove_small_channel_layer(layers, askrene, amount, localmods);
+				l = remove_small_channel_layer(info->layers, askrene, *info->amount, localmods);
 			} else {
-				assert(streq(layers[i], "auto.sourcefree"));
+				assert(streq(info->layers[i], "auto.sourcefree"));
 				plugin_log(rq->plugin, LOG_DBG, "Adding auto.sourcefree");
-				l = source_free_layer(layers, askrene, source, localmods);
+				l = source_free_layer(info->layers, askrene, info->source, localmods);
 			}
 		}
 
@@ -413,140 +391,14 @@ static const char *get_routes(const tal_t *ctx,
 		 * override them (incl local channels) */
 		layer_clear_overridden_capacities(l, askrene->gossmap, rq->capacities);
 	}
+}
 
-	/* Clear scids with reservations, too, so we don't have to look up
-	 * all the time! */
-	reserves_clear_capacities(askrene->reserved, askrene->gossmap, rq->capacities);
-
-	gossmap_apply_localmods(askrene->gossmap, localmods);
-
-	/* localmods can add channels, so we need to allocate biases array *afterwards* */
-	rq->biases = tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
-
-	/* Note any channel biases */
-	for (size_t i = 0; i < tal_count(rq->layers); i++)
-		layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
-
-	srcnode = gossmap_find_node(askrene->gossmap, source);
-	if (!srcnode) {
-		ret = rq_log(ctx, rq, LOG_INFORM,
-			     "Unknown source node %s",
-			     fmt_node_id(tmpctx, source));
-		goto fail;
-	}
-
-	dstnode = gossmap_find_node(askrene->gossmap, dest);
-	if (!dstnode) {
-		ret = rq_log(ctx, rq, LOG_INFORM,
-			     "Unknown destination node %s",
-			     fmt_node_id(tmpctx, dest));
-		goto fail;
-	}
-
-	delay_feefactor = 1.0/1000000;
-
-	/* First up, don't care about fees (well, just enough to tiebreak!) */
-	mu = 1;
-	flows = minflow(rq, rq, srcnode, dstnode, amount,
-			mu, delay_feefactor, single_path);
-	if (!flows) {
-		ret = explain_failure(ctx, rq, srcnode, dstnode, amount);
-		goto fail;
-	}
-
-	/* Too much delay? */
-	while (finalcltv + flows_worst_delay(flows) > maxdelay) {
-		delay_feefactor *= 2;
-		rq_log(tmpctx, rq, LOG_UNUSUAL,
-		       "The worst flow delay is %"PRIu64" (> %i), retrying with delay_feefactor %f...",
-		       flows_worst_delay(flows), maxdelay - finalcltv, delay_feefactor);
-		flows = minflow(rq, rq, srcnode, dstnode, amount,
-				mu, delay_feefactor, single_path);
-		if (!flows || delay_feefactor > 10) {
-			ret = rq_log(ctx, rq, LOG_UNUSUAL,
-				     "Could not find route without excessive delays");
-			goto fail;
-		}
-	}
-
-	/* Too expensive? */
-too_expensive:
-	while (amount_msat_greater(flowset_fee(rq->plugin, flows), maxfee)) {
-		struct flow **new_flows;
-
-		if (mu == 1)
-			mu = 10;
-		else
-			mu += 10;
-		rq_log(tmpctx, rq, LOG_UNUSUAL,
-		       "The flows had a fee of %s, greater than max of %s, retrying with mu of %u%%...",
-		       fmt_amount_msat(tmpctx, flowset_fee(rq->plugin, flows)),
-		       fmt_amount_msat(tmpctx, maxfee),
-		       mu);
-		new_flows = minflow(rq, rq, srcnode, dstnode, amount,
-				    mu > 100 ? 100 : mu, delay_feefactor, single_path);
-		if (!flows || mu >= 100) {
-			ret = rq_log(ctx, rq, LOG_UNUSUAL,
-				     "Could not find route without excessive cost");
-			goto fail;
-		}
-
-		/* This is possible, because MCF's linear fees are not the same. */
-		if (amount_msat_greater(flowset_fee(rq->plugin, new_flows),
-					flowset_fee(rq->plugin, flows))) {
-			struct amount_msat old_cost = linear_flows_cost(flows, amount, delay_feefactor);
-			struct amount_msat new_cost = linear_flows_cost(new_flows, amount, delay_feefactor);
-			if (amount_msat_greater_eq(new_cost, old_cost)) {
-				rq_log(tmpctx, rq, LOG_BROKEN, "Old flows cost %s:",
-				       fmt_amount_msat(tmpctx, old_cost));
-				for (size_t i = 0; i < tal_count(flows); i++) {
-					rq_log(tmpctx, rq, LOG_BROKEN,
-					       "Flow %zu/%zu: %s (linear cost %s)", i, tal_count(flows),
-					       fmt_flow_full(tmpctx, rq, flows[i]),
-					       fmt_amount_msat(tmpctx, linear_flow_cost(flows[i],
-											amount,
-											delay_feefactor)));
-				}
-				rq_log(tmpctx, rq, LOG_BROKEN, "Old flows cost %s:",
-				       fmt_amount_msat(tmpctx, new_cost));
-				for (size_t i = 0; i < tal_count(new_flows); i++) {
-					rq_log(tmpctx, rq, LOG_BROKEN,
-					       "Flow %zu/%zu: %s (linear cost %s)", i, tal_count(new_flows),
-					       fmt_flow_full(tmpctx, rq, new_flows[i]),
-					       fmt_amount_msat(tmpctx, linear_flow_cost(new_flows[i],
-											amount,
-											delay_feefactor)));
-				}
-			}
-		}
-		tal_free(flows);
-		flows = new_flows;
-	}
-
-	if (finalcltv + flows_worst_delay(flows) > maxdelay) {
-		ret = rq_log(ctx, rq, LOG_UNUSUAL,
-			     "Could not find route without excessive cost or delays");
-		goto fail;
-	}
-
-	/* The above did not take into account the extra funds to pay
-	 * fees, so we try to adjust now.  We could re-run MCF if this
-	 * fails, but failure basically never happens where payment is
-	 * still possible */
-	ret = refine_with_fees_and_limits(ctx, rq, amount, &flows, probability);
-	if (ret)
-		goto fail;
-
-	/* Again, a tiny corner case: refine step can make us exceed maxfee */
-	if (amount_msat_greater(flowset_fee(rq->plugin, flows), maxfee)) {
-		rq_log(tmpctx, rq, LOG_UNUSUAL,
-		       "After final refinement, fee was excessive: retrying");
-		goto too_expensive;
-	}
-
-	rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows with mu=%u",
-	       tal_count(flows), mu);
-
+static void convert_flows_to_routes(const tal_t *ctx, struct route_query *rq,
+				    struct route ***routes,
+				    struct amount_msat **amounts,
+				    u32 finalcltv,
+				    struct flow **flows)
+{
 	/* Convert back into routes, with delay and other information fixed */
 	*routes = tal_arr(ctx, struct route *, tal_count(flows));
 	*amounts = tal_arr(ctx, struct amount_msat, tal_count(flows));
@@ -584,17 +436,6 @@ static const char *get_routes(const tal_t *ctx,
 		       i, tal_count(flows),
 		       fmt_route(tmpctx, r, (*amounts)[i], finalcltv));
 	}
-
-	gossmap_remove_localmods(askrene->gossmap, localmods);
-
-	return NULL;
-
-	/* Explicit failure path keeps the compiler (gcc version 12.3.0 -O3) from
-	 * warning about uninitialized variables in the caller */
-fail:
-	assert(ret != NULL);
-	gossmap_remove_localmods(askrene->gossmap, localmods);
-	return ret;
 }
 
 void get_constraints(const struct route_query *rq,
@@ -633,16 +474,40 @@ void get_constraints(const struct route_query *rq,
 	reserve_sub(rq->reserved, &scidd, max);
 }
 
-struct getroutes_info {
-	struct command *cmd;
-	struct node_id *source, *dest;
-	struct amount_msat *amount, *maxfee;
-	u32 *finalcltv, *maxdelay;
-	const char **layers;
-	struct additional_cost_htable *additional_costs;
-	/* Non-NULL if we are told to use "auto.localchans" */
-	struct layer *local_layer;
-};
+static void json_add_getroutes(
+    struct json_stream *js,
+    struct route **routes,
+    const struct amount_msat *amounts,
+    double probability,
+    u32 final_cltv)
+{
+	json_add_u64(js, "probability_ppm", (u64)(probability * 1000000));
+	json_array_start(js, "routes");
+	for (size_t i = 0; i < tal_count(routes); i++) {
+		json_object_start(js, NULL);
+		json_add_u64(js, "probability_ppm",
+			     (u64)(routes[i]->success_prob * 1000000));
+		json_add_amount_msat(js, "amount_msat", amounts[i]);
+		json_add_u32(js, "final_cltv", final_cltv);
+		json_array_start(js, "path");
+		for (size_t j = 0; j < tal_count(routes[i]->hops); j++) {
+			struct short_channel_id_dir scidd;
+			const struct route_hop *r = &routes[i]->hops[j];
+			json_object_start(js, NULL);
+			scidd.scid = r->scid;
+			scidd.dir = r->direction;
+			json_add_short_channel_id_dir(
+			    js, "short_channel_id_dir", scidd);
+			json_add_node_id(js, "next_node_id", &r->node_id);
+			json_add_amount_msat(js, "amount_msat", r->amount);
+			json_add_u32(js, "delay", r->delay);
+			json_object_end(js);
+		}
+		json_array_end(js);
+		json_object_end(js);
+	}
+	json_array_end(js);
+}
 
 static struct command_result *do_getroutes(struct command *cmd,
 					   struct gossmap_localmods *localmods,
@@ -652,43 +517,112 @@ static struct command_result *do_getroutes(struct command *cmd,
 	double probability;
 	struct amount_msat *amounts;
 	struct route **routes;
+	struct flow **flows;
 	struct json_stream *response;
 
-	err = get_routes(cmd, cmd,
-			 info->source, info->dest,
-			 *info->amount, *info->maxfee, *info->finalcltv,
-			 *info->maxdelay, info->layers, localmods, info->local_layer,
-			 have_layer(info->layers, "auto.no_mpp_support"),
-			 &routes, &amounts, info->additional_costs, &probability);
+	/* get me the global state structure */
+	struct askrene *askrene = get_askrene(cmd->plugin);
+
+	/* update the gossmap */
+	if (gossmap_refresh(askrene->gossmap)) {
+		/* FIXME: gossmap_refresh callbacks to we can update in place */
+		tal_free(askrene->capacities);
+		askrene->capacities =
+		    get_capacities(askrene, askrene->plugin, askrene->gossmap);
+	}
+
+	/* build this request structure */
+	struct route_query *rq = tal(cmd, struct route_query);
+	rq->cmd = cmd;
+	rq->plugin = cmd->plugin;
+	rq->gossmap = askrene->gossmap;
+	rq->reserved = askrene->reserved;
+	rq->layers = tal_arr(rq, const struct layer *, 0);
+	rq->capacities = tal_dup_talarr(rq, fp16_t, askrene->capacities);
+	/* FIXME: we still need to do something useful with these */
+	rq->additional_costs = info->additional_costs;
+
+	/* apply selected layers to the localmods */
+	apply_layers(askrene, rq, localmods, info);
+
+	/* Clear scids with reservations, too, so we don't have to look up
+	 * all the time! */
+	reserves_clear_capacities(askrene->reserved, askrene->gossmap,
+				  rq->capacities);
+
+	/* we temporarily apply localmods */
+	gossmap_apply_localmods(askrene->gossmap, localmods);
+
+	/* localmods can add channels, so we need to allocate biases array
+	 * *afterwards* */
+	rq->biases =
+	    tal_arrz(rq, s8, gossmap_max_chan_idx(askrene->gossmap) * 2);
+
+	/* Note any channel biases */
+	for (size_t i = 0; i < tal_count(rq->layers); i++)
+		layer_apply_biases(rq->layers[i], askrene->gossmap, rq->biases);
+
+	/* checkout the source */
+	const struct gossmap_node *srcnode =
+	    gossmap_find_node(askrene->gossmap, info->source);
+	if (!srcnode) {
+		err = rq_log(tmpctx, rq, LOG_INFORM, "Unknown source node %s",
+			     fmt_node_id(tmpctx, info->source));
+		goto fail;
+	}
+
+	/* checkout the destination */
+	const struct gossmap_node *dstnode =
+	    gossmap_find_node(askrene->gossmap, info->dest);
+	if (!dstnode) {
+		err = rq_log(tmpctx, rq, LOG_INFORM,
+			     "Unknown destination node %s",
+			     fmt_node_id(tmpctx, info->dest));
+		goto fail;
+	}
+
+	/* Compute the routes. At this point we might select between multiple
+	 * algorithms. Right now there is only one algorithm available. */
+	struct timemono time_start = time_mono();
+	assert(*info->dev_algo == ALGO_DEFAULT);
+	err = default_routes(rq, rq, srcnode, dstnode, *info->amount,
+			     /* only one path? = */
+			     have_layer(info->layers, "auto.no_mpp_support"),
+			     *info->maxfee, *info->finalcltv, *info->maxdelay,
+			     &flows, &probability);
+	struct timerel time_delta = timemono_between(time_mono(), time_start);
+
+	/* log the time of computation */
+	rq_log(tmpctx, rq, LOG_DBG, "get_routes %s %" PRIu64 " ms",
+	       err ? "failed after" : "completed in",
+	       time_to_msec(time_delta));
 	if (err)
-		return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
+		goto fail;
+
+	/* otherwise we continue */
+	assert(tal_count(flows) > 0);
+	rq_log(tmpctx, rq, LOG_DBG, "Final answer has %zu flows",
+	       tal_count(flows));
+
+	/* convert flows to routes */
+	convert_flows_to_routes(rq, rq, &routes, &amounts, *info->finalcltv,
+				flows);
+	assert(tal_count(routes) == tal_count(flows));
+	assert(tal_count(amounts) == tal_count(flows));
 
+	/* At last we remove the localmods from the gossmap. */
+	gossmap_remove_localmods(askrene->gossmap, localmods);
+
+	/* output the results */
 	response = jsonrpc_stream_success(cmd);
-	json_add_u64(response, "probability_ppm", (u64)(probability * 1000000));
-	json_array_start(response, "routes");
-	for (size_t i = 0; i < tal_count(routes); i++) {
-		json_object_start(response, NULL);
-		json_add_u64(response, "probability_ppm", (u64)(routes[i]->success_prob * 1000000));
-		json_add_amount_msat(response, "amount_msat", amounts[i]);
-		json_add_u32(response, "final_cltv", *info->finalcltv);
-		json_array_start(response, "path");
-		for (size_t j = 0; j < tal_count(routes[i]->hops); j++) {
-			struct short_channel_id_dir scidd;
-			const struct route_hop *r = &routes[i]->hops[j];
-			json_object_start(response, NULL);
-			scidd.scid = r->scid;
-			scidd.dir = r->direction;
-			json_add_short_channel_id_dir(response, "short_channel_id_dir", scidd);
-			json_add_node_id(response, "next_node_id", &r->node_id);
-			json_add_amount_msat(response, "amount_msat", r->amount);
-			json_add_u32(response, "delay", r->delay);
-			json_object_end(response);
-		}
-		json_array_end(response);
-		json_object_end(response);
-	}
-	json_array_end(response);
+	json_add_getroutes(response, routes, amounts, probability,
+			   *info->finalcltv);
 	return command_finished(cmd, response);
+
+fail:
+	assert(err);
+	gossmap_remove_localmods(askrene->gossmap, localmods);
+	return command_fail(cmd, PAY_ROUTE_NOT_FOUND, "%s", err);
 }
 
 static void add_localchan(struct gossmap_localmods *mods,
@@ -810,6 +744,8 @@ static struct command_result *json_getroutes(struct command *cmd,
 			 p_req("final_cltv", param_u32, &info->finalcltv),
 			 p_opt_def("maxdelay", param_u32, &info->maxdelay,
 				   maxdelay_allowed),
+			 p_opt_dev("dev_algorithm", param_algorithm,
+				   &info->dev_algo, ALGO_DEFAULT),
 			 NULL))
 		return command_param_failed();
 	plugin_log(cmd->plugin, LOG_TRACE, "%s called: %.*s", __func__,
diff --git a/plugins/askrene/mcf.c b/plugins/askrene/mcf.c
index 6339510a5ce9..cb2b1ea83075 100644
--- a/plugins/askrene/mcf.c
+++ b/plugins/askrene/mcf.c
@@ -11,9 +11,11 @@
 #include <plugins/askrene/algorithm.h>
 #include <plugins/askrene/askrene.h>
 #include <plugins/askrene/dijkstra.h>
+#include <plugins/askrene/explain_failure.h>
 #include <plugins/askrene/flow.h>
 #include <plugins/askrene/graph.h>
 #include <plugins/askrene/mcf.h>
+#include <plugins/askrene/refine.h>
 #include <plugins/libplugin.h>
 #include <stdint.h>
 
@@ -1080,3 +1082,159 @@ struct flow **minflow(const tal_t *ctx,
 	tal_free(working_ctx);
 	return NULL;
 }
+
+static struct amount_msat linear_flows_cost(struct flow **flows,
+					    struct amount_msat total_amount,
+					    double delay_feefactor)
+{
+	struct amount_msat total = AMOUNT_MSAT(0);
+
+	for (size_t i = 0; i < tal_count(flows); i++) {
+		if (!amount_msat_accumulate(&total,
+					    linear_flow_cost(flows[i],
+							     total_amount,
+							     delay_feefactor)))
+			abort();
+	}
+	return total;
+}
+
+
+const char *default_routes(const tal_t *ctx, struct route_query *rq,
+			   const struct gossmap_node *srcnode,
+			   const struct gossmap_node *dstnode,
+			   struct amount_msat amount, bool single_path,
+			   struct amount_msat maxfee, u32 finalcltv,
+			   u32 maxdelay, struct flow ***flows,
+			   double *probability)
+{
+	*flows = NULL;
+	const char *ret;
+	double delay_feefactor = 1.0 / 1000000;
+
+	/* First up, don't care about fees (well, just enough to tiebreak!) */
+	u32 mu = 1;
+	tal_free(*flows);
+	*flows = minflow(ctx, rq, srcnode, dstnode, amount, mu, delay_feefactor,
+			single_path);
+	if (!*flows) {
+		ret = explain_failure(ctx, rq, srcnode, dstnode, amount);
+		goto fail;
+	}
+
+	/* Too much delay? */
+	while (finalcltv + flows_worst_delay(*flows) > maxdelay) {
+		delay_feefactor *= 2;
+		rq_log(tmpctx, rq, LOG_UNUSUAL,
+		       "The worst flow delay is %" PRIu64
+		       " (> %i), retrying with delay_feefactor %f...",
+		       flows_worst_delay(*flows), maxdelay - finalcltv,
+		       delay_feefactor);
+		tal_free(*flows);
+		*flows = minflow(ctx, rq, srcnode, dstnode, amount, mu,
+				delay_feefactor, single_path);
+		if (!*flows || delay_feefactor > 10) {
+			ret = rq_log(
+			    ctx, rq, LOG_UNUSUAL,
+			    "Could not find route without excessive delays");
+			goto fail;
+		}
+	}
+
+	/* Too expensive? */
+too_expensive:
+	while (amount_msat_greater(flowset_fee(rq->plugin, *flows), maxfee)) {
+		struct flow **new_flows;
+
+		if (mu == 1)
+			mu = 10;
+		else
+			mu += 10;
+		rq_log(tmpctx, rq, LOG_UNUSUAL,
+		       "The flows had a fee of %s, greater than max of %s, "
+		       "retrying with mu of %u%%...",
+		       fmt_amount_msat(tmpctx, flowset_fee(rq->plugin, *flows)),
+		       fmt_amount_msat(tmpctx, maxfee), mu);
+		new_flows =
+		    minflow(ctx, rq, srcnode, dstnode, amount,
+			    mu > 100 ? 100 : mu, delay_feefactor, single_path);
+		if (!*flows || mu >= 100) {
+			ret = rq_log(
+			    ctx, rq, LOG_UNUSUAL,
+			    "Could not find route without excessive cost");
+			goto fail;
+		}
+
+		/* This is possible, because MCF's linear fees are not the same.
+		 */
+		if (amount_msat_greater(flowset_fee(rq->plugin, new_flows),
+					flowset_fee(rq->plugin, *flows))) {
+			struct amount_msat old_cost =
+			    linear_flows_cost(*flows, amount, delay_feefactor);
+			struct amount_msat new_cost = linear_flows_cost(
+			    new_flows, amount, delay_feefactor);
+			if (amount_msat_greater_eq(new_cost, old_cost)) {
+				rq_log(tmpctx, rq, LOG_BROKEN,
+				       "Old flows cost %s:",
+				       fmt_amount_msat(tmpctx, old_cost));
+				for (size_t i = 0; i < tal_count(*flows); i++) {
+					rq_log(
+					    tmpctx, rq, LOG_BROKEN,
+					    "Flow %zu/%zu: %s (linear cost %s)",
+					    i, tal_count(*flows),
+					    fmt_flow_full(tmpctx, rq, (*flows)[i]),
+					    fmt_amount_msat(
+						tmpctx, linear_flow_cost(
+							    (*flows)[i], amount,
+							    delay_feefactor)));
+				}
+				rq_log(tmpctx, rq, LOG_BROKEN,
+				       "Old flows cost %s:",
+				       fmt_amount_msat(tmpctx, new_cost));
+				for (size_t i = 0; i < tal_count(new_flows);
+				     i++) {
+					rq_log(
+					    tmpctx, rq, LOG_BROKEN,
+					    "Flow %zu/%zu: %s (linear cost %s)",
+					    i, tal_count(new_flows),
+					    fmt_flow_full(tmpctx, rq,
+							  new_flows[i]),
+					    fmt_amount_msat(
+						tmpctx,
+						linear_flow_cost(
+						    new_flows[i], amount,
+						    delay_feefactor)));
+				}
+			}
+		}
+		tal_free(*flows);
+		*flows = new_flows;
+	}
+
+	if (finalcltv + flows_worst_delay(*flows) > maxdelay) {
+		ret = rq_log(
+		    ctx, rq, LOG_UNUSUAL,
+		    "Could not find route without excessive cost or delays");
+		goto fail;
+	}
+
+	/* The above did not take into account the extra funds to pay
+	 * fees, so we try to adjust now.  We could re-run MCF if this
+	 * fails, but failure basically never happens where payment is
+	 * still possible */
+	ret = refine_with_fees_and_limits(ctx, rq, amount, flows, probability);
+	if (ret)
+		goto fail;
+
+	/* Again, a tiny corner case: refine step can make us exceed maxfee */
+	if (amount_msat_greater(flowset_fee(rq->plugin, *flows), maxfee)) {
+		rq_log(tmpctx, rq, LOG_UNUSUAL,
+		       "After final refinement, fee was excessive: retrying");
+		goto too_expensive;
+	}
+
+	return NULL;
+fail:
+	assert(ret != NULL);
+	return ret;
+}
diff --git a/plugins/askrene/mcf.h b/plugins/askrene/mcf.h
index f8100e766dd6..701a1ac5bf75 100644
--- a/plugins/askrene/mcf.h
+++ b/plugins/askrene/mcf.h
@@ -40,4 +40,14 @@ struct amount_msat linear_flow_cost(const struct flow *flow,
 				    struct amount_msat total_amount,
 				    double delay_feefactor);
 
+/* A wrapper to the min. cost flow solver that actually takes into consideration
+ * the extra msats per channel needed to pay for fees. */
+const char *default_routes(const tal_t *ctx, struct route_query *rq,
+			   const struct gossmap_node *srcnode,
+			   const struct gossmap_node *dstnode,
+			   struct amount_msat amount, bool single_path,
+			   struct amount_msat maxfee, u32 finalcltv,
+			   u32 maxdelay, struct flow ***flows,
+			   double *probability);
+
 #endif /* LIGHTNING_PLUGINS_ASKRENE_MCF_H */