Skip to content

Commit 9e0afea

Browse files
committed
Add Docker support for containerized deployments
- Add Dockerfile with Python 3.12 slim base image - Install dependencies using uv for faster builds - Create docker-compose.yml for easy setup with Meilisearch - Add .dockerignore to exclude unnecessary files - Add Docker integration tests - Update README with Docker usage instructions - Support for n8n and other containerized environments Fixes #47
1 parent c71ac74 commit 9e0afea

File tree

5 files changed

+276
-0
lines changed

5 files changed

+276
-0
lines changed

.dockerignore

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Python cache
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
.Python
7+
build/
8+
develop-eggs/
9+
dist/
10+
downloads/
11+
eggs/
12+
.eggs/
13+
lib/
14+
lib64/
15+
parts/
16+
sdist/
17+
var/
18+
wheels/
19+
*.egg-info/
20+
.installed.cfg
21+
*.egg
22+
23+
# Virtual environments
24+
.venv/
25+
venv/
26+
ENV/
27+
env/
28+
29+
# Testing
30+
.pytest_cache/
31+
.coverage
32+
htmlcov/
33+
.tox/
34+
.hypothesis/
35+
36+
# IDE
37+
.vscode/
38+
.idea/
39+
*.swp
40+
*.swo
41+
*~
42+
43+
# Git
44+
.git/
45+
.gitignore
46+
47+
# Documentation
48+
docs/
49+
*.md
50+
!README.md
51+
52+
# CI/CD
53+
.github/
54+
55+
# Development files
56+
.env
57+
.env.*
58+
CLAUDE.md
59+
60+
# Logs
61+
logs/
62+
*.log
63+
64+
# macOS
65+
.DS_Store
66+
67+
# Test data
68+
tests/
69+
data.ms/

