diff --git a/Cargo.lock b/Cargo.lock
index c062366923d..5ce35c5b1dc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -658,9 +658,9 @@ dependencies = [
 
 [[package]]
 name = "lsp-server"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5383e043329615624bbf45e1ba27bd75c176762b2592855c659bc28ac580a06b"
+checksum = "dccec31bfd027ac0dd288a78e19005fd89624d9099456e284b5241316a6c3072"
 dependencies = [
  "crossbeam-channel",
  "log",
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 09908458dba..f5b4fee2bc7 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -74,12 +74,25 @@ fn run_server() -> Result<()> {
     log::info!("lifecycle: server started");
 
     let (connection, io_threads) = Connection::stdio();
-    let server_capabilities = serde_json::to_value(rust_analyzer::server_capabilities()).unwrap();
 
-    let initialize_params = connection.initialize(server_capabilities)?;
+    let (initialize_id, initialize_params) = connection.initialize_start()?;
     let initialize_params =
         from_json::<lsp_types::InitializeParams>("InitializeParams", initialize_params)?;
 
+    let server_capabilities = rust_analyzer::server_capabilities(&initialize_params.capabilities);
+
+    let initialize_result = lsp_types::InitializeResult {
+        capabilities: server_capabilities,
+        server_info: Some(lsp_types::ServerInfo {
+            name: String::from("rust-analyzer"),
+            version: None,
+        }),
+    };
+
+    let initialize_result = serde_json::to_value(initialize_result).unwrap();
+
+    connection.initialize_finish(initialize_id, initialize_result)?;
+
     if let Some(client_info) = initialize_params.client_info {
         log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default());
     }
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 110c9a44297..5ac98c65728 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -4,16 +4,47 @@ use std::env;
 use crate::semantic_tokens;
 
 use lsp_types::{
-    CallHierarchyServerCapability, CodeActionOptions, CodeActionProviderCapability,
-    CodeLensOptions, CompletionOptions, DocumentOnTypeFormattingOptions,
-    FoldingRangeProviderCapability, ImplementationProviderCapability, RenameOptions,
-    RenameProviderCapability, SaveOptions, SelectionRangeProviderCapability,
-    SemanticTokensDocumentProvider, SemanticTokensLegend, SemanticTokensOptions,
-    ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
-    TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
+    CallHierarchyServerCapability, ClientCapabilities, CodeActionOptions,
+    CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
+    DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability,
+    ImplementationProviderCapability, RenameOptions, RenameProviderCapability, SaveOptions,
+    SelectionRangeProviderCapability, SemanticTokensDocumentProvider, SemanticTokensLegend,
+    SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions, TextDocumentSyncCapability,
+    TextDocumentSyncKind, TextDocumentSyncOptions, TypeDefinitionProviderCapability,
+    WorkDoneProgressOptions,
 };
 
-pub fn server_capabilities() -> ServerCapabilities {
+pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabilities {
+    let mut code_action_provider = CodeActionProviderCapability::Simple(true);
+
+    match client_caps.text_document.as_ref() {
+        Some(it) => {
+            match it.code_action.as_ref().and_then(|c| c.code_action_literal_support.as_ref()) {
+                Some(_literal_support) => {
+                    code_action_provider =
+                        CodeActionProviderCapability::Options(CodeActionOptions {
+                            // Advertise support for all built-in CodeActionKinds.
+                            // Ideally we would base this off of the client capabilities
+                            // but the client is supposed to fall back gracefully for unknown values.
+                            code_action_kinds: Some(vec![
+                                lsp_types::code_action_kind::EMPTY.to_string(),
+                                lsp_types::code_action_kind::QUICKFIX.to_string(),
+                                lsp_types::code_action_kind::REFACTOR.to_string(),
+                                lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(),
+                                lsp_types::code_action_kind::REFACTOR_INLINE.to_string(),
+                                lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(),
+                                lsp_types::code_action_kind::SOURCE.to_string(),
+                                lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(),
+                            ]),
+                            work_done_progress_options: Default::default(),
+                        });
+                }
+                None => {}
+            }
+        }
+        None => {}
+    };
+
     ServerCapabilities {
         text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
             open_close: Some(true),
@@ -45,20 +76,7 @@ pub fn server_capabilities() -> ServerCapabilities {
         document_highlight_provider: Some(true),
         document_symbol_provider: Some(true),
         workspace_symbol_provider: Some(true),
-        code_action_provider: Some(CodeActionProviderCapability::Options(CodeActionOptions {
-            // Advertise support for all built-in CodeActionKinds
-            code_action_kinds: Some(vec![
-                lsp_types::code_action_kind::EMPTY.to_string(),
-                lsp_types::code_action_kind::QUICKFIX.to_string(),
-                lsp_types::code_action_kind::REFACTOR.to_string(),
-                lsp_types::code_action_kind::REFACTOR_EXTRACT.to_string(),
-                lsp_types::code_action_kind::REFACTOR_INLINE.to_string(),
-                lsp_types::code_action_kind::REFACTOR_REWRITE.to_string(),
-                lsp_types::code_action_kind::SOURCE.to_string(),
-                lsp_types::code_action_kind::SOURCE_ORGANIZE_IMPORTS.to_string(),
-            ]),
-            work_done_progress_options: Default::default(),
-        })),
+        code_action_provider: Some(code_action_provider),
         code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
         document_formatting_provider: Some(true),
         document_range_formatting_provider: None,