diff --git a/.github/scripts/release.sh b/.github/scripts/release.sh index 2a1f6a9..35568a2 100644 --- a/.github/scripts/release.sh +++ b/.github/scripts/release.sh @@ -19,7 +19,7 @@ GIT_TOKEN=$1 WORK_DIR=$2 VERSION_TYPE=$3 # possible values: major, minor, patch -# Check if GIT_TOKEN is empty + Check if GIT_TOKEN is empty if [ -z "$GIT_TOKEN" ]; then echo "❌ Error: GIT_TOKEN is not set." exit 1 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 775003e..0000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,71 +0,0 @@ -name: Build and Push container -run-name: Build and Push container -on: - workflow_dispatch: - #schedule: - # - cron: "0 10 * * *" - push: - branches: - - 'main' - - 'master' - tags: - - 'v*' - pull_request: - branches: - - 'main' - - 'master' -env: - IMAGE: git.kvant.cloud/${{github.repository}} -jobs: - build_concierge_backend: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set current time - uses: https://github.com/gerred/actions/current-time@master - id: current_time - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to git.kvant.cloud registry - uses: docker/login-action@v3 - with: - registry: git.kvant.cloud - username: ${{ vars.ORG_PACKAGE_WRITER_USERNAME }} - password: ${{ secrets.ORG_PACKAGE_WRITER_TOKEN }} - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - # list of Docker images to use as base name for tags - images: | - ${{env.IMAGE}} - # generate Docker tags based on the following events/attributes - tags: | - type=schedule - type=ref,event=branch - type=ref,event=pr - type=semver,pattern={{version}} - - - name: Build and push to gitea registry - uses: docker/build-push-action@v6 - with: - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - context: . - provenance: mode=max - sbom: true - build-args: | - BUILD_DATE=${{ steps.current_time.outputs.time }} - cache-from: | - type=registry,ref=${{ env.IMAGE }}:buildcache - type=registry,ref=${{ env.IMAGE }}:${{ github.ref_name }} - type=registry,ref=${{ env.IMAGE }}:main - cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max,image-manifest=true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0c51bc7..e55f6b6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: with: ref: 'main' fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.GIT_BOT_PAT }} - uses: actions/checkout@v2 - name: Set up Go 1.x @@ -60,5 +60,5 @@ jobs: - name: Update artifact version, package, commit, and create release. env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GIT_BOT_PAT }} run: bash ./.github/scripts/release.sh $GITHUB_TOKEN ${{ github.workspace }} ${{ github.event.inputs.version_type }} diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index dc468b1..0000000 --- a/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.24@sha256:d9db32125db0c3a680cfb7a1afcaefb89c898a075ec148fdc2f0f646cc2ed509 AS build - -ARG TARGETPLATFORM -ARG BUILDPLATFORM -ARG TARGETOS -ARG TARGETARCH - -WORKDIR /workspace - -RUN apt update -qq && apt install -qq -y git bash curl g++ - -# Download libraries -ADD go.* . -RUN go mod download - -# Build -ADD cmd cmd -ADD internal internal -RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o webhook -ldflags '-w -extldflags "-static"' -o openmcpauthproxy ./cmd/proxy - -#Test -RUN CGO_ENABLED=1 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go test -v -race ./... - - -# Build production container -FROM --platform=${BUILDPLATFORM:-linux/amd64} ubuntu:24.04 - -RUN apt-get update \ - && apt-get install --no-install-recommends -y \ - python3-pip \ - python-is-python3 \ - npm \ - && apt-get autoremove \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* - -RUN pip install uvenv --break-system-packages - -WORKDIR /app -COPY --from=build /workspace/openmcpauthproxy /app/ - -ADD config.yaml /app - - -ENTRYPOINT ["/app/openmcpauthproxy"] - -ARG IMAGE_SOURCE -LABEL org.opencontainers.image.source=$IMAGE_SOURCE diff --git a/Makefile b/Makefile index b0d0926..c9ef883 100644 --- a/Makefile +++ b/Makefile @@ -30,19 +30,19 @@ build: clean test build-linux build-linux-arm build-darwin build-linux: mkdir -p $(BUILD_DIR)/linux - GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -x -ldflags "-X main.version=$(BUILD_VERSION)" \ + GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -x -ldflags "-X main.version=$(BUILD_VERSION) \ -o $(BUILD_DIR)/linux/openmcpauthproxy $(PROJECT_ROOT)/cmd/proxy cp config.yaml $(BUILD_DIR)/linux build-linux-arm: mkdir -p $(BUILD_DIR)/linux-arm - GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -x -ldflags "-X main.version=$(BUILD_VERSION)" \ + GOOS=linux GOARCH=arm CGO_ENABLED=0 go build -x -ldflags "-X main.version=$(BUILD_VERSION) \ -o $(BUILD_DIR)/linux-arm/openmcpauthproxy $(PROJECT_ROOT)/cmd/proxy cp config.yaml $(BUILD_DIR)/linux-arm build-darwin: mkdir -p $(BUILD_DIR)/darwin - GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -x -ldflags "-X main.version=$(BUILD_VERSION)" \ + GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -x -ldflags "-X main.version=$(BUILD_VERSION) \ -o $(BUILD_DIR)/darwin/openmcpauthproxy $(PROJECT_ROOT)/cmd/proxy cp config.yaml $(BUILD_DIR)/darwin diff --git a/README.md b/README.md index 6be3ece..8fe18d6 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ # Open MCP Auth Proxy -A lightweight authorization proxy for Model Context Protocol (MCP) servers that enforces authorization according to the [MCP authorization specification](https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/authorization/) - -[![πŸš€ Release](https://github.com/wso2/open-mcp-auth-proxy/actions/workflows/release.yml/badge.svg)](https://github.com/wso2/open-mcp-auth-proxy/actions/workflows/release.yml) -[![πŸ’¬ Stackoverflow](https://img.shields.io/badge/Ask%20for%20help%20on-Stackoverflow-orange)](https://stackoverflow.com/questions/tagged/wso2is) -[![πŸ’¬ Discord](https://img.shields.io/badge/Join%20us%20on-Discord-%23e01563.svg)](https://discord.gg/wso2) -[![🐦 Twitter](https://img.shields.io/twitter/follow/wso2.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=wso2) -[![πŸ“ License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/wso2/product-is/blob/master/LICENSE) +A lightweight authorization proxy for Model Context Protocol (MCP) servers that enforces authorization according to the [MCP authorization specification](https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/authorization/). ![Architecture Diagram](https://github.com/user-attachments/assets/41cf6723-c488-4860-8640-8fec45006f92) @@ -47,7 +41,15 @@ Open MCP Auth Proxy sits between MCP clients and your MCP server to: ### Basic Usage -1. Download the latest release from [Github releases](https://github.com/wso2/open-mcp-auth-proxy/releases/latest). +1. The repository comes with a default `config.yaml` file that contains the basic configuration: + +```yaml +listen_port: 8080 +base_url: "http://localhost:8000" # Your MCP server URL +paths: + sse: "/sse" + messages: "/messages/" +``` 2. Start the proxy in demo mode (uses pre-configured authentication with Asgardeo sandbox): @@ -55,16 +57,6 @@ Open MCP Auth Proxy sits between MCP clients and your MCP server to: ./openmcpauthproxy --demo ``` -> The repository comes with a default `config.yaml` file that contains the basic configuration: -> -> ```yaml -> listen_port: 8080 -> base_url: "http://localhost:8000" # Your MCP server URL -> paths: -> sse: "/sse" -> messages: "/messages/" -> ``` - 3. Connect using an MCP client like [MCP Inspector](https://github.com/shashimalcse/inspector)(This is a temporary fork with fixes for authentication [issues](https://github.com/modelcontextprotocol/typescript-sdk/issues/257) in the original implementation) ## Connect an Identity Provider diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index c43dd7d..6424f18 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -12,7 +12,7 @@ import ( "github.com/wso2/open-mcp-auth-proxy/internal/authz" "github.com/wso2/open-mcp-auth-proxy/internal/config" "github.com/wso2/open-mcp-auth-proxy/internal/constants" - logger "github.com/wso2/open-mcp-auth-proxy/internal/logging" + "github.com/wso2/open-mcp-auth-proxy/internal/logging" "github.com/wso2/open-mcp-auth-proxy/internal/proxy" "github.com/wso2/open-mcp-auth-proxy/internal/subprocess" "github.com/wso2/open-mcp-auth-proxy/internal/util" @@ -58,7 +58,7 @@ func main() { logger.Warn("%v", err) logger.Warn("Subprocess may fail to start due to missing dependencies") } - + procManager = subprocess.NewManager() if err := procManager.Start(cfg); err != nil { logger.Warn("Failed to start subprocess: %v", err) @@ -95,7 +95,7 @@ func main() { // 5. Build the main router mux := proxy.NewRouter(cfg, provider) - listen_address := fmt.Sprintf("0.0.0.0:%d", cfg.ListenPort) + listen_address := fmt.Sprintf(":%d", cfg.ListenPort) // 6. Start the server srv := &http.Server{ diff --git a/config.yaml b/config.yaml index ef70fbb..5621195 100644 --- a/config.yaml +++ b/config.yaml @@ -6,23 +6,29 @@ base_url: "http://localhost:8000" # Base URL for the MCP server port: 8000 # Port for the MCP server timeout_seconds: 10 +# Path configuration +paths: + sse: "/sse" # SSE endpoint path + messages: "/messages/" # Messages endpoint path # Transport mode configuration -transport_mode: "stdio" # Options: "sse" or "stdio" +transport_mode: "sse" # Options: "sse" or "stdio" # stdio-specific configuration (used only when transport_mode is "stdio") stdio: enabled: true - user_command: uvx mcp-server-time --local-timezone=Europe/Zurich - #user_command: "npx -y @modelcontextprotocol/server-github" + user_command: "npx -y @modelcontextprotocol/server-github" work_dir: "" # Working directory (optional) # env: # Environment variables (optional) # - "NODE_ENV=development" -# CORS settings +# Path mapping (optional) +path_mapping: + +# CORS configuration cors: allowed_origins: - - "http://localhost:6274" # Origin of your frontend/client app + - "http://localhost:5173" allowed_methods: - "GET" - "POST" @@ -34,32 +40,8 @@ cors: - "mcp-protocol-version" allow_credentials: true -# Keycloak endpoint path mappings -path_mapping: - sse: "/sse" # SSE endpoint path - messages: "/messages/" # Messages endpoint path - /token: /realms/master/protocol/openid-connect/token - /register: /realms/master/clients-registrations/openid-connect - -# Keycloak configuration block -default: - base_url: "https://iam.phoenix-systems.ch" - jwks_url: "https://iam.phoenix-systems.ch/realms/kvant/protocol/openid-connect/certs" - path: - /.well-known/oauth-authorization-server: - response: - issuer: "https://iam.phoenix-systems.ch/realms/kvant" - jwks_uri: "https://iam.phoenix-systems.ch/realms/kvant/protocol/openid-connect/certs" - authorization_endpoint: "https://iam.phoenix-systems.ch/realms/kvant/protocol/openid-connect/auth" - response_types_supported: - - "code" - grant_types_supported: - - "authorization_code" - - "refresh_token" - code_challenge_methods_supported: - - "S256" - - "plain" - /token: - addBodyParams: - - name: "audience" - value: "mcp_proxy" \ No newline at end of file +# Demo configuration for Asgardeo +demo: + org_name: "openmcpauthdemo" + client_id: "N0U9e_NNGr9mP_0fPnPfPI0a6twa" + client_secret: "qFHfiBp5gNGAO9zV4YPnDofBzzfInatfUbHyPZvM0jka" diff --git a/pull_request_template.md b/pull_request_template.md index c401a06..9b32185 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,11 +1,52 @@ ## Purpose - +> Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc. -## Related Issues - +## Goals +> Describe the solutions that this feature/fix will introduce to resolve the problems described above + +## Approach +> Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here. + +## User stories +> Summary of user stories addressed by this change> + +## Release note +> Brief description of the new feature or bug fix as it will appear in the release notes + +## Documentation +> Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter β€œN/A” plus brief explanation of why there’s no doc impact + +## Training +> Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable + +## Certification +> Type β€œSent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type β€œN/A” and explain why. + +## Marketing +> Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable + +## Automation tests + - Unit tests + > Code coverage information + - Integration tests + > Details about the test cases and coverage + +## Security checks + - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no + - Ran FindSecurityBugs plugin and verified report? yes/no + - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no + +## Samples +> Provide high-level details about the samples related to this feature ## Related PRs - +> List any other related PRs ## Migrations (if applicable) - +> Describe migration steps and platforms on which migration has been tested + +## Test environment +> List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested + +## Learning +> Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem. \ No newline at end of file