Dockerfile

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Use Python 3.12 slim image for smaller size
2+
FROM python:3.12-slim
3+
4+
# Set working directory
5+
WORKDIR /app
6+
7+
# Install system dependencies
8+
RUN apt-get update && apt-get install -y --no-install-recommends \
9+
curl \
10+
&& rm -rf /var/lib/apt/lists/*
11+
12+
# Install uv for faster Python package management
13+
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
14+
ENV PATH="/root/.local/bin:${PATH}"
15+
16+
# Copy project files
17+
COPY pyproject.toml README.md ./
18+
COPY src/ ./src/
19+
20+
# Install the package
21+
RUN uv pip install --system .
22+
23+
# Set default environment variables
24+
ENV MEILI_HTTP_ADDR=http://meilisearch:7700
25+
ENV MEILI_MASTER_KEY=""
26+
27+
# Run the MCP server
28+
CMD ["python", "-m", "src.meilisearch_mcp"]

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,32 @@ source .venv/bin/activate # On Windows: .venv\Scripts\activate
137137
uv pip install -e .
138138
```
139139

140+
### Using Docker
141+
142+
Perfect for containerized environments like n8n workflows!
143+
144+
```bash
145+
# Using Docker Compose (includes Meilisearch)
146+
docker-compose up -d
147+
148+
# Or build and run standalone
149+
docker build -t meilisearch-mcp .
150+
docker run -it \
151+
-e MEILI_HTTP_ADDR=http://your-meilisearch:7700 \
152+
-e MEILI_MASTER_KEY=your-master-key \
153+
meilisearch-mcp
154+
```
155+
156+
For n8n integration, use the Docker image in your workflow:
157+
```yaml
158+
# Example n8n docker-compose service
159+
meilisearch-mcp:
160+
image: meilisearch-mcp:latest
161+
environment:
162+
- MEILI_HTTP_ADDR=http://meilisearch:7700
163+
- MEILI_MASTER_KEY=masterKey
164+
```
165+
140166
## 🛠️ What Can You Do?
141167
142168
<details>

docker-compose.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
services:
2+
meilisearch:
3+
image: getmeili/meilisearch:v1.6
4+
ports:
5+
- "7700:7700"
6+
environment:
7+
- MEILI_MASTER_KEY=masterKey
8+
- MEILI_ENV=development
9+
volumes:
10+
- meilisearch_data:/meili_data
11+
networks:
12+
- meilisearch-network
13+
14+
meilisearch-mcp:
15+
build: .
16+
environment:
17+
- MEILI_HTTP_ADDR=http://meilisearch:7700
18+
- MEILI_MASTER_KEY=masterKey
19+
depends_on:
20+
- meilisearch
21+
networks:
22+
- meilisearch-network
23+
stdin_open: true
24+
tty: true
25+
26+
volumes:
27+
meilisearch_data:
28+
29+
networks:
30+
meilisearch-network:
31+
driver: bridge

tests/test_docker_integration.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""
2+
Integration tests for Docker setup.
3+
4+
These tests verify that the Docker container works correctly and can
5+
communicate with Meilisearch.
6+
"""
7+
import os
8+
import subprocess
9+
import time
10+
import pytest
11+
import requests
12+
13+
14+
def wait_for_service(url, timeout=30):
15+
"""Wait for a service to become available."""
16+
start_time = time.time()
17+
while time.time() - start_time < timeout:
18+
try:
19+
response = requests.get(f"{url}/health")
20+
if response.status_code == 200:
21+
return True
22+
except requests.exceptions.ConnectionError:
23+
pass
24+
time.sleep(1)
25+
return False
26+
27+
28+
@pytest.fixture(scope="module")
29+
def docker_services():
30+
"""Start Docker services for testing."""
31+
# Start services
32+
subprocess.run(["docker-compose", "up", "-d"], check=True)
33+
34+
# Wait for Meilisearch to be ready
35+
if not wait_for_service("http://localhost:7700"):
36+
subprocess.run(["docker-compose", "down"], check=True)
37+
pytest.fail("Meilisearch failed to start")
38+
39+
yield
40+
41+
# Cleanup
42+
subprocess.run(["docker-compose", "down", "-v"], check=True)
43+
44+
45+
def test_docker_build():
46+
"""Test that the Docker image can be built successfully."""
47+
result = subprocess.run(
48+
["docker", "build", "-t", "meilisearch-mcp-test", "."],
49+
capture_output=True,
50+
text=True
51+
)
52+
assert result.returncode == 0, f"Docker build failed: {result.stderr}"
53+
54+
55+
def test_meilisearch_connectivity(docker_services):
56+
"""Test that the MCP container can connect to Meilisearch."""
57+
# Run a simple connectivity test in the container
58+
result = subprocess.run(
59+
[
60+
"docker-compose", "run", "--rm", "meilisearch-mcp",
61+
"python", "-c",
62+
"""
63+
import os
64+
from meilisearch import Client
65+
client = Client(os.getenv('MEILI_HTTP_ADDR'), os.getenv('MEILI_MASTER_KEY'))
66+
health = client.health()
67+
assert health['status'] == 'available'
68+
print('SUCCESS: Connected to Meilisearch')
69+
"""
70+
],
71+
capture_output=True,
72+
text=True
73+
)
74+
75+
assert result.returncode == 0, f"Connectivity test failed: {result.stderr}"
76+
assert "SUCCESS: Connected to Meilisearch" in result.stdout
77+
78+
79+
def test_mcp_server_import(docker_services):
80+
"""Test that the MCP server module can be imported in the container."""
81+
result = subprocess.run(
82+
[
83+
"docker-compose", "run", "--rm", "meilisearch-mcp",
84+
"python", "-c",
85+
"""
86+
import src.meilisearch_mcp
87+
from src.meilisearch_mcp.server import MeilisearchMCPServer
88+
print('SUCCESS: MCP server imported')
89+
"""
90+
],
91+
capture_output=True,
92+
text=True
93+
)
94+
95+
assert result.returncode == 0, f"Import test failed: {result.stderr}"
96+
assert "SUCCESS: MCP server imported" in result.stdout
97+
98+
99+
def test_environment_variables(docker_services):
100+
"""Test that environment variables are correctly set in the container."""
101+
result = subprocess.run(
102+
[
103+
"docker-compose", "run", "--rm", "meilisearch-mcp",
104+
"python", "-c",
105+
"""
106+
import os
107+
assert os.getenv('MEILI_HTTP_ADDR') == 'http://meilisearch:7700'
108+
assert os.getenv('MEILI_MASTER_KEY') == 'masterKey'
109+
print('SUCCESS: Environment variables are correct')
110+
"""
111+
],
112+
capture_output=True,
113+
text=True
114+
)
115+
116+
assert result.returncode == 0, f"Environment test failed: {result.stderr}"
117+
assert "SUCCESS: Environment variables are correct" in result.stdout
118+
119+
120+
if __name__ == "__main__":
121+
# Run tests
122+
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)