diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,13 @@
 # Revision history for lsp-test
 
+## 0.18.0.0 -- 2026-02-14
+
+- Add a context parameter for getSignatureHelp
+- Add signature help request
+- Add workspace symbol request
+- Relax dependency version bounds
+- Expose resolveCompletion helper
+
 ## 0.17.1.1 -- 2024-12-31
 
 - Relax dependency version bounds
@@ -20,7 +28,7 @@
 
 - `ignoreRegistrationRequests` option to ignore `client/registerCapability` requests, on
   by default.
-- New functions `setIgnoringRegistrationRequests` to change whether such messages are 
+- New functions `setIgnoringRegistrationRequests` to change whether such messages are
   ignored during a `Session` without having to change the `SessionConfig`.
 - `lsp-test` will no longer send `workspace/didChangConfiguration` notifications unless
   the server dynamically registers for them.
@@ -60,7 +68,7 @@
 
 * Compatibility with new `lsp-types` major version.
 
-## 0.14.0.2 
+## 0.14.0.2
 
 * Compatibility with new `lsp-types` major version.
 
diff --git a/func-test/FuncTest.hs b/func-test/FuncTest.hs
--- a/func-test/FuncTest.hs
+++ b/func-test/FuncTest.hs
@@ -39,13 +39,15 @@
   (hinRead, hinWrite) <- createPipe
   (houtRead, houtWrite) <- createPipe
 
-  server <- async $ void $ runServerWithHandles logger (L.hoistLogAction liftIO logger) hinRead houtWrite defn
+  server <- async $ runServerWithHandles logger (L.hoistLogAction liftIO logger) hinRead houtWrite defn
 
   res <- Test.runSessionWithHandles hinWrite houtRead testConfig caps root session
 
   timeout 3000000 $ do
-    Left (fromException -> Just ExitSuccess) <- waitCatch server
-    pure ()
+    return_code <- wait server
+    case return_code of
+      0 -> pure ()
+      _ -> error $ "Server exited with non-zero code: " ++ show return_code
 
   pure res
 
diff --git a/lsp-test.cabal b/lsp-test.cabal
--- a/lsp-test.cabal
+++ b/lsp-test.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               lsp-test
-version:            0.17.1.1
+version:            0.18.0.0
 synopsis:           Functional test framework for LSP servers.
 description:
   A test framework for writing tests against
@@ -22,9 +22,10 @@
 copyright:          2021 Luke Lau
 category:           Testing
 build-type:         Simple
-extra-source-files:
+extra-doc-files:
   ChangeLog.md
   README.md
+extra-source-files:
   test/data/**/*.hs
 
 source-repository head
@@ -55,7 +56,7 @@
     , co-log-core         ^>=0.3
     , conduit             ^>=1.3
     , conduit-parse       ^>=0.2
-    , containers          >=0.6 && < 0.8
+    , containers          >=0.6 && < 0.9
     , data-default        >=0.7 && < 0.9
     , Diff                >=0.4   && <1.1
     , directory           ^>=1.3
@@ -65,14 +66,14 @@
     , Glob                >=0.9   && <0.11
     , lens                >=5.1   && <5.4
     , lens-aeson          ^>=1.2
-    , lsp                 ^>=2.7
-    , lsp-types           ^>=2.3
+    , lsp                 ^>=2.8
+    , lsp-types           ^>=2.4
     , mtl                 >=2.2   && <2.4
     , parser-combinators  ^>=1.3
     , process             ^>=1.6
     , some                ^>=1.0
     , text                >=1     && <2.2
-    , time                >=1.10  && <1.15
+    , time                >=1.10  && <1.16
     , transformers        >=0.5   && <0.7
 
   if os(windows)
diff --git a/src/Language/LSP/Test.hs b/src/Language/LSP/Test.hs
--- a/src/Language/LSP/Test.hs
+++ b/src/Language/LSP/Test.hs
@@ -93,6 +93,7 @@
   -- ** Completions
   getCompletions,
   getAndResolveCompletions,
