The ecr-mcp-service is a Spring AI based Model Context Protocol (MCP) server for the arveo Content Repository Service. It exposes selected repository capabilities as MCP tools and resources so that MCP clients and AI assistants can inspect repository metadata, search entities, and retrieve document content.
The service supports the streamable HTTP and SSE MCP transports. The default transport is streamable HTTP and the
default MCP endpoint is /mcp. The deprecated SSE transport can be enabled through spring.ai.mcp.server.protocol=SSE;
its default endpoint is /sse.
1. Security
The MCP Service supports two alternative mechanisms to authenticate requests to its MCP endpoints: OAuth2 and API keys. The two mechanisms are mutually exclusive, exactly one of them can be active. OAuth2 is the default.
1.1. OAuth2 Authentication
By default, the MCP Service is secured with OAuth2 and is configured as a protected resource. Requests to the MCP endpoints must be authenticated with a valid OAuth2 access token.
The service also provides the OAuth2 auto-discovery endpoint required by MCP clients. Clients can use this endpoint to discover the OAuth2 configuration, including the protected resource information and authorization server metadata. The default protected resource advertised by the discovery information is the active MCP endpoint: the configured SSE endpoint when SSE is enabled, otherwise the configured streamable HTTP endpoint.
The service uses OAuth2 token exchange when calling the Content Repository Service. Repository requests are therefore performed with the credentials of the currently authenticated user.
1.2. API Key Authentication
Instead of OAuth2, the MCP endpoints can be secured with static API keys. This is intended for clients that cannot
perform an OAuth2 flow. Clients send their key in the API-Key request header. The key is compared against the keys
configured for the service, so no request to the authorization server is involved in authenticating a caller. Requests
without a valid key are rejected with status 401. API key authentication protects the same endpoints as OAuth2
authentication, and the CORS configuration is applied in both modes.
API key authentication is enabled with commons.security.api-key.server.enabled. At the same time the OAuth2 resource
server must be disabled by setting spring.security.oauth2.resourceserver.enabled to false. If both mechanisms are
enabled, the service does not start, because both security configurations contribute conflicting security filter chains.
If both mechanisms are disabled, the MCP endpoints are not protected at all.
| Property | Default | Description |
|---|---|---|
|
|
Enables API key authentication for the MCP endpoints. Requires |
|
not set |
A valid API key. Any number of keys can be configured. The label is freely chosen and is only used to identify the key within the service; it is never sent by clients. |
|
|
Enables the OAuth2 resource server. Must be set to |
An example configuration for API key authentication:
spring:
security:
oauth2:
resourceserver:
enabled: false
client:
registration:
keycloak-client-credentials:
provider: keycloak
client-id: "techclient"
client-secret: "<client-secret>"
authorization-grant-type: "client_credentials"
scope: openid
provider:
keycloak:
issuer-uri: "https://<keycloak-host>/realms/<realm>"
commons:
security:
api-key:
server:
enabled: true
keys:
key1: "<api-key>"
API keys are credentials and should be provided through the configuration server or through Vault instead of a local configuration file.
Two restrictions apply when API key authentication is used. The OAuth2 auto-discovery endpoint is disabled together with the OAuth2 resource server, so MCP clients that determine their configuration from that endpoint cannot connect to the service in this mode.
There is also no impersonation. The OAuth2 client configuration shown above is still required, because requests to the
Content Repository Service continue to use OAuth2, but they are performed with the credentials of the technical user of
the keycloak-client-credentials registration. All API keys therefore share the same repository identity and the same
repository permissions, and the label of the key is not propagated to the Content Repository Service.
1.3. Client Configuration
The ecr-mcp-service-client-spring module provides an auto-configuration that authenticates the MCP requests of a
Spring based MCP client. By default the OAuth2 access token of the current security context is sent as a bearer token.
For MCP servers that are secured with an API key, the key is configured per server through
spring.ai.mcp.client.api-keys.servers. The map key is the base URL of the MCP server, the map value is the API key.
Servers that are not listed are authenticated with an OAuth2 bearer token.
| Property | Default | Description |
|---|---|---|
|
not set |
The API key sent in the |
An example configuration for a client that connects to an OAuth2 secured and an API key secured MCP server:
spring:
ai:
mcp:
client:
api-keys:
servers:
"[http://localhost:30771]": "<api-key>"
streamable-http:
connections:
oauth2-server:
url: http://localhost:30770
api-key-server:
url: http://localhost:30771
The base URL must be enclosed in square brackets, because it contains characters that Spring interprets as separators within a property name. It must match the configured connection URL, including scheme and port.
2. Tools
All built-in tools are read-only, non-destructive, idempotent operations.
2.1. Enabling and Disabling Tool Groups
The built-in tools are grouped, and each group can be enabled or disabled independently through a Spring property of the
form mcp-service.tools.<group>.enabled. All tool groups are enabled by default; set the corresponding property to
false to disable a group and remove its tools and resources from the MCP server.
| Property | Default | Description |
|---|---|---|
|
|
General information tools ( |
|
|
Current-user tool and resource ( |
|
|
Type definition tools and resources ( |
|
|
Search tools and resources ( |
|
|
Dynamically generated type tools and document content resources (see Dynamic Type Tools). |
2.2. General Information
getCurrentDateTime-
Returns the current date and time in the user’s time zone. The result contains the date and time fields, milliseconds, and the resolved time zone identifier.
getUserInfo-
Returns information about the currently authenticated user as seen by the Content Repository Service. The response contains the user’s additional identifier, external ID, and internal ID.
2.3. Type Definitions
getTypeDefinitions-
Returns the names and optional descriptions of all available type definitions. Type definitions describe the attributes and features of entities in the repository. Each entity belongs to exactly one type definition.
getTypeDefinitionDetails-
Returns detailed information for a single type definition by name. The response contains the type definition name, entity type, attributes, system attributes, data type information, and optional descriptions.
2.4. Search
eql-grammar-
Returns the ANTLR 4 grammar of the ECR Query Language (EQL). MCP clients should inspect this grammar before constructing queries for the
searchtool. search-
Searches for entities within a specific type definition. The
queryStringmust conform to the EQL grammar provided by theeql-grammartool or resource. Attribute names and literal formats must match the selected type definition and its data type descriptions. Query parameters should be preferred over inline literals. The current implementation searches documents and containers and returns matching arveo entities.
2.5. Dynamic Type Tools
When mcp-service.tools.dynamic.enabled is enabled, which is the default, the service creates additional read-only
tools from the configured repository type definitions.
For each document type definition, the service provides:
get-meta-data-<type-definition-name>-
Returns the metadata attributes of a document with the given entity ID.
get-content-links-<type-definition-name>-
Returns MCP resource links for all content elements of a document with the given entity ID. The returned links point to download resources for the individual binary content elements.
For each container type definition, the service provides:
get-meta-data-<type-definition-name>-
Returns the metadata attributes of a container with the given entity ID.
Dynamic tools are currently not generated for folder, meta, or relation type definitions.
3. Resources
3.1. Static Resources
arveo://current-user-
JSON resource containing the same current-user information returned by the
getUserInfotool. arveo://type-definitions-
JSON resource containing the list of all available type definitions with their names and descriptions.
arveo://type-definition/{name}-
JSON resource containing detailed information about the type definition identified by
{name}. arveo://eql-grammar-
Text resource containing the ANTLR 4 grammar of the query language used by the
searchtool.
3.2. Dynamic Document Resources
When dynamic tools are enabled, the service also creates document content resource templates for document type definitions:
arveo://document/<type-definition-name>/{entityId}/{contentElement}-
Downloads the binary content of the selected document content element. The content is returned as an MCP blob resource and is Base64 encoded by the MCP transport.
4. Custom Plugins
The MCP Service can be extended with custom MCP tools by adding a Spring Boot auto-configuration in a separate plugin
JAR. A plugin contributes regular Spring beans to the MCP Service application context. Methods annotated with
@McpTool are detected by Spring AI and exposed as MCP tools.
4.1. Add Dependencies
A custom tool plugin needs Spring Boot auto-configuration support and the Spring AI MCP annotations:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-annotations</artifactId>
</dependency>
</dependencies>
4.2. Implement a Tool
Create a Spring bean class and annotate the methods that should become MCP tools with @McpTool. The annotation defines
the public tool name, the description shown to MCP clients, optional schema generation, and tool behavior hints.
import org.springframework.ai.mcp.annotation.McpTool;
public class MyCustomTool {
@McpTool(
name = "add",
description = "This tool adds two numbers",
generateOutputSchema = true,
annotations = @McpTool.McpAnnotations(title = "Add", readOnlyHint = true, openWorldHint = false, destructiveHint = false, idempotentHint = true)
)
public int add(int a, int b) {
return a + b;
}
}
Use precise descriptions and behavior hints. The built-in tools are read-only and idempotent; custom plugins should set
the readOnlyHint, destructiveHint, and idempotentHint values to match their real behavior so that MCP clients can
choose and present tools correctly.
4.3. Register the Tool Bean
Expose the tool class as a Spring bean from an auto-configuration class:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
public class CustomToolsAutoConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomToolsAutoConfiguration.class);
public CustomToolsAutoConfiguration() {
LOGGER.info("CustomToolsAutoConfiguration started");
}
@Bean
public MyCustomTool myCustomTool() {
return new MyCustomTool();
}
}
The auto-configuration class must be listed in
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports so that Spring Boot can discover it
when the plugin JAR is on the application class path:
de.eitco.ecr.mcp.test.tools.CustomToolsAutoConfiguration
4.4. Deploy the Plugin
Build the plugin as a JAR and add it to the MCP Service runtime class path by placing the plugin JAR and its
additional dependencies in a directory that is added to loader.path when starting ecr-mcp-service.jar.
After startup, the custom tool appears in the MCP tool list with the configured name. In the example plugin, the exposed
tool is named add.