This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new ad595d25cb03 CAMEL-24399: Add configurable MCP server metadata to 
camel-mcp-server
ad595d25cb03 is described below

commit ad595d25cb038a813d5fb9bda6bdd261ab498c70
Author: Omar Atie <[email protected]>
AuthorDate: Tue Aug 25 03:10:05 2026 -0700

    CAMEL-24399: Add configurable MCP server metadata to camel-mcp-server
    
    Expose title, description, website URL, instructions and icons through
    McpServerConfiguration and camel.server.mcp-* properties so Vert.x MCP
    servers advertise full serverInfo metadata on initialize. Includes catalog
    and main-configuration metadata regeneration, docs, and tests.
    
    Closes #25525
    
    Co-authored-by: Omar Atie <[email protected]>
    Co-authored-by: Cursor <[email protected]>
---
 .../org/apache/camel/catalog/docs/main.adoc        |   7 +-
 .../org/apache/camel/catalog/docs/mcp-server.adoc  |  22 +++++
 .../main/camel-main-configuration-metadata.json    |   5 +
 .../component/mcp/server/McpServerBridge.java      |  24 ++++-
 .../mcp/server/McpServerConfiguration.java         |  70 +++++++++++++-
 .../camel/component/mcp/server/McpServerIcon.java  |  45 +++++++++
 .../camel/component/mcp/server/McpServerInfo.java  |  26 ++++-
 .../component/mcp/server/McpServerBridgeTest.java  |  36 +++++++
 .../component/mcp/server/McpServerIconTest.java    |  44 +++++++++
 .../camel-mcp-server/src/main/docs/mcp-server.adoc |  22 +++++
 .../mcp/server/main/DefaultMcpServerFactory.java   |   5 +
 .../mcp/server/main/McpServerIconsParser.java      |  86 +++++++++++++++++
 .../mcp/server/vertx/VertxMcpServerEngine.java     |  49 +++++++++-
 .../mcp/server/main/McpServerIconsParserTest.java  |  95 ++++++++++++++++++
 .../mcp/server/main/McpServerMainMetadataTest.java |  98 +++++++++++++++++++
 ...ttpServerConfigurationPropertiesConfigurer.java |  35 +++++++
 .../camel-main-configuration-metadata.json         |   5 +
 core/camel-main/src/main/docs/main.adoc            |   7 +-
 .../main/HttpServerConfigurationProperties.java    | 106 +++++++++++++++++++++
 19 files changed, 773 insertions(+), 14 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
index 8ed7976b3865..869f38ff8ff3 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/main.adoc
@@ -195,7 +195,7 @@ The camel.routecontroller supports 12 options, which are 
listed below.
 
 
 === Camel Embedded HTTP Server (only for standalone; not Spring Boot or 
Quarkus) configurations
-The camel.server supports 28 options, which are listed below.
+The camel.server supports 33 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -216,8 +216,13 @@ The camel.server supports 28 options, which are listed 
below.
 | *camel.server.jwtKeystoreType* | Type of the keystore used for JWT tokens 
validation (jks, pkcs12, etc.). |  | String
 | *camel.server.maxBodySize* | Maximum HTTP body size the embedded HTTP server 
can accept. |  | Long
 | *camel.server.mcpEnabled* | Whether to expose ai-tool routes as MCP tools 
over streamable HTTP. Requires camel-mcp-server on the classpath. By default, 
the MCP server is not enabled. | false | boolean
+| *camel.server.mcpInstructions* | Top-level MCP instructions returned to 
clients on initialize. |  | String
 | *camel.server.mcpPath* | HTTP path where the MCP endpoint is served. | /mcp 
| String
+| *camel.server.mcpServerDescription* | MCP server description advertised to 
clients in serverInfo.description . |  | String
+| *camel.server.mcpServerIcons* | JSON array of MCP server icons advertised to 
clients in serverInfo.icons . Each entry must include a src URL and may include 
mimeType , sizes and theme . |  | String
 | *camel.server.mcpServerName* | MCP server name advertised to clients. 
Defaults to the CamelContext name. |  | String
+| *camel.server.mcpServerTitle* | MCP server display title advertised to 
clients in serverInfo.title . |  | String
+| *camel.server.mcpServerWebsiteUrl* | MCP server website URL advertised to 
clients in serverInfo.websiteUrl . |  | String
 | *camel.server.mcpSessionIdleTtl* | Idle TTL in milliseconds for MCP sessions 
on the Vert.x streamable transport. Sessions with no activity for longer than 
this interval are evicted. 0 disables idle eviction. | 300000 | long
 | *camel.server.mcpSessionKeepAliveInterval* | Keep-alive ping interval in 
milliseconds for MCP sessions on the Vert.x streamable transport. Dead sessions 
are evicted after consecutive ping failures. 0 disables keep-alive pings. | 
30000 | long
 | *camel.server.mcpTags* | Comma-separated list of ai-tool tag patterns to 
expose as MCP tools. Matching is case-insensitive and supports exact match, 
wildcard prefix ( {code foo} ), and {code } to match all tags. Only tools 
registered under a matching tag are exposed; the untagged default pool is never 
exposed. When not set, no tools are exposed. |  | String
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
index 6b761dc26029..39564e2eaf1c 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/mcp-server.adoc
@@ -118,6 +118,11 @@ camel.server.enabled = true
 camel.server.mcp-enabled = true
 camel.server.mcp-tags = crm,notify
 camel.server.mcp-server-name = my-integration-app
+camel.server.mcp-server-title = My Integration MCP
+camel.server.mcp-server-description = Tools for customer operations
+camel.server.mcp-server-website-url = https://example.com/docs
+camel.server.mcp-instructions = Use these tools to operate the integration.
+camel.server.mcp-server-icons = 
[{"src":"https://example.com/icon.png","mimeType":"image/png","sizes":["48x48"],"theme":"light"}]
 ----
 
 Tag patterns support wildcards: use `*` to expose all tagged tools, or a
@@ -130,6 +135,12 @@ On other runtimes, or when wiring programmatically, add the
 ----
 McpServerConfiguration configuration = new McpServerConfiguration();
 configuration.setTags("crm,notify");
+configuration.setServerName("my-integration-app");
+configuration.setServerTitle("My Integration MCP");
+configuration.setServerDescription("Tools for customer operations");
+configuration.setServerWebsiteUrl("https://example.com/docs";);
+configuration.setInstructions("Use these tools to operate the integration.");
+configuration.setServerIcons(List.of(new 
McpServerIcon("https://example.com/icon.png";, "image/png", List.of("48x48"), 
"light")));
 camelContext.addService(new McpServerBridge(configuration));
 ----
 
@@ -173,6 +184,17 @@ JBang (see the xref:main.adoc[camel-main] options) or on
   `/mcp` | engine
 | `camel.server.mcp-server-name` | MCP server name advertised to clients. |
   CamelContext name | engine
