diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 720a9a0b7..a59e1d075 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -25,22 +25,37 @@ jobs: - uses: actions/checkout@v4 - name: Prepare tag name id: prepare_tag + env: + DOCKER_IMAGE_TAG_NAME: ${{ github.event.inputs.docker_image_tag_name }} + REF_NAME: ${{ github.ref_name }} run: | if [ "${{ github.event_name }}" = "push" ]; then echo "type=sha" > tags.txt echo "type=schedule" >> tags.txt + mcp_version="sha-$(git rev-parse --short HEAD)" fi if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - if [ -n "${{ github.event.inputs.docker_image_tag_name }}" ]; then - tag_name=${{ github.event.inputs.docker_image_tag_name }} + if [ -n "$DOCKER_IMAGE_TAG_NAME" ]; then + if ! echo "$DOCKER_IMAGE_TAG_NAME" | grep -qE '^[A-Za-z0-9_][A-Za-z0-9_.-]*$'; then + echo "Invalid docker_image_tag_name: must start with [A-Za-z0-9_] and contain only [A-Za-z0-9_.-]" >&2 + exit 1 + fi + if [ "${#DOCKER_IMAGE_TAG_NAME}" -gt 128 ]; then + echo "docker_image_tag_name exceeds 128 characters" >&2 + exit 1 + fi + tag_name="$DOCKER_IMAGE_TAG_NAME" else - tag_name=$(echo ${{ github.ref_name }} | sed 's/[^a-zA-Z0-9]/-/g')-$(git log -1 --pretty=%h) + tag_name=$(echo "$REF_NAME" | sed 's/[^a-zA-Z0-9]/-/g')-$(git rev-parse --short HEAD) fi echo "type=raw,value=$tag_name" > tags.txt + mcp_version="$tag_name" fi echo "tags=$(cat tags.txt)" >> $GITHUB_OUTPUT + printf 'mcp_version=%s\n' "$mcp_version" >> $GITHUB_OUTPUT outputs: tags: ${{ steps.prepare_tag.outputs.tags }} + mcp_version: ${{ steps.prepare_tag.outputs.mcp_version }} build-image: needs: prepare-tag runs-on: ubuntu-latest @@ -126,6 +141,8 @@ jobs: platforms: ${{ matrix.arch.platform }} labels: ${{ steps.meta.outputs.labels }} context: ./ibis-server + build-args: | + MCP_SERVER_VERSION=${{ needs.prepare-tag.outputs.mcp_version }} build-contexts: | wren-core-py=./wren-core-py wren-core=./wren-core diff --git a/.github/workflows/stable-release.yml b/.github/workflows/stable-release.yml index 3795ce1e2..86fc4b8b2 100644 --- a/.github/workflows/stable-release.yml +++ b/.github/workflows/stable-release.yml @@ -52,6 +52,14 @@ jobs: git commit -m "Upgrade ibis version to $version" git push echo "value=$version" >> $GITHUB_OUTPUT + - name: Sync mcp-server version + run: | + version="${{ steps.next_version.outputs.value }}" + escaped_version=$(printf '%s\n' "$version" | sed 's/[&/\]/\\&/g') + sed -i "s/^version = \".*\"/version = \"$escaped_version\"/" mcp-server/pyproject.toml + git add mcp-server/pyproject.toml + git commit --amend --no-edit + git push --force-with-lease - name: Set up JDK 21 uses: actions/setup-java@v4 with: @@ -174,6 +182,7 @@ jobs: context: ./ibis-server build-args: | ENV=prod + MCP_SERVER_VERSION=${{ needs.prepare-version.outputs.next_version }} build-contexts: | wren-core-py=./wren-core-py wren-core=./wren-core diff --git a/ibis-server/Dockerfile b/ibis-server/Dockerfile index 1a5b93ce0..aafd48f18 100644 --- a/ibis-server/Dockerfile +++ b/ibis-server/Dockerfile @@ -102,6 +102,11 @@ COPY wren/ ./wren/ # Copy MCP server COPY --from=mcp-server ./app /mcp-server/app/ COPY --from=mcp-server ./mdl.schema.json /mcp-server/ +COPY --from=mcp-server ./pyproject.toml /mcp-server/ +ARG MCP_SERVER_VERSION=unknown +RUN if [ -n "$MCP_SERVER_VERSION" ]; then \ + sed -i "s/^version = \".*\"/version = \"$MCP_SERVER_VERSION\"/" /mcp-server/pyproject.toml; \ + fi COPY pyproject.toml poetry.lock ./ @@ -118,6 +123,8 @@ RUN jupyter lab --generate-config --allow-root COPY entrypoint.sh ./ RUN chmod +x ./entrypoint.sh +LABEL org.opencontainers.image.mcp-server.version=${MCP_SERVER_VERSION} + EXPOSE 8000 8888 9000 ENTRYPOINT ["./entrypoint.sh"] diff --git a/mcp-server/app/wren.py b/mcp-server/app/wren.py index f66c3def4..4cb6ec075 100644 --- a/mcp-server/app/wren.py +++ b/mcp-server/app/wren.py @@ -704,5 +704,31 @@ async def health_check() -> str: ) +@mcp.tool( + annotations=ToolAnnotations( + title="Get Version", + readOnlyHint=True, + ), +) +def get_version() -> str: + """Return the current version of the Wren MCP server.""" + try: + from importlib.metadata import version + + return version("mcp-server") + except Exception: + pass + try: + pyproject = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "pyproject.toml") + with open(pyproject, "rb") as f: + for line in f: + decoded = line.decode() + if decoded.startswith("version"): + return decoded.split('"')[1] + except Exception: + pass + return "unknown" + + if __name__ == "__main__": mcp.run(transport=MCP_TRANSPORT) diff --git a/mcp-server/pyproject.toml b/mcp-server/pyproject.toml index b6ff902f8..7fc873e25 100644 --- a/mcp-server/pyproject.toml +++ b/mcp-server/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "mcp-server" -version = "0.1.0" -description = "Add your description here" +version = "0.23.0" +description = "MCP server exposing Wren Engine to AI agents" readme = "README.md" requires-python = ">=3.11" dependencies = [ @@ -10,6 +10,10 @@ dependencies = [ "orjson>=3.11.7", "pydantic>=2.10.6", "python-dotenv>=1.0.1", +] + +[project.optional-dependencies] +dev = [ "ruff>=0.11.0", ]