Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
83 changes: 83 additions & 0 deletions .github/workflows/mcp-server-giphy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
name: mcp-server-giphy continuous integration

on:
pull_request:
branches: ["main"]
paths:
- "mcp-servers/mcp-server-giphy/**"
- "libraries/python/**"
- "tools/docker/**"
- ".github/workflows/mcp-server-giphy.yml"

push:
branches: ["main"]
paths:
- "mcp-servers/mcp-server-giphy/**"
- "libraries/python/**"
- "tools/docker/**"
- ".github/workflows/mcp-server-giphy.yml"

workflow_dispatch:

defaults:
run:
working-directory: mcp-servers/mcp-server-giphy

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v3

- name: Set up Python 3.11
run: uv python install 3.11

- name: test
run: |
make test

build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4

- name: docker-build
run: |
make docker-build

deploy:
runs-on: ubuntu-latest
environment: production
permissions:
id-token: write # for OIDC login
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
needs: build
if: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/main' && vars.DEPLOYMENT_ENABLED == 'true' }}
env:
DOCKER_IMAGE_TAG: ${{ github.sha }}
DOCKER_REGISTRY_NAME: ${{ secrets.AZURE_CONTAINER_REGISTRY_NAME }}
AZURE_WEBSITE_RESOURCE_GROUP: ${{ secrets.AZURE_WEBSITE_RESOURCE_GROUP }}
AZURE_WEBSITE_SUBSCRIPTION: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

steps:
- uses: actions/checkout@v4

- uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: docker-push
run: |
make docker-push

- name: docker-deploy
run: |
make docker-deploy
3 changes: 3 additions & 0 deletions mcp-servers/mcp-server-giphy/Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
repo_root = $(shell git rev-parse --show-toplevel)
include $(repo_root)/tools/makefiles/python.mk
include $(repo_root)/tools/makefiles/docker-mcp-server.mk

MCP_SERVER_MAIN_MODULE=mcp_server.start
3 changes: 0 additions & 3 deletions mcp-servers/mcp-server-giphy/mcp_server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from dotenv import load_dotenv
from . import config

# Load environment variables from .env into the settings object.
load_dotenv()
settings = config.Settings()
16 changes: 4 additions & 12 deletions mcp-servers/mcp-server-giphy/mcp_server/config.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import os
from pydantic_settings import BaseSettings

log_level = os.environ.get("LOG_LEVEL", "INFO")

def load_required_env_var(env_var_name: str) -> str:
value = os.environ.get(env_var_name, "")
if not value:
raise ValueError(f"Missing required environment variable: {env_var_name}")
return value
class Settings(BaseSettings):
log_level: str = "INFO"
giphy_api_key: str = ""

giphy_api_key = load_required_env_var("GIPHY_API_KEY")

class Settings(BaseSettings):
log_level: str = log_level
giphy_api_key: str = giphy_api_key
settings = Settings()
9 changes: 4 additions & 5 deletions mcp-servers/mcp-server-giphy/mcp_server/giphy_search.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Giphy Search Functionality

import os
from typing import List, Optional
from .config import settings

import requests
from mcp.server.fastmcp import Context
Expand Down Expand Up @@ -43,11 +43,10 @@ async def perform_search(context: str, search_term: str, ctx: Context) -> Option


async def search(search_term: str) -> Optional[List[dict]]:
api_key = os.getenv("GIPHY_API_KEY") # Retrieve the GIPHY API Key from the environment
if not api_key:
raise ValueError("GIPHY_API_KEY not set in the environment")
if not settings.giphy_api_key:
raise ValueError("Giphy API key is not set in the configuration.")

giphy_url = f"https://api.giphy.com/v1/gifs/search?api_key={api_key}&q={search_term}&limit=5"
giphy_url = f"https://api.giphy.com/v1/gifs/search?api_key={settings.giphy_api_key}&q={search_term}&limit=5"
response = requests.get(giphy_url)
if response.status_code == 200:
return GiphyResponse(**response.json()).data
Expand Down
2 changes: 1 addition & 1 deletion mcp-servers/mcp-server-giphy/mcp_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from mcp.server.fastmcp import Context, FastMCP

from . import settings
from .config import settings
from .giphy_search import perform_search

