Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Python cache
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Virtual environments
.venv/
venv/
ENV/
env/

# Testing
.pytest_cache/
.coverage
htmlcov/
.tox/
.hypothesis/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# Git
.git/
.gitignore

# Documentation
docs/
*.md
!README.md

# CI/CD
.github/

# Development files
.env
.env.*
CLAUDE.md

# Logs
logs/
*.log

# macOS
.DS_Store

# Test data
tests/
data.ms/
28 changes: 28 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Use Python 3.12 slim image for smaller size
FROM python:3.12-slim

# Set working directory
WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*

# Install uv for faster Python package management
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV PATH="/root/.local/bin:${PATH}"

# Copy project files
COPY pyproject.toml README.md ./
COPY src/ ./src/

# Install the package
RUN uv pip install --system .

# Set default environment variables
ENV MEILI_HTTP_ADDR=http://meilisearch:7700
ENV MEILI_MASTER_KEY=""

# Run the MCP server
CMD ["python", "-m", "src.meilisearch_mcp"]
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,32 @@ source .venv/bin/activate # On Windows: .venv\Scripts\activate
uv pip install -e .
```

### Using Docker

Perfect for containerized environments like n8n workflows!

```bash
# Using Docker Compose (includes Meilisearch)
docker-compose up -d

# Or build and run standalone
docker build -t meilisearch-mcp .
docker run -it \
-e MEILI_HTTP_ADDR=http://your-meilisearch:7700 \
-e MEILI_MASTER_KEY=your-master-key \
meilisearch-mcp
```

For n8n integration, use the Docker image in your workflow:
```yaml
# Example n8n docker-compose service
meilisearch-mcp:
image: meilisearch-mcp:latest
environment:
- MEILI_HTTP_ADDR=http://meilisearch:7700
- MEILI_MASTER_KEY=masterKey
```

## 🛠️ What Can You Do?

<details>
Expand Down
31 changes: 31 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
services:
meilisearch:
image: getmeili/meilisearch:v1.6
ports:
- "7700:7700"
environment:
- MEILI_MASTER_KEY=masterKey
- MEILI_ENV=development
volumes:
- meilisearch_data:/meili_data
networks:
- meilisearch-network

meilisearch-mcp:
build: .
environment:
- MEILI_HTTP_ADDR=http://meilisearch:7700
- MEILI_MASTER_KEY=masterKey
depends_on:
- meilisearch
networks:
- meilisearch-network
stdin_open: true
tty: true

volumes:
meilisearch_data:

networks:
meilisearch-network:
driver: bridge
122 changes: 122 additions & 0 deletions tests/test_docker_integration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
"""
Integration tests for Docker setup.

These tests verify that the Docker container works correctly and can
communicate with Meilisearch.
"""
import os
import subprocess
import time
import pytest
import requests


def wait_for_service(url, timeout=30):
"""Wait for a service to become available."""
start_time = time.time()
while time.time() - start_time < timeout:
try:
response = requests.get(f"{url}/health")
if response.status_code == 200:
return True
except requests.exceptions.ConnectionError:
pass
time.sleep(1)
return False


@pytest.fixture(scope="module")
def docker_services():
"""Start Docker services for testing."""
# Start services
subprocess.run(["docker-compose", "up", "-d"], check=True)

# Wait for Meilisearch to be ready
if not wait_for_service("http://localhost:7700"):
subprocess.run(["docker-compose", "down"], check=True)
pytest.fail("Meilisearch failed to start")

yield

# Cleanup
subprocess.run(["docker-compose", "down", "-v"], check=True)


def test_docker_build():
"""Test that the Docker image can be built successfully."""
result = subprocess.run(
["docker", "build", "-t", "meilisearch-mcp-test", "."],
capture_output=True,
text=True
)
assert result.returncode == 0, f"Docker build failed: {result.stderr}"


def test_meilisearch_connectivity(docker_services):
"""Test that the MCP container can connect to Meilisearch."""
# Run a simple connectivity test in the container
result = subprocess.run(
[
"docker-compose", "run", "--rm", "meilisearch-mcp",
"python", "-c",
"""
import os
from meilisearch import Client
client = Client(os.getenv('MEILI_HTTP_ADDR'), os.getenv('MEILI_MASTER_KEY'))
health = client.health()
assert health['status'] == 'available'
print('SUCCESS: Connected to Meilisearch')
"""
],
capture_output=True,
text=True
)

assert result.returncode == 0, f"Connectivity test failed: {result.stderr}"
assert "SUCCESS: Connected to Meilisearch" in result.stdout


def test_mcp_server_import(docker_services):
"""Test that the MCP server module can be imported in the container."""
result = subprocess.run(
[
"docker-compose", "run", "--rm", "meilisearch-mcp",
"python", "-c",
"""
import src.meilisearch_mcp
from src.meilisearch_mcp.server import MeilisearchMCPServer
print('SUCCESS: MCP server imported')
"""
],
capture_output=True,
text=True
)

assert result.returncode == 0, f"Import test failed: {result.stderr}"
assert "SUCCESS: MCP server imported" in result.stdout


def test_environment_variables(docker_services):
"""Test that environment variables are correctly set in the container."""
result = subprocess.run(
[
"docker-compose", "run", "--rm", "meilisearch-mcp",
"python", "-c",
"""
import os
assert os.getenv('MEILI_HTTP_ADDR') == 'http://meilisearch:7700'
assert os.getenv('MEILI_MASTER_KEY') == 'masterKey'
print('SUCCESS: Environment variables are correct')
"""
],
capture_output=True,
text=True
)

assert result.returncode == 0, f"Environment test failed: {result.stderr}"
assert "SUCCESS: Environment variables are correct" in result.stdout


if __name__ == "__main__":
# Run tests
pytest.main([__file__, "-v"])
Loading