diff --git a/lib/layer/cookiemonster.c b/lib/layer/cookiemonster.c
index a8732f3d3dee8ac3d8170e68bc23f472d400e3b5..795cf067c38b225b86480a507a226c268607dcd2 100644
--- a/lib/layer/cookiemonster.c
+++ b/lib/layer/cookiemonster.c
@@ -382,6 +382,39 @@ static int knot_pkt_set_ext_rcode(knot_pkt_t *pkt, uint16_t whole_rcode)
 	return kr_ok();
 }
 
+/** Only adds cookies into the OPT RR. */
+static int answer_opt_rr_add_cookies(knot_pkt_t *answer,
+                                     const struct kr_srvr_cookie_input *input,
+                                     const struct kr_srvr_cookie_alg_descr *alg)
+{
+	assert(answer && input && alg);
+
+	size_t cookie_size = KNOT_OPT_COOKIE_CLNT + alg->srvr_cookie_size;
+	uint8_t *data = NULL;
+
+	if (!answer->opt_rr) {
+		kr_error(EINVAL);
+	}
+	int ret = knot_edns_reserve_option(answer->opt_rr,
+	                                   KNOT_EDNS_OPTION_COOKIE,
+	                                   cookie_size, &data, &answer->mm);
+	if (ret != KNOT_EOK) {
+		return kr_error(ret);
+	}
+
+	memcpy(data, input->clnt_cookie, KNOT_OPT_COOKIE_CLNT);
+	cookie_size = alg->srvr_cookie_size;
+	ret = alg->gen_func(input, data + KNOT_OPT_COOKIE_CLNT, &cookie_size);
+	if (ret != kr_ok()) {
+		/* TODO -- Delete COOKIE option. */
+		return ret;
+	}
+
+	return ret;
+}
+
+/* TODO -- DNS cookie request. */
+
 static int check_request(knot_layer_t *ctx, void *module_param)
 {
 	if (!kr_glob_cookie_ctx.srvr.enabled) {
@@ -463,10 +496,13 @@ static int check_request(knot_layer_t *ctx, void *module_param)
 	if (ret == kr_error(EBADMSG) &&
 	    srvr_cntrl->recent.ssec && srvr_cntrl->recent.salg) {
 		/* Try recent algorithm. */
-		check_ctx.secret_data = srvr_cntrl->recent.ssec->data;
-		check_ctx.secret_len = srvr_cntrl->recent.ssec->size;
+		struct kr_srvr_cookie_check_ctx recent_ctx = {
+			.clnt_sockaddr = req->qsource.addr,
+			.secret_data = srvr_cntrl->recent.ssec->data,
+			.secret_len = srvr_cntrl->recent.ssec->size
+		};
 		ret = kr_srvr_cookie_check(req_cc, req_sc, req_sc_len,
-		                           &check_ctx,
+		                           &recent_ctx,
 		                           srvr_cntrl->recent.salg);
 	}
 	if (ret != kr_ok()) {
@@ -491,29 +527,14 @@ static int check_request(knot_layer_t *ctx, void *module_param)
 
 	/* Server cookie OK. */
 
-	return ctx->state;
-}
-
-static int process_response(knot_layer_t *ctx)
-{
-	if (!kr_glob_cookie_ctx.srvr.enabled) {
-		return ctx->state;
-	}
-
-	struct kr_request *req = ctx->data;
-	const knot_rrset_t *req_opt_rr = req->qsource.opt;
-
-	if (!req_opt_rr) {
-		return ctx->state;
-	}
-
-	uint8_t *req_cookie_opt = knot_edns_get_option(req_opt_rr,
-	                                               KNOT_EDNS_OPTION_COOKIE);
-	if (!req_cookie_opt) {
-		return ctx->state;
-	}
-
-	/* TODO -- Add server cookie into answer. */
+	/* Add server cookie into response. */
+	struct kr_srvr_cookie_input input = {
+		.clnt_cookie = req_cc,
+		.nonce = 0, /*TODO -- Some pseudo-random value? */
+		.time = req->current_query->timestamp.tv_sec,
+		.srvr_data = &check_ctx
+	};
+	answer_opt_rr_add_cookies(req->answer, &input, srvr_cntrl->current.salg);
 
 	return ctx->state;
 }
@@ -523,9 +544,11 @@ static int process_response(knot_layer_t *ctx)
 KR_EXPORT
 const knot_layer_api_t *cookiemonster_layer(struct kr_module *module)
 {
+	/* The function answer_finalize() in resolver is called before any
+	 * .finish callback. Therefore this layer does not use it. */
+
 	static knot_layer_api_t _layer = {
 		.begin = &check_request,
-		.finish = &process_response,
 		.consume = &check_response
 	};
 	/* Store module reference */