# Set the name of the MCP server
Expand Down
1 change: 1 addition & 0 deletions tools/docker/Dockerfile.assistant
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ ENV ASSISTANT_APP=${app}

ENV assistant__host=0.0.0.0
ENV assistant__port=3001
ENV PYTHONUNBUFFERED=1

SHELL ["/bin/bash", "-c"]
ENTRYPOINT ["/scripts/docker-entrypoint.sh"]
Expand Down
60 changes: 60 additions & 0 deletions tools/docker/Dockerfile.mcp-server
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# syntax=docker/dockerfile:1

# Dockerfile for mcp-servers
# Context root is expected to be the root of the repo
ARG python_image=python:3.11-slim

# These build arguments will differ per mcp-server:
# package is the directory name of the mcp-server package under /mcp-servers
ARG package
ARG main_module

FROM ${python_image} AS build

ARG package

COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

# copy all library packages
COPY ./libraries/python /packages/libraries/python
# copy the assistant package
COPY ./mcp-servers/${package} /packages/mcp-servers/mcp-server

# install the mcp-server and dependencies to /.venv
RUN uv sync --directory /packages/mcp-servers/mcp-server --no-editable --no-dev --locked

FROM ${python_image}

ARG main_module

# BEGIN: enable ssh in azure web app - comment out if not needed
########
# install sshd and set password for root
RUN apt-get update && apt-get install -y --no-install-recommends \
openssh-server \
&& rm -rf /var/lib/apt/lists/* \
&& echo "root:Docker!" | chpasswd

# azure sshd config
COPY ./tools/docker/azure_website_sshd.conf /etc/ssh/sshd_config
ENV SSHD_PORT=2222
########
# END: enable ssh in azure web app

RUN apt-get update && apt-get install -y --no-install-recommends \
gettext \
&& rm -rf /var/lib/apt/lists/*

COPY --from=build /packages/mcp-servers/mcp-server/.venv /packages/mcp-servers/mcp-server/.venv
ENV PATH=/packages/mcp-servers/mcp-server/.venv/bin:$PATH

COPY ./tools/docker/docker-entrypoint.sh /scripts/docker-entrypoint.sh
RUN chmod +x /scripts/docker-entrypoint.sh

ENV MAIN_MODULE=${main_module}
ENV PORT=3001
ENV PYTHONUNBUFFERED=1

SHELL ["/bin/bash", "-c"]
ENTRYPOINT ["/scripts/docker-entrypoint.sh"]
CMD ["python", "-m", "${MAIN_MODULE}", "--transport", "sse", "--port", "${PORT}"]
3 changes: 2 additions & 1 deletion tools/docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ if [ -n "${SSHD_PORT}" ]; then
service ssh start
fi

exec "$@"
cmd=$(echo "$@" | envsubst)
exec ${cmd}
22 changes: 22 additions & 0 deletions tools/makefiles/docker-mcp-server.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
repo_root = $(shell git rev-parse --show-toplevel)
mkfile_dir = $(patsubst %/,%,$(dir $(realpath $(lastword $(MAKEFILE_LIST)))))

# the directory containing the mcp-servers's Makefile is expected to be
# the directory of the mcp-server
invoking_makefile_directory = $(notdir $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST))))))

MCP_SERVER_PACKAGE ?= $(invoking_makefile_directory)
MCP_SERVER_IMAGE_NAME ?= $(subst -,_,$(invoking_makefile_directory))
MCP_SERVER_MAIN_MODULE ?= $(MCP_SERVER_PACKAGE).start

DOCKER_PATH = $(repo_root)
DOCKER_FILE = $(repo_root)/tools/docker/Dockerfile.mcp-server
DOCKER_BUILD_ARGS = main_module=$(MCP_SERVER_MAIN_MODULE) package=$(MCP_SERVER_PACKAGE)
DOCKER_IMAGE_NAME = $(MCP_SERVER_IMAGE_NAME)

AZURE_WEBSITE_NAME ?= $(MCP_SERVER_PACKAGE)-service

include $(mkfile_dir)/docker.mk

docker-run-local: docker-build
docker run --rm -it --add-host=host.docker.internal:host-gateway $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)