-
-
Notifications
You must be signed in to change notification settings - Fork 75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dockerized It #21
Dockerized It #21
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ mcpo makes your AI tools usable, secure, and interoperable—right now, with zer | |
|
||
## 🚀 Quick Usage | ||
|
||
|
||
We recommend using uv for lightning-fast startup and zero config. | ||
|
||
```bash | ||
|
@@ -48,6 +49,30 @@ uvx mcpo --port 8000 -- uvx mcp-server-time --local-timezone=America/New_York | |
|
||
That’s it. Your MCP tool is now available at http://localhost:8000 with a generated OpenAPI schema — test it live at [http://localhost:8000/docs](http://localhost:8000/docs). | ||
|
||
## 🐋 Docker | ||
|
||
mcpo can be run in Docker with the enclosed dockerfile. Mount a volume containing config.json to /app and add custom (offline/source) servers to /servers. | ||
|
||
Each time the container launches it will look for new (python) tools it has not yet installed and install them + their requirements.txt with pip. | ||
|
||
If config.json doesn't exist, the example.config.json will be used so that boot is successful. | ||
|
||
Example docker-compose: | ||
|
||
```yaml | ||
services: | ||
mcpo: | ||
build: | ||
context: . | ||
dockerfile: dockerfile | ||
container_name: mcpo | ||
ports: | ||
- "8080:8000" | ||
volumes: | ||
- ./app:/app | ||
- ./servers:/servers | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mark as optional |
||
``` | ||
|
||
### 🔄 Using a Config File | ||
|
||
You can serve multiple MCP tools via a single config file that follows the [Claude Desktop](https://modelcontextprotocol.io/quickstart/user) format: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# This script checks /servers for any new subfolders (custom mcp servers). If it finds | ||
# a subfolder with python requirements.txt that have not yet been installed, | ||
# it installs them, then finally runs mcpo (or whatever command is passed). | ||
# /servers dir also allows adding custom executables, etc. on the fly. | ||
# TO DO: Add support for offline node modules. | ||
|
||
set -e # Exit immediately if a command exits with a non-zero status | ||
|
||
DIR="/servers" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should leave this as an optional env var and set the default as an empty string |
||
if [ ! -d "$DIR" ]; then | ||
echo "$DIR does not exist. Creating it..." | ||
mkdir -p "$DIR" | ||
fi | ||
|
||
if [ -d "$DIR" ] && [ -z "$(ls -A "$DIR")" ]; then | ||
# Servers directory is empty | ||
echo "$DIR is empty" | ||
fi | ||
|
||
if ! [ -f "/app/config.json" ]; then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it should raise an exception instead of using example.config.json |
||
echo "No config supplied, using example config" | ||
cp /usr/local/bin/example.config.json /app/config.json | ||
else | ||
echo "Config file exists." | ||
fi | ||
|
||
# Directory to track which /servers/ subfolders we've installed | ||
INSTALLED_DIR="/usr/local/bin/installed_servers" | ||
|
||
# Ensure the tracking directory exists | ||
mkdir -p "$INSTALLED_DIR" | ||
|
||
# Temporary file to combine new requirements | ||
NEW_REQS_FILE=$(mktemp) | ||
|
||
# For each subfolder in /servers, if not yet installed, add its requirements | ||
if [ -d "$DIR" ]; then | ||
for folder in "$DIR/*"; do | ||
if [ -d "$folder" ]; then | ||
subfolder="$(basename "$folder")" | ||
# Install the actual server | ||
echo "$folder" >> "$NEW_REQS_FILE" | ||
# If we haven't installed this subfolder yet | ||
if [ ! -f "$INSTALLED_DIR/$subfolder" ]; then | ||
# If it has a requirements.txt, add to the combined file | ||
if [ -f "$folder/requirements.txt" ]; then | ||
for l in "$folder/requirements.txt"; do (cat "${l}"; echo) >> "$NEW_REQS_FILE"; done | ||
fi | ||
|
||
# Mark this subfolder as installed | ||
touch "$INSTALLED_DIR/$subfolder" | ||
fi | ||
fi | ||
done | ||
fi | ||
|
||
# If NEW_REQS_FILE is non-empty, install new python dependencies | ||
if [ -s "$NEW_REQS_FILE" ]; then | ||
pip install -r "$NEW_REQS_FILE" | ||
fi | ||
|
||
# Clean up | ||
rm "$NEW_REQS_FILE" | ||
|
||
# Finally, execute the command that was passed in (defaults to "mcpo --config $CONFIG_PATH" from the Dockerfile) | ||
exec "$@" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
|
||
# Use the official Python image as a base | ||
FROM ghcr.io/astral-sh/uv:python3.11-bookworm-slim | ||
|
||
# Set environment variables | ||
ENV PYTHONUNBUFFERED=1 \ | ||
CONFIG_PATH=/app/config.json \ | ||
UVICORN_PORT=8000 \ | ||
UVICORN_LOG_LEVEL=info | ||
|
||
# Create and set the working directory | ||
WORKDIR /app | ||
|
||
# Copy source to container | ||
COPY . /app | ||
|
||
# Install mcpo from source | ||
RUN pip install . | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better to run this after apt-get since apt-get would be cached all the time, and only the next layers will be re-built. |
||
|
||
# Install git, curl, and npm (and clean up) | ||
RUN apt-get update && \ | ||
apt-get install -y git curl npm && \ | ||
tjbck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
rm -rf /var/lib/apt/lists/* | ||
|
||
# Copy the entrypoint script into the container | ||
COPY docker-entrypoint.sh /usr/local/bin/ | ||
|
||
# Copy the example configuration JSON into the container in case the user does not supply one | ||
COPY example.config.json /usr/local/bin/ | ||
|
||
# Make sure the entrypoint script is executable | ||
RUN chmod +x /usr/local/bin/docker-entrypoint.sh | ||
|
||
# Expose the port mcpo will run on | ||
EXPOSE $UVICORN_PORT | ||
|
||
# Use the entrypoint script | ||
ENTRYPOINT ["docker-entrypoint.sh"] | ||
|
||
# Command to run mcpo with the specified configuration | ||
CMD mcpo --config "$CONFIG_PATH" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"mcpServers": { | ||
"memory": { | ||
"command": "npx", | ||
"args": ["-y", "@modelcontextprotocol/server-memory"] | ||
}, | ||
"time": { | ||
"command": "uvx", | ||
"args": ["mcp-server-time"] | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(optional)