diff --git a/bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF b/bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF
index eaef9c94..cc8e33ed 100644
--- a/bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.cdt.lsp/META-INF/MANIFEST.MF
@@ -7,7 +7,9 @@ Export-Package: org.eclipse.cdt.lsp,
  org.eclipse.cdt.lsp.editor,
  org.eclipse.cdt.lsp.server,
  org.eclipse.cdt.lsp.server.enable,
- org.eclipse.cdt.lsp.services
+ org.eclipse.cdt.lsp.services,
+ org.eclipse.cdt.lsp.services.ast,
+ org.eclipse.cdt.lsp.services.symbolinfo
 Bundle-Activator: org.eclipse.cdt.lsp.LspPlugin
 Bundle-Vendor: %Bundle-Vendor
 Require-Bundle: org.eclipse.ui,
diff --git a/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ClangdLanguageServer.java b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ClangdLanguageServer.java
index 82b5397d..e7162154 100644
--- a/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ClangdLanguageServer.java
+++ b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ClangdLanguageServer.java
@@ -9,24 +9,32 @@
  *
  * Contributors:
  * Dominic Scharfe (COSEDA Technologies GmbH) - initial implementation
+ * Dietrich Travkin (Solunar GmbH) - extensions for AST and symbol info
  *******************************************************************************/
 package org.eclipse.cdt.lsp.services;
 
 import java.util.concurrent.CompletableFuture;
 
+import org.eclipse.cdt.lsp.services.ast.AstNode;
+import org.eclipse.cdt.lsp.services.ast.AstParams;
+import org.eclipse.cdt.lsp.services.symbolinfo.SymbolDetails;
 import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.lsp4j.TextDocumentPositionParams;
 import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
 import org.eclipse.lsp4j.services.LanguageServer;
 
 /**
  * Interface extending the {@link LanguageServer} with clangd extensions.
+ * More details about LSP usage and extension see the
+ * 
+ * org.eclipse.lsp4j project's documentation.
  *
  * @see https://clangd.llvm.org/extensions
  */
 public interface ClangdLanguageServer extends LanguageServer {
 
 	/**
-	 * The switchSourceHeader request is sent from the client to the server to
+	 * The textDocument/switchSourceHeader request is sent from the client to the server to
 	 * 
 	 * - get the corresponding header if a source file was provided*
- get the source file if a header was provided@@ -39,4 +47,31 @@ public interface ClangdLanguageServer extends LanguageServer {
 	 */
 	@JsonRequest(value = "textDocument/switchSourceHeader")
 	CompletableFuture switchSourceHeader(TextDocumentIdentifier textDocument);
+
+	/**
+	 * The textDocument/ast request is sent from the client to the server in order to get
+	 * details about the program structure (so called abstract syntax tree or AST) in a C++ file.
+	 * The structure can be requested for the whole file or for a certain range.
+	 *
+	 * @param astParameters request parameters containing the document identifier and requested documented range
+	 * @return the abstract syntax tree root node (with child hierarchy) for the requested document and range
+	 *
+	 * @see https://clangd.llvm.org/extensions#ast
+	 */
+	@JsonRequest(value = "textDocument/ast")
+	CompletableFuture getAst(AstParams astParameters);
+
+	/**
+	 * The textDocument/symbolInfo request is sent from the client to the server in order to access
+	 * details about the element under the cursor. The response provides details like the element's name,
+	 * its parent container's name, and some clangd-specific element IDs (e.g. the "unified symbol resolution"
+	 * identifier).
+	 *
+	 * @param positionParameters request parameters containing the document identifier and the current cursor position
+	 * @return the details about the symbol on the given position
+	 *
+	 * @see https://clangd.llvm.org/extensions#symbol-info-request
+	 */
+	@JsonRequest(value = "textDocument/symbolInfo")
+	CompletableFuture getSymbolInfo(TextDocumentPositionParams positionParameters);
 }