+| `camel.server.mcp-server-title` | MCP server display title advertised to 
clients in
+  `serverInfo.title`. |  | engine
+| `camel.server.mcp-server-description` | MCP server description advertised to 
clients in
+  `serverInfo.description`. |  | engine
+| `camel.server.mcp-server-website-url` | MCP server website URL advertised to 
clients in
+  `serverInfo.websiteUrl`. |  | engine
+| `camel.server.mcp-instructions` | Top-level MCP instructions returned to 
clients on
+  initialize (not part of `serverInfo`). |  | engine
+| `camel.server.mcp-server-icons` | JSON array of MCP server icons advertised 
to clients in
+  `serverInfo.icons`. Each entry must include a `src` URL and may include
+  `mimeType`, `sizes` and `theme`. |  | engine
 | `camel.server.mcp-session-keep-alive-interval` | Keep-alive ping interval in
   milliseconds for MCP sessions on the Vert.x streamable transport. Dead 
sessions
   are evicted after consecutive ping failures. `0` disables keep-alive
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 6287ad28e0ae..fc0b05196272 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -441,8 +441,13 @@
     { "name": "camel.server.jwtKeystoreType", "required": false, 
"description": "Type of the keystore used for JWT tokens validation (jks, 
pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.maxBodySize", "required": false, "description": 
"Maximum HTTP body size the embedded HTTP server can accept.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "java.lang.Long", "secret": false },
     { "name": "camel.server.mcpEnabled", "required": false, "description": 
"Whether to expose ai-tool routes as MCP tools over streamable HTTP. Requires 
camel-mcp-server on the classpath. By default, the MCP server is not enabled.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": 
false },
+    { "name": "camel.server.mcpInstructions", "required": false, 
"description": "Top-level MCP instructions returned to clients on initialize.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.mcpPath", "required": false, "description": "HTTP 
path where the MCP endpoint is served.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/mcp", "secret": false },
+    { "name": "camel.server.mcpServerDescription", "required": false, 
"description": "MCP server description advertised to clients in 
serverInfo.description .", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpServerIcons", "required": false, "description": 
"JSON array of MCP server icons advertised to clients in serverInfo.icons . 
Each entry must include a src URL and may include mimeType , sizes and theme 
.", "sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.mcpServerName", "required": false, "description": 
"MCP server name advertised to clients. Defaults to the CamelContext name.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpServerTitle", "required": false, "description": 
"MCP server display title advertised to clients in serverInfo.title .", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpServerWebsiteUrl", "required": false, 
"description": "MCP server website URL advertised to clients in 
serverInfo.websiteUrl .", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.mcpSessionIdleTtl", "required": false, 
"description": "Idle TTL in milliseconds for MCP sessions on the Vert.x 
streamable transport. Sessions with no activity for longer than this interval 
are evicted. 0 disables idle eviction.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "long", "defaultValue": 300000, "secret": false },
     { "name": "camel.server.mcpSessionKeepAliveInterval", "required": false, 
"description": "Keep-alive ping interval in milliseconds for MCP sessions on 
the Vert.x streamable transport. Dead sessions are evicted after consecutive 
ping failures. 0 disables keep-alive pings.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "long", "defaultValue": 30000, "secret": false },
     { "name": "camel.server.mcpTags", "required": false, "description": 
"Comma-separated list of ai-tool tag patterns to expose as MCP tools. Matching 
is case-insensitive and supports exact match, wildcard prefix ( {code foo} ), 
and {code } to match all tags. Only tools registered under a matching tag are 
exposed; the untagged default pool is never exposed. When not set, no tools are 
exposed.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"ja [...]
diff --git 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerBridge.java
 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerBridge.java
index 277833c5b3ec..ae1b887e8c7b 100644
--- 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerBridge.java
+++ 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerBridge.java
@@ -121,7 +121,10 @@ public class McpServerBridge extends ServiceSupport 
implements CamelContextAware
         }
         engine.initialize(new McpServerInfo(
                 serverName, version, configuration.getPath(),
-                configuration.getSessionKeepAliveInterval(), 
configuration.getSessionIdleTtl()));
+                configuration.getSessionKeepAliveInterval(), 
configuration.getSessionIdleTtl(),
+                configuration.getServerTitle(), 
configuration.getServerDescription(),
+                configuration.getServerWebsiteUrl(), 
configuration.getInstructions(),
+                configuration.getServerIcons()));
 
         if (!engine.consumesServingConfiguration()) {
             if 
(!McpServerConstants.DEFAULT_PATH.equals(configuration.getPath())) {
@@ -129,9 +132,9 @@ public class McpServerBridge extends ServiceSupport 
implements CamelContextAware
                          + "decides the endpoint path",
                         engine.getClass().getSimpleName());
             }
-            if (configuration.getServerName() != null) {
-                LOG.warn("The MCP serverName option may be ignored by engine 
{}: the runtime's native MCP server "
-                         + "configuration decides the server identity",
+            if (hasServerMetadataConfiguration()) {
+                LOG.warn("The MCP server metadata options may be ignored by 
engine {}: the runtime's native MCP "
+                         + "server configuration decides the server identity 
and initialize metadata",
                         engine.getClass().getSimpleName());
             }
         }
@@ -172,6 +175,19 @@ public class McpServerBridge extends ServiceSupport 
implements CamelContextAware
         }
     }
 
+    private boolean hasServerMetadataConfiguration() {
+        return isSet(configuration.getServerName())
+                || isSet(configuration.getServerTitle())
+                || isSet(configuration.getServerDescription())
+                || isSet(configuration.getServerWebsiteUrl())
+                || isSet(configuration.getInstructions())
+                || (configuration.getServerIcons() != null && 
!configuration.getServerIcons().isEmpty());
+    }
+
+    private static boolean isSet(String value) {
+        return value != null && !value.isBlank();
+    }
+
     private McpServerEngine resolveEngine() {
         McpServerEngine answer = 
camelContext.getRegistry().findSingleByType(McpServerEngine.class);
         if (answer == null) {
diff --git 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerConfiguration.java
 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerConfiguration.java
index 09fed0658340..1af4a1ad138d 100644
--- 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerConfiguration.java
+++ 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerConfiguration.java
@@ -16,12 +16,15 @@
  */
 package org.apache.camel.component.mcp.server;
 
+import java.util.List;
+
 /**
  * Configuration for the {@link McpServerBridge}.
  * <p>
  * Bridge-owned options ({@code tags}, {@code toolTimeout}) are honored on 
every runtime. Engine-owned options
- * ({@code path}, {@code serverName}) are consumed only by engines that serve 
through Camel — native engines (Quarkus,
- * Spring Boot) use their own runtime configuration instead.
+ * ({@code path}, {@code serverName}, {@code serverTitle}, {@code 
serverDescription}, {@code serverWebsiteUrl},
+ * {@code instructions}, {@code serverIcons}) are consumed only by engines 
that serve through Camel — native engines
+ * (Quarkus, Spring Boot) use their own runtime configuration instead.
  *
  * @since 4.22
  */
@@ -31,6 +34,11 @@ public class McpServerConfiguration {
     private long toolTimeout = McpServerConstants.DEFAULT_TOOL_TIMEOUT;
     private String path = McpServerConstants.DEFAULT_PATH;
     private String serverName;
+    private String serverTitle;
+    private String serverDescription;
+    private String serverWebsiteUrl;
+    private String instructions;
+    private List<McpServerIcon> serverIcons;
     private long sessionKeepAliveInterval = 
McpServerConstants.DEFAULT_SESSION_KEEP_ALIVE_INTERVAL;
     private long sessionIdleTtl = McpServerConstants.DEFAULT_SESSION_IDLE_TTL;
 
@@ -82,6 +90,64 @@ public class McpServerConfiguration {
         this.serverName = serverName;
     }
 
+    /**
+     * MCP server display title advertised to clients in {@code 
serverInfo.title}. Engine-owned hint: native engines MAY
+     * ignore it.
+     */
+    public String getServerTitle() {
+        return serverTitle;
+    }
+
+    public void setServerTitle(String serverTitle) {
+        this.serverTitle = serverTitle;
+    }
+
+    /**
+     * MCP server description advertised to clients in {@code 
serverInfo.description}. Engine-owned hint: native engines
+     * MAY ignore it.
+     */
+    public String getServerDescription() {
+        return serverDescription;
+    }
+
+    public void setServerDescription(String serverDescription) {
+        this.serverDescription = serverDescription;
+    }
+
+    /**
+     * MCP server website URL advertised to clients in {@code 
serverInfo.websiteUrl}. Engine-owned hint: native engines
+     * MAY ignore it.
+     */
+    public String getServerWebsiteUrl() {
+        return serverWebsiteUrl;
+    }
+
+    public void setServerWebsiteUrl(String serverWebsiteUrl) {
+        this.serverWebsiteUrl = serverWebsiteUrl;
+    }
+
+    /**
+     * Top-level MCP instructions returned to clients on initialize. 
Engine-owned hint: native engines MAY ignore it.
+     */
+    public String getInstructions() {
+        return instructions;
+    }
+
+    public void setInstructions(String instructions) {
+        this.instructions = instructions;
+    }
+
+    /**
+     * Icons advertised to clients in {@code serverInfo.icons}. Engine-owned 
hint: native engines MAY ignore them.
+     */
+    public List<McpServerIcon> getServerIcons() {
+        return serverIcons;
+    }
+
+    public void setServerIcons(List<McpServerIcon> serverIcons) {
+        this.serverIcons = serverIcons;
+    }
+
     /**
      * Keep-alive ping interval in milliseconds for the Vert.x streamable 
transport. Dead sessions are evicted after
      * consecutive ping failures. {@code 0} disables keep-alive pings. 
Engine-owned: ignored by native engines.
diff --git 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerIcon.java
 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerIcon.java
new file mode 100644
index 000000000000..31d9652142ad
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerIcon.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mcp.server;
+
+import java.util.List;
+
+/**
+ * Icon metadata advertised in the MCP {@code serverInfo} block.
+ *
+ * @param src      icon URL (required)
+ * @param mimeType optional MIME type (for example {@code image/png})
+ * @param sizes    optional size descriptors (for example {@code 48x48})
+ * @param theme    optional theme hint (for example {@code light} or {@code 
dark})
+ *
+ * @since          4.23
+ */
+public record McpServerIcon(String src, String mimeType, List<String> sizes, 
String theme) {
+
+    public McpServerIcon {
+        if (src == null || src.isBlank()) {
+            throw new IllegalArgumentException("src must be set");
+        }
+        if (sizes != null) {
+            sizes = List.copyOf(sizes);
+        }
+    }
+
+    public McpServerIcon(String src) {
+        this(src, null, null, null);
+    }
+}
diff --git 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerInfo.java
 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerInfo.java
index 9e13bfb4baa0..5169a3426e97 100644
--- 
a/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerInfo.java
+++ 
b/components/camel-ai/camel-mcp-server-api/src/main/java/org/apache/camel/component/mcp/server/McpServerInfo.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.mcp.server;
 
+import java.util.List;
+
 /**
  * Identity and serving hints passed to an {@link McpServerEngine} before it 
is started.
  * <p>
@@ -29,6 +31,11 @@ package org.apache.camel.component.mcp.server;
  *                                   {@code 0} disables keep-alive pings
  * @param sessionIdleTtlMs           idle TTL in milliseconds; sessions with 
no activity for longer are evicted;
  *                                   {@code 0} disables idle eviction
+ * @param title                      optional display title advertised in 
{@code serverInfo}
+ * @param description                optional human-readable description 
advertised in {@code serverInfo}
+ * @param websiteUrl                 optional documentation or home page URL 
advertised in {@code serverInfo}
+ * @param instructions               optional top-level instructions returned 
to MCP clients on initialize
+ * @param icons                      optional icons advertised in {@code 
serverInfo}
  *
  * @since                            4.22
  */
@@ -37,12 +44,24 @@ public record McpServerInfo(
         String version,
         String path,
         long sessionKeepAliveIntervalMs,
-        long sessionIdleTtlMs) {
+        long sessionIdleTtlMs,
+        String title,
+        String description,
+        String websiteUrl,
+        String instructions,
+        List<McpServerIcon> icons) {
 
     public McpServerInfo(String serverName, String version, String path) {
         this(serverName, version, path,
              McpServerConstants.DEFAULT_SESSION_KEEP_ALIVE_INTERVAL,
-             McpServerConstants.DEFAULT_SESSION_IDLE_TTL);
+             McpServerConstants.DEFAULT_SESSION_IDLE_TTL,
+             null, null, null, null, null);
+    }
+
+    public McpServerInfo(String serverName, String version, String path,
+                         long sessionKeepAliveIntervalMs, long 
sessionIdleTtlMs) {
+        this(serverName, version, path, sessionKeepAliveIntervalMs, 
sessionIdleTtlMs,
+             null, null, null, null, null);
     }
 
     public McpServerInfo {
@@ -52,5 +71,8 @@ public record McpServerInfo(
         if (sessionIdleTtlMs < 0) {
             throw new IllegalArgumentException("sessionIdleTtlMs must be >= 
0");
         }
+        if (icons != null) {
+            icons = List.copyOf(icons);
+        }
     }
 }
diff --git 
a/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerBridgeTest.java
 
b/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerBridgeTest.java
index 26c927ba5f36..d11d3ef2a177 100644
--- 
a/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerBridgeTest.java
+++ 
b/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerBridgeTest.java
@@ -16,10 +16,12 @@
  */
 package org.apache.camel.component.mcp.server;
 
+import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.test.junit6.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 
@@ -183,6 +185,40 @@ class McpServerBridgeTest extends CamelTestSupport {
         assertThat(result.structuredContent()).isNotNull();
     }
 
+    @Test
+    void testServerMetadataPassedToEngine() throws Exception {
+        CamelContext metadataContext = new DefaultCamelContext();
+        RecordingMcpServerEngine metadataEngine = new 
RecordingMcpServerEngine();
+        metadataContext.getRegistry().bind("mcpServerEngine", metadataEngine);
+        McpServerConfiguration configuration = new McpServerConfiguration();
+        configuration.setTags("crm");
+        configuration.setServerName("wanaku-camel-mcp");
+        configuration.setServerTitle("Wanaku Camel MCP");
+        configuration.setServerDescription("Integration tools for Wanaku");
+        configuration.setServerWebsiteUrl("https://camel.apache.org/";);
+        configuration.setInstructions("Use these tools to operate the 
integration.");
+        configuration.setServerIcons(List.of(new McpServerIcon(
+                "https://example.com/icon.png";, "image/png", List.of("48x48"), 
"light")));
+        McpServerBridge metadataBridge = new McpServerBridge(configuration);
+        metadataContext.addService(metadataBridge);
+        metadataContext.start();
+        metadataBridge.start();
+
+        try {
+            McpServerInfo info = metadataEngine.info();
+            assertThat(info.serverName()).isEqualTo("wanaku-camel-mcp");
+            assertThat(info.title()).isEqualTo("Wanaku Camel MCP");
+            assertThat(info.description()).isEqualTo("Integration tools for 
Wanaku");
+            
assertThat(info.websiteUrl()).isEqualTo("https://camel.apache.org/";);
+            assertThat(info.instructions()).isEqualTo("Use these tools to 
operate the integration.");
+            assertThat(info.icons()).hasSize(1);
+            
assertThat(info.icons().get(0).src()).isEqualTo("https://example.com/icon.png";);
+        } finally {
+            metadataBridge.stop();
+            metadataContext.stop();
+        }
+    }
+
     @Test
     void testNameCollisionIsRefused() throws Exception {
         McpServerTool published = engine.tools().get("query_db");
diff --git 
a/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerIconTest.java
 
b/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerIconTest.java
new file mode 100644
index 000000000000..3337db032ad3
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server-api/src/test/java/org/apache/camel/component/mcp/server/McpServerIconTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mcp.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class McpServerIconTest {
+
+    @Test
+    void testRejectsBlankSrc() {
+        assertThatThrownBy(() -> new McpServerIcon(" "))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("src");
+    }
+
+    @Test
+    void testSizesAreDefensivelyCopied() {
+        List<String> sizes = new ArrayList<>(List.of("48x48"));
+        McpServerIcon icon = new McpServerIcon("https://example.com/icon.png";, 
"image/png", sizes, "light");
+
+        sizes.add("96x96");
+        assertThat(icon.sizes()).containsExactly("48x48");
+    }
+}
diff --git a/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc 
b/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc
index 6b761dc26029..39564e2eaf1c 100644
--- a/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc
+++ b/components/camel-ai/camel-mcp-server/src/main/docs/mcp-server.adoc
@@ -118,6 +118,11 @@ camel.server.enabled = true
 camel.server.mcp-enabled = true
 camel.server.mcp-tags = crm,notify
 camel.server.mcp-server-name = my-integration-app
+camel.server.mcp-server-title = My Integration MCP
+camel.server.mcp-server-description = Tools for customer operations
+camel.server.mcp-server-website-url = https://example.com/docs
+camel.server.mcp-instructions = Use these tools to operate the integration.
+camel.server.mcp-server-icons = 
[{"src":"https://example.com/icon.png","mimeType":"image/png","sizes":["48x48"],"theme":"light"}]
 ----
 
 Tag patterns support wildcards: use `*` to expose all tagged tools, or a
@@ -130,6 +135,12 @@ On other runtimes, or when wiring programmatically, add the
 ----
 McpServerConfiguration configuration = new McpServerConfiguration();
 configuration.setTags("crm,notify");
+configuration.setServerName("my-integration-app");
+configuration.setServerTitle("My Integration MCP");
+configuration.setServerDescription("Tools for customer operations");
+configuration.setServerWebsiteUrl("https://example.com/docs";);
+configuration.setInstructions("Use these tools to operate the integration.");
+configuration.setServerIcons(List.of(new 
McpServerIcon("https://example.com/icon.png";, "image/png", List.of("48x48"), 
"light")));
 camelContext.addService(new McpServerBridge(configuration));
 ----
 
@@ -173,6 +184,17 @@ JBang (see the xref:main.adoc[camel-main] options) or on
   `/mcp` | engine
 | `camel.server.mcp-server-name` | MCP server name advertised to clients. |
   CamelContext name | engine
+| `camel.server.mcp-server-title` | MCP server display title advertised to 
clients in
+  `serverInfo.title`. |  | engine
+| `camel.server.mcp-server-description` | MCP server description advertised to 
clients in
+  `serverInfo.description`. |  | engine
+| `camel.server.mcp-server-website-url` | MCP server website URL advertised to 
clients in
+  `serverInfo.websiteUrl`. |  | engine
+| `camel.server.mcp-instructions` | Top-level MCP instructions returned to 
clients on
+  initialize (not part of `serverInfo`). |  | engine
+| `camel.server.mcp-server-icons` | JSON array of MCP server icons advertised 
to clients in
+  `serverInfo.icons`. Each entry must include a `src` URL and may include
+  `mimeType`, `sizes` and `theme`. |  | engine
 | `camel.server.mcp-session-keep-alive-interval` | Keep-alive ping interval in
   milliseconds for MCP sessions on the Vert.x streamable transport. Dead 
sessions
   are evicted after consecutive ping failures. `0` disables keep-alive
diff --git 
a/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
index e080fdf2c559..426226f89fdf 100644
--- 
a/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
+++ 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/DefaultMcpServerFactory.java
@@ -39,6 +39,11 @@ public class DefaultMcpServerFactory implements 
McpServerFactory {
         mcpConfiguration.setToolTimeout(configuration.getMcpToolTimeout());
         mcpConfiguration.setPath(configuration.getMcpPath());
         mcpConfiguration.setServerName(configuration.getMcpServerName());
+        mcpConfiguration.setServerTitle(configuration.getMcpServerTitle());
+        
mcpConfiguration.setServerDescription(configuration.getMcpServerDescription());
+        
mcpConfiguration.setServerWebsiteUrl(configuration.getMcpServerWebsiteUrl());
+        mcpConfiguration.setInstructions(configuration.getMcpInstructions());
+        
mcpConfiguration.setServerIcons(McpServerIconsParser.parse(configuration.getMcpServerIcons()));
         
mcpConfiguration.setSessionKeepAliveInterval(configuration.getMcpSessionKeepAliveInterval());
         
mcpConfiguration.setSessionIdleTtl(configuration.getMcpSessionIdleTtl());
         return new McpServerBridge(mcpConfiguration);
diff --git 
a/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/McpServerIconsParser.java
 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/McpServerIconsParser.java
new file mode 100644
index 000000000000..51622f504d75
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/main/McpServerIconsParser.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mcp.server.main;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.camel.component.mcp.server.McpServerIcon;
+
+/**
+ * Parses {@code camel.server.mcp-server-icons} JSON into {@link 
McpServerIcon} instances.
+ */
+final class McpServerIconsParser {
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    private McpServerIconsParser() {
+    }
+
+    static List<McpServerIcon> parse(String json) {
+        if (json == null || json.isBlank()) {
+            return null;
+        }
+        try {
+            JsonNode root = MAPPER.readTree(json);
+            if (!root.isArray()) {
+                throw new IllegalArgumentException("mcp-server-icons must be a 
JSON array");
+            }
+            List<McpServerIcon> icons = new ArrayList<>(root.size());
+            for (JsonNode node : root) {
+                if (!node.isObject()) {
+                    throw new IllegalArgumentException("Each MCP server icon 
must be a JSON object");
+                }
+                String src = text(node, "src");
+                if (src == null || src.isBlank()) {
+                    throw new IllegalArgumentException("Each MCP server icon 
must include a non-blank src");
+                }
+                icons.add(new McpServerIcon(
+                        src,
+                        text(node, "mimeType"),
+                        stringList(node.get("sizes")),
+                        text(node, "theme")));
+            }
+            return List.copyOf(icons);
+        } catch (IllegalArgumentException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Failed to parse 
mcp-server-icons JSON", e);
+        }
+    }
+
+    private static String text(JsonNode node, String field) {
+        JsonNode value = node.get(field);
+        return value != null && !value.isNull() ? value.asText() : null;
+    }
+
+    private static List<String> stringList(JsonNode node) {
+        if (node == null || node.isNull()) {
+            return null;
+        }
+        if (!node.isArray()) {
+            throw new IllegalArgumentException("MCP server icon sizes must be 
a JSON array");
+        }
+        List<String> values = new ArrayList<>(node.size());
+        for (JsonNode item : node) {
+            values.add(item.asText());
+        }
+        return List.copyOf(values);
+    }
+}
diff --git 
a/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/vertx/VertxMcpServerEngine.java
 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/vertx/VertxMcpServerEngine.java
index 63ed18dfc355..05c467dd2085 100644
--- 
a/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/vertx/VertxMcpServerEngine.java
+++ 
b/components/camel-ai/camel-mcp-server/src/main/java/org/apache/camel/component/mcp/server/vertx/VertxMcpServerEngine.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.mcp.server.vertx;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -29,6 +30,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.component.ai.tool.AiToolAnnotations;
 import org.apache.camel.component.mcp.server.McpServerConstants;
 import org.apache.camel.component.mcp.server.McpServerEngine;
+import org.apache.camel.component.mcp.server.McpServerIcon;
 import org.apache.camel.component.mcp.server.McpServerInfo;
 import org.apache.camel.component.mcp.server.McpServerTool;
 import org.apache.camel.component.mcp.server.McpToolCallResult;
@@ -107,11 +109,14 @@ public class VertxMcpServerEngine extends ServiceSupport 
implements McpServerEng
         transport = new VertxMcpStreamableServerTransportProvider(
                 jsonMapper, info.path(),
                 info.sessionKeepAliveIntervalMs(), info.sessionIdleTtlMs());
-        server = McpServer.sync(transport)
-                .serverInfo(info.serverName(), info.version())
+        McpServer.SyncSpecification<?> specification = 
McpServer.sync(transport)
+                .serverInfo(buildServerInfo(info))
                 
.capabilities(McpSchema.ServerCapabilities.builder().tools(true).build())
-                .immediateExecution(true)
-                .build();
+                .immediateExecution(true);
+        if (info.instructions() != null && !info.instructions().isBlank()) {
+            specification.instructions(info.instructions());
+        }
+        server = specification.build();
         // register routes only once the server has set the session factory on 
the transport
         transport.registerRoutes(router);
 
@@ -217,6 +222,42 @@ public class VertxMcpServerEngine extends ServiceSupport 
implements McpServerEng
         }
     }
 
+    private static McpSchema.Implementation buildServerInfo(McpServerInfo 
info) {
+        McpSchema.Implementation.Builder builder
+                = McpSchema.Implementation.builder(info.serverName(), 
info.version());
+        if (info.title() != null && !info.title().isBlank()) {
+            builder.title(info.title());
+        }
+        if (info.description() != null && !info.description().isBlank()) {
+            builder.description(info.description());
+        }
+        if (info.websiteUrl() != null && !info.websiteUrl().isBlank()) {
+            builder.websiteUrl(info.websiteUrl());
+        }
+        if (info.icons() != null && !info.icons().isEmpty()) {
+            builder.icons(mapIcons(info.icons()));
+        }
+        return builder.build();
+    }
+
+    private static List<McpSchema.Icon> mapIcons(List<McpServerIcon> icons) {
+        return icons.stream().map(VertxMcpServerEngine::mapIcon).toList();
+    }
+
+    private static McpSchema.Icon mapIcon(McpServerIcon icon) {
+        McpSchema.Icon.Builder builder = McpSchema.Icon.builder(icon.src());
+        if (icon.mimeType() != null && !icon.mimeType().isBlank()) {
+            builder.mimeType(icon.mimeType());
+        }
+        if (icon.sizes() != null && !icon.sizes().isEmpty()) {
+            builder.sizes(icon.sizes());
+        }
+        if (icon.theme() != null && !icon.theme().isBlank()) {
+            builder.theme(icon.theme());
+        }
+        return builder.build();
+    }
+
     private VertxPlatformHttpRouter lookupRouter() {
         boolean mainTarget = 
VertxPlatformHttpRouter.SERVER_TYPE_SERVER.equals(targetServerType);
         Set<VertxPlatformHttpRouter> routers = 
camelContext.getRegistry().findByType(VertxPlatformHttpRouter.class);
diff --git 
a/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerIconsParserTest.java
 
b/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerIconsParserTest.java
new file mode 100644
index 000000000000..7e765df01c2f
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerIconsParserTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mcp.server.main;
+
+import java.util.List;
+
+import org.apache.camel.component.mcp.server.McpServerIcon;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class McpServerIconsParserTest {
+
+    @Test
+    void testParsesIconsArray() {
+        List<McpServerIcon> icons = McpServerIconsParser.parse("""
+                [
+                  {
+                    "src": "https://example.com/icon.png";,
+                    "mimeType": "image/png",
+                    "sizes": ["48x48", "96x96"],
+                    "theme": "light"
+                  }
+                ]
+                """);
+
+        assertThat(icons).hasSize(1);
+        
assertThat(icons.get(0).src()).isEqualTo("https://example.com/icon.png";);
+        assertThat(icons.get(0).mimeType()).isEqualTo("image/png");
+        assertThat(icons.get(0).sizes()).containsExactly("48x48", "96x96");
+        assertThat(icons.get(0).theme()).isEqualTo("light");
+    }
+
+    @Test
+    void testBlankJsonReturnsNull() {
+        assertThat(McpServerIconsParser.parse(null)).isNull();
+        assertThat(McpServerIconsParser.parse("   ")).isNull();
+    }
+
+    @Test
+    void testRejectsNonArrayJson() {
+        assertThatThrownBy(() -> 
McpServerIconsParser.parse("{\"src\":\"https://example.com/icon.png\"}";))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("JSON array");
+    }
+
+    @Test
+    void testParsesSrcOnlyIcon() {
+        List<McpServerIcon> icons = McpServerIconsParser.parse("""
+                [{"src":"https://example.com/icon.png"}]
+                """);
+
+        assertThat(icons).hasSize(1);
+        
assertThat(icons.get(0).src()).isEqualTo("https://example.com/icon.png";);
+        assertThat(icons.get(0).mimeType()).isNull();
+    }
+
+    @Test
+    void testRejectsNonObjectIconEntry() {
+        assertThatThrownBy(() -> 
McpServerIconsParser.parse("[\"https://example.com/icon.png\"]";))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("JSON object");
+    }
+
+    @Test
+    void testRejectsNonArraySizes() {
+        assertThatThrownBy(() -> McpServerIconsParser.parse("""
+                [{"src":"https://example.com/icon.png","sizes":"48x48"}]
+                """))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("sizes");
+    }
+
+    @Test
+    void testRejectsMissingSrc() {
+        assertThatThrownBy(() -> 
McpServerIconsParser.parse("[{\"mimeType\":\"image/png\"}]"))
+                .isInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("src");
+    }
+}
diff --git 
a/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerMainMetadataTest.java
 
b/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerMainMetadataTest.java
new file mode 100644
index 000000000000..506d9c348b99
--- /dev/null
+++ 
b/components/camel-ai/camel-mcp-server/src/test/java/org/apache/camel/component/mcp/server/main/McpServerMainMetadataTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.mcp.server.main;
+
+import java.time.Duration;
+import java.util.Map;
+
+import io.modelcontextprotocol.client.McpClient;
+import io.modelcontextprotocol.client.McpSyncClient;
+import 
io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
+import io.modelcontextprotocol.spec.McpSchema;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.main.Main;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Verifies CAMEL-24399: additional MCP server metadata is advertised on 
initialize.
+ */
+class McpServerMainMetadataTest {
+
+    @Test
+    void testMcpServerMetadataFromProperties() throws Exception {
+        int port = AvailablePortFinder.getNextAvailable();
+
+        Main main = new Main();
+        main.configure().addRoutesBuilder(new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("ai-tool:say_hello?tags=crm&description=Say hello")
+                        .setBody(constant("Hello"));
+            }
+        });
+        main.addInitialProperty("camel.server.enabled", "true");
+        main.addInitialProperty("camel.server.port", String.valueOf(port));
+        main.addInitialProperty("camel.server.mcp-enabled", "true");
+        main.addInitialProperty("camel.server.mcp-tags", "crm");
+        main.addInitialProperty("camel.server.mcp-server-name", 
"wanaku-camel-mcp");
+        main.addInitialProperty("camel.server.mcp-server-title", "Wanaku Camel 
MCP");
+        main.addInitialProperty("camel.server.mcp-server-description", 
"Integration tools for Wanaku");
+        main.addInitialProperty("camel.server.mcp-server-website-url", 
"https://camel.apache.org/";);
+        main.addInitialProperty("camel.server.mcp-instructions", "Use these 
tools to operate the integration.");
+        main.addInitialProperty("camel.server.mcp-server-icons", """
+                
[{"src":"https://example.com/icon.png","mimeType":"image/png","sizes":["48x48"],"theme":"light"}]
+                """);
+        main.start();
+
+        McpSyncClient client = null;
+        try {
+            client = 
McpClient.sync(HttpClientStreamableHttpTransport.builder("http://localhost:"; + 
port).build())
+                    .requestTimeout(Duration.ofSeconds(10))
+                    .initializationTimeout(Duration.ofSeconds(10))
+                    .build();
+
+            McpSchema.InitializeResult init = client.initialize();
+            McpSchema.Implementation serverInfo = init.serverInfo();
+
+            assertThat(serverInfo.name()).isEqualTo("wanaku-camel-mcp");
+            assertThat(serverInfo.title()).isEqualTo("Wanaku Camel MCP");
+            assertThat(serverInfo.description()).isEqualTo("Integration tools 
for Wanaku");
+            
assertThat(serverInfo.websiteUrl()).isEqualTo("https://camel.apache.org/";);
+            assertThat(serverInfo.version()).isNotBlank();
+            assertThat(serverInfo.icons()).hasSize(1);
+            
assertThat(serverInfo.icons().get(0).src()).isEqualTo("https://example.com/icon.png";);
+            
assertThat(serverInfo.icons().get(0).mimeType()).isEqualTo("image/png");
+            
assertThat(serverInfo.icons().get(0).sizes()).containsExactly("48x48");
+            assertThat(serverInfo.icons().get(0).theme()).isEqualTo("light");
+            assertThat(init.instructions()).isEqualTo("Use these tools to 
operate the integration.");
+
+            assertThat(client.listTools().tools())
+                    .extracting(McpSchema.Tool::name)
+                    .contains("say_hello");
+            assertThat(client.callTool(new 
McpSchema.CallToolRequest("say_hello", Map.of())).isError())
+                    .isNotEqualTo(Boolean.TRUE);
+        } finally {
+            if (client != null) {
+                client.closeGracefully();
+            }
+            main.stop();
+        }
+    }
+}
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
index 42f63d53a06d..bf84ae5dddcf 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
@@ -38,8 +38,13 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         map.put("JwtKeystoreType", java.lang.String.class);
         map.put("MaxBodySize", java.lang.Long.class);
         map.put("McpEnabled", boolean.class);
+        map.put("McpInstructions", java.lang.String.class);
         map.put("McpPath", java.lang.String.class);
+        map.put("McpServerDescription", java.lang.String.class);
+        map.put("McpServerIcons", java.lang.String.class);
         map.put("McpServerName", java.lang.String.class);
+        map.put("McpServerTitle", java.lang.String.class);
+        map.put("McpServerWebsiteUrl", java.lang.String.class);
         map.put("McpSessionIdleTtl", long.class);
         map.put("McpSessionKeepAliveInterval", long.class);
         map.put("McpTags", java.lang.String.class);
@@ -87,10 +92,20 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "maxBodySize": target.setMaxBodySize(property(camelContext, 
java.lang.Long.class, value)); return true;
         case "mcpenabled":
         case "mcpEnabled": target.setMcpEnabled(property(camelContext, 
boolean.class, value)); return true;
+        case "mcpinstructions":
+        case "mcpInstructions": 
target.setMcpInstructions(property(camelContext, java.lang.String.class, 
value)); return true;
         case "mcppath":
         case "mcpPath": target.setMcpPath(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "mcpserverdescription":
+        case "mcpServerDescription": 
target.setMcpServerDescription(property(camelContext, java.lang.String.class, 
value)); return true;
+        case "mcpservericons":
+        case "mcpServerIcons": target.setMcpServerIcons(property(camelContext, 
java.lang.String.class, value)); return true;
         case "mcpservername":
         case "mcpServerName": target.setMcpServerName(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "mcpservertitle":
+        case "mcpServerTitle": target.setMcpServerTitle(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "mcpserverwebsiteurl":
+        case "mcpServerWebsiteUrl": 
target.setMcpServerWebsiteUrl(property(camelContext, java.lang.String.class, 
value)); return true;
         case "mcpsessionidlettl":
         case "mcpSessionIdleTtl": 
target.setMcpSessionIdleTtl(property(camelContext, long.class, value)); return 
true;
         case "mcpsessionkeepaliveinterval":
@@ -151,10 +166,20 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "maxBodySize": return java.lang.Long.class;
         case "mcpenabled":
         case "mcpEnabled": return boolean.class;
+        case "mcpinstructions":
+        case "mcpInstructions": return java.lang.String.class;
         case "mcppath":
         case "mcpPath": return java.lang.String.class;
+        case "mcpserverdescription":
+        case "mcpServerDescription": return java.lang.String.class;
+        case "mcpservericons":
+        case "mcpServerIcons": return java.lang.String.class;
         case "mcpservername":
         case "mcpServerName": return java.lang.String.class;
+        case "mcpservertitle":
+        case "mcpServerTitle": return java.lang.String.class;
+        case "mcpserverwebsiteurl":
+        case "mcpServerWebsiteUrl": return java.lang.String.class;
         case "mcpsessionidlettl":
         case "mcpSessionIdleTtl": return long.class;
         case "mcpsessionkeepaliveinterval":
@@ -211,10 +236,20 @@ public class HttpServerConfigurationPropertiesConfigurer 
extends org.apache.came
         case "maxBodySize": return target.getMaxBodySize();
         case "mcpenabled":
         case "mcpEnabled": return target.isMcpEnabled();
+        case "mcpinstructions":
+        case "mcpInstructions": return target.getMcpInstructions();
         case "mcppath":
         case "mcpPath": return target.getMcpPath();
+        case "mcpserverdescription":
+        case "mcpServerDescription": return target.getMcpServerDescription();
+        case "mcpservericons":
+        case "mcpServerIcons": return target.getMcpServerIcons();
         case "mcpservername":
         case "mcpServerName": return target.getMcpServerName();
+        case "mcpservertitle":
+        case "mcpServerTitle": return target.getMcpServerTitle();
+        case "mcpserverwebsiteurl":
+        case "mcpServerWebsiteUrl": return target.getMcpServerWebsiteUrl();
         case "mcpsessionidlettl":
         case "mcpSessionIdleTtl": return target.getMcpSessionIdleTtl();
         case "mcpsessionkeepaliveinterval":
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 6287ad28e0ae..fc0b05196272 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -441,8 +441,13 @@
     { "name": "camel.server.jwtKeystoreType", "required": false, 
"description": "Type of the keystore used for JWT tokens validation (jks, 
pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.maxBodySize", "required": false, "description": 
"Maximum HTTP body size the embedded HTTP server can accept.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "java.lang.Long", "secret": false },
     { "name": "camel.server.mcpEnabled", "required": false, "description": 
"Whether to expose ai-tool routes as MCP tools over streamable HTTP. Requires 
camel-mcp-server on the classpath. By default, the MCP server is not enabled.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "boolean", "javaType": "boolean", "defaultValue": false, "secret": 
false },
+    { "name": "camel.server.mcpInstructions", "required": false, 
"description": "Top-level MCP instructions returned to clients on initialize.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.mcpPath", "required": false, "description": "HTTP 
path where the MCP endpoint is served.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "defaultValue": "\/mcp", "secret": false },
+    { "name": "camel.server.mcpServerDescription", "required": false, 
"description": "MCP server description advertised to clients in 
serverInfo.description .", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpServerIcons", "required": false, "description": 
"JSON array of MCP server icons advertised to clients in serverInfo.icons . 
Each entry must include a src URL and may include mimeType , sizes and theme 
.", "sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.mcpServerName", "required": false, "description": 
"MCP server name advertised to clients. Defaults to the CamelContext name.", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpServerTitle", "required": false, "description": 
"MCP server display title advertised to clients in serverInfo.title .", 
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties", 
"type": "string", "javaType": "java.lang.String", "secret": false },
+    { "name": "camel.server.mcpServerWebsiteUrl", "required": false, 
"description": "MCP server website URL advertised to clients in 
serverInfo.websiteUrl .", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"javaType": "java.lang.String", "secret": false },
     { "name": "camel.server.mcpSessionIdleTtl", "required": false, 
"description": "Idle TTL in milliseconds for MCP sessions on the Vert.x 
streamable transport. Sessions with no activity for longer than this interval 
are evicted. 0 disables idle eviction.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "long", "defaultValue": 300000, "secret": false },
     { "name": "camel.server.mcpSessionKeepAliveInterval", "required": false, 
"description": "Keep-alive ping interval in milliseconds for MCP sessions on 
the Vert.x streamable transport. Dead sessions are evicted after consecutive 
ping failures. 0 disables keep-alive pings.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "integer", 
"javaType": "long", "defaultValue": 30000, "secret": false },
     { "name": "camel.server.mcpTags", "required": false, "description": 
"Comma-separated list of ai-tool tag patterns to expose as MCP tools. Matching 
is case-insensitive and supports exact match, wildcard prefix ( {code foo} ), 
and {code } to match all tags. Only tools registered under a matching tag are 
exposed; the untagged default pool is never exposed. When not set, no tools are 
exposed.", "sourceType": 
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string", 
"ja [...]
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index 8ed7976b3865..869f38ff8ff3 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -195,7 +195,7 @@ The camel.routecontroller supports 12 options, which are 
listed below.
 
 
 === Camel Embedded HTTP Server (only for standalone; not Spring Boot or 
Quarkus) configurations
-The camel.server supports 28 options, which are listed below.
+The camel.server supports 33 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -216,8 +216,13 @@ The camel.server supports 28 options, which are listed 
below.
 | *camel.server.jwtKeystoreType* | Type of the keystore used for JWT tokens 
validation (jks, pkcs12, etc.). |  | String
 | *camel.server.maxBodySize* | Maximum HTTP body size the embedded HTTP server 
can accept. |  | Long
 | *camel.server.mcpEnabled* | Whether to expose ai-tool routes as MCP tools 
over streamable HTTP. Requires camel-mcp-server on the classpath. By default, 
the MCP server is not enabled. | false | boolean
+| *camel.server.mcpInstructions* | Top-level MCP instructions returned to 
clients on initialize. |  | String
 | *camel.server.mcpPath* | HTTP path where the MCP endpoint is served. | /mcp 
| String
+| *camel.server.mcpServerDescription* | MCP server description advertised to 
clients in serverInfo.description . |  | String
+| *camel.server.mcpServerIcons* | JSON array of MCP server icons advertised to 
clients in serverInfo.icons . Each entry must include a src URL and may include 
mimeType , sizes and theme . |  | String
 | *camel.server.mcpServerName* | MCP server name advertised to clients. 
Defaults to the CamelContext name. |  | String
+| *camel.server.mcpServerTitle* | MCP server display title advertised to 
clients in serverInfo.title . |  | String
+| *camel.server.mcpServerWebsiteUrl* | MCP server website URL advertised to 
clients in serverInfo.websiteUrl . |  | String
 | *camel.server.mcpSessionIdleTtl* | Idle TTL in milliseconds for MCP sessions 
on the Vert.x streamable transport. Sessions with no activity for longer than 
this interval are evicted. 0 disables idle eviction. | 300000 | long
 | *camel.server.mcpSessionKeepAliveInterval* | Keep-alive ping interval in 
milliseconds for MCP sessions on the Vert.x streamable transport. Dead sessions 
are evicted after consecutive ping failures. 0 disables keep-alive pings. | 
30000 | long
 | *camel.server.mcpTags* | Comma-separated list of ai-tool tag patterns to 
expose as MCP tools. Matching is case-insensitive and supports exact match, 
wildcard prefix ( {code foo} ), and {code } to match all tags. Only tools 
registered under a matching tag are exposed; the untagged default pool is never 
exposed. When not set, no tools are exposed. |  | String
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
index 1bf2b23fe5b5..9e452fdcfc69 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
@@ -85,6 +85,16 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
     private long mcpSessionIdleTtl = 300000;
     @Metadata
     private String mcpServerName;
+    @Metadata
+    private String mcpServerTitle;
+    @Metadata
+    private String mcpServerDescription;
+    @Metadata
+    private String mcpServerWebsiteUrl;
+    @Metadata
+    private String mcpInstructions;
+    @Metadata
+    private String mcpServerIcons;
 
     public HttpServerConfigurationProperties(MainConfigurationProperties 
parent) {
         this.parent = parent;
@@ -400,6 +410,62 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
         this.mcpServerName = mcpServerName;
     }
 
+    public String getMcpServerTitle() {
+        return mcpServerTitle;
+    }
+
+    /**
+     * MCP server display title advertised to clients in {@code 
serverInfo.title}.
+     */
+    public void setMcpServerTitle(String mcpServerTitle) {
+        this.mcpServerTitle = mcpServerTitle;
+    }
+
+    public String getMcpServerDescription() {
+        return mcpServerDescription;
+    }
+
+    /**
+     * MCP server description advertised to clients in {@code 
serverInfo.description}.
+     */
+    public void setMcpServerDescription(String mcpServerDescription) {
+        this.mcpServerDescription = mcpServerDescription;
+    }
+
+    public String getMcpServerWebsiteUrl() {
+        return mcpServerWebsiteUrl;
+    }
+
+    /**
+     * MCP server website URL advertised to clients in {@code 
serverInfo.websiteUrl}.
+     */
+    public void setMcpServerWebsiteUrl(String mcpServerWebsiteUrl) {
+        this.mcpServerWebsiteUrl = mcpServerWebsiteUrl;
+    }
+
+    public String getMcpInstructions() {
+        return mcpInstructions;
+    }
+
+    /**
+     * Top-level MCP instructions returned to clients on initialize.
+     */
+    public void setMcpInstructions(String mcpInstructions) {
+        this.mcpInstructions = mcpInstructions;
+    }
+
+    public String getMcpServerIcons() {
+        return mcpServerIcons;
+    }
+
+    /**
+     * JSON array of MCP server icons advertised to clients in {@code 
serverInfo.icons}. Each entry must include a
+     * {@code src} URL and may include {@code mimeType}, {@code sizes} and 
{@code theme}.
+     */
+    public void setMcpServerIcons(String mcpServerIcons) {
+        this.mcpServerIcons = mcpServerIcons;
+    }
+
     public long getMcpSessionKeepAliveInterval() {
         return mcpSessionKeepAliveInterval;
     }
@@ -648,6 +714,46 @@ public class HttpServerConfigurationProperties implements 
BootstrapCloseable {
         return this;
     }
 
+    /**
+     * MCP server display title advertised to clients in {@code 
serverInfo.title}.
+     */
+    public HttpServerConfigurationProperties withMcpServerTitle(String 
mcpServerTitle) {
+        this.mcpServerTitle = mcpServerTitle;
+        return this;
+    }
+
+    /**
+     * MCP server description advertised to clients in {@code 
serverInfo.description}.
+     */
+    public HttpServerConfigurationProperties withMcpServerDescription(String 
mcpServerDescription) {
+        this.mcpServerDescription = mcpServerDescription;
+        return this;
+    }
+
+    /**
+     * MCP server website URL advertised to clients in {@code 
serverInfo.websiteUrl}.
+     */
+    public HttpServerConfigurationProperties withMcpServerWebsiteUrl(String 
mcpServerWebsiteUrl) {
+        this.mcpServerWebsiteUrl = mcpServerWebsiteUrl;
+        return this;
+    }
+
+    /**
+     * Top-level MCP instructions returned to clients on initialize.
+     */
+    public HttpServerConfigurationProperties withMcpInstructions(String 
mcpInstructions) {
+        this.mcpInstructions = mcpInstructions;
+        return this;
+    }
+
+    /**
+     * JSON array of MCP server icons advertised to clients in {@code 
serverInfo.icons}.
+     */
+    public HttpServerConfigurationProperties withMcpServerIcons(String 
mcpServerIcons) {
+        this.mcpServerIcons = mcpServerIcons;
+        return this;
+    }
+
     /**
      * Keep-alive ping interval in milliseconds for MCP sessions on the Vert.x 
streamable transport.
      */

Reply via email to