diff --git a/include/mcdstub/mcdstub.h b/include/mcdstub/mcdstub.h
index 85ca8b3b62..0375cf7311 100644
--- a/include/mcdstub/mcdstub.h
+++ b/include/mcdstub/mcdstub.h
@@ -439,6 +439,33 @@ int process_string_cmd(void *user_ctx, const char *data,
  */
 int cmd_parse_params(const char *data, const char *schema, GArray *params);
 
+/**
+ * handle_vm_start() - Handler for the VM start TCP packet.
+ *
+ * Evaluates whether all cores or just a perticular core should get started and
+ * calls :c:func:`mcd_vm_start` or :c:func:`mcd_cpu_start` respectively.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_vm_start(GArray *params, void *user_ctx);
+
+/**
+ * handle_vm_step() - Handler for the VM step TCP packet.
+ *
+ * Calls :c:func:`mcd_cpu_sstep` for the CPU which sould be stepped.
+ * Stepping all CPUs is currently not supported.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_vm_step(GArray *params, void *user_ctx);
+
+/**
+ * handle_vm_stop() - Handler for the VM stop TCP packet.
+ *
+ * Always calls :c:func:`mcd_vm_stop` and stops all cores. Stopping individual
+ * cores is currently not supported.
+ * @params: GArray with all TCP packet parameters.
+ */
+void handle_vm_stop(GArray *params, void *user_ctx);
+
 /**
  * handle_gen_query() - Handler for all TCP query packets.
  *
@@ -550,6 +577,32 @@ void handle_close_core(GArray *params, void *user_ctx);
  */
 void handle_query_trigger(GArray *params, void *user_ctx);
 
+/**
+ * mcd_vm_start() - Starts all CPUs with the vm_start function.
+ */
+void mcd_vm_start(void);
+
+/**
+ * mcd_cpu_start() - Starts the selected CPU with the cpu_resume function.
+ *
+ * @cpu: The CPU about to be started.
+ */
+void mcd_cpu_start(CPUState *cpu);
+
+/**
+ * mcd_cpu_sstep() - Performes a step on the selected CPU.
+ *
+ * This function first sets the correct single step flags for the CPU with
+ * cpu_single_step and then starts the CPU with cpu_resume.
+ * @cpu: The CPU about to be stepped.
+ */
+int mcd_cpu_sstep(CPUState *cpu);
+
+/**
+ * mcd_vm_stop() - Brings all CPUs in debug state with the vm_stop function.
+ */
+void mcd_vm_stop(void);
+
 /**
  * handle_query_reg_groups_f() - Handler for the first register group query.
  *
diff --git a/mcdstub/mcdstub.c b/mcdstub/mcdstub.c
index cd2f5db8e4..6313459bac 100644
--- a/mcdstub/mcdstub.c
+++ b/mcdstub/mcdstub.c
@@ -432,6 +432,37 @@ int mcd_handle_packet(const char *line_buf)
             cmd_parser = &open_server_cmd_desc;
         }
         break;
+    case TCP_CHAR_GO:
+        {
+            static MCDCmdParseEntry go_cmd_desc = {
+                .handler = handle_vm_start,
+            };
+            go_cmd_desc.cmd = (char[2]) { TCP_CHAR_GO, '\0' };
+            strcpy(go_cmd_desc.schema,
+                (char[3]) { ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0' });
+            cmd_parser = &go_cmd_desc;
+        }
+        break;
+    case TCP_CHAR_STEP:
+        {
+            static MCDCmdParseEntry step_cmd_desc = {
+                .handler = handle_vm_step,
+            };
+            step_cmd_desc.cmd = (char[2]) { TCP_CHAR_STEP, '\0' };
+            strcpy(step_cmd_desc.schema,
+                (char[3]) { ARG_SCHEMA_INT, ARG_SCHEMA_CORENUM, '\0' });
+            cmd_parser = &step_cmd_desc;
+        }
+        break;
+    case TCP_CHAR_BREAK:
+        {
+            static MCDCmdParseEntry break_cmd_desc = {
+                .handler = handle_vm_stop,
+            };
+            break_cmd_desc.cmd = (char[2]) { TCP_CHAR_BREAK, '\0' };
+            cmd_parser = &break_cmd_desc;
+        }
+        break;
     case TCP_CHAR_KILLQEMU:
         /* kill qemu completely */
         error_report("QEMU: Terminated via MCDstub");
@@ -494,6 +525,40 @@ int mcd_handle_packet(const char *line_buf)
     return RS_IDLE;
 }
 
+void handle_vm_start(GArray *params, void *user_ctx)
+{
+    uint32_t global = get_param(params, 0)->data_uint32_t;
+    if (global == 1) {
+        mcd_vm_start();
+    } else{
+        uint32_t cpu_id = get_param(params, 1)->cpu_id;
+        CPUState *cpu = mcd_get_cpu(cpu_id);
+        mcd_cpu_start(cpu);
+    }
+}
+
+void handle_vm_step(GArray *params, void *user_ctx)
+{
+    uint32_t global = get_param(params, 0)->data_uint32_t;
+    if (global == 1) {
+        /* TODO: add multicore support */
+    } else{
+        uint32_t cpu_id = get_param(params, 1)->cpu_id;
+        CPUState *cpu = mcd_get_cpu(cpu_id);
+        int return_value = mcd_cpu_sstep(cpu);
+        if (return_value != 0) {
+            g_assert_not_reached();
+        }
+    }
+}
+
+
+void handle_vm_stop(GArray *params, void *user_ctx)
+{
+    /* TODO: add core dependant break option */
+    mcd_vm_stop();
+}
+
 void handle_gen_query(GArray *params, void *user_ctx)
 {
     if (!params->len) {
@@ -1286,6 +1351,42 @@ void handle_query_trigger(GArray *params, void *user_ctx)
     mcd_put_strbuf();
 }
 
+void mcd_vm_start(void)
+{
+    if (!runstate_needs_reset() && !runstate_is_running()) {
+        vm_start();
+    }
+}
+
+void mcd_cpu_start(CPUState *cpu)
+{
+    if (!runstate_needs_reset() && !runstate_is_running() &&
+        !vm_prepare_start(false)) {
+        mcdserver_state.c_cpu = cpu;
+        qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+        cpu_resume(cpu);
+    }
+}
+
+int mcd_cpu_sstep(CPUState *cpu)
+{
+    mcdserver_state.c_cpu = cpu;
+    cpu_single_step(cpu, mcdserver_state.sstep_flags);
+    if (!runstate_needs_reset() && !runstate_is_running() &&
+        !vm_prepare_start(true)) {
+        qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
+        cpu_resume(cpu);
+    }
+    return 0;
+}
+
+void mcd_vm_stop(void)
+{
+    if (runstate_is_running()) {
+        vm_stop(RUN_STATE_DEBUG);
+    }
+}
+
 void handle_query_mem_spaces_f(GArray *params, void *user_ctx)
 {
     /* 1. get correct memspaces and set the query_cpu */