diff --git a/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ast/AstNode.java b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ast/AstNode.java
new file mode 100644
index 00000000..a69f2c17
--- /dev/null
+++ b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ast/AstNode.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Advantest Europe GmbH and others.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Dietrich Travkin (Solunar GmbH) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.lsp.services.ast;
+
+import java.util.Arrays;
+
+import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
+import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
+import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
+
+/**
+ * Return type for the textDocument/ast request.
+ * This class was generated by the org.eclipse.lsp4j.generator bundle
+ * using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
+ * the documentation).
+ *
+ * @see {@link ClangdLanguageServer#getAst(AstParams)}
+ */
+public class AstNode {
+
+	@NonNull
+	private String role;
+
+	@NonNull
+	private String kind;
+
+	private String detail;
+
+	private String arcana;
+
+	@NonNull
+	private Range range;
+
+	private AstNode[] children;
+
+	public AstNode() {
+
+	}
+
+	@NonNull
+	public String getRole() {
+		return role;
+	}
+
+	public void setRole(@NonNull final String role) {
+		this.role = Preconditions.checkNotNull(role, "role"); //$NON-NLS-1$
+	}
+
+	@NonNull
+	public String getKind() {
+		return this.kind;
+	}
+
+	public void setKind(@NonNull final String kind) {
+		this.kind = Preconditions.checkNotNull(kind, "kind"); //$NON-NLS-1$
+	}
+
+	public String getDetail() {
+		return detail;
+	}
+
+	public void setDetail(final String detail) {
+		this.detail = detail;
+	}
+
+	public String getArcana() {
+		return arcana;
+	}
+
+	public void setArcana(final String arcana) {
+		this.arcana = arcana;
+	}
+
+	@NonNull
+	public Range getRange() {
+		return range;
+	}
+
+	public void setRange(@NonNull final Range range) {
+		this.range = Preconditions.checkNotNull(range, "range"); //$NON-NLS-1$
+	}
+
+	public AstNode[] getChildren() {
+		return children;
+	}
+
+	public void setChildren(final AstNode[] children) {
+		this.children = children;
+	}
+
+	@Override
+	public String toString() {
+		ToStringBuilder b = new ToStringBuilder(this);
+		b.add("role", this.role); //$NON-NLS-1$
+		b.add("kind", this.kind); //$NON-NLS-1$
+		b.add("detail", this.detail); //$NON-NLS-1$
+		b.add("arcana", this.arcana); //$NON-NLS-1$
+		b.add("range", this.range); //$NON-NLS-1$
+		b.add("children", this.children); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		AstNode other = (AstNode) obj;
+		if (this.role == null) {
+			if (other.role != null)
+				return false;
+		} else if (!this.role.equals(other.role))
+			return false;
+		if (this.kind == null) {
+			if (other.kind != null)
+				return false;
+		} else if (!this.kind.equals(other.kind))
+			return false;
+		if (this.detail == null) {
+			if (other.detail != null)
+				return false;
+		} else if (!this.detail.equals(other.detail))
+			return false;
+		if (this.arcana == null) {
+			if (other.arcana != null)
+				return false;
+		} else if (!this.arcana.equals(other.arcana))
+			return false;
+		if (this.range == null) {
+			if (other.range != null)
+				return false;
+		} else if (!this.range.equals(other.range))
+			return false;
+		if (this.children == null) {
+			if (other.children != null)
+				return false;
+		} else if (!Arrays.deepEquals(this.children, other.children))
+			return false;
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((this.role == null) ? 0 : this.role.hashCode());
+		result = prime * result + ((this.kind == null) ? 0 : this.kind.hashCode());
+		result = prime * result + ((this.detail == null) ? 0 : this.detail.hashCode());
+		result = prime * result + ((this.arcana == null) ? 0 : this.arcana.hashCode());
+		result = prime * result + ((this.range == null) ? 0 : this.range.hashCode());
+		return prime * result + ((this.children == null) ? 0 : Arrays.deepHashCode(this.children));
+	}
+}
diff --git a/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ast/AstParams.java b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ast/AstParams.java
new file mode 100644
index 00000000..4ebc56a7
--- /dev/null
+++ b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/ast/AstParams.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Advantest Europe GmbH and others.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Dietrich Travkin (Solunar GmbH) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.lsp.services.ast;
+
+import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
+import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
+import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
+
+/**
+ * Parameter object type for the textDocument/ast request.
+ * This class was generated by the org.eclipse.lsp4j.generator bundle
+ * using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
+ * the documentation).
+ *
+ * @see {@link ClangdLanguageServer#getAst(AstParams)}
+ */
+public class AstParams {
+
+	@NonNull
+	private TextDocumentIdentifier textDocument;
+
+	@NonNull
+	private Range range;
+
+	public AstParams() {
+	}
+
+	public AstParams(@NonNull final TextDocumentIdentifier textDocument, @NonNull final Range range) {
+		this.textDocument = Preconditions.checkNotNull(textDocument, "textDocument"); //$NON-NLS-1$
+		this.range = Preconditions.checkNotNull(range, "range"); //$NON-NLS-1$
+	}
+
+	@NonNull
+	public TextDocumentIdentifier getTextDocument() {
+		return this.textDocument;
+	}
+
+	public void setTextDocument(@NonNull final TextDocumentIdentifier textDocument) {
+		this.textDocument = Preconditions.checkNotNull(textDocument, "textDocument"); //$NON-NLS-1$
+	}
+
+	@NonNull
+	public Range getRange() {
+		return range;
+	}
+
+	public void setRange(@NonNull Range range) {
+		this.range = Preconditions.checkNotNull(range, "range"); //$NON-NLS-1$
+	}
+
+	@Override
+	public String toString() {
+		ToStringBuilder b = new ToStringBuilder(this);
+		b.add("textDocument", getTextDocument()); //$NON-NLS-1$
+		b.add("range", getRange()); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		AstParams other = (AstParams) obj;
+		if (this.getTextDocument() == null) {
+			if (other.getTextDocument() != null)
+				return false;
+		} else if (!this.getTextDocument().equals(other.getTextDocument()))
+			return false;
+		if (this.range == null) {
+			if (other.range != null)
+				return false;
+		} else if (!this.range.equals(other.range))
+			return false;
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((this.getTextDocument() == null) ? 0 : this.getTextDocument().hashCode());
+		return prime * result + ((this.range == null) ? 0 : this.range.hashCode());
+	}
+}
diff --git a/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/symbolinfo/RangeAndUri.java b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/symbolinfo/RangeAndUri.java
new file mode 100644
index 00000000..16ba99b3
--- /dev/null
+++ b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/symbolinfo/RangeAndUri.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Advantest Europe GmbH and others.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Dietrich Travkin (Solunar GmbH) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.lsp.services.symbolinfo;
+
+import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
+import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
+import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
+
+/**
+ * Data type used in {@link SymbolDetails} for the textDocument/symbolInfo request.
+ * This class was generated by the org.eclipse.lsp4j.generator bundle
+ * using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
+ * the documentation).
+ *
+ * @see {@link SymbolDetails}
+ * @see {@link ClangdLanguageServer#getSymbolInfo(org.eclipse.lsp4j.TextDocumentPositionParams)}
+ */
+public class RangeAndUri {
+	@NonNull
+	private Range range;
+
+	@NonNull
+	private String uri;
+
+	@NonNull
+	public Range getRange() {
+		return this.range;
+	}
+
+	public void setRange(@NonNull final Range range) {
+		this.range = Preconditions.checkNotNull(range, "range"); //$NON-NLS-1$
+	}
+
+	@NonNull
+	public String getUri() {
+		return this.uri;
+	}
+
+	public void setUri(@NonNull final String uri) {
+		this.uri = Preconditions.checkNotNull(uri, "uri"); //$NON-NLS-1$
+	}
+
+	@Override
+	public String toString() {
+		ToStringBuilder b = new ToStringBuilder(this);
+		b.add("range", this.range); //$NON-NLS-1$
+		b.add("uri", this.uri); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		RangeAndUri other = (RangeAndUri) obj;
+		if (this.range == null) {
+			if (other.range != null)
+				return false;
+		} else if (!this.range.equals(other.range))
+			return false;
+		if (this.uri == null) {
+			if (other.uri != null)
+				return false;
+		} else if (!this.uri.equals(other.uri))
+			return false;
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((this.range == null) ? 0 : this.range.hashCode());
+		return prime * result + ((this.uri == null) ? 0 : this.uri.hashCode());
+	}
+}
diff --git a/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/symbolinfo/SymbolDetails.java b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/symbolinfo/SymbolDetails.java
new file mode 100644
index 00000000..4aa59811
--- /dev/null
+++ b/bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/services/symbolinfo/SymbolDetails.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2024 Advantest Europe GmbH and others.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Dietrich Travkin (Solunar GmbH) - Initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.lsp.services.symbolinfo;
+
+import org.eclipse.cdt.lsp.services.ClangdLanguageServer;
+import org.eclipse.lsp4j.jsonrpc.util.Preconditions;
+import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
+import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
+
+/**
+ * Return type for the textDocument/symbolInfo request.
+ * This class was generated by the org.eclipse.lsp4j.generator bundle
+ * using xtend (see {@link org.eclipse.lsp4j.generator.JsonRpcData JsonRpcData} and
+ * the documentation).
+ *
+ * @see {@link ClangdLanguageServer#getSymbolInfo(org.eclipse.lsp4j.TextDocumentPositionParams)}
+ */
+public class SymbolDetails {
+
+	@NonNull
+	private String name;
+
+	@NonNull
+	private String containerName;
+
+	@NonNull
+	private String usr;
+
+	private String id;
+
+	private RangeAndUri declarationRange;
+
+	private RangeAndUri definitionRange;
+
+	@NonNull
+	public String getName() {
+		return this.name;
+	}
+
+	public void setName(@NonNull final String name) {
+		this.name = Preconditions.checkNotNull(name, "name"); //$NON-NLS-1$
+	}
+
+	@NonNull
+	public String getContainerName() {
+		return this.containerName;
+	}
+
+	public void setContainerName(@NonNull final String containerName) {
+		this.containerName = Preconditions.checkNotNull(containerName, "containerName"); //$NON-NLS-1$
+	}
+
+	@NonNull
+	public String getUsr() {
+		return this.usr;
+	}
+
+	public void setUsr(@NonNull final String usr) {
+		this.usr = Preconditions.checkNotNull(usr, "usr"); //$NON-NLS-1$
+	}
+
+	public String getId() {
+		return this.id;
+	}
+
+	public void setId(final String id) {
+		this.id = id;
+	}
+
+	public RangeAndUri getDeclarationRange() {
+		return this.declarationRange;
+	}
+
+	public void setDeclarationRange(final RangeAndUri declarationRange) {
+		this.declarationRange = declarationRange;
+	}
+
+	public RangeAndUri getDefinitionRange() {
+		return this.definitionRange;
+	}
+
+	public void setDefinitionRange(final RangeAndUri definitionRange) {
+		this.definitionRange = definitionRange;
+	}
+
+	@Override
+	public String toString() {
+		ToStringBuilder b = new ToStringBuilder(this);
+		b.add("name", this.name); //$NON-NLS-1$
+		b.add("containerName", this.containerName); //$NON-NLS-1$
+		b.add("usr", this.usr); //$NON-NLS-1$
+		b.add("id", this.id); //$NON-NLS-1$
+		b.add("declarationRange", this.declarationRange); //$NON-NLS-1$
+		b.add("definitionRange", this.definitionRange); //$NON-NLS-1$
+		return b.toString();
+	}
+
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		SymbolDetails other = (SymbolDetails) obj;
+		if (this.name == null) {
+			if (other.name != null)
+				return false;
+		} else if (!this.name.equals(other.name))
+			return false;
+		if (this.containerName == null) {
+			if (other.containerName != null)
+				return false;
+		} else if (!this.containerName.equals(other.containerName))
+			return false;
+		if (this.usr == null) {
+			if (other.usr != null)
+				return false;
+		} else if (!this.usr.equals(other.usr))
+			return false;
+		if (this.id == null) {
+			if (other.id != null)
+				return false;
+		} else if (!this.id.equals(other.id))
+			return false;
+		if (this.declarationRange == null) {
+			if (other.declarationRange != null)
+				return false;
+		} else if (!this.declarationRange.equals(other.declarationRange))
+			return false;
+		if (this.definitionRange == null) {
+			if (other.definitionRange != null)
+				return false;
+		} else if (!this.definitionRange.equals(other.definitionRange))
+			return false;
+		return true;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
+		result = prime * result + ((this.containerName == null) ? 0 : this.containerName.hashCode());
+		result = prime * result + ((this.usr == null) ? 0 : this.usr.hashCode());
+		result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
+		result = prime * result + ((this.declarationRange == null) ? 0 : this.declarationRange.hashCode());
+		return prime * result + ((this.definitionRange == null) ? 0 : this.definitionRange.hashCode());
+	}
+}