+  resolveCompletion,
 
   -- ** References
   getReferences,
@@ -109,6 +110,9 @@
   -- ** Hover
   getHover,
 
+  -- ** Signature Help
+  getSignatureHelp,
+
   -- ** Highlights
   getHighlights,
 
@@ -137,6 +141,10 @@
   -- ** SemanticTokens
   getSemanticTokens,
 
+  -- ** Workspace Symbols
+  getWorkspaceSymbols,
+  resolveWorkspaceSymbols,
+
   -- ** Capabilities
   getRegisteredCapabilities,
 ) where
@@ -366,7 +374,7 @@
 documentContents :: TextDocumentIdentifier -> Session T.Text
 documentContents doc = do
   vfs <- vfs <$> get
-  let Just file = vfs ^. vfsMap . at (toNormalizedUri (doc ^. L.uri))
+  let Just file = vfs ^? vfsMap . ix (toNormalizedUri (doc ^. L.uri)) . _Open
   return (virtualFileText file)
 
 {- | Parses an ApplyEditRequest, checks that it is for the passed document
@@ -796,7 +804,7 @@
 getVersionedDoc :: TextDocumentIdentifier -> Session VersionedTextDocumentIdentifier
 getVersionedDoc (TextDocumentIdentifier uri) = do
   vfs <- vfs <$> get
-  let ver = vfs ^? vfsMap . ix (toNormalizedUri uri) . to virtualFileVersion
+  let ver = vfs ^? vfsMap . ix (toNormalizedUri uri) . _Open . to virtualFileVersion
   -- TODO: is this correct? Could return an OptionalVersionedTextDocumentIdentifier,
   -- but that complicated callers...
   return (VersionedTextDocumentIdentifier uri (fromMaybe 0 ver))
@@ -928,6 +936,12 @@
   let params = HoverParams doc pos Nothing
    in nullToMaybe . getResponseResult <$> request SMethod_TextDocumentHover params
 
+-- | Returns the signature help at the specified position.
+getSignatureHelp :: TextDocumentIdentifier -> Position -> Maybe SignatureHelpContext -> Session (Maybe SignatureHelp)
+getSignatureHelp doc pos mCtx =
+  let params = SignatureHelpParams doc pos Nothing mCtx
+   in nullToMaybe . getResponseResult <$> request SMethod_TextDocumentSignatureHelp params
+
 -- | Returns the highlighted occurrences of the term at the specified position
 getHighlights :: TextDocumentIdentifier -> Position -> Session [DocumentHighlight]
 getHighlights doc pos =
@@ -1034,6 +1048,19 @@
 getSemanticTokens doc = do
   let params = SemanticTokensParams Nothing Nothing doc
   rsp <- request SMethod_TextDocumentSemanticTokensFull params
+  pure $ getResponseResult rsp
+
+{- | Query the workspace and filter by the given 'T.Text'.
+If empty, this queries the entire workspace.
+-}
+getWorkspaceSymbols :: T.Text -> Session ([SymbolInformation] |? ([WorkspaceSymbol] |? Null))
+getWorkspaceSymbols query = do
+  rsp <- request SMethod_WorkspaceSymbol (WorkspaceSymbolParams Nothing Nothing query)
+  pure $ getResponseResult rsp
+
+resolveWorkspaceSymbols :: WorkspaceSymbol -> Session WorkspaceSymbol
+resolveWorkspaceSymbols item = do
+  rsp <- request SMethod_WorkspaceSymbolResolve item
   pure $ getResponseResult rsp
 
 {- | Returns a list of capabilities that the server has requested to /dynamically/
diff --git a/src/Language/LSP/Test/Session.hs b/src/Language/LSP/Test/Session.hs
--- a/src/Language/LSP/Test/Session.hs
+++ b/src/Language/LSP/Test/Session.hs
@@ -83,6 +83,7 @@
 import Colog.Core (LogAction (..), WithSeverity (..), Severity (..))
 import Data.String (fromString)
 import Data.Either (partitionEithers)
+import Control.Concurrent.Async (async, cancel)
 
 -- | A session representing one instance of launching and connecting to a server.
 --
@@ -303,9 +304,9 @@
 
       errorHandler = throwTo mainThreadId :: SessionException -> IO ()
       serverListenerLauncher =
-        forkIO $ catch (serverHandler serverOut context) errorHandler
+        async $ catch (serverHandler serverOut context) errorHandler
       msgTimeoutMs = messageTimeout config * 10^6
-      serverAndListenerFinalizer tid = do
+      serverAndListenerFinalizer async = do
         let cleanup
               | Just sp <- mServerProc = do
                   -- Give the server some time to exit cleanly
@@ -318,7 +319,7 @@
         finally (timeout msgTimeoutMs (runSession' exitServer))
                 -- Make sure to kill the listener first, before closing
                 -- handles etc via cleanupProcess
-                (killThread tid >> cleanup)
+                (cancel async >> cleanup)
 
   (result, _) <- bracket serverListenerLauncher
                          serverAndListenerFinalizer
@@ -445,8 +446,8 @@
   forM_ latestVersions $ \(VersionedTextDocumentIdentifier uri v) ->
     modify $ \s ->
       let oldVFS = vfs s
-          update (VirtualFile _ file_ver t) = VirtualFile v (file_ver +1) t
-          newVFS = oldVFS & vfsMap . ix (toNormalizedUri uri) %~ update
+          update (VirtualFile _ file_ver t _kind) = VirtualFile v (file_ver +1) t _kind
+          newVFS = oldVFS & vfsMap . ix (toNormalizedUri uri) . _Open %~ update
       in s { vfs = newVFS }
 
   where
@@ -486,7 +487,7 @@
         -- where n is the current version
         textDocumentVersions uri = do
           vfs <- vfs <$> get
-          let curVer = fromMaybe 0 $ vfs ^? vfsMap . ix (toNormalizedUri uri) . lsp_version
+          let curVer = fromMaybe 0 $ vfs ^? vfsMap . ix (toNormalizedUri uri) . _Open . lsp_version
           pure $ map (VersionedTextDocumentIdentifier uri) [curVer + 1..]
 
         textDocumentEdits uri edits = do
diff --git a/test/DummyServer.hs b/test/DummyServer.hs
--- a/test/DummyServer.hs
+++ b/test/DummyServer.hs
@@ -72,6 +72,12 @@
             Right $
               InL $
                 Hover (InL (MarkupContent MarkupKind_PlainText "hello")) Nothing
+    , requestHandler SMethod_TextDocumentSignatureHelp $
+        \_req responder ->
+          responder $
+            Right $
+              InL $
+                SignatureHelp [] Nothing Nothing
     , requestHandler SMethod_TextDocumentDocumentSymbol $
         \_req responder ->
           responder $
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -307,6 +307,12 @@
       hover <- getHover doc (Position 45 9)
       liftIO $ hover `shouldSatisfy` isJust
 
+  describe "getSignatureHelp" $
+    it "works" $ \(hin, hout) -> runSessionWithHandles hin hout def fullLatestClientCaps "." $ do
+      doc <- openDoc "test/data/renamePass/Desktop/simple.hs" "haskell"
+      signatureHelp <- getSignatureHelp doc (Position 22 32) Nothing
+      liftIO $ signatureHelp `shouldSatisfy` isJust
+
   -- describe "getHighlights" $
   --   it "works" $ \(hin, hout) -> runSessionWithHandles hin hout def fullLatestClientCaps "." $ do
   --     doc <- openDoc "test/data/renamePass/Desktop/simple.hs" "haskell"
