# 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:
--------------------------------------------------------------------------------
```
1 | data
2 | logs
3 |
```
--------------------------------------------------------------------------------
/alfresco-mcp-client/.gitignore:
--------------------------------------------------------------------------------
```
1 | target
2 | .idea
3 | .mvn
4 |
```
--------------------------------------------------------------------------------
/alfresco-mcp-server/.gitignore:
--------------------------------------------------------------------------------
```
1 | # .gitignore
2 | node_modules
3 | .env
4 |
5 |
```
--------------------------------------------------------------------------------
/alfresco/.env:
--------------------------------------------------------------------------------
```
1 | # Docker Image versions
2 | ALFRESCO_CE_TAG=23.4.0
3 | SEARCH_CE_TAG=2.0.13
4 | SHARE_TAG=23.4.0
5 | ACA_TAG=5.2.0
6 | POSTGRES_TAG=15.6
7 | MARIADB_TAG=11.3.2
8 | TRANSFORM_ENGINE_TAG=5.1.5
9 | ACTIVEMQ_TAG=5.18-jre17-rockylinux8
10 |
11 | # Server properties
12 | SERVER_NAME=localhost
13 |
14 | # Binding properties
15 | BIND_IP_NGINX=
16 | BIND_IP_FTP=
17 |
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Alfresco MCP Proof of Concept (PoC)
2 |
3 | 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.
4 |
5 | 
6 |
7 | ## Project Structure
8 |
9 | The repository is structured as follows:
10 |
11 | - **`alfresco/`**: Contains a Docker Compose setup for a standard Alfresco deployment. This must be run before the MCP integration.
12 | - **`alfresco-mcp-client/`**: A Java-based client application for interacting with the MCP server using [Spring AI](https://spring.io/projects/spring-ai)
13 | - **`alfresco-mcp-server/`**: A Node.js-based server application for handling MCP requests using [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
14 |
15 | ## Prerequisites
16 |
17 | Before running the project, ensure you have the following installed:
18 |
19 | - Docker (version 20.10.0 or higher)
20 | - Docker Compose (version 1.29.0 or higher)
21 | - Java Development Kit (JDK) 17 or higher (for the client application)
22 | - Node.js (version 18 or higher) and npm (for the server application)
23 | - Git (for cloning the repository)
24 |
25 | ## Getting Started
26 |
27 | ### Step 1: Clone the Repository
28 |
29 | Clone the repository to your local machine:
30 |
31 | ```bash
32 | git clone https://github.com/aborroy/alfresco-mcp-poc.git
33 | cd alfresco-mcp-poc
34 | ```
35 |
36 | ### Step 2: Run the Alfresco Docker Compose
37 |
38 | Navigate to the `alfresco/` directory and start the Alfresco deployment using Docker Compose:
39 |
40 | ```bash
41 | cd alfresco
42 | docker-compose up --build --force-recreate
43 | ```
44 |
45 | This will start the Alfresco Content Services stack, including the repository, Share, and other required services. Wait for all services to initialize completely.
46 |
47 | ### Step 3: Verify Alfresco Deployment
48 |
49 | Once the services are up, you can access the Alfresco Share interface at:
50 |
51 | - **Alfresco Share**: [http://localhost:8080/share](http://localhost:8080/share)
52 | - **Alfresco Repository**: [http://localhost:8080/alfresco](http://localhost:8080/alfresco)
53 |
54 | Use the default credentials (`admin` / `admin`) to log in.
55 |
56 | ### Step 4: Set Up and Run the MCP Client
57 |
58 | Start the Ollama server locally:
59 |
60 | ```bash
61 | ollama serve
62 | ```
63 |
64 | Navigate to the `alfresco-mcp-client/` directory and follow the instructions in its `README.md` to set up and run the MCP client:
65 |
66 | ```bash
67 | cd ../alfresco-mcp-client
68 | mvn clean package
69 | java -jar target/alfresco-mcp-client-0.8.0.jar
70 | ```
71 |
72 | ## Customization
73 |
74 | 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.
75 |
76 | ## Contributing
77 |
78 | Contributions to this project are welcome! Please open an issue or submit a pull request with your proposed changes.
79 |
```
--------------------------------------------------------------------------------
/alfresco-mcp-server/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Alfresco MCP Server
2 |
3 | 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`.
4 |
5 | ## Features
6 |
7 | - **Read Node Metadata**: Retrieve metadata for a specific Alfresco node.
8 | - **Download Node Content**: Download the content of a specific Alfresco node.
9 | - **Search Nodes**: Perform advanced searches for files in Alfresco.
10 | - **Tool Integration**: Supports tools like `search` and `readContent` for integration with the Model Context Protocol.
11 |
12 | ## Prerequisites
13 |
14 | Before running the service, ensure you have the following:
15 |
16 | 1. **Node.js**: Version 16 or higher.
17 | 2. **Alfresco Repository**: A running Alfresco instance with REST API access.
18 | 3. **Environment Variables**: Set up the required environment variables (see [Configuration](#configuration)).
19 |
20 | ## Setup and Installation
21 |
22 | 1. Clone the repository or download the service script.
23 | 2. Install dependencies:
24 | ```bash
25 | npm install dotenv @modelcontextprotocol/sdk
26 | ```
27 | 3. Set up the required environment variables (see [Configuration](#configuration)).
28 | 4. Run the service:
29 | ```bash
30 | node alfresco-rest-server.js
31 | ```
32 |
33 | ## Configuration
34 |
35 | The service requires the following environment variables to be set:
36 |
37 | | Variable Name | Description |
38 | |---------------------|-----------------------------------------------------------------------------|
39 | | `ALFRESCO_HOST` | The base URL of the Alfresco repository (e.g., `https://alfresco.example.com`). |
40 | | `ALFRESCO_USERNAME` | The username for Alfresco authentication. |
41 | | `ALFRESCO_PASSWORD` | The password for Alfresco authentication. |
42 |
43 | ### Example `.env` File
44 |
45 | ```env
46 | ALFRESCO_HOST=http://localhost:8080
47 | ALFRESCO_USERNAME=admin
48 | ALFRESCO_PASSWORD=admin
49 | ```
50 |
51 | ## API Endpoints
52 |
53 | The service implements the following functionality through the Model Context Protocol:
54 |
55 | ### 1. **Read Resource**
56 | - **Description**: Retrieves metadata or content for a specific Alfresco node.
57 | - **Request Schema**: `ReadResourceRequestSchema`
58 | - **Example URI**: `alfresco://{nodeId}`
59 |
60 | ### 2. **List Tools**
61 | - **Description**: Lists available tools for interacting with Alfresco.
62 | - **Request Schema**: `ListToolsRequestSchema`
63 | - **Supported Tools**:
64 | - `search`: Performs a full-text search in Alfresco.
65 | - `readContent`: Reads the content of a file by its Alfresco URI.
66 |
67 | ### 3. **Call Tool**
68 | - **Description**: Executes a specific tool (e.g., `search` or `readContent`).
69 | - **Request Schema**: `CallToolRequestSchema`
70 |
71 | ## Troubleshooting
72 |
73 | 1. **Service Fails to Start**:
74 | - Ensure all dependencies are installed (`npm install`).
75 | - Verify that the required environment variables are set.
76 |
77 | 2. **API Requests Fail**:
78 | - Check the Alfresco repository logs for errors.
79 | - Verify that the provided credentials (`ALFRESCO_USERNAME` and `ALFRESCO_PASSWORD`) are correct.
80 |
81 | 3. **Invalid Node ID**:
82 | - Ensure the node ID in the URI (e.g., `alfresco://{nodeId}`) is valid and exists in the repository.
83 |
84 | 4. **Search Returns No Results**:
85 | - Verify the search query and ensure the repository contains matching files.
```
--------------------------------------------------------------------------------
/alfresco-mcp-client/README.md:
--------------------------------------------------------------------------------
```markdown
1 | # Alfresco MCP Client
2 |
3 | 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.
4 |
5 | ## Features
6 |
7 | - **AI-Powered Queries**: Use an AI model (e.g., Llama3) to interact with Alfresco documents.
8 | - **Predefined Questions**: Execute predefined questions to retrieve specific information from Alfresco.
9 | - **Custom MCP Client**: Integrates with a custom MCP client to interact with Alfresco REST services.
10 | - **Command-Line Interface**: Runs as a command-line application without a web interface.
11 |
12 | ## Requirements
13 |
14 | To run this project, you need the following:
15 |
16 | 1. **Java Development Kit (JDK) 17 or higher**:
17 | - 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/).
18 |
19 | 2. **Node.js (v18.19.1 or higher)**:
20 | - Download and install Node.js from [nodejs.org](https://nodejs.org/).
21 |
22 | 3. **Ollama**:
23 | - Install and run Ollama locally. Follow the instructions at [Ollama GitHub](https://github.com/ollama/ollama).
24 |
25 | 4. **Alfresco Instance**:
26 | - A running instance of Alfresco (e.g., `http://localhost:8080`).
27 |
28 | 5. **Alfresco REST Server Script**:
29 | - A Node.js script (`alfresco-rest-server.js`) that acts as a bridge between the MCP client and Alfresco.
30 |
31 | ## How to Build
32 |
33 | 1. **Clone the Repository**:
34 | ```bash
35 | git clone https://github.com/your-repo/alfresco-mcp-client.git
36 | cd alfresco-mcp-client
37 | ```
38 | 2. **Build the Project:**
39 | Use Maven to build the project:
40 | ```bash
41 | ./mvn clean package
42 | ```
43 |
44 | 3. **Run the Application:**
45 | After building, run the application using the generated JAR file:
46 |
47 | ```bash
48 | java -jar target/alfresco-mcp-client.jar
49 | ```
50 |
51 | ## Configuration
52 |
53 | The application is configured using the `application.properties file. Below are the key configuration options:
54 |
55 | * Spring AI (LLM) Configuration
56 |
57 | spring.ai.ollama.base-url=http://localhost:11434: Base URL for the Ollama API.
58 |
59 | spring.ai.ollama.chat.options.model=llama3.1: Specifies the AI model to use for chat interactions.
60 |
61 | * Alfresco MCP Configuration
62 |
63 | node.path=/path/to/node: Path to the Node.js executable.
64 |
65 | alfresco.host=http://localhost:8080: URL of the Alfresco instance.
66 |
67 | alfresco.username=admin: Username for Alfresco authentication.
68 |
69 | alfresco.password=admin: Password for Alfresco authentication.
70 |
71 | alfresco.rest-server.path=/path/to/alfresco-rest-server.js: Path to the Alfresco REST server script.
72 |
73 | ## How to Run
74 |
75 | 1. **Ensure Ollama is Running:**
76 |
77 | Start the Ollama server locally:
78 | ```bash
79 | ollama serve
80 | ```
81 |
82 | 2. Update Configuration:
83 |
84 | Modify the `application.properties` file to match your environment (e.g., Alfresco host, credentials, Node.js path, etc.).
85 |
86 | Run the Application:
87 |
88 | ```bash
89 | java -jar target/alfresco-mcp-client-0.8.0.jar
90 | ```
91 |
92 | View Output: The application will execute predefined questions and print the AI model's responses to the console.
93 |
94 | ## Predefined Questions
95 |
96 | The application includes the following predefined questions, but you can experiment your proposals.
97 |
98 | Retrieve Invoice Documents:
99 |
100 | Question: "Get a list with all the Invoice documents together with the Alfresco URI."
101 |
102 | Purpose: Retrieves a list of all invoice documents along with their Alfresco URIs.
103 |
104 | Summarize an Invoice:
105 |
106 | Question: "Provide a summary of the invoice 'alfresco://723a0cff-3fce-495d-baa3-a3cd245ea5dc'."
107 |
108 | Purpose: Provides a summary of a specific invoice document.
```
--------------------------------------------------------------------------------
/alfresco-mcp-server/package.json:
--------------------------------------------------------------------------------
```json
1 | {
2 | "name": "alfresco-mcp-server",
3 | "version": "1.0.0",
4 | "description": "Alfresco REST + Model Context Protocol",
5 | "type": "module",
6 | "scripts": {
7 | "start": "node alfresco-rest-server.js"
8 | },
9 | "dependencies": {
10 | "@modelcontextprotocol/sdk": "latest",
11 | "dotenv": "^16.4.7"
12 | },
13 | "engines": {
14 | "node": ">=18"
15 | }
16 | }
17 |
```
--------------------------------------------------------------------------------
/alfresco/share/web-extension/share-config-custom-dev.xml:
--------------------------------------------------------------------------------
```
1 | <alfresco-config>
2 | <config evaluator="string-compare" condition="Users" replace="true">
3 | <users>
4 | <!-- minimum length for username and password -->
5 | <username-min-length>2</username-min-length>
6 | <password-min-length>3</password-min-length>
7 | <show-authorization-status>false</show-authorization-status>
8 | </users>
9 | <!-- This enables/disables the Add External Users Panel on the Add Users page. -->
10 | <enable-external-users-panel>false</enable-external-users-panel>
11 | </config>
12 | <config evaluator="string-compare" condition="DocumentLibrary" >
13 | <repository-url>http://localhost:8080/alfresco</repository-url>
14 | </config>
15 | </alfresco-config>
16 |
```
--------------------------------------------------------------------------------
/alfresco/share/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
1 | ARG SHARE_TAG
2 | FROM alfresco/alfresco-share:${SHARE_TAG}
3 |
4 | ARG TOMCAT_DIR=/usr/local/tomcat
5 |
6 | # Server data
7 | ARG SERVER_NAME
8 | ENV SERVER_NAME $SERVER_NAME
9 |
10 |
11 |
12 |
13 |
14 | # Install modules and addons
15 | RUN mkdir -p $TOMCAT_DIR/amps
16 | COPY modules/amps $TOMCAT_DIR/amps
17 | COPY modules/jars $TOMCAT_DIR/webapps/share/WEB-INF/lib
18 |
19 | RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \
20 | $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/share -directory -nobackup -force
21 |
22 | # Increase default cacheMaxSize
23 | RUN sed -i "s|<Context>|<Context>\n<Resources cacheMaxSize=\"51200\"/> |g" $TOMCAT_DIR/conf/context.xml
24 |
25 | # Fix for https://github.com/Alfresco/acs-community-packaging/issues/367 in Share 6.2.0
26 | COPY web-extension/share-config-custom-dev.xml $TOMCAT_DIR/shared/classes/alfresco/web-extension/
27 |
```
--------------------------------------------------------------------------------
/alfresco-mcp-client/src/main/resources/application.properties:
--------------------------------------------------------------------------------
```
1 | # ==================================================
2 | # Logging Configuration
3 | # ==================================================
4 |
5 | # Set logging level for the DefaultMcpSession class to WARN to reduce noise in logs
6 | logging.level.org.springframework.ai.mcp.spec.DefaultMcpSession=WARN
7 |
8 | # ==================================================
9 | # Application Configuration
10 | # ==================================================
11 |
12 | # Application name for identification
13 | spring.application.name=alfresco-mcp-client
14 |
15 | # Disable web application type since this is a command-line application
16 | spring.main.web-application-type=none
17 |
18 | # ==================================================
19 | # Spring AI (LLM) Configuration
20 | # ==================================================
21 |
22 | # Base URL for the Ollama API (local instance)
23 | spring.ai.ollama.base-url=http://localhost:11434
24 |
25 | # Model to use for chat interactions with Ollama
26 | spring.ai.ollama.chat.options.model=llama3.1
27 |
28 | # Download model when missing
29 | spring.ai.ollama.init.pull-model-strategy=when_missing
30 |
31 | # ==================================================
32 | # Alfresco MCP Configuration
33 | # ==================================================
34 |
35 | # Node.js Path Configuration
36 | # Path to the Node.js executable
37 | node.path=/Users/angel.fernandoborroy/.nvm/versions/node/v18.19.1/bin/node
38 |
39 | # Alfresco Host Configuration
40 | # URL of the Alfresco instance
41 | alfresco.host=http://localhost:8080
42 |
43 | # Alfresco Credentials
44 | # Username and password for Alfresco authentication
45 | alfresco.username=admin
46 | alfresco.password=admin
47 |
48 | # Alfresco REST Server Script Path
49 | # Path to the Alfresco REST server script
50 | alfresco.rest-server.path=/Users/angel.fernandoborroy/Downloads/zz/alfresco-mcp-server/alfresco-rest-server.js
```
--------------------------------------------------------------------------------
/alfresco/config/nginx.conf:
--------------------------------------------------------------------------------
```
1 | worker_processes 1;
2 |
3 | events {
4 | worker_connections 1024;
5 | }
6 |
7 | http {
8 | server {
9 |
10 | listen *:8080 ;
11 |
12 |
13 |
14 | client_max_body_size 0;
15 |
16 | set $allowOriginSite *;
17 | proxy_pass_request_headers on;
18 | proxy_pass_header Set-Cookie;
19 |
20 | # Increment timeout values
21 | proxy_connect_timeout 600;
22 | proxy_send_timeout 600;
23 | proxy_read_timeout 600;
24 | send_timeout 600;
25 |
26 | # External settings, do not remove
27 | #ENV_ACCESS_LOG
28 |
29 | proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
30 | proxy_redirect off;
31 | proxy_buffering off;
32 | proxy_set_header Host $host:$server_port;
33 | proxy_set_header X-Real-IP $remote_addr;
34 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
35 | proxy_pass_header Set-Cookie;
36 |
37 | location ~ ^(/.*/service/api/solr/.*)$ {return 403;}
38 | location ~ ^(/.*/s/api/solr/.*)$ {return 403;}
39 | location ~ ^(/.*/wcservice/api/solr/.*)$ {return 403;}
40 | location ~ ^(/.*/wcs/api/solr/.*)$ {return 403;}
41 | location ~ ^(/.*/proxy/alfresco/api/solr/.*)$ {return 403 ;}
42 | location ~ ^(/.*/-default-/proxy/alfresco/api/.*)$ {return 403;}
43 |
44 | # Alfresco Content Application Proxy
45 | location / {
46 | proxy_pass http://content-app:8080;
47 | }
48 |
49 | # Repository Proxy
50 | location /alfresco/ {
51 | proxy_pass http://alfresco:8080;
52 | }
53 |
54 | # Api-Explorer Proxy
55 | location /api-explorer/ {
56 | proxy_pass http://alfresco:8080;
57 | }
58 |
59 | # Share Proxy
60 | location /share/ {
61 | proxy_pass http://share:8080;
62 | }
63 |
64 |
65 | # SOLR Proxy
66 | location /solr/ {
67 | proxy_pass http://solr6:8983;
68 | auth_basic "Solr web console";
69 | auth_basic_user_file /etc/nginx/conf.d/nginx.htpasswd;
70 | }
71 |
72 |
73 |
74 |
75 | }
76 | }
77 |
```
--------------------------------------------------------------------------------
/alfresco-mcp-client/pom.xml:
--------------------------------------------------------------------------------
```
1 | <?xml version="1.0" encoding="UTF-8"?>
2 |
3 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 | <modelVersion>4.0.0</modelVersion>
6 |
7 | <parent>
8 | <groupId>org.springframework.boot</groupId>
9 | <artifactId>spring-boot-starter-parent</artifactId>
10 | <version>3.4.1</version>
11 | <relativePath/>
12 | </parent>
13 |
14 | <groupId>com.hyland</groupId>
15 | <artifactId>alfresco-mcp-client</artifactId>
16 | <version>0.8.0</version>
17 |
18 | <name>alfresco-mcp-client</name>
19 | <description>A simple alfresco-mcp-client.</description>
20 |
21 | <properties>
22 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
23 | <maven.compiler.source>21</maven.compiler.source>
24 | <maven.compiler.target>21</maven.compiler.target>
25 | </properties>
26 |
27 | <dependencyManagement>
28 | <dependencies>
29 | <dependency>
30 | <groupId>org.springframework.ai</groupId>
31 | <artifactId>spring-ai-bom</artifactId>
32 | <version>1.0.0-M5</version>
33 | <type>pom</type>
34 | <scope>import</scope>
35 | </dependency>
36 | </dependencies>
37 | </dependencyManagement>
38 |
39 | <dependencies>
40 | <dependency>
41 | <groupId>org.springframework.boot</groupId>
42 | <artifactId>spring-boot-starter</artifactId>
43 | </dependency>
44 |
45 |
46 | <dependency>
47 | <groupId>org.springframework.ai</groupId>
48 | <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
49 | </dependency>
50 |
51 | <dependency>
52 | <groupId>org.springframework.experimental</groupId>
53 | <artifactId>spring-ai-mcp</artifactId>
54 | <version>0.5.1</version>
55 | </dependency>
56 |
57 | </dependencies>
58 |
59 | <build>
60 | <plugins>
61 | <plugin>
62 | <groupId>org.springframework.boot</groupId>
63 | <artifactId>spring-boot-maven-plugin</artifactId>
64 | </plugin>
65 | </plugins>
66 | </build>
67 |
68 | <repositories>
69 | <repository>
70 | <id>spring-milestones</id>
71 | <name>Spring Milestones</name>
72 | <url>https://repo.spring.io/libs-milestone-local</url>
73 | <snapshots>
74 | <enabled>false</enabled>
75 | </snapshots>
76 | </repository>
77 | <repository>
78 | <id>spring-snapshots</id>
79 | <name>Spring Snapshots</name>
80 | <url>https://repo.spring.io/snapshot</url>
81 | <releases>
82 | <enabled>false</enabled>
83 | </releases>
84 | </repository>
85 | </repositories>
86 | </project>
87 |
```
--------------------------------------------------------------------------------
/alfresco/alfresco/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
1 | ARG ALFRESCO_TAG
2 | FROM alfresco/alfresco-content-repository-community:${ALFRESCO_TAG}
3 |
4 | ARG TOMCAT_DIR=/usr/local/tomcat
5 | ARG IMAGEUSERNAME=alfresco
6 |
7 | # default user is alfresco (added on the base image alfresco/alfresco-content-repository-community)
8 | # change to root user to be able to install the addons and packages
9 | USER root
10 |
11 | # Install modules and addons
12 | RUN mkdir -p $TOMCAT_DIR/amps
13 | COPY modules/amps $TOMCAT_DIR/amps
14 | COPY modules/jars $TOMCAT_DIR/webapps/alfresco/WEB-INF/lib
15 |
16 | RUN java -jar $TOMCAT_DIR/alfresco-mmt/alfresco-mmt*.jar install \
17 | $TOMCAT_DIR/amps $TOMCAT_DIR/webapps/alfresco -directory -nobackup -force
18 |
19 |
20 |
21 | # DATABASE
22 | ARG DB
23 | ENV DB $DB
24 |
25 | RUN ls -la /etc/yum.repos.d/ && \
26 | ((sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* && \
27 | sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 2>/dev/null) || \
28 | (sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/Rocky-* && \
29 | sed -i 's|#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=http://dl.rockylinux.org/$contentdir|g' /etc/yum.repos.d/Rocky-*)) || \
30 | (dnf clean all && dnf makecache && dnf update -y)
31 |
32 | # Install mysql JDBC driver
33 | RUN if [ "$DB" == "mariadb" ] ; then \
34 | set -x \
35 | && yum clean all \
36 | && yum install -y wget \
37 | && yum clean all \
38 | && wget -P /tmp/ https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.7.4/mariadb-java-client-2.7.4.jar \
39 | && cp /tmp/mariadb-java-client-2.7.4.jar $TOMCAT_DIR/lib/ \
40 | && rm -rf /tmp/mariadb-java-client-2.7.4.jar; \
41 | fi
42 |
43 |
44 |
45 | # COMMS
46 | ARG SOLR_COMMS
47 | ENV SOLR_COMMS $SOLR_COMMS
48 |
49 | # SSL
50 | ARG TRUSTSTORE_TYPE
51 | ARG TRUSTSTORE_PASS
52 | ARG KEYSTORE_TYPE
53 | ARG KEYSTORE_PASS
54 | ARG CERT_ALIAS
55 |
56 | ENV TRUSTSTORE_TYPE=$TRUSTSTORE_TYPE \
57 | TRUSTSTORE_PASS=$TRUSTSTORE_PASS \
58 | KEYSTORE_TYPE=$KEYSTORE_TYPE \
59 | KEYSTORE_PASS=$KEYSTORE_PASS \
60 | CERT_ALIAS=$CERT_ALIAS
61 |
62 | # Enable SSL by adding the proper Connector to server.xml
63 | RUN if [ "$SOLR_COMMS" == "https" ] ; then \
64 | sed -i "s/\
65 | [[:space:]]\+<\/Engine>/\n\
66 | <\/Engine>\n\
67 | <Connector port=\"8443\" protocol=\"org.apache.coyote.http11.Http11NioProtocol\"\n\
68 | connectionTimeout=\"20000\" maxThreads=\"150\"\n\
69 | SSLEnabled=\"true\" scheme=\"https\" secure=\"true\"\n\
70 | defaultSSLHostConfigName=\"localhost\">\n\
71 | <SSLHostConfig hostName=\"localhost\" protocols=\"TLSv1.3\"\n\
72 | certificateVerification=\"required\"\n\
73 | truststoreFile=\"\/usr\/local\/tomcat\/keystore\/ssl.truststore\"\n\
74 | truststorePassword=\"${TRUSTSTORE_PASS}\" truststoreType=\"${TRUSTSTORE_TYPE}\">\n\
75 | <Certificate certificateKeystoreFile=\"\/usr\/local\/tomcat\/keystore\/ssl.keystore\"\n\
76 | certificateKeyAlias=\"${CERT_ALIAS}\" type=\"RSA\"\n\
77 | certificateKeystorePassword=\"${KEYSTORE_PASS}\" certificateKeystoreType=\"${KEYSTORE_TYPE}\"\/>\n\
78 | <\/SSLHostConfig>\n\
79 | <\/Connector>/g" ${TOMCAT_DIR}/conf/server.xml; \
80 | fi
81 |
82 |
83 |
84 |
85 |
86 |
87 |
```
--------------------------------------------------------------------------------
/alfresco/search/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
1 | ARG SEARCH_TAG
2 | FROM alfresco/alfresco-search-services:${SEARCH_TAG}
3 |
4 | # COMMON
5 | ARG ALFRESCO_HOSTNAME
6 | ARG SOLR_HOSTNAME
7 | ENV ALFRESCO_HOSTNAME $ALFRESCO_HOSTNAME
8 | ENV SOLR_HOSTNAME $SOLR_HOSTNAME
9 |
10 | # Configure Alfresco Service Name
11 | 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' \
12 | ${DIST_DIR}/solr/bin/search_config_setup.sh && \
13 | sed -i '/^bash.*/i sed -i "'"s/solr.host=localhost/solr.host=${SOLR_HOSTNAME}/g"'" ${DIST_DIR}/solrhome/conf/shared.properties\n' \
14 | ${DIST_DIR}/solr/bin/search_config_setup.sh
15 |
16 | # Disable content indexing
17 | ARG DISABLE_CONTENT_INDEXING
18 | ENV DISABLE_CONTENT_INDEXING $DISABLE_CONTENT_INDEXING
19 | RUN if [ "$DISABLE_CONTENT_INDEXING" == "true" ] ; then \
20 | sed -i '/^bash.*/i sed -i "'"/alfresco.index.transformContent/s/^#//g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
21 | ${DIST_DIR}/solr/bin/search_config_setup.sh && \
22 | sed -i '/^bash.*/i sed -i "'"/alfresco.ignore.datatype.1/s/^#//g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
23 | ${DIST_DIR}/solr/bin/search_config_setup.sh; \
24 | fi
25 |
26 | # Cross Locale
27 | ARG CROSS_LOCALE
28 | ENV CROSS_LOCALE $CROSS_LOCALE
29 |
30 | # Enable Cross Locale SOLR Configuration
31 | RUN if [ "$CROSS_LOCALE" == "true" ] ; then \
32 | sed -i '/^bash.*/i sed -i "'"/alfresco.cross.locale.datatype/s/^#//g"'" $DIST_DIR/solrhome/conf/shared.properties\n' \
33 | ${DIST_DIR}/solr/bin/search_config_setup.sh; \
34 | fi
35 |
36 | # COMMS
37 | ARG ALFRESCO_COMMS
38 | ENV ALFRESCO_COMMS $ALFRESCO_COMMS
39 |
40 | # Configure SOLR cores to run in HTTPs mode from template
41 | RUN if [ "$ALFRESCO_COMMS" == "https" ] ; then \
42 | sed -i '/^bash.*/i sed -i "'"s/alfresco.secureComms=none/alfresco.secureComms=https/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
43 | ${DIST_DIR}/solr/bin/search_config_setup.sh; \
44 | elif [ "$ALFRESCO_COMMS" == "secret" ] ; then \
45 | sed -i '/^bash.*/i sed -i "'"s/alfresco.secureComms=https/alfresco.secureComms=secret/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
46 | ${DIST_DIR}/solr/bin/search_config_setup.sh; \
47 | else \
48 | sed -i '/^bash.*/i sed -i "'"s/alfresco.secureComms=https/alfresco.secureComms=none/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties\n' \
49 | ${DIST_DIR}/solr/bin/search_config_setup.sh; \
50 | fi
51 |
52 | # SSL
53 | ARG TRUSTSTORE_TYPE
54 | ENV TRUSTSTORE_TYPE $TRUSTSTORE_TYPE
55 | ARG KEYSTORE_TYPE
56 | ENV KEYSTORE_TYPE $KEYSTORE_TYPE
57 |
58 | # Set mTLS properties
59 | RUN if [ "$ALFRESCO_COMMS" == "https" ] ; then \
60 | sed -i '/^bash.*/i \
61 | 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 && \
62 | sed -i "'"s/alfresco.encryption.ssl.keystore.passwordFileLocation=.*/alfresco.encryption.ssl.keystore.passwordFileLocation=/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
63 | sed -i "'"s/alfresco.encryption.ssl.keystore.type=.*/alfresco.encryption.ssl.keystore.type=${KEYSTORE_TYPE}/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
64 | 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 && \
65 | sed -i "'"s/alfresco.encryption.ssl.truststore.passwordFileLocation=.*/alfresco.encryption.ssl.truststore.passwordFileLocation=/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties && \
66 | sed -i "'"s/alfresco.encryption.ssl.truststore.type=.*/alfresco.encryption.ssl.truststore.type=${TRUSTSTORE_TYPE}/g"'" ${DIST_DIR}/solrhome/templates/rerank/conf/solrcore.properties' \
67 | ${DIST_DIR}/solr/bin/search_config_setup.sh; \
68 | fi
69 |
```
--------------------------------------------------------------------------------
/alfresco-mcp-client/src/main/java/com/hyland/Application.java:
--------------------------------------------------------------------------------
```java
1 | package com.hyland;
2 |
3 | import java.time.Duration;
4 | import java.util.List;
5 | import org.springframework.ai.chat.client.ChatClient;
6 | import org.springframework.ai.mcp.client.McpClient;
7 | import org.springframework.ai.mcp.client.McpSyncClient;
8 | import org.springframework.ai.mcp.client.transport.ServerParameters;
9 | import org.springframework.ai.mcp.client.transport.StdioClientTransport;
10 | import org.springframework.ai.mcp.spring.McpFunctionCallback;
11 | import org.springframework.beans.factory.annotation.Value;
12 | import org.springframework.boot.CommandLineRunner;
13 | import org.springframework.boot.SpringApplication;
14 | import org.springframework.boot.autoconfigure.SpringBootApplication;
15 | import org.springframework.context.ConfigurableApplicationContext;
16 | import org.springframework.context.annotation.Bean;
17 | import org.springframework.context.annotation.Configuration;
18 |
19 | /**
20 | * Main application class for interacting with an AI model and Alfresco services.
21 | * This class initializes the MCP client, sets up predefined questions, and retrieves responses from the AI model.
22 | */
23 | @SpringBootApplication
24 | @Configuration
25 | public class Application {
26 |
27 | /**
28 | * Main method to start the Spring Boot application.
29 | *
30 | * @param args Command-line arguments.
31 | */
32 | public static void main(String[] args) {
33 | SpringApplication.run(Application.class, args);
34 | }
35 |
36 | /**
37 | * Bean definition for running predefined questions using the ChatClient.
38 | *
39 | * @param chatClientBuilder Builder for creating the ChatClient.
40 | * @param functionCallbacks List of McpFunctionCallbacks for the ChatClient.
41 | * @param context ConfigurableApplicationContext to close the application after execution.
42 | * @return CommandLineRunner instance.
43 | */
44 | @Bean
45 | public CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder,
46 | List<McpFunctionCallback> functionCallbacks,
47 | ConfigurableApplicationContext context) {
48 |
49 | return args -> {
50 | try (context) {
51 | var chatClient = chatClientBuilder
52 | .defaultFunctions(functionCallbacks.toArray(new McpFunctionCallback[0]))
53 | .build();
54 |
55 | System.out.println("Running predefined questions with AI model responses:\n");
56 |
57 | // Question 1: Retrieve a list of Invoice documents with Alfresco URIs
58 | String question1 = "Get a list with all the Invoice documents together with the Alfresco URI.";
59 | System.out.println("QUESTION: " + question1);
60 | System.out.println("ASSISTANT: " + chatClient.prompt(question1).call().content());
61 |
62 | // Question 2: Provide a summary of a specific invoice
63 | String question2 = "Provide the total cost and the due date of the invoice 'alfresco://723a0cff-3fce-495d-baa3-a3cd245ea5dc'.";
64 | System.out.println("\nQUESTION: " + question2);
65 | System.out.println("ASSISTANT: " + chatClient.prompt(question2).call().content());
66 |
67 | } catch (Exception e) {
68 | System.err.println("An error occurred while processing the questions: " + e.getMessage());
69 | e.printStackTrace();
70 | }
71 | };
72 | }
73 |
74 | /**
75 | * Bean definition for creating a list of McpFunctionCallbacks.
76 | *
77 | * @param mcpClient McpSyncClient instance to list tools.
78 | * @return List of McpFunctionCallbacks.
79 | */
80 | @Bean
81 | public List<McpFunctionCallback> functionCallbacks(McpSyncClient mcpClient) {
82 | return mcpClient.listTools(null)
83 | .tools()
84 | .stream()
85 | .map(tool -> new McpFunctionCallback(mcpClient, tool))
86 | .toList();
87 | }
88 |
89 | /**
90 | * Bean definition for creating and initializing the McpSyncClient.
91 | *
92 | * @param nodePath Path to the node executable.
93 | * @param alfrescoHost Alfresco host URL.
94 | * @param alfrescoUsername Alfresco username.
95 | * @param alfrescoPassword Alfresco password.
96 | * @param restServerPath Path to the REST server script.
97 | * @return Initialized McpSyncClient instance.
98 | */
99 | @Bean(destroyMethod = "close")
100 | public McpSyncClient mcpClient(@Value("${node.path}") String nodePath,
101 | @Value("${alfresco.host}") String alfrescoHost,
102 | @Value("${alfresco.username}") String alfrescoUsername,
103 | @Value("${alfresco.password}") String alfrescoPassword,
104 | @Value("${alfresco.rest-server.path}") String restServerPath) {
105 |
106 | try {
107 | // Construct the command to set environment variables and start the REST server
108 | String command = String.join(" && ",
109 | "export ALFRESCO_HOST=\"" + alfrescoHost + "\"",
110 | "export ALFRESCO_USERNAME=\"" + alfrescoUsername + "\"",
111 | "export ALFRESCO_PASSWORD=\"" + alfrescoPassword + "\"",
112 | nodePath + " " + restServerPath
113 | );
114 |
115 | // Configure server parameters for the StdioClientTransport
116 | var stdioParams = ServerParameters.builder("/bin/bash")
117 | .args("-c", command)
118 | .build();
119 |
120 | // Create and initialize the McpSyncClient
121 | var mcpClient = McpClient.using(new StdioClientTransport(stdioParams))
122 | .requestTimeout(Duration.ofSeconds(10))
123 | .sync();
124 |
125 | var init = mcpClient.initialize();
126 | System.out.println("MCP Initialized: " + init);
127 |
128 | return mcpClient;
129 | } catch (Exception e) {
130 | System.err.println("Failed to initialize MCP client: " + e.getMessage());
131 | throw new RuntimeException("MCP client initialization failed", e);
132 | }
133 | }
134 | }
```
--------------------------------------------------------------------------------
/alfresco-mcp-server/alfresco-rest-server.js:
--------------------------------------------------------------------------------
```javascript
1 | #!/usr/bin/env node
2 | /**
3 | * Alfresco REST API Server implementing Model Context Protocol Server
4 | *
5 | * This service provides a REST API interface to interact with Alfresco repositories.
6 | * It supports operations like reading node metadata, downloading node content, and searching nodes.
7 | * The service is built using the Model Context Protocol SDK and communicates via stdio.
8 | */
9 |
10 | import 'dotenv/config';
11 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
12 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13 | import {
14 | CallToolRequestSchema,
15 | ListToolsRequestSchema,
16 | ReadResourceRequestSchema,
17 | } from "@modelcontextprotocol/sdk/types.js";
18 |
19 | // Configuration validation
20 | function validateConfig() {
21 | const requiredEnvVars = ['ALFRESCO_HOST', 'ALFRESCO_USERNAME', 'ALFRESCO_PASSWORD'];
22 |
23 | for (const varName of requiredEnvVars) {
24 | if (!process.env[varName]) {
25 | console.error(`Missing required environment variable: ${varName}`);
26 | process.exit(1);
27 | }
28 | }
29 |
30 | try {
31 | new URL(process.env.ALFRESCO_HOST);
32 | } catch {
33 | console.error('Invalid Alfresco host URL');
34 | process.exit(1);
35 | }
36 |
37 | return {
38 | ALFRESCO_HOST: process.env.ALFRESCO_HOST,
39 | ALFRESCO_USERNAME: process.env.ALFRESCO_USERNAME,
40 | ALFRESCO_PASSWORD: process.env.ALFRESCO_PASSWORD
41 | };
42 | }
43 |
44 | const {
45 | ALFRESCO_HOST,
46 | ALFRESCO_USERNAME,
47 | ALFRESCO_PASSWORD
48 | } = validateConfig();
49 |
50 | // Authentication and API helpers
51 | class AlfrescoAPIClient {
52 | constructor(host, username, password) {
53 | this.host = host;
54 | this.basicAuthHeader = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
55 | }
56 |
57 | _buildUrl(path, apiType = 'alfresco') {
58 | const basePathMap = {
59 | 'alfresco': `/alfresco/api/-default-/public/alfresco/versions/1${path}`,
60 | 'search': '/alfresco/api/-default-/public/search/versions/1/search'
61 | };
62 | return `${this.host}${basePathMap[apiType]}`;
63 | }
64 |
65 | async _fetchWithAuth(url, options = {}) {
66 | const defaultHeaders = {
67 | Authorization: this.basicAuthHeader,
68 | Accept: 'application/json',
69 | ...options.headers
70 | };
71 |
72 | try {
73 | const response = await fetch(url, {
74 | ...options,
75 | headers: defaultHeaders
76 | });
77 |
78 | if (!response.ok) {
79 | const errorText = await response.text();
80 | throw new Error(`HTTP ${response.status}: ${errorText}`);
81 | }
82 |
83 | return response;
84 | } catch (error) {
85 | console.error('API Request Failed:', error);
86 | throw error;
87 | }
88 | }
89 |
90 | async getNodeMetadata(nodeId) {
91 | const url = this._buildUrl(`/nodes/${nodeId}`);
92 | const response = await this._fetchWithAuth(url);
93 | return response.json();
94 | }
95 |
96 | async downloadNodeContent(nodeId) {
97 | const url = this._buildUrl(`/nodes/${nodeId}/content`);
98 | return this._fetchWithAuth(url);
99 | }
100 |
101 | async searchNodes(query, options = {}) {
102 | const url = this._buildUrl('', 'search');
103 | const body = {
104 | query: {
105 | query: `${query} AND TYPE:'cm:content'`,
106 | language: 'afts',
107 | },
108 | paging: {
109 | maxItems: options.maxItems || 10,
110 | skipCount: options.skipCount || 0,
111 | },
112 | include: ['properties'],
113 | };
114 |
115 | const response = await this._fetchWithAuth(url, {
116 | method: 'POST',
117 | headers: { 'Content-Type': 'application/json' },
118 | body: JSON.stringify(body),
119 | });
120 |
121 | return response.json();
122 | }
123 | }
124 |
125 | const apiClient = new AlfrescoAPIClient(ALFRESCO_HOST, ALFRESCO_USERNAME, ALFRESCO_PASSWORD);
126 |
127 | // Server configuration
128 | const server = new Server(
129 | {
130 | name: "alfresco-rest-server",
131 | version: "0.2.0",
132 | },
133 | {
134 | capabilities: {
135 | resources: {},
136 | tools: {},
137 | },
138 | }
139 | );
140 |
141 | server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
142 | try {
143 | const nodeId = request.params.uri.replace("alfresco://", "");
144 | const metadata = await apiClient.getNodeMetadata(nodeId);
145 | const entry = metadata.entry;
146 |
147 | if (entry.isFolder) {
148 | return {
149 | contents: [{
150 | uri: request.params.uri,
151 | mimeType: "text/plain",
152 | blob: Buffer.from(`Folder: ${nodeId}`).toString('base64')
153 | }]
154 | };
155 | }
156 |
157 | const downloadResp = await apiClient.downloadNodeContent(nodeId);
158 | const mimeType = entry?.content?.mimeType || "application/octet-stream";
159 | const arrayBuffer = await downloadResp.arrayBuffer();
160 |
161 | return {
162 | contents: [{
163 | uri: request.params.uri,
164 | mimeType,
165 | blob: Buffer.from(arrayBuffer).toString('base64')
166 | }]
167 | };
168 | } catch (error) {
169 | console.error('Read Resource Error:', error);
170 | throw error;
171 | }
172 | });
173 |
174 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
175 | tools: [
176 | {
177 | name: "search",
178 | description: "Advanced Alfresco file search",
179 | inputSchema: {
180 | type: "object",
181 | properties: {
182 | query: { type: "string", description: "Full-text search query" },
183 | maxItems: { type: "number", description: "Maximum search results" }
184 | },
185 | required: ["query"]
186 | }
187 | },
188 | {
189 | name: "readContent",
190 | description: "Read file content by Alfresco URI",
191 | inputSchema: {
192 | type: "object",
193 | properties: {
194 | fileUri: { type: "string", description: "Alfresco file URI" }
195 | },
196 | required: ["fileUri"]
197 | }
198 | }
199 | ]
200 | }));
201 |
202 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
203 | const { name, arguments: args } = request.params;
204 |
205 | switch(name) {
206 | case "readContent": {
207 | const nodeId = args.fileUri.replace("alfresco://", "");
208 | const response = await apiClient.downloadNodeContent(nodeId);
209 | const content = await response.text();
210 |
211 | return {
212 | content: [{ type: "text", text: content }],
213 | isError: false
214 | };
215 | }
216 |
217 | case "search": {
218 | const result = await apiClient.searchNodes(args.query, {
219 | maxItems: args.maxItems
220 | });
221 |
222 | const entries = result.list?.entries || [];
223 | const totalItems = result.list?.pagination?.totalItems ?? 0;
224 |
225 | const searchResults = entries.map(item => ({
226 | uri: `alfresco://${item.entry.id}`,
227 | mimeType: item.entry.content?.mimeType || "application/octet-stream",
228 | name: item.entry.name
229 | }));
230 |
231 | return {
232 | content: [{
233 | type: "text",
234 | text: `Found ${totalItems} items:\n${JSON.stringify(searchResults, null, 2)}`
235 | }],
236 | isError: false
237 | };
238 | }
239 |
240 | default:
241 | throw new Error(`Unsupported tool: ${name}`);
242 | }
243 | });
244 |
245 | // Server initialization
246 | async function runServer() {
247 | console.error("Initializing Alfresco REST Server...");
248 | const transport = new StdioServerTransport();
249 | await server.connect(transport);
250 | console.error("Server ready.");
251 | }
252 |
253 | runServer().catch(err => {
254 | console.error("Server initialization failed:", err);
255 | process.exit(1);
256 | });
```
--------------------------------------------------------------------------------
/alfresco/docker-compose.yml:
--------------------------------------------------------------------------------
```yaml
1 | services:
2 | alfresco:
3 | build:
4 | context: ./alfresco
5 | args:
6 | ALFRESCO_TAG: ${ALFRESCO_CE_TAG}
7 | DB: postgres
8 | SOLR_COMMS: secret
9 | mem_limit: 7488m
10 | depends_on:
11 | postgres:
12 | condition: service_healthy
13 |
14 | environment:
15 | JAVA_TOOL_OPTIONS: "
16 | -Dencryption.keystore.type=JCEKS
17 | -Dencryption.cipherAlgorithm=DESede/CBC/PKCS5Padding
18 | -Dencryption.keyAlgorithm=DESede
19 | -Dencryption.keystore.location=/usr/local/tomcat/shared/classes/alfresco/extension/keystore/keystore
20 | -Dmetadata-keystore.password=mp6yc0UD9e
21 | -Dmetadata-keystore.aliases=metadata
22 | -Dmetadata-keystore.metadata.password=oKIWzVdEdA
23 | -Dmetadata-keystore.metadata.algorithm=DESede
24 | "
25 | JAVA_OPTS : '
26 | -Ddb.username=alfresco
27 | -Ddb.password=alfresco
28 | -Ddb.driver=org.postgresql.Driver
29 | -Ddb.url=jdbc:postgresql://postgres:5432/alfresco
30 | -Dalfresco_user_store.adminpassword=209c6174da490caeb422f3fa5a7ae634
31 | -Dsystem.preferred.password.encoding=bcrypt10
32 | -Dsolr.host=solr6
33 | -Dsolr.port=8983
34 | -Dsolr.port.ssl=8983
35 | -Dsolr.secureComms=secret
36 | -Dsolr.baseUrl=/solr
37 | -Dindex.subsystem.name=solr6
38 | -Dsolr.sharedSecret=ui701yldedh
39 | -Dalfresco.host=${SERVER_NAME}
40 | -Dalfresco.port=8080
41 | -Dapi-explorer.url=http://${SERVER_NAME}:8080/api-explorer
42 | -Dalfresco.protocol=http
43 | -Dshare.host=${SERVER_NAME}
44 | -Dshare.port=8080
45 | -Dshare.protocol=http
46 | -Daos.baseUrlOverwrite=http://${SERVER_NAME}/alfresco/aos
47 | -Dmessaging.subsystem.autoStart=false
48 | -Drepo.event2.enabled=false
49 | -Ddeployment.method=DOCKER_COMPOSE
50 | -Dcsrf.filter.enabled=false
51 | -Dopencmis.server.override=true
52 | -Dopencmis.server.value=http://${SERVER_NAME}:8080
53 | -DlocalTransform.core-aio.url=http://transform-core-aio:8090/
54 | -Dhttpclient.config.transform.connectionRequestTimeout=500000
55 | -Dcsrf.filter.enabled=false
56 | -Dalfresco.restApi.basicAuthScheme=true
57 | -Dauthentication.protection.enabled=false
58 | -XX:+UseG1GC -XX:+UseStringDeduplication
59 | -Dgoogledocs.enabled=false
60 | -Ddev.email.not.sent=true
61 | -XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80
62 | '
63 | healthcheck:
64 | test:
65 | - CMD
66 | - curl
67 | - -f
68 | - http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/probes/-ready-
69 | interval: 30s
70 | timeout: 3s
71 | retries: 3
72 | start_period: 1m
73 | volumes:
74 | - ./data/alf-repo-data:/usr/local/tomcat/alf_data
75 | - ./logs/alfresco:/usr/local/tomcat/logs
76 |
77 |
78 | transform-core-aio:
79 | image: alfresco/alfresco-transform-core-aio:${TRANSFORM_ENGINE_TAG}
80 | restart: on-failure
81 | mem_limit: 2048m
82 | environment:
83 | JAVA_OPTS: "
84 | -XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80
85 | -Dserver.tomcat.threads.max=12
86 | -Dserver.tomcat.threads.min=4
87 | -Dlogging.level.org.alfresco.transform.common.TransformerDebug=ERROR
88 | -Dlogging.level.org.alfresco.transform=ERROR
89 | -Dlogging.level.org.apache.fontbox.ttf=ERROR
90 | -Dlogging.level.org.apache.pdfbox.cos.COSDocument=ERROR
91 | -Dlogging.level.org.apache.pdfbox.pdfparser=ERROR
92 | -Dlogging.level.org.apache.pdfbox.filter.FlateFilter=ERROR
93 | -Dlogging.level.org.apache.pdfbox.pdmodel.font=ERROR
94 | -Dlogging.level.org.apache.pdfbox.pdmodel.font.PDSimpleFont=FATAL
95 | -Dlogging.level.org.apache.pdfbox.pdmodel.font.PDFont=FATAL
96 | -Dlogging.level.org.apache.pdfbox.pdmodel.font.PDCIDFont=FATAL
97 | "
98 |
99 | share:
100 | build:
101 | context: ./share
102 | args:
103 | SHARE_TAG: ${SHARE_TAG}
104 | SERVER_NAME: ${SERVER_NAME}
105 | mem_limit: 1872m
106 | environment:
107 | REPO_HOST: "alfresco"
108 | REPO_PORT: "8080"
109 | CSRF_FILTER_REFERER: "http://localhost:8080/.*"
110 | CSRF_FILTER_ORIGIN: "http://localhost:8080"
111 | JAVA_OPTS: "
112 | -Dalfresco.context=alfresco
113 | -Dalfresco.protocol=http
114 | -XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80
115 | "
116 | depends_on:
117 | alfresco:
118 | condition: service_healthy
119 | volumes:
120 | - ./logs/share:/usr/local/tomcat/logs
121 |
122 |
123 | postgres:
124 | image: postgres:${POSTGRES_TAG}
125 | mem_limit: 1872m
126 | environment:
127 | - POSTGRES_PASSWORD=alfresco
128 | - POSTGRES_USER=alfresco
129 | - POSTGRES_DB=alfresco
130 | - PGUSER=alfresco
131 | command: "
132 | postgres
133 | -c max_connections=200
134 | -c logging_collector=on
135 | -c log_min_messages=LOG
136 | -c log_directory=/var/log/postgresql"
137 | healthcheck:
138 | test: ["CMD-SHELL", "pg_isready"]
139 | interval: 10s
140 | timeout: 5s
141 | retries: 5
142 | volumes:
143 | - ./data/postgres-data:/var/lib/postgresql/data
144 | - ./logs/postgres:/var/log/postgresql
145 |
146 |
147 | solr6:
148 | build:
149 | context: ./search
150 | args:
151 | SEARCH_TAG: ${SEARCH_CE_TAG}
152 | SOLR_HOSTNAME: solr6
153 | ALFRESCO_HOSTNAME: alfresco
154 | ALFRESCO_COMMS: secret
155 | CROSS_LOCALE: "true"
156 | DISABLE_CONTENT_INDEXING: "false"
157 | mem_limit: 3744m
158 | environment:
159 | SOLR_JAVA_MEM: "-XX:MinRAMPercentage=50 -XX:MaxRAMPercentage=80"
160 | #Solr needs to know how to register itself with Alfresco
161 | SOLR_ALFRESCO_HOST: "alfresco"
162 | SOLR_ALFRESCO_PORT: "8080"
163 | #Alfresco needs to know how to call solr
164 | SOLR_SOLR_HOST: "solr6"
165 | SOLR_SOLR_PORT: "8983"
166 | #Create the default alfresco and archive cores
167 | SOLR_CREATE_ALFRESCO_DEFAULTS: "alfresco,archive"
168 | SOLR_OPTS: "
169 | -XX:-UseLargePages
170 | -Dalfresco.secureComms.secret=ui701yldedh
171 | "
172 | depends_on:
173 | alfresco:
174 | condition: service_healthy
175 | volumes:
176 | - ./data/solr-data:/opt/alfresco-search-services/data
177 |
178 |
179 |
180 | content-app:
181 | image: alfresco/alfresco-content-app:${ACA_TAG}
182 | mem_limit: 256m
183 | environment:
184 | APP_BASE_SHARE_URL: "http://${SERVER_NAME}:8080/#/preview/s"
185 | depends_on:
186 | alfresco:
187 | condition: service_healthy
188 |
189 |
190 | # HTTP proxy to provide HTTP Default port access to services
191 | # SOLR API and SOLR Web Console are protected to avoid unauthenticated access
192 | proxy:
193 | image: nginx:stable-alpine
194 | mem_limit: 128m
195 | depends_on:
196 | - alfresco
197 | - solr6
198 | - share
199 | - content-app
200 | volumes:
201 | - ./config/nginx.conf:/etc/nginx/nginx.conf
202 | - ./config/nginx.htpasswd:/etc/nginx/conf.d/nginx.htpasswd
203 | ports:
204 | - ${BIND_IP_NGINX:-0.0.0.0}:8080:8080
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
```