#
tokens: 11758/50000 18/18 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── alfresco
│   ├── .env
│   ├── .gitignore
│   ├── alfresco
│   │   ├── Dockerfile
│   │   └── modules
│   │       ├── amps
│   │       │   └── empty
│   │       └── jars
│   │           ├── activemq-broker-5.18.3.jar
│   │           └── empty
│   ├── config
│   │   ├── nginx.conf
│   │   └── nginx.htpasswd
│   ├── docker-compose.yml
│   ├── search
│   │   └── Dockerfile
│   └── share
│       ├── Dockerfile
│       ├── modules
│       │   ├── amps
│       │   │   └── empty
│       │   └── jars
│       │       └── empty
│       └── web-extension
│           └── share-config-custom-dev.xml
├── alfresco-mcp-client
│   ├── .gitignore
│   ├── pom.xml
│   ├── README.md
│   └── src
│       └── main
│           ├── java
│           │   └── com
│           │       └── hyland
│           │           └── Application.java
│           └── resources
│               └── application.properties
├── alfresco-mcp-server
│   ├── .gitignore
│   ├── alfresco-rest-server.js
│   ├── package-lock.json
│   ├── package.json
│   └── README.md
├── docs
│   └── diagram.png
├── LICENSE
└── README.md
```

# Files

--------------------------------------------------------------------------------
/alfresco/.gitignore:
--------------------------------------------------------------------------------

```
data
logs

```

--------------------------------------------------------------------------------
/alfresco-mcp-client/.gitignore:
--------------------------------------------------------------------------------

```
target
.idea
.mvn

```

--------------------------------------------------------------------------------
/alfresco-mcp-server/.gitignore:
--------------------------------------------------------------------------------

```
# .gitignore
node_modules
.env


```

--------------------------------------------------------------------------------
/alfresco/.env:
--------------------------------------------------------------------------------

```
# Docker Image versions
ALFRESCO_CE_TAG=23.4.0
SEARCH_CE_TAG=2.0.13
SHARE_TAG=23.4.0
ACA_TAG=5.2.0
POSTGRES_TAG=15.6
MARIADB_TAG=11.3.2
TRANSFORM_ENGINE_TAG=5.1.5
ACTIVEMQ_TAG=5.18-jre17-rockylinux8

# Server properties
SERVER_NAME=localhost

# Binding properties
BIND_IP_NGINX=
BIND_IP_FTP=

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# Alfresco MCP Proof of Concept (PoC)

This repository contains a Proof of Concept (PoC) for integrating Alfresco as a [Model Context Protocol server](https://modelcontextprotocol.io/quickstart/server). The project demonstrates how to connect Alfresco capabilities to AI using standard client-server applications.

![General Diagram](docs/diagram.png)

## Project Structure

The repository is structured as follows:

- **`alfresco/`**: Contains a Docker Compose setup for a standard Alfresco deployment. This must be run before the MCP integration.
- **`alfresco-mcp-client/`**: A Java-based client application for interacting with the MCP server using [Spring AI](https://spring.io/projects/spring-ai)
- **`alfresco-mcp-server/`**: A Node.js-based server application for handling MCP requests using [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)

## Prerequisites

Before running the project, ensure you have the following installed:

- Docker (version 20.10.0 or higher)
- Docker Compose (version 1.29.0 or higher)
- Java Development Kit (JDK) 17 or higher (for the client application)
- Node.js (version 18 or higher) and npm (for the server application)
- Git (for cloning the repository)

## Getting Started

### Step 1: Clone the Repository

Clone the repository to your local machine:

```bash
git clone https://github.com/aborroy/alfresco-mcp-poc.git
cd alfresco-mcp-poc
```

### Step 2: Run the Alfresco Docker Compose

Navigate to the `alfresco/` directory and start the Alfresco deployment using Docker Compose:

```bash
cd alfresco
docker-compose up --build --force-recreate
```

This will start the Alfresco Content Services stack, including the repository, Share, and other required services. Wait for all services to initialize completely.

### Step 3: Verify Alfresco Deployment

Once the services are up, you can access the Alfresco Share interface at:

- **Alfresco Share**: [http://localhost:8080/share](http://localhost:8080/share)
- **Alfresco Repository**: [http://localhost:8080/alfresco](http://localhost:8080/alfresco)

Use the default credentials (`admin` / `admin`) to log in.

### Step 4: Set Up and Run the MCP Client

Start the Ollama server locally:

```bash
ollama serve
```

Navigate to the `alfresco-mcp-client/` directory and follow the instructions in its `README.md` to set up and run the MCP client:

```bash
cd ../alfresco-mcp-client
mvn clean package
java -jar target/alfresco-mcp-client-0.8.0.jar
```

## Customization

You can customize the Alfresco deployment by modifying the `docker-compose.yml` file in the `alfresco/` directory. Additionally, the MCP server and client components can be configured to suit your specific use case.

## Contributing

Contributions to this project are welcome! Please open an issue or submit a pull request with your proposed changes.

```

--------------------------------------------------------------------------------
/alfresco-mcp-server/README.md:
--------------------------------------------------------------------------------

```markdown
# Alfresco MCP Server

This service provides a REST API interface to interact with Alfresco repositories using the **Model Context Protocol Server**. It supports operations such as reading node metadata, downloading node content, and searching nodes. The service is built using the `@modelcontextprotocol/sdk` and communicates via `stdio`.

## Features

- **Read Node Metadata**: Retrieve metadata for a specific Alfresco node.
- **Download Node Content**: Download the content of a specific Alfresco node.
- **Search Nodes**: Perform advanced searches for files in Alfresco.
- **Tool Integration**: Supports tools like `search` and `readContent` for integration with the Model Context Protocol.

## Prerequisites

Before running the service, ensure you have the following:

1. **Node.js**: Version 16 or higher.
2. **Alfresco Repository**: A running Alfresco instance with REST API access.
3. **Environment Variables**: Set up the required environment variables (see [Configuration](#configuration)).

## Setup and Installation

1. Clone the repository or download the service script.
2. Install dependencies:
   ```bash
   npm install dotenv @modelcontextprotocol/sdk
   ```
3. Set up the required environment variables (see [Configuration](#configuration)).
4. Run the service:
   ```bash
   node alfresco-rest-server.js
   ```

## Configuration

The service requires the following environment variables to be set:

| Variable Name       | Description                                                                 |
|---------------------|-----------------------------------------------------------------------------|
| `ALFRESCO_HOST`     | The base URL of the Alfresco repository (e.g., `https://alfresco.example.com`). |
| `ALFRESCO_USERNAME` | The username for Alfresco authentication.                                   |
| `ALFRESCO_PASSWORD` | The password for Alfresco authentication.                                   |

### Example `.env` File

```env
ALFRESCO_HOST=http://localhost:8080
ALFRESCO_USERNAME=admin
ALFRESCO_PASSWORD=admin
```

## API Endpoints

The service implements the following functionality through the Model Context Protocol:

### 1. **Read Resource**
- **Description**: Retrieves metadata or content for a specific Alfresco node.
- **Request Schema**: `ReadResourceRequestSchema`
- **Example URI**: `alfresco://{nodeId}`

### 2. **List Tools**
- **Description**: Lists available tools for interacting with Alfresco.
- **Request Schema**: `ListToolsRequestSchema`
- **Supported Tools**:
  - `search`: Performs a full-text search in Alfresco.
  - `readContent`: Reads the content of a file by its Alfresco URI.

### 3. **Call Tool**
- **Description**: Executes a specific tool (e.g., `search` or `readContent`).
- **Request Schema**: `CallToolRequestSchema`

## Troubleshooting

1. **Service Fails to Start**:
   - Ensure all dependencies are installed (`npm install`).
   - Verify that the required environment variables are set.

2. **API Requests Fail**:
   - Check the Alfresco repository logs for errors.
   - Verify that the provided credentials (`ALFRESCO_USERNAME` and `ALFRESCO_PASSWORD`) are correct.

3. **Invalid Node ID**:
   - Ensure the node ID in the URI (e.g., `alfresco://{nodeId}`) is valid and exists in the repository.

4. **Search Returns No Results**:
   - Verify the search query and ensure the repository contains matching files.
```

--------------------------------------------------------------------------------
/alfresco-mcp-client/README.md:
--------------------------------------------------------------------------------

```markdown
# Alfresco MCP Client

The Alfresco [MCP Client](https://modelcontextprotocol.io/quickstart/client) is a Spring Boot application designed to interact with Alfresco content management system using an AI model (via Ollama). It allows users to query Alfresco documents and retrieve summaries or other relevant information using natural language prompts.

## Features

- **AI-Powered Queries**: Use an AI model (e.g., Llama3) to interact with Alfresco documents.
- **Predefined Questions**: Execute predefined questions to retrieve specific information from Alfresco.
- **Custom MCP Client**: Integrates with a custom MCP client to interact with Alfresco REST services.
- **Command-Line Interface**: Runs as a command-line application without a web interface.

## Requirements

To run this project, you need the following:

1. **Java Development Kit (JDK) 17 or higher**:
    - Download and install the latest JDK from [Oracle](https://www.oracle.com/java/technologies/javase-downloads.html) or use an open-source alternative like [OpenJDK](https://openjdk.org/).

2. **Node.js (v18.19.1 or higher)**:
    - Download and install Node.js from [nodejs.org](https://nodejs.org/).

3. **Ollama**:
    - Install and run Ollama locally. Follow the instructions at [Ollama GitHub](https://github.com/ollama/ollama).

4. **Alfresco Instance**:
    - A running instance of Alfresco (e.g., `http://localhost:8080`).

5. **Alfresco REST Server Script**:
    - A Node.js script (`alfresco-rest-server.js`) that acts as a bridge between the MCP client and Alfresco.

## How to Build

1. **Clone the Repository**:
   ```bash
   git clone https://github.com/your-repo/alfresco-mcp-client.git
   cd alfresco-mcp-client
   ```
2. **Build the Project:**
    Use Maven to build the project:
    ```bash
    ./mvn clean package
    ```

3. **Run the Application:**
    After building, run the application using the generated JAR file:

    ```bash
    java -jar target/alfresco-mcp-client.jar
    ```

## Configuration

The application is configured using the `application.properties file. Below are the key configuration options:

* Spring AI (LLM) Configuration

    spring.ai.ollama.base-url=http://localhost:11434: Base URL for the Ollama API.

    spring.ai.ollama.chat.options.model=llama3.1: Specifies the AI model to use for chat interactions.

* Alfresco MCP Configuration

    node.path=/path/to/node: Path to the Node.js executable.

    alfresco.host=http://localhost:8080: URL of the Alfresco instance.

    alfresco.username=admin: Username for Alfresco authentication.

    alfresco.password=admin: Password for Alfresco authentication.

    alfresco.rest-server.path=/path/to/alfresco-rest-server.js: Path to the Alfresco REST server script.

## How to Run

1. **Ensure Ollama is Running:**

    Start the Ollama server locally:
    ```bash
    ollama serve
    ```

2. Update Configuration:

    Modify the `application.properties` file to match your environment (e.g., Alfresco host, credentials, Node.js path, etc.).

    Run the Application:

    ```bash
    java -jar target/alfresco-mcp-client-0.8.0.jar
    ```

    View Output: The application will execute predefined questions and print the AI model's responses to the console.

## Predefined Questions

The application includes the following predefined questions, but you can experiment your proposals.

    Retrieve Invoice Documents:

        Question: "Get a list with all the Invoice documents together with the Alfresco URI."

        Purpose: Retrieves a list of all invoice documents along with their Alfresco URIs.

    Summarize an Invoice:

        Question: "Provide a summary of the invoice 'alfresco://723a0cff-3fce-495d-baa3-a3cd245ea5dc'."

        Purpose: Provides a summary of a specific invoice document.
```

--------------------------------------------------------------------------------
/alfresco-mcp-server/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "alfresco-mcp-server",
  "version": "1.0.0",
  "description": "Alfresco REST + Model Context Protocol",
  "type": "module",
  "scripts": {
    "start": "node alfresco-rest-server.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "latest",
    "dotenv": "^16.4.7"
  },
  "engines": {
    "node": ">=18"
  }
}

```

--------------------------------------------------------------------------------
/alfresco/share/web-extension/share-config-custom-dev.xml:
--------------------------------------------------------------------------------

```
<alfresco-config>
   <config evaluator="string-compare" condition="Users" replace="true">
      <users>
         <!-- minimum length for username and password -->
         <username-min-length>2</username-min-length>
         <password-min-length>3</password-min-length>
         <show-authorization-status>false</show-authorization-status>
      </users>
      <!-- This enables/disables the Add External Users Panel on the Add Users page. -->
      <enable-external-users-panel>false</enable-external-users-panel>
   </config>
  <config evaluator="string-compare" condition="DocumentLibrary" >
    <repository-url>http://localhost:8080/alfresco</repository-url>
  </config>
</alfresco-config>

```

--------------------------------------------------------------------------------
/alfresco/share/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
ARG SHARE_TAG
FROM alfresco/alfresco-share:${SHARE_TAG}

ARG TOMCAT_DIR=/usr/local/tomcat

# Server data
ARG SERVER_NAME
ENV SERVER_NAME $SERVER_NAME





# Install modules and addons
RUN mkdir -p $TOMCAT_DIR/amps
COPY modules/amps $TOMCAT_DIR/amps
COPY modules/jars $TOMCAT_DIR/webapps/share/WEB-INF/lib

RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \
    $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/share -directory -nobackup -force

# Increase default cacheMaxSize
RUN sed -i "s|<Context>|<Context>\n<Resources cacheMaxSize=\"51200\"/> |g" $TOMCAT_DIR/conf/context.xml

# Fix for https://github.com/Alfresco/acs-community-packaging/issues/367 in Share 6.2.0
COPY web-extension/share-config-custom-dev.xml $TOMCAT_DIR/shared/classes/alfresco/web-extension/

```

--------------------------------------------------------------------------------
/alfresco-mcp-client/src/main/resources/application.properties:
--------------------------------------------------------------------------------

```
# ==================================================
# Logging Configuration
# ==================================================

# Set logging level for the DefaultMcpSession class to WARN to reduce noise in logs
logging.level.org.springframework.ai.mcp.spec.DefaultMcpSession=WARN

# ==================================================
# Application Configuration
# ==================================================

# Application name for identification
spring.application.name=alfresco-mcp-client

# Disable web application type since this is a command-line application
spring.main.web-application-type=none

# ==================================================
# Spring AI (LLM) Configuration
# ==================================================

# Base URL for the Ollama API (local instance)
spring.ai.ollama.base-url=http://localhost:11434

# Model to use for chat interactions with Ollama
spring.ai.ollama.chat.options.model=llama3.1

# Download model when missing
spring.ai.ollama.init.pull-model-strategy=when_missing

# ==================================================
# Alfresco MCP Configuration
# ==================================================

# Node.js Path Configuration
# Path to the Node.js executable
node.path=/Users/angel.fernandoborroy/.nvm/versions/node/v18.19.1/bin/node

# Alfresco Host Configuration
# URL of the Alfresco instance
alfresco.host=http://localhost:8080

# Alfresco Credentials
# Username and password for Alfresco authentication
alfresco.username=admin
alfresco.password=admin

# Alfresco REST Server Script Path
# Path to the Alfresco REST server script
alfresco.rest-server.path=/Users/angel.fernandoborroy/Downloads/zz/alfresco-mcp-server/alfresco-rest-server.js
```

--------------------------------------------------------------------------------
/alfresco/config/nginx.conf:
--------------------------------------------------------------------------------

```
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    server {

        listen *:8080 ;

        

        client_max_body_size 0;

        set  $allowOriginSite *;
        proxy_pass_request_headers on;
        proxy_pass_header Set-Cookie;

        # Increment timeout values
        proxy_connect_timeout 600;
        proxy_send_timeout    600;
        proxy_read_timeout    600;
        send_timeout          600;

        # External settings, do not remove
        #ENV_ACCESS_LOG

        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
        proxy_redirect off;
        proxy_buffering off;
        proxy_set_header Host            $host:$server_port;
        proxy_set_header X-Real-IP       $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass_header Set-Cookie;

        location ~ ^(/.*/service/api/solr/.*)$ {return 403;}
        location ~ ^(/.*/s/api/solr/.*)$ {return 403;}
        location ~ ^(/.*/wcservice/api/solr/.*)$ {return 403;}
        location ~ ^(/.*/wcs/api/solr/.*)$ {return 403;}
        location ~ ^(/.*/proxy/alfresco/api/solr/.*)$ {return 403 ;}
        location ~ ^(/.*/-default-/proxy/alfresco/api/.*)$ {return 403;}

        # Alfresco Content Application Proxy
        location / {
          proxy_pass http://content-app:8080;
        }

        # Repository Proxy
        location /alfresco/ {
          proxy_pass http://alfresco:8080;
        }

        # Api-Explorer Proxy
        location /api-explorer/ {
          proxy_pass http://alfresco:8080;
        }

        # Share Proxy
        location /share/ {
          proxy_pass http://share:8080;
        }

        
        # SOLR Proxy
        location /solr/ {
          proxy_pass http://solr6:8983;
          auth_basic "Solr web console";
          auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
        }
        

        

    }
}

```

--------------------------------------------------------------------------------
/alfresco-mcp-client/pom.xml:
--------------------------------------------------------------------------------

```
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.4.1</version>
    <relativePath/>
  </parent>

  <groupId>com.hyland</groupId>
  <artifactId>alfresco-mcp-client</artifactId>
  <version>0.8.0</version>

  <name>alfresco-mcp-client</name>
  <description>A simple alfresco-mcp-client.</description>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-bom</artifactId>
        <version>1.0.0-M5</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>


    <dependency>
      <groupId>org.springframework.ai</groupId>
      <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.experimental</groupId>
      <artifactId>spring-ai-mcp</artifactId>
      <version>0.5.1</version>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>spring-milestones</id>
      <name>Spring Milestones</name>
      <url>https://repo.spring.io/libs-milestone-local</url>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>spring-snapshots</id>
      <name>Spring Snapshots</name>
      <url>https://repo.spring.io/snapshot</url>
      <releases>
        <enabled>false</enabled>
      </releases>
    </repository>
  </repositories>
</project>

```

--------------------------------------------------------------------------------
/alfresco/alfresco/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
ARG ALFRESCO_TAG
FROM alfresco/alfresco-content-repository-community:${ALFRESCO_TAG}

ARG TOMCAT_DIR=/usr/local/tomcat
ARG IMAGEUSERNAME=alfresco

# default user is alfresco (added on the base image alfresco/alfresco-content-repository-community)
# change to root user to be able to install the addons and packages
USER root

# Install modules and addons
RUN mkdir -p $TOMCAT_DIR/amps
COPY modules/amps $TOMCAT_DIR/amps
COPY modules/jars $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib

RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \
    $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/alfresco -directory -nobackup -force



# DATABASE
ARG DB
ENV DB $DB

RUN ls -la /etc/yum.repos.d/ && \
    ((sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \
    sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 2>/dev/null) || \
    (sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/Rocky-* && \
    sed -i 's|#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=http://dl.rockylinux.org/$contentdir|g' /etc/yum.repos.d/Rocky-*)) || \
    (dnf clean all && dnf makecache && dnf update -y)

# Install mysql JDBC driver
RUN if [ "$DB" == "mariadb" ] ; then \
    set -x \
        && yum clean all \
        && yum install -y wget \
        && yum clean all \
        && wget -P /tmp/ https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.7.4/mariadb-java-client-2.7.4.jar \
        && cp /tmp/mariadb-java-client-2.7.4.jar $TOMCAT_DIR/lib/ \
        && rm -rf /tmp/mariadb-java-client-2.7.4.jar; \
fi



# COMMS
ARG SOLR_COMMS
ENV SOLR_COMMS $SOLR_COMMS

# SSL
ARG TRUSTSTORE_TYPE
ARG TRUSTSTORE_PASS
ARG KEYSTORE_TYPE
ARG KEYSTORE_PASS
ARG CERT_ALIAS

ENV TRUSTSTORE_TYPE=$TRUSTSTORE_TYPE \
    TRUSTSTORE_PASS=$TRUSTSTORE_PASS \
    KEYSTORE_TYPE=$KEYSTORE_TYPE \
    KEYSTORE_PASS=$KEYSTORE_PASS \
    CERT_ALIAS=$CERT_ALIAS

# Enable SSL by adding the proper Connector to server.xml
RUN if [ "$SOLR_COMMS" == "https" ] ; then \
      sed -i "s/\
[[:space:]]\+<\/Engine>/\n\
        <\/Engine>\n\
        <Connector port=\"8443\" protocol=\"org.apache.coyote.http11.Http11NioProtocol\"\n\
            connectionTimeout=\"20000\" maxThreads=\"150\"\n\
            SSLEnabled=\"true\" scheme=\"https\" secure=\"true\"\n\
            defaultSSLHostConfigName=\"localhost\">\n\
                <SSLHostConfig hostName=\"localhost\" protocols=\"TLSv1.3\"\n\
                    certificateVerification=\"required\"\n\
                    truststoreFile=\"\/usr\/local\/tomcat\/keystore\/ssl.truststore\"\n\
                    truststorePassword=\"${TRUSTSTORE_PASS}\" truststoreType=\"${TRUSTSTORE_TYPE}\">\n\
                    <Certificate certificateKeystoreFile=\"\/usr\/local\/tomcat\/keystore\/ssl.keystore\"\n\
                       certificateKeyAlias=\"${CERT_ALIAS}\" type=\"RSA\"\n\
                       certificateKeystorePassword=\"${KEYSTORE_PASS}\" certificateKeystoreType=\"${KEYSTORE_TYPE}\"\/>\n\
                <\/SSLHostConfig>\n\
        <\/Connector>/g" ${TOMCAT_DIR}/conf/server.xml; \
    fi







```

--------------------------------------------------------------------------------
/alfresco/search/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
ARG SEARCH_TAG
FROM alfresco/alfresco-search-services:${SEARCH_TAG}

# COMMON
ARG ALFRESCO_HOSTNAME
ARG SOLR_HOSTNAME
ENV ALFRESCO_HOSTNAME $ALFRESCO_HOSTNAME
ENV SOLR_HOSTNAME $SOLR_HOSTNAME

# Configure Alfresco Service Name
RUN sed -i '/^bash.*/i sed -i "'"s/alfresco.host=localhost/alfresco.host=${ALFRESCO_HOSTNAME}/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
    ${DIST_DIR}/solr/bin/search_config_setup.sh && \
    sed -i '/^bash.*/i sed -i "'"s/solr.host=localhost/solr.host=${SOLR_HOSTNAME}/g"'" ${DIST_DIR}/solrhome/conf/shared.properties\n' \
    ${DIST_DIR}/solr/bin/search_config_setup.sh

# Disable content indexing
ARG DISABLE_CONTENT_INDEXING
ENV DISABLE_CONTENT_INDEXING $DISABLE_CONTENT_INDEXING
RUN if [ "$DISABLE_CONTENT_INDEXING" == "true" ] ; then \
   sed -i '/^bash.*/i sed -i "'"/alfresco.index.transformContent/s/^#//g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
   ${DIST_DIR}/solr/bin/search_config_setup.sh && \
   sed -i '/^bash.*/i sed -i "'"/alfresco.ignore.datatype.1/s/^#//g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
   ${DIST_DIR}/solr/bin/search_config_setup.sh; \
fi

# Cross Locale
ARG CROSS_LOCALE
ENV CROSS_LOCALE $CROSS_LOCALE

# Enable Cross Locale SOLR Configuration
RUN if [ "$CROSS_LOCALE" == "true" ] ; then \
    sed -i '/^bash.*/i sed -i "'"/alfresco.cross.locale.datatype/s/^#//g"'" $DIST_DIR/solrhome/conf/shared.properties\n' \
    ${DIST_DIR}/solr/bin/search_config_setup.sh; \
fi

# COMMS
ARG ALFRESCO_COMMS
ENV ALFRESCO_COMMS $ALFRESCO_COMMS

# Configure SOLR cores to run in HTTPs mode from template
RUN if [ "$ALFRESCO_COMMS" == "https" ] ; then \
    sed -i '/^bash.*/i sed -i "'"s/alfresco.secureComms=none/alfresco.secureComms=https/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
    ${DIST_DIR}/solr/bin/search_config_setup.sh; \
elif [ "$ALFRESCO_COMMS" == "secret" ] ; then \
    sed -i '/^bash.*/i sed -i "'"s/alfresco.secureComms=https/alfresco.secureComms=secret/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
    ${DIST_DIR}/solr/bin/search_config_setup.sh; \
else \
    sed -i '/^bash.*/i sed -i "'"s/alfresco.secureComms=https/alfresco.secureComms=none/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
    ${DIST_DIR}/solr/bin/search_config_setup.sh; \
fi

# SSL
ARG TRUSTSTORE_TYPE
ENV TRUSTSTORE_TYPE $TRUSTSTORE_TYPE
ARG KEYSTORE_TYPE
ENV KEYSTORE_TYPE $KEYSTORE_TYPE

# Set mTLS properties
RUN if [ "$ALFRESCO_COMMS" == "https" ] ; then \
  sed -i '/^bash.*/i \
  sed -i "'"s/alfresco.encryption.ssl.keystore.location=.*/alfresco.encryption.ssl.keystore.location=\\\/opt\\\/alfresco-search-services\\\/keystore\\\/ssl-repo-client.keystore/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
  sed -i "'"s/alfresco.encryption.ssl.keystore.passwordFileLocation=.*/alfresco.encryption.ssl.keystore.passwordFileLocation=/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
  sed -i "'"s/alfresco.encryption.ssl.keystore.type=.*/alfresco.encryption.ssl.keystore.type=${KEYSTORE_TYPE}/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
  sed -i "'"s/alfresco.encryption.ssl.truststore.location=.*/alfresco.encryption.ssl.truststore.location=\\\/opt\\\/alfresco-search-services\\\/keystore\\\/ssl-repo-client.truststore/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
  sed -i "'"s/alfresco.encryption.ssl.truststore.passwordFileLocation=.*/alfresco.encryption.ssl.truststore.passwordFileLocation=/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
  sed -i "'"s/alfresco.encryption.ssl.truststore.type=.*/alfresco.encryption.ssl.truststore.type=${TRUSTSTORE_TYPE}/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties' \
  ${DIST_DIR}/solr/bin/search_config_setup.sh; \
fi

```

--------------------------------------------------------------------------------
/alfresco-mcp-client/src/main/java/com/hyland/Application.java:
--------------------------------------------------------------------------------

```java
package com.hyland;

import java.time.Duration;
import java.util.List;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.mcp.client.McpClient;
import org.springframework.ai.mcp.client.McpSyncClient;
import org.springframework.ai.mcp.client.transport.ServerParameters;
import org.springframework.ai.mcp.client.transport.StdioClientTransport;
import org.springframework.ai.mcp.spring.McpFunctionCallback;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Main application class for interacting with an AI model and Alfresco services.
 * This class initializes the MCP client, sets up predefined questions, and retrieves responses from the AI model.
 */
@SpringBootApplication
@Configuration
public class Application {

    /**
     * Main method to start the Spring Boot application.
     *
     * @param args Command-line arguments.
     */
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    /**
     * Bean definition for running predefined questions using the ChatClient.
     *
     * @param chatClientBuilder Builder for creating the ChatClient.
     * @param functionCallbacks List of McpFunctionCallbacks for the ChatClient.
     * @param context           ConfigurableApplicationContext to close the application after execution.
     * @return CommandLineRunner instance.
     */
    @Bean
    public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder,
                                                 List<McpFunctionCallback> functionCallbacks,
                                                 ConfigurableApplicationContext context) {

        return args -> {
            try (context) {
                var chatClient = chatClientBuilder
                        .defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0]))
                        .build();

                System.out.println("Running predefined questions with AI model responses:\n");

                // Question 1: Retrieve a list of Invoice documents with Alfresco URIs
                String question1 = "Get a list with all the Invoice documents together with the Alfresco URI.";
                System.out.println("QUESTION: " + question1);
                System.out.println("ASSISTANT: " + chatClient.prompt(question1).call().content());

                // Question 2: Provide a summary of a specific invoice
                String question2 = "Provide the total cost and the due date of the invoice 'alfresco://723a0cff-3fce-495d-baa3-a3cd245ea5dc'.";
                System.out.println("\nQUESTION: " + question2);
                System.out.println("ASSISTANT: " + chatClient.prompt(question2).call().content());

            } catch (Exception e) {
                System.err.println("An error occurred while processing the questions: " + e.getMessage());
                e.printStackTrace();
            }
        };
    }

    /**
     * Bean definition for creating a list of McpFunctionCallbacks.
     *
     * @param mcpClient McpSyncClient instance to list tools.
     * @return List of McpFunctionCallbacks.
     */
    @Bean
    public List<McpFunctionCallback> functionCallbacks(McpSyncClient mcpClient) {
        return mcpClient.listTools(null)
                .tools()
                .stream()
                .map(tool -> new McpFunctionCallback(mcpClient, tool))
                .toList();
    }

    /**
     * Bean definition for creating and initializing the McpSyncClient.
     *
     * @param nodePath         Path to the node executable.
     * @param alfrescoHost     Alfresco host URL.
     * @param alfrescoUsername Alfresco username.
     * @param alfrescoPassword Alfresco password.
     * @param restServerPath   Path to the REST server script.
     * @return Initialized McpSyncClient instance.
     */
    @Bean(destroyMethod = "close")
    public McpSyncClient mcpClient(@Value("${node.path}") String nodePath,
                                   @Value("${alfresco.host}") String alfrescoHost,
                                   @Value("${alfresco.username}") String alfrescoUsername,
                                   @Value("${alfresco.password}") String alfrescoPassword,
                                   @Value("${alfresco.rest-server.path}") String restServerPath) {

        try {
            // Construct the command to set environment variables and start the REST server
            String command = String.join(" && ",
                    "export ALFRESCO_HOST=\"" + alfrescoHost + "\"",
                    "export ALFRESCO_USERNAME=\"" + alfrescoUsername + "\"",
                    "export ALFRESCO_PASSWORD=\"" + alfrescoPassword + "\"",
                    nodePath + " " + restServerPath
            );

            // Configure server parameters for the StdioClientTransport
            var stdioParams = ServerParameters.builder("/bin/bash")
                    .args("-c", command)
                    .build();

            // Create and initialize the McpSyncClient
            var mcpClient = McpClient.using(new StdioClientTransport(stdioParams))
                    .requestTimeout(Duration.ofSeconds(10))
                    .sync();

            var init = mcpClient.initialize();
            System.out.println("MCP Initialized: " + init);

            return mcpClient;
        } catch (Exception e) {
            System.err.println("Failed to initialize MCP client: " + e.getMessage());
            throw new RuntimeException("MCP client initialization failed", e);
        }
    }
}
```

--------------------------------------------------------------------------------
/alfresco-mcp-server/alfresco-rest-server.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node
/**
 * Alfresco REST API Server implementing Model Context Protocol Server
 * 
 * This service provides a REST API interface to interact with Alfresco repositories.
 * It supports operations like reading node metadata, downloading node content, and searching nodes.
 * The service is built using the Model Context Protocol SDK and communicates via stdio.
 */

import 'dotenv/config';
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
  ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

// Configuration validation
function validateConfig() {
  const requiredEnvVars = ['ALFRESCO_HOST', 'ALFRESCO_USERNAME', 'ALFRESCO_PASSWORD'];
  
  for (const varName of requiredEnvVars) {
    if (!process.env[varName]) {
      console.error(`Missing required environment variable: ${varName}`);
      process.exit(1);
    }
  }

  try {
    new URL(process.env.ALFRESCO_HOST);
  } catch {
    console.error('Invalid Alfresco host URL');
    process.exit(1);
  }

  return {
    ALFRESCO_HOST: process.env.ALFRESCO_HOST,
    ALFRESCO_USERNAME: process.env.ALFRESCO_USERNAME,
    ALFRESCO_PASSWORD: process.env.ALFRESCO_PASSWORD
  };
}

const {
  ALFRESCO_HOST, 
  ALFRESCO_USERNAME, 
  ALFRESCO_PASSWORD 
} = validateConfig();

// Authentication and API helpers
class AlfrescoAPIClient {
  constructor(host, username, password) {
    this.host = host;
    this.basicAuthHeader = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
  }

  _buildUrl(path, apiType = 'alfresco') {
    const basePathMap = {
      'alfresco': `/alfresco/api/-default-/public/alfresco/versions/1${path}`,
      'search': '/alfresco/api/-default-/public/search/versions/1/search'
    };
    return `${this.host}${basePathMap[apiType]}`;
  }

  async _fetchWithAuth(url, options = {}) {
    const defaultHeaders = {
      Authorization: this.basicAuthHeader,
      Accept: 'application/json',
      ...options.headers
    };

    try {
      const response = await fetch(url, { 
        ...options, 
        headers: defaultHeaders 
      });

      if (!response.ok) {
        const errorText = await response.text();
        throw new Error(`HTTP ${response.status}: ${errorText}`);
      }

      return response;
    } catch (error) {
      console.error('API Request Failed:', error);
      throw error;
    }
  }

  async getNodeMetadata(nodeId) {
    const url = this._buildUrl(`/nodes/${nodeId}`);
    const response = await this._fetchWithAuth(url);
    return response.json();
  }

  async downloadNodeContent(nodeId) {
    const url = this._buildUrl(`/nodes/${nodeId}/content`);
    return this._fetchWithAuth(url);
  }

  async searchNodes(query, options = {}) {
    const url = this._buildUrl('', 'search');
    const body = {
      query: {
        query: `${query} AND TYPE:'cm:content'`,
        language: 'afts',
      },
      paging: {
        maxItems: options.maxItems || 10,
        skipCount: options.skipCount || 0,
      },
      include: ['properties'],
    };

    const response = await this._fetchWithAuth(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });

    return response.json();
  }
}

const apiClient = new AlfrescoAPIClient(ALFRESCO_HOST, ALFRESCO_USERNAME, ALFRESCO_PASSWORD);

// Server configuration
const server = new Server(
  {
    name: "alfresco-rest-server",
    version: "0.2.0",
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  }
);

server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
  try {
    const nodeId = request.params.uri.replace("alfresco://", "");
    const metadata = await apiClient.getNodeMetadata(nodeId);
    const entry = metadata.entry;

    if (entry.isFolder) {
      return {
        contents: [{
          uri: request.params.uri,
          mimeType: "text/plain",
          blob: Buffer.from(`Folder: ${nodeId}`).toString('base64')
        }]
      };
    }

    const downloadResp = await apiClient.downloadNodeContent(nodeId);
    const mimeType = entry?.content?.mimeType || "application/octet-stream";
    const arrayBuffer = await downloadResp.arrayBuffer();

    return {
      contents: [{
        uri: request.params.uri,
        mimeType,
        blob: Buffer.from(arrayBuffer).toString('base64')
      }]
    };
  } catch (error) {
    console.error('Read Resource Error:', error);
    throw error;
  }
});

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "search",
      description: "Advanced Alfresco file search",
      inputSchema: {
        type: "object",
        properties: {
          query: { type: "string", description: "Full-text search query" },
          maxItems: { type: "number", description: "Maximum search results" }
        },
        required: ["query"]
      }
    },
    {
      name: "readContent",
      description: "Read file content by Alfresco URI",
      inputSchema: {
        type: "object",
        properties: {
          fileUri: { type: "string", description: "Alfresco file URI" }
        },
        required: ["fileUri"]
      }
    }
  ]
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  switch(name) {
    case "readContent": {
      const nodeId = args.fileUri.replace("alfresco://", "");
      const response = await apiClient.downloadNodeContent(nodeId);
      const content = await response.text();
      
      return {
        content: [{ type: "text", text: content }],
        isError: false
      };
    }
    
    case "search": {
      const result = await apiClient.searchNodes(args.query, {
        maxItems: args.maxItems
      });

      const entries = result.list?.entries || [];
      const totalItems = result.list?.pagination?.totalItems ?? 0;

      const searchResults = entries.map(item => ({
        uri: `alfresco://${item.entry.id}`,
        mimeType: item.entry.content?.mimeType || "application/octet-stream",
        name: item.entry.name
      }));

      return {
        content: [{
          type: "text", 
          text: `Found ${totalItems} items:\n${JSON.stringify(searchResults, null, 2)}`
        }],
        isError: false
      };
    }

    default:
      throw new Error(`Unsupported tool: ${name}`);
  }
});

// Server initialization
async function runServer() {
  console.error("Initializing Alfresco REST Server...");
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("Server ready.");
}

runServer().catch(err => {
  console.error("Server initialization failed:", err);
  process.exit(1);
});
```

--------------------------------------------------------------------------------
/alfresco/docker-compose.yml:
--------------------------------------------------------------------------------

```yaml
services:
    alfresco:
        build:
          context: ./alfresco
          args:
            ALFRESCO_TAG: ${ALFRESCO_CE_TAG}
            DB: postgres
            SOLR_COMMS: secret 
        mem_limit: 7488m
        depends_on: 
          postgres:
            condition: service_healthy
              
        environment:
            JAVA_TOOL_OPTIONS: "
                -Dencryption.keystore.type=JCEKS
                -Dencryption.cipherAlgorithm=DESede/CBC/PKCS5Padding
                -Dencryption.keyAlgorithm=DESede
                -Dencryption.keystore.location=/usr/local/tomcat/shared/classes/alfresco/extension/keystore/keystore
                -Dmetadata-keystore.password=mp6yc0UD9e
                -Dmetadata-keystore.aliases=metadata
                -Dmetadata-keystore.metadata.password=oKIWzVdEdA
                -Dmetadata-keystore.metadata.algorithm=DESede
                "
            JAVA_OPTS : '
                -Ddb.username=alfresco
                -Ddb.password=alfresco
                -Ddb.driver=org.postgresql.Driver
                -Ddb.url=jdbc:postgresql://postgres:5432/alfresco  
                -Dalfresco_user_store.adminpassword=209c6174da490caeb422f3fa5a7ae634
                -Dsystem.preferred.password.encoding=bcrypt10
                -Dsolr.host=solr6
                -Dsolr.port=8983
                -Dsolr.port.ssl=8983
                -Dsolr.secureComms=secret
                -Dsolr.baseUrl=/solr
                -Dindex.subsystem.name=solr6
                -Dsolr.sharedSecret=ui701yldedh  
                -Dalfresco.host=${SERVER_NAME}
                -Dalfresco.port=8080
                -Dapi-explorer.url=http://${SERVER_NAME}:8080/api-explorer
                -Dalfresco.protocol=http 
                -Dshare.host=${SERVER_NAME}
                -Dshare.port=8080
                -Dshare.protocol=http 
                -Daos.baseUrlOverwrite=http://${SERVER_NAME}/alfresco/aos 
                -Dmessaging.subsystem.autoStart=false
                -Drepo.event2.enabled=false
                -Ddeployment.method=DOCKER_COMPOSE
                -Dcsrf.filter.enabled=false 
                -Dopencmis.server.override=true
                -Dopencmis.server.value=http://${SERVER_NAME}:8080
                -DlocalTransform.core-aio.url=http://transform-core-aio:8090/
                -Dhttpclient.config.transform.connectionRequestTimeout=500000
                -Dcsrf.filter.enabled=false
                -Dalfresco.restApi.basicAuthScheme=true
                -Dauthentication.protection.enabled=false
                -XX:+UseG1GC -XX:+UseStringDeduplication
                -Dgoogledocs.enabled=false  
                -Ddev.email.not.sent=true  
                -XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80
            '
        healthcheck:
          test:
            - CMD
            - curl
            - -f
            - http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/probes/-ready-
          interval: 30s
          timeout: 3s
          retries: 3
          start_period: 1m
        volumes: 
            - ./data/alf-repo-data:/usr/local/tomcat/alf_data
            - ./logs/alfresco:/usr/local/tomcat/logs    
        

    transform-core-aio:
        image: alfresco/alfresco-transform-core-aio:${TRANSFORM_ENGINE_TAG}
        restart: on-failure
        mem_limit: 2048m
        environment:
            JAVA_OPTS: "
              -XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80
              -Dserver.tomcat.threads.max=12
              -Dserver.tomcat.threads.min=4
              -Dlogging.level.org.alfresco.transform.common.TransformerDebug=ERROR
              -Dlogging.level.org.alfresco.transform=ERROR
              -Dlogging.level.org.apache.fontbox.ttf=ERROR
              -Dlogging.level.org.apache.pdfbox.cos.COSDocument=ERROR
              -Dlogging.level.org.apache.pdfbox.pdfparser=ERROR
              -Dlogging.level.org.apache.pdfbox.filter.FlateFilter=ERROR
              -Dlogging.level.org.apache.pdfbox.pdmodel.font=ERROR
              -Dlogging.level.org.apache.pdfbox.pdmodel.font.PDSimpleFont=FATAL
              -Dlogging.level.org.apache.pdfbox.pdmodel.font.PDFont=FATAL
              -Dlogging.level.org.apache.pdfbox.pdmodel.font.PDCIDFont=FATAL
            "

    share:
        build:
          context: ./share
          args:
            SHARE_TAG: ${SHARE_TAG}
            SERVER_NAME: ${SERVER_NAME}
        mem_limit: 1872m
        environment:
            REPO_HOST: "alfresco"
            REPO_PORT: "8080"
            CSRF_FILTER_REFERER: "http://localhost:8080/.*"
            CSRF_FILTER_ORIGIN: "http://localhost:8080"
            JAVA_OPTS: "
                -Dalfresco.context=alfresco
                -Dalfresco.protocol=http
                -XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80
                "
        depends_on:
          alfresco:
            condition: service_healthy
        volumes: 
            - ./logs/share:/usr/local/tomcat/logs  

    
    postgres:
        image: postgres:${POSTGRES_TAG}
        mem_limit: 1872m
        environment:
            - POSTGRES_PASSWORD=alfresco
            - POSTGRES_USER=alfresco
            - POSTGRES_DB=alfresco
            - PGUSER=alfresco
        command: "
            postgres
              -c max_connections=200
              -c logging_collector=on
              -c log_min_messages=LOG
              -c log_directory=/var/log/postgresql"
        healthcheck:
          test: ["CMD-SHELL", "pg_isready"]
          interval: 10s
          timeout: 5s
          retries: 5
        volumes: 
            - ./data/postgres-data:/var/lib/postgresql/data
            - ./logs/postgres:/var/log/postgresql  
     

    solr6:
        build:
          context: ./search
          args:
            SEARCH_TAG: ${SEARCH_CE_TAG}
            SOLR_HOSTNAME: solr6
            ALFRESCO_HOSTNAME: alfresco
            ALFRESCO_COMMS: secret 
            CROSS_LOCALE: "true"
            DISABLE_CONTENT_INDEXING: "false"
        mem_limit: 3744m
        environment:
            SOLR_JAVA_MEM: "-XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80"
            #Solr needs to know how to register itself with Alfresco
            SOLR_ALFRESCO_HOST: "alfresco"
            SOLR_ALFRESCO_PORT:  "8080" 
            #Alfresco needs to know how to call solr
            SOLR_SOLR_HOST: "solr6"
            SOLR_SOLR_PORT: "8983"
            #Create the default alfresco and archive cores
            SOLR_CREATE_ALFRESCO_DEFAULTS: "alfresco,archive" 
            SOLR_OPTS: "
                -XX:-UseLargePages
                -Dalfresco.secureComms.secret=ui701yldedh 
            "
        depends_on:
          alfresco:
            condition: service_healthy
        volumes: 
            - ./data/solr-data:/opt/alfresco-search-services/data   

    

    content-app:
        image: alfresco/alfresco-content-app:${ACA_TAG}
        mem_limit: 256m
        environment:
            APP_BASE_SHARE_URL: "http://${SERVER_NAME}:8080/#/preview/s"
        depends_on:
          alfresco:
            condition: service_healthy


    # HTTP proxy to provide HTTP Default port access to services
    # SOLR API and SOLR Web Console are protected to avoid unauthenticated access
    proxy:
        image: nginx:stable-alpine
        mem_limit: 128m
        depends_on:
            - alfresco
            - solr6
            - share
            - content-app
        volumes:
            - ./config/nginx.conf:/etc/nginx/nginx.conf
            - ./config/nginx.htpasswd:/etc/nginx/conf.d/nginx.htpasswd 
        ports:
            - ${BIND_IP_NGINX:-0.0.0.0}:8080:8080

    

    

    

    



```