mcp-contextforge-gateway


Namemcp-contextforge-gateway JSON
Version 0.3.1 PyPI version JSON
download
home_pageNone
SummaryA production-grade MCP Gateway & Proxy built with FastAPI. Supports multi-server registration, virtual server composition, authentication, retry logic, observability, protocol translation, and a unified federated tool catalog.
upload_time2025-07-11 03:26:52
maintainerNone
docs_urlNone
authorNone
requires_python<3.14,>=3.11
licenseNone
keywords mcp api gateway proxy tools agents agentic ai model context protocol multi-agent fastapi json-rpc sse websocket federation security authentication
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI
coveralls test coverage
            # MCP Gateway

> Model Context Protocol gateway & proxy - unify REST, MCP, and A2A with federation, virtual servers, retries, security, and an optional admin UI.

![](docs/docs/images/contextforge-banner.png)

<!-- === CI / Security / Build Badges === -->
[![Build Python Package](https://github.com/IBM/mcp-context-forge/actions/workflows/python-package.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/python-package.yml)&nbsp;
[![CodeQL](https://github.com/IBM/mcp-context-forge/actions/workflows/codeql.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/codeql.yml)&nbsp;
[![Bandit Security](https://github.com/IBM/mcp-context-forge/actions/workflows/bandit.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/bandit.yml)&nbsp;
[![Dependency Review](https://github.com/IBM/mcp-context-forge/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/dependency-review.yml)&nbsp;
[![Tests & Coverage](https://github.com/IBM/mcp-context-forge/actions/workflows/pytest.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/pytest.yml)&nbsp;
[![Lint & Static Analysis](https://github.com/IBM/mcp-context-forge/actions/workflows/lint.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/lint.yml)

<!-- === Container Build & Deploy === -->
[![Secure Docker Build](https://github.com/IBM/mcp-context-forge/actions/workflows/docker-image.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/docker-image.yml)&nbsp;
[![Deploy to IBM Code Engine](https://github.com/IBM/mcp-context-forge/actions/workflows/ibm-cloud-code-engine.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/ibm-cloud-code-engine.yml)

<!-- === Package / Container === -->
[![Async](https://img.shields.io/badge/async-await-green.svg)](https://docs.python.org/3/library/asyncio.html)
[![License](https://img.shields.io/github/license/ibm/mcp-context-forge)](LICENSE)&nbsp;
[![PyPI](https://img.shields.io/pypi/v/mcp-contextforge-gateway)](https://pypi.org/project/mcp-contextforge-gateway/)&nbsp;
[![Docker Image](https://img.shields.io/badge/docker-ghcr.io%2Fibm%2Fmcp--context--forge-blue)](https://github.com/ibm/mcp-context-forge/pkgs/container/mcp-context-forge)&nbsp;


ContextForge MCP Gateway is a feature-rich gateway, proxy and MCP Registry that federates MCP and REST services - unifying discovery, auth, rate-limiting, observability, virtual servers, multi-transport protocols, and an optional Admin UI into one clean endpoint for your AI clients. It runs as a fully compliant MCP server, deployable via PyPI or Docker, and scales to multi-cluster environments on Kubernetes with Redis-backed federation and caching.

![MCP Gateway](https://ibm.github.io/mcp-context-forge/images/mcpgateway.gif)
---

## Table of Contents

<!-- vscode-markdown-toc -->
## Table of Contents

* 1. [Table of Contents](#table-of-contents)
* 2. [๐Ÿš€ Overview & Goals](#-overview--goals)
* 3. [Quick Start - PyPI](#quick-start---pypi)
    * 3.1. [1 - Install & run (copy-paste friendly)](#1---install--run-copy-paste-friendly)
* 4. [Quick Start - Containers](#quick-start---containers)
    * 4.1. [๐Ÿณ Docker](#-docker)
        * 4.1.1. [1 - Minimum viable run](#1---minimum-viable-run)
        * 4.1.2. [2 - Persist the SQLite database](#2---persist-the-sqlite-database)
        * 4.1.3. [3 - Local tool discovery (host network)](#3---local-tool-discovery-host-network)
    * 4.2. [๐Ÿฆญ Podman (rootless-friendly)](#-podman-rootless-friendly)
        * 4.2.1. [1 - Basic run](#1---basic-run)
        * 4.2.2. [2 - Persist SQLite](#2---persist-sqlite)
        * 4.2.3. [3 - Host networking (rootless)](#3---host-networking-rootless)
* 5. [Testing `mcpgateway.wrapper` by hand](#testing-mcpgatewaywrapper-by-hand)
    * 5.1. [๐Ÿงฉ Running from an MCP Client (`mcpgateway.wrapper`)](#-running-from-an-mcp-client-mcpgatewaywrapper)
        * 5.1.1. [1 - Install `uv` (`uvx` is an alias it provides)](#1---install-uv-uvx-is-an-alias-it-provides)
        * 5.1.2. [2 - Create an on-the-spot venv & run the wrapper](#2---create-an-on-the-spot-venv--run-the-wrapper)
        * 5.1.3. [Claude Desktop JSON (runs through **uvx**)](#claude-desktop-json-runs-through-uvx)
    * 5.2. [๐Ÿš€ Using with Claude Desktop (or any GUI MCP client)](#-using-with-claude-desktop-or-any-gui-mcp-client)
* 6. [๐Ÿš€ Quick Start: VS Code Dev Container](#-quick-start-vs-code-dev-container)
    * 6.1. [1 - Clone & Open](#1---clone--open)
    * 6.2. [2 - First-Time Build (Automatic)](#2---first-time-build-automatic)
* 7. [Quick Start (manual install)](#quick-start-manual-install)
    * 7.1. [Prerequisites](#prerequisites)
    * 7.2. [One-liner (dev)](#one-liner-dev)
    * 7.3. [Containerised (self-signed TLS)](#containerised-self-signed-tls)
    * 7.4. [Smoke-test the API](#smoke-test-the-api)
* 8. [Installation](#installation)
    * 8.1. [Via Make](#via-make)
    * 8.2. [UV (alternative)](#uv-alternative)
    * 8.3. [pip (alternative)](#pip-alternative)
    * 8.4. [Optional (PostgreSQL adapter)](#optional-postgresql-adapter)
        * 8.4.1. [Quick Postgres container](#quick-postgres-container)
* 9. [Configuration (`.env` or env vars)](#configuration-env-or-env-vars)
    * 9.1. [Basic](#basic)
    * 9.2. [Authentication](#authentication)
    * 9.3. [UI Features](#ui-features)
    * 9.4. [Security](#security)
    * 9.5. [Logging](#logging)
    * 9.6. [Transport](#transport)
    * 9.7. [Federation](#federation)
    * 9.8. [Resources](#resources)
    * 9.9. [Tools](#tools)
    * 9.10. [Prompts](#prompts)
    * 9.11. [Health Checks](#health-checks)
    * 9.12. [Database](#database)
    * 9.13. [Cache Backend](#cache-backend)
    * 9.14. [Development](#development)
* 10. [Running](#running)
    * 10.1. [Makefile](#makefile)
    * 10.2. [Script helper](#script-helper)
    * 10.3. [Manual (Uvicorn)](#manual-uvicorn)
* 11. [Authentication examples](#authentication-examples)
* 12. [โ˜๏ธ AWS / Azure / OpenShift](#๏ธ-aws--azure--openshift)
* 13. [โ˜๏ธ IBM Cloud Code Engine Deployment](#๏ธ-ibm-cloud-code-engine-deployment)
    * 13.1. [๐Ÿ”ง Prerequisites](#-prerequisites-1)
    * 13.2. [๐Ÿ“ฆ Environment Variables](#-environment-variables)
    * 13.3. [๐Ÿš€ Make Targets](#-make-targets)
    * 13.4. [๐Ÿ“ Example Workflow](#-example-workflow)
* 14. [API Endpoints](#api-endpoints)
* 15. [Testing](#testing)
* 16. [Project Structure](#project-structure)
* 17. [API Documentation](#api-documentation)
* 18. [Makefile targets](#makefile-targets)
* 19. [๐Ÿ” Troubleshooting](#-troubleshooting)
    * 19.1. [Diagnose the listener](#diagnose-the-listener)
    * 19.2. [Why localhost fails on Windows](#why-localhost-fails-on-windows)
        * 19.2.1. [Fix (Podman rootless)](#fix-podman-rootless)
        * 19.2.2. [Fix (Docker Desktop > 4.19)](#fix-docker-desktop--419)
* 20. [Contributing](#contributing)
* 21. [Changelog](#changelog)
* 22. [License](#license)
* 23. [Core Authors and Maintainers](#core-authors-and-maintainers)
* 24. [Star History and Project Activity](#star-history-and-project-activity)

<!-- vscode-markdown-toc-config
    numbering=true
    autoSave=true
    /vscode-markdown-toc-config -->
<!-- /vscode-markdown-toc -->



## ๐Ÿš€ Overview & Goals

**ContextForge MCP Gateway** is a production-grade gateway, registry, and proxy that sits in front of any [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server or REST API-exposing a unified endpoint for all your AI clients.

It supports:

* Federation across multiple MCP and REST services
* Virtualization of legacy APIs as MCP-compliant tools and servers
* Transport over HTTP, JSON-RPC, WebSocket, SSE, stdio and streamable-HTTP
* An Admin UI for real-time management and configuration
* Built-in auth, observability, retries, and rate-limiting
* Scalable deployments via Docker or PyPI, Redis-backed caching, and multi-cluster federation

![MCP Gateway Architecture](https://ibm.github.io/mcp-context-forge/images/mcpgateway.svg)

For a list of upcoming features, check out the [ContextForge MCP Gateway Roadmap](https://ibm.github.io/mcp-context-forge/architecture/roadmap/)

---

<details>
<summary><strong>๐Ÿ”Œ Gateway Layer with Protocol Flexibility</strong></summary>

* Sits in front of any MCP server or REST API
* Lets you choose your MCP protocol version (e.g., `2025-03-26`)
* Exposes a single, unified interface for diverse backends

</details>

<details>
<summary><strong>๐ŸŒ Federation of Peer Gateways (MCP Registry)</strong></summary>

* Auto-discovers or configures peer gateways (via mDNS or manual)
* Performs health checks and merges remote registries transparently
* Supports Redis-backed syncing and fail-over

</details>

<details>
<summary><strong>๐Ÿงฉ Virtualization of REST/gRPC Services</strong></summary>

* Wraps non-MCP services as virtual MCP servers
* Registers tools, prompts, and resources with minimal configuration

</details>

<details>
<summary><strong>๐Ÿ” REST-to-MCP Tool Adapter</strong></summary>

* Adapts REST APIs into tools with:

  * Automatic JSON Schema extraction
  * Support for headers, tokens, and custom auth
  * Retry, timeout, and rate-limit policies

</details>

<details>
<summary><strong>๐Ÿง  Unified Registries</strong></summary>

* **Prompts**: Jinja2 templates, multimodal support, rollback/versioning
* **Resources**: URI-based access, MIME detection, caching, SSE updates
* **Tools**: Native or adapted, with input validation and concurrency controls

</details>

<details>
<summary><strong>๐Ÿ“ˆ Admin UI, Observability & Dev Experience</strong></summary>

* Admin UI built with HTMX + Alpine.js
* Auth: Basic, JWT, or custom schemes
* Structured logs, health endpoints, metrics
* 400+ tests, Makefile targets, live reload, pre-commit hooks

</details>

---

## Quick Start - PyPI

MCP Gateway is published on [PyPI](https://pypi.org/project/mcp-contextforge-gateway/) as `mcp-contextforge-gateway`.

---

<details>
<summary><strong>๐Ÿ“‹ Prerequisites</strong></summary>

* **Python โ‰ฅ 3.10** (3.11 recommended)
* **curl + jq** - only for the last smoke-test step

</details>

### 1 - Install & run (copy-paste friendly)

```bash
# 1๏ธโƒฃ  Isolated env + install from pypi
mkdir mcpgateway && cd mcpgateway
python3 -m venv .venv && source .venv/bin/activate
pip install --upgrade pip
pip install mcp-contextforge-gateway

# 2๏ธโƒฃ  Launch on all interfaces with custom creds & secret key
# Enable the Admin API endpoints (true/false) - disabled by default
export MCPGATEWAY_UI_ENABLED=true
export MCPGATEWAY_ADMIN_API_ENABLED=true

BASIC_AUTH_PASSWORD=pass JWT_SECRET_KEY=my-test-key \
  mcpgateway --host 0.0.0.0 --port 4444 &   # admin/pass

# 3๏ธโƒฃ  Generate a bearer token & smoke-test the API
export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \
    --username admin --exp 10080 --secret my-test-key)

curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://127.0.0.1:4444/version | jq
```

<details>
<summary><strong>More configuration</strong></summary>

Copy [.env.example](.env.example) to `.env` and tweak any of the settings (or use them as env variables).

</details>

<details>
<summary><strong>๐Ÿš€ End-to-end demo (register a local MCP server)</strong></summary>

```bash
# 1๏ธโƒฃ  Spin up the sample GO MCP time server using mcpgateway.translate & docker
python3 -m mcpgateway.translate \
     --stdio "docker run --rm -i -p 8888:8080 ghcr.io/ibm/fast-time-server:latest -transport=stdio" \
     --port 8003

# Or using the official mcp-server-git using uvx:
pip install uv # to install uvx, if not already installed
python3 -m mcpgateway.translate --stdio "uvx mcp-server-git" --port 9000

# Alternative: running the local binary
# cd mcp-servers/go/fast-time-server; make build
# python3 -m mcpgateway.translate --stdio "./dist/fast-time-server -transport=stdio" --port 8002

# 2๏ธโƒฃ  Register it with the gateway
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"name":"fast_time","url":"http://localhost:9000/sse"}' \
     http://localhost:4444/gateways

# 3๏ธโƒฃ  Verify tool catalog
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/tools | jq

# 4๏ธโƒฃ  Create a *virtual server* bundling those tools. Use the ID of tools from the tool catalog (Step #3) and pass them in the associatedTools list.
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"name":"time_server","description":"Fast time tools","associatedTools":[<ID_OF_TOOLS>]}' \
     http://localhost:4444/servers | jq

# Example curl
curl -s -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN"
     -H "Content-Type: application/json"
     -d '{"name":"time_server","description":"Fast time tools","associatedTools":["6018ca46d32a4ac6b4c054c13a1726a2"]}' \
     http://localhost:4444/servers | jq

# 5๏ธโƒฃ  List servers (should now include the UUID of the newly created virtual server)
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/servers | jq

# 6๏ธโƒฃ  Client SSE endpoint. Inspect it interactively with the MCP Inspector CLI (or use any MCP client)
npx -y @modelcontextprotocol/inspector
# Transport Type: SSE, URL: http://localhost:4444/servers/UUID_OF_SERVER_1/sse,  Header Name: "Authorization", Bearer Token
```

</details>

<details>
<summary><strong>๐Ÿ–ง Using the stdio wrapper (mcpgateway-wrapper)</strong></summary>

```bash
export MCP_AUTH_TOKEN=$MCPGATEWAY_BEARER_TOKEN
export MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1
python3 -m mcpgateway.wrapper  # Ctrl-C to exit
```

You can also run it with `uv` or inside Docker/Podman - see the *Containers* section above.

In MCP Inspector, define `MCP_AUTH_TOKEN` and `MCP_SERVER_CATALOG_URLS` env variables, and select `python3` as the Command, and `-m mcpgateway.wrapper` as Arguments.

```bash
echo $PWD/.venv/bin/python3 # Using the Python3 full path ensures you have a working venv
export MCP_SERVER_CATALOG_URLS='http://localhost:4444/servers/UUID_OF_SERVER_1'
export MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN}
npx -y @modelcontextprotocol/inspector
```

When using a MCP Client such as Claude with stdio:

```json
{
  "mcpServers": {
    "mcpgateway-wrapper": {
      "command": "python",
      "args": ["-m", "mcpgateway.wrapper"],
      "env": {
        "MCP_AUTH_TOKEN": "your-token-here",
        "MCP_SERVER_CATALOG_URLS": "http://localhost:4444/servers/UUID_OF_SERVER_1",
        "MCP_TOOL_CALL_TIMEOUT": "120"
      }
    }
  }
}
```

</details>

---

## Quick Start - Containers

Use the official OCI image from GHCR with **Docker** *or* **Podman**.

---

### ๐Ÿณ Docker

#### 1 - Minimum viable run

```bash
docker run -d --name mcpgateway \
  -p 4444:4444 \
  -e HOST=0.0.0.0 \
  -e JWT_SECRET_KEY=my-test-key \
  -e BASIC_AUTH_USER=admin \
  -e BASIC_AUTH_PASSWORD=changeme \
  -e AUTH_REQUIRED=true \
  -e DATABASE_URL=sqlite:///./mcp.db \
  ghcr.io/ibm/mcp-context-forge:0.3.1

# Tail logs (Ctrl+C to quit)
docker logs -f mcpgateway

# Generating an API key
docker run --rm -it ghcr.io/ibm/mcp-context-forge:0.3.1 \
  python -m mcpgateway.utils.create_jwt_token --username admin --exp 0 --secret my-test-key
```

Browse to **[http://localhost:4444/admin](http://localhost:4444/admin)** (user `admin` / pass `changeme`).

#### 2 - Persist the SQLite database

```bash
mkdir -p $(pwd)/data

touch $(pwd)/data/mcp.db

sudo chown -R :docker $(pwd)/data

chmod 777 $(pwd)/data

docker run -d --name mcpgateway \
  --restart unless-stopped \
  -p 4444:4444 \
  -v $(pwd)/data:/data \
  -e DATABASE_URL=sqlite:////data/mcp.db \
  -e HOST=0.0.0.0 \
  -e JWT_SECRET_KEY=my-test-key \
  -e BASIC_AUTH_USER=admin \
  -e BASIC_AUTH_PASSWORD=changeme \
  ghcr.io/ibm/mcp-context-forge:0.3.1
```

SQLite now lives on the host at `./data/mcp.db`.

#### 3 - Local tool discovery (host network)

```bash
mkdir -p $(pwd)/data

touch $(pwd)/data/mcp.db

sudo chown -R :docker $(pwd)/data

chmod 777 $(pwd)/data

docker run -d --name mcpgateway \
  --network=host \
  -e HOST=0.0.0.0 \
  -e PORT=4444 \
  -e DATABASE_URL=sqlite:////data/mcp.db \
  -v $(pwd)/data:/data \
  ghcr.io/ibm/mcp-context-forge:0.3.1
```

Using `--network=host` allows Docker to access the local network, allowing you to add MCP servers running on your host. See [Docker Host network driver documentation](https://docs.docker.com/engine/network/drivers/host/) for more details.

---

### ๐Ÿฆญ Podman (rootless-friendly)

#### 1 - Basic run

```bash
podman run -d --name mcpgateway \
  -p 4444:4444 \
  -e HOST=0.0.0.0 \
  -e DATABASE_URL=sqlite:///./mcp.db \
  ghcr.io/ibm/mcp-context-forge:0.3.1
```

#### 2 - Persist SQLite

```bash
mkdir -p $(pwd)/data

touch $(pwd)/data/mcp.db

sudo chown -R :docker $(pwd)/data

chmod 777 $(pwd)/data

podman run -d --name mcpgateway \
  --restart=on-failure \
  -p 4444:4444 \
  -v $(pwd)/data:/data \
  -e DATABASE_URL=sqlite:////data/mcp.db \
  ghcr.io/ibm/mcp-context-forge:0.3.1
```

#### 3 - Host networking (rootless)

```bash
mkdir -p $(pwd)/data

touch $(pwd)/data/mcp.db

sudo chown -R :docker $(pwd)/data

chmod 777 $(pwd)/data

podman run -d --name mcpgateway \
  --network=host \
  -v $(pwd)/data:/data \
  -e DATABASE_URL=sqlite:////data/mcp.db \
  ghcr.io/ibm/mcp-context-forge:0.3.1
```

---

<details>
<summary><strong>โœ๏ธ Docker/Podman tips</strong></summary>

* **.env files** - Put all the `-e FOO=` lines into a file and replace them with `--env-file .env`. See the provided [.env.example](.env.example) for reference.
* **Pinned tags** - Use an explicit version (e.g. `v0.3.1`) instead of `latest` for reproducible builds.
* **JWT tokens** - Generate one in the running container:

  ```bash
  docker exec mcpgateway python3 -m mcpgateway.utils.create_jwt_token -u admin -e 10080 --secret my-test-key
  ```
* **Upgrades** - Stop, remove, and rerun with the same `-v $(pwd)/data:/data` mount; your DB and config stay intact.

</details>

---

<details>
<summary><strong>๐Ÿš‘ Smoke-test the running container</strong></summary>

```bash
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/health | jq
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/tools | jq
curl -s -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/version | jq
```

</details>

---

<details>
<summary><strong>๐Ÿ–ง Running the MCP Gateway stdio wrapper</strong></summary>

The `mcpgateway.wrapper` lets you connect to the gateway over **stdio** while keeping JWT authentication. You should run this from the MCP Client. The example below is just for testing.

```bash
# Set environment variables
export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token --username admin --exp 10080 --secret my-test-key)
export MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN}
export MCP_SERVER_CATALOG_URLS='http://localhost:4444/servers/UUID_OF_SERVER_1'
export MCP_TOOL_CALL_TIMEOUT=120
export MCP_WRAPPER_LOG_LEVEL=DEBUG  # or OFF to disable logging

docker run --rm -i \
  -e MCP_AUTH_TOKEN=$MCPGATEWAY_BEARER_TOKEN \
  -e MCP_SERVER_CATALOG_URLS=http://host.docker.internal:4444/servers/UUID_OF_SERVER_1 \
  -e MCP_TOOL_CALL_TIMEOUT=120 \
  -e MCP_WRAPPER_LOG_LEVEL=DEBUG \
  ghcr.io/ibm/mcp-context-forge:0.3.1 \
  python3 -m mcpgateway.wrapper
```

</details>

---

## Testing `mcpgateway.wrapper` by hand:

Because the wrapper speaks JSON-RPC over stdin/stdout, you can interact with it using nothing more than a terminal or pipes.

```bash
# Start the MCP Gateway Wrapper
export MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN}
export MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/YOUR_SERVER_UUID
python3 -m mcpgateway.wrapper
```

<details>
<summary><strong>Initialize the protocol</strong></summary>

```json
# Initialize the protocol
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"demo","version":"0.0.1"}}}

# Then after the reply:
{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}

# Get prompts
{"jsonrpc":"2.0","id":4,"method":"prompts/list"}
{"jsonrpc":"2.0","id":5,"method":"prompts/get","params":{"name":"greeting","arguments":{"user":"Bob"}}}

# Get resources
{"jsonrpc":"2.0","id":6,"method":"resources/list"}
{"jsonrpc":"2.0","id":7,"method":"resources/read","params":{"uri":"https://example.com/some.txt"}}

# Get / call tools
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_system_time","arguments":{"timezone":"Europe/Dublin"}}}
```

</details>

<details>
<summary><strong>Expected responses from mcpgateway.wrapper</strong></summary>

```json
{"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-03-26","capabilities":{"experimental":{},"prompts":{"listChanged":false},"resources":{"subscribe":false,"listChanged":false},"tools":{"listChanged":false}},"serverInfo":{"name":"mcpgateway-wrapper","version":"0.3.0"}}}

# When there's no tools
{"jsonrpc":"2.0","id":2,"result":{"tools":[]}}

# After you add some tools and create a virtual server
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"description":"Convert time between different timezones","inputSchema":{"properties":{"source_timezone":{"description":"Source IANA timezone name","type":"string"},"target_timezone":{"description":"Target IANA timezone name","type":"string"},"time":{"description":"Time to convert in RFC3339 format or common formats like '2006-01-02 15:04:05'","type":"string"}},"required":["time","source_timezone","target_timezone"],"type":"object"},"name":"convert_time"},{"annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false,"openWorldHint":true},"description":"Get current system time in specified timezone","inputSchema":{"properties":{"timezone":{"description":"IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Defaults to UTC","type":"string"}},"type":"object"},"name":"get_system_time"}]}}

# Running the time tool:
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"2025-07-09T00:09:45+01:00"}]}}
```

</details>

### ๐Ÿงฉ Running from an MCP Client (`mcpgateway.wrapper`)

The `mcpgateway.wrapper` exposes everything your Gateway knows about over **stdio**, so any MCP client that *can't* (or *shouldn't*) open an authenticated SSE stream still gets full tool-calling power.

> **Remember** to substitute your real Gateway URL (and server ID) for `http://localhost:4444/servers/UUID_OF_SERVER_1`.
> When inside Docker/Podman, that often becomes `http://host.docker.internal:4444/servers/UUID_OF_SERVER_1` (macOS/Windows) or the gateway container's hostname (Linux).

---

<details>
<summary><strong>๐Ÿณ Docker / Podman</strong></summary>

```bash
docker run -i --rm \
  --network=host \
  -e MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1 \
  -e MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN} \
  -e MCP_TOOL_CALL_TIMEOUT=120 \
  ghcr.io/ibm/mcp-context-forge:0.3.1 \
  python3 -m mcpgateway.wrapper
```

</details>

---

<details>
<summary><strong>๐Ÿ“ฆ pipx (one-liner install &amp; run)</strong></summary>

```bash
# Install gateway package in its own isolated venv
pipx install --include-deps mcp-contextforge-gateway

# Run the stdio wrapper
MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN} \
MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1 \
python3 -m mcpgateway.wrapper
# Alternatively with uv
uv run --directory . -m mcpgateway.wrapper
```

**Claude Desktop JSON** (uses the host Python that pipx injected):

```json
{
  "mcpServers": {
    "mcpgateway-wrapper": {
      "command": "python3",
      "args": ["-m", "mcpgateway.wrapper"],
      "env": {
        "MCP_AUTH_TOKEN": "<your-token>",
        "MCP_SERVER_CATALOG_URLS": "http://localhost:4444/servers/UUID_OF_SERVER_1",
        "MCP_TOOL_CALL_TIMEOUT": "120"
      }
    }
  }
}
```

</details>

---

<details>
<summary><strong>โšก uv / uvx (light-speed venvs)</strong></summary>

#### 1 - Install <code>uv</code>  (<code>uvx</code> is an alias it provides)

```bash
# (a) official one-liner
curl -Ls https://astral.sh/uv/install.sh | sh

# (b) or via pipx
pipx install uv
```

#### 2 - Create an on-the-spot venv & run the wrapper

```bash
# Create venv in ~/.venv/mcpgateway (or current dir if you prefer)
uv venv ~/.venv/mcpgateway
source ~/.venv/mcpgateway/bin/activate

# Install the gateway package using uv
uv pip install mcp-contextforge-gateway

# Launch wrapper
MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN} \
MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1 \
uv run --directory . -m mcpgateway.wrapper # Use this just for testing, as the Client will run the uv command
```

#### Claude Desktop JSON (runs through **uvx**)

```json
{
  "mcpServers": {
    "mcpgateway-wrapper": {
      "command": "uvx",
      "args": [
        "run",
        "--",
        "python",
        "-m",
        "mcpgateway.wrapper"
      ],
      "env": {
        "MCP_AUTH_TOKEN": "<your-token>",
        "MCP_SERVER_CATALOG_URLS": "http://localhost:4444/servers/UUID_OF_SERVER_1"
    }
  }
}
```

</details>

---

### ๐Ÿš€ Using with Claude Desktop (or any GUI MCP client)

1. **Edit Config** โ†’ `File โ–ธ Settings โ–ธ Developer โ–ธ Edit Config`
2. Paste one of the JSON blocks above (Docker / pipx / uvx).
3. Restart the app so the new stdio server is spawned.
4. Open logs in the same menu to verify `mcpgateway-wrapper` started and listed your tools.

Need help? See:

* **MCP Debugging Guide** - [https://modelcontextprotocol.io/docs/tools/debugging](https://modelcontextprotocol.io/docs/tools/debugging)

---

## ๐Ÿš€ Quick Start: VS Code Dev Container

Spin up a fully-loaded dev environment (Python 3.11, Docker/Podman CLI, all project dependencies) in just two clicks.

---

<details>
<summary><strong>๐Ÿ“‹ Prerequisites</strong></summary>

* **VS Code** with the [Dev Containers extension](https://code.visualstudio.com/docs/devcontainers/containers)
* **Docker** or **Podman** installed and running locally

</details>

<details>
<summary><strong>๐Ÿงฐ Setup Instructions</strong></summary>

### 1 - Clone & Open

```bash
git clone https://github.com/ibm/mcp-context-forge.git
cd mcp-context-forge
code .
```

VS Code will detect the `.devcontainer` and prompt:
**"Reopen in Container"**
*or* manually run: <kbd>Ctrl/Cmd โ‡ง P</kbd> โ†’ **Dev Containers: Reopen in Container**

---

### 2 - First-Time Build (Automatic)

The container build will:

* Install system packages & Python 3.11
* Run `make install-dev` to pull all dependencies
* Execute tests to verify the toolchain

You'll land in `/workspace` ready to develop.

</details>

<details>
<summary><strong>๐Ÿ› ๏ธ Daily Developer Workflow</strong></summary>

Common tasks inside the container:

```bash
# Start dev server (hot reload)
make dev            # http://localhost:4444

# Run tests & linters
make test
make lint
```

Optional:

* `make bash` - drop into an interactive shell
* `make clean` - clear build artefacts & caches
* Port forwarding is automatic (customize via `.devcontainer/devcontainer.json`)

</details>

<details>
<summary><strong>โ˜๏ธ GitHub Codespaces: 1-Click Cloud IDE</strong></summary>

No local Docker? Use Codespaces:

1. Go to the repo โ†’ **Code โ–ธ Codespaces โ–ธ Create codespace on main**
2. Wait for the container image to build in the cloud
3. Develop using the same workflow above

</details>

---

## Quick Start (manual install)

### Prerequisites

* **Python โ‰ฅ 3.10**
* **GNU Make** (optional, but all common workflows are available as Make targets)
* Optional: **Docker / Podman** for containerised runs

### One-liner (dev)

```bash
make venv install serve
```

What it does:

1. Creates / activates a `.venv` in your home folder `~/.venv/mcpgateway`
2. Installs the gateway and necessary dependencies
3. Launches **Gunicorn** (Uvicorn workers) on [http://localhost:4444](http://localhost:4444)

For development, you can use:

```bash
make install-dev # Install development dependencies, ex: linters and test harness
make lint          # optional: run style checks (ruff, mypy, etc.)
```

### Containerised (self-signed TLS)


> You can use docker or podman, ex:

```bash
make podman            # build production image
make podman-run-ssl    # run at https://localhost:4444
# or listen on port 4444 on your host directly, adds --network=host to podman
make podman-run-ssl-host
```

### Smoke-test the API

```bash
curl -k -sX GET \
     -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     https://localhost:4444/tools | jq
```

You should receive `[]` until you register a tool.

---

## Installation

### Via Make

```bash
make venv install          # create .venv + install deps
make serve                 # gunicorn on :4444
```

### UV (alternative)

```bash
uv venv && source .venv/bin/activate
uv pip install -e '.[dev]' # IMPORTANT: in zsh, quote to disable glob expansion!
```

### pip (alternative)

```bash
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
```

### Optional (PostgreSQL adapter)

You can configure the gateway with SQLite, PostgreSQL (or any other compatible database) in .env.

When using PostgreSQL, you need to install `psycopg2` driver.

```bash
uv pip install psycopg2-binary   # dev convenience
# or
uv pip install psycopg2          # production build
```

#### Quick Postgres container

```bash
docker run --name mcp-postgres \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_PASSWORD=mysecretpassword \
  -e POSTGRES_DB=mcp \
  -p 5432:5432 -d postgres
```

A `make compose-up` target is provided along with a [docker-compose.yml](docker-compose.yml) file to make this process simpler.

---

## Configuration (`.env` or env vars)

> โš ๏ธ If any required `.env` variable is missing or invalid, the gateway will fail fast at startup with a validation error via Pydantic.

You can get started by copying the provided [.env.example](.env.example) to `.env` and making the necessary edits to fit your environment.

<details>
<summary><strong>๐Ÿ”ง Environment Configuration Variables</strong></summary>

### Basic

| Setting         | Description                              | Default                | Options                |
| --------------- | ---------------------------------------- | ---------------------- | ---------------------- |
| `APP_NAME`      | Gateway / OpenAPI title                  | `MCP Gateway`          | string                 |
| `HOST`          | Bind address for the app                 | `0.0.0.0`              | IPv4/IPv6              |
| `PORT`          | Port the server listens on               | `4444`                 | 1-65535                |
| `DATABASE_URL`  | SQLAlchemy connection URL                | `sqlite:///./mcp.db`   | any SQLAlchemy dialect |
| `APP_ROOT_PATH` | Subpath prefix for app (e.g. `/gateway`) | (empty)                | string                 |
| `TEMPLATES_DIR` | Path to Jinja2 templates                 | `mcpgateway/templates` | path                   |
| `STATIC_DIR`    | Path to static files                     | `mcpgateway/static`    | path                   |

> ๐Ÿ’ก Use `APP_ROOT_PATH=/foo` if reverse-proxying under a subpath like `https://host.com/foo/`.

### Authentication

| Setting               | Description                                                      | Default       | Options    |
| --------------------- | ---------------------------------------------------------------- | ------------- | ---------- |
| `BASIC_AUTH_USER`     | Username for Admin UI login and HTTP Basic authentication        | `admin`       | string     |
| `BASIC_AUTH_PASSWORD` | Password for Admin UI login and HTTP Basic authentication        | `changeme`    | string     |
| `AUTH_REQUIRED`       | Require authentication for all API routes                        | `true`        | bool       |
| `JWT_SECRET_KEY`      | Secret key used to **sign JWT tokens** for API access            | `my-test-key` | string     |
| `JWT_ALGORITHM`       | Algorithm used to sign the JWTs (`HS256` is default, HMAC-based) | `HS256`       | PyJWT algs |
| `TOKEN_EXPIRY`        | Expiry of generated JWTs in minutes                              | `10080`       | int > 0    |
| `AUTH_ENCRYPTION_SECRET` | Passphrase used to derive AES key for encrypting tool auth headers | `my-test-salt` | string |

> ๐Ÿ” `BASIC_AUTH_USER`/`PASSWORD` are used for:
>
> * Logging into the web-based Admin UI
> * Accessing APIs via Basic Auth (`curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN"`)
>
> ๐Ÿ”‘ `JWT_SECRET_KEY` is used to:
>
> * Sign JSON Web Tokens (`Authorization: Bearer <token>`)
> * Generate tokens via:
>
>   ```bash
>   export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token --username admin --exp 0 --secret my-test-key)
>   echo $MCPGATEWAY_BEARER_TOKEN
>   ```
> * Tokens allow non-interactive API clients to authenticate securely.
>
> ๐Ÿงช Set `AUTH_REQUIRED=false` during development if you want to disable all authentication (e.g. for local testing or open APIs) or clients that don't support SSE authentication.
> In production, you should use the SSE to stdio `mcpgateway-wrapper` for such tools that don't support authenticated SSE, while still ensuring the gateway uses authentication.
>
> ๐Ÿ” `AUTH_ENCRYPTION_SECRET` is used to encrypt and decrypt tool authentication credentials (`auth_value`).
> You must set the same value across environments to decode previously stored encrypted auth values.
> Recommended: use a long, random string.

### UI Features

| Setting                        | Description                            | Default | Options |
| ------------------------------ | -------------------------------------- | ------- | ------- |
| `MCPGATEWAY_UI_ENABLED`        | Enable the interactive Admin dashboard | `true`  | bool    |
| `MCPGATEWAY_ADMIN_API_ENABLED` | Enable API endpoints for admin ops     | `true`  | bool    |

> ๐Ÿ–ฅ๏ธ Set both to `false` to disable management UI and APIs in production.

### Security

| Setting           | Description                    | Default                                        | Options    |
| ----------------- | ------------------------------ | ---------------------------------------------- | ---------- |
| `SKIP_SSL_VERIFY` | Skip upstream TLS verification | `false`                                        | bool       |
| `ALLOWED_ORIGINS` | CORS allow-list                | `["http://localhost","http://localhost:4444"]` | JSON array |
| `CORS_ENABLED`    | Enable CORS                    | `true`                                         | bool       |

> Note: do not quote the ALLOWED_ORIGINS values, this needs to be valid JSON, such as: `ALLOWED_ORIGINS=["http://localhost", "http://localhost:4444"]`

### Logging

| Setting      | Description       | Default | Options            |
| ------------ | ----------------- | ------- | ------------------ |
| `LOG_LEVEL`  | Minimum log level | `INFO`  | `DEBUG`...`CRITICAL` |
| `LOG_FORMAT` | Log format        | `json`  | `json`, `text`     |
| `LOG_FILE`   | Log output file   | (none)  | path or empty      |

### Transport

| Setting                   | Description                        | Default | Options                         |
| ------------------------- | ---------------------------------- | ------- | ------------------------------- |
| `TRANSPORT_TYPE`          | Enabled transports                 | `all`   | `http`,`ws`,`sse`,`stdio`,`all` |
| `WEBSOCKET_PING_INTERVAL` | WebSocket ping (secs)              | `30`    | int > 0                         |
| `SSE_RETRY_TIMEOUT`       | SSE retry timeout (ms)             | `5000`  | int > 0                         |
| `USE_STATEFUL_SESSIONS`   | streamable http config             | `false` | bool                            |
| `JSON_RESPONSE_ENABLED`   | json/sse streams (streamable http) | `true`  | bool                            |

### Federation

| Setting                    | Description            | Default | Options    |
| -------------------------- | ---------------------- | ------- | ---------- |
| `FEDERATION_ENABLED`       | Enable federation      | `true`  | bool       |
| `FEDERATION_DISCOVERY`     | Auto-discover peers    | `false` | bool       |
| `FEDERATION_PEERS`         | Comma-sep peer URLs    | `[]`    | JSON array |
| `FEDERATION_TIMEOUT`       | Gateway timeout (secs) | `30`    | int > 0    |
| `FEDERATION_SYNC_INTERVAL` | Sync interval (secs)   | `300`   | int > 0    |

### Resources

| Setting               | Description           | Default    | Options    |
| --------------------- | --------------------- | ---------- | ---------- |
| `RESOURCE_CACHE_SIZE` | LRU cache size        | `1000`     | int > 0    |
| `RESOURCE_CACHE_TTL`  | Cache TTL (seconds)   | `3600`     | int > 0    |
| `MAX_RESOURCE_SIZE`   | Max resource bytes    | `10485760` | int > 0    |
| `ALLOWED_MIME_TYPES`  | Acceptable MIME types | see code   | JSON array |

### Tools

| Setting                 | Description                    | Default | Options |
| ----------------------- | ------------------------------ | ------- | ------- |
| `TOOL_TIMEOUT`          | Tool invocation timeout (secs) | `60`    | int > 0 |
| `MAX_TOOL_RETRIES`      | Max retry attempts             | `3`     | int โ‰ฅ 0 |
| `TOOL_RATE_LIMIT`       | Tool calls per minute          | `100`   | int > 0 |
| `TOOL_CONCURRENT_LIMIT` | Concurrent tool invocations    | `10`    | int > 0 |

### Prompts

| Setting                 | Description                      | Default  | Options |
| ----------------------- | -------------------------------- | -------- | ------- |
| `PROMPT_CACHE_SIZE`     | Cached prompt templates          | `100`    | int > 0 |
| `MAX_PROMPT_SIZE`       | Max prompt template size (bytes) | `102400` | int > 0 |
| `PROMPT_RENDER_TIMEOUT` | Jinja render timeout (secs)      | `10`     | int > 0 |

### Health Checks

| Setting                 | Description                               | Default | Options |
| ----------------------- | ----------------------------------------- | ------- | ------- |
| `HEALTH_CHECK_INTERVAL` | Health poll interval (secs)               | `60`    | int > 0 |
| `HEALTH_CHECK_TIMEOUT`  | Health request timeout (secs)             | `10`    | int > 0 |
| `UNHEALTHY_THRESHOLD`   | Fail-count before peer deactivation,      | `3`     | int > 0 |
|                         | Set to -1 if deactivation is not needed.  |         |         |

### Database

| Setting                 | Description                     | Default | Options |
| ----------------------- | ------------------------------- | ------- | ------- |
| `DB_POOL_SIZE`   .      | SQLAlchemy connection pool size | `200`   | int > 0 |
| `DB_MAX_OVERFLOW`.      | Extra connections beyond pool   | `10`    | int โ‰ฅ 0 |
| `DB_POOL_TIMEOUT`.      | Wait for connection (secs)      | `30`    | int > 0 |
| `DB_POOL_RECYCLE`.      | Recycle connections (secs)      | `3600`  | int > 0 |
| `DB_MAX_RETRIES` .      | Max Retry Attempts              | `3`     | int > 0 |
| `DB_RETRY_INTERVAL_MS`  | Retry Interval (ms)             | `2000`  | int > 0 |

### Cache Backend

| Setting                   | Description                | Default  | Options                  |
| ------------------------- | -------------------------- | -------- | ------------------------ |
| `CACHE_TYPE`              | Backend (`memory`/`redis`) | `memory` | `none`, `memory`,`redis` |
| `REDIS_URL`               | Redis connection URL       | (none)   | string or empty          |
| `CACHE_PREFIX`            | Key prefix                 | `mcpgw:` | string                   |
| `REDIS_MAX_RETRIES`       | Max Retry Attempts         | `3`      | int > 0                  |
| `REDIS_RETRY_INTERVAL_MS` | Retry Interval (ms)        | `2000`   | int > 0                  |

> ๐Ÿง  `none` disables caching entirely. Use `memory` for dev, `database` for persistence, or `redis` for distributed caching.

### Development

| Setting    | Description            | Default | Options |
| ---------- | ---------------------- | ------- | ------- |
| `DEV_MODE` | Enable dev mode        | `false` | bool    |
| `RELOAD`   | Auto-reload on changes | `false` | bool    |
| `DEBUG`    | Debug logging          | `false` | bool    |

</details>

---

## Running

### Makefile

```bash
 make serve               # Run production Gunicorn server on
 make serve-ssl           # Run Gunicorn behind HTTPS on :4444 (uses ./certs)
```

### Script helper

To run the development (uvicorn) server:

```bash
make dev
# or
./run.sh --reload --log debug --workers 2
```

> `run.sh` is a wrapper around `uvicorn` that loads `.env`, supports reload, and passes arguments to the server.

Key flags:

| Flag             | Purpose          | Example            |
| ---------------- | ---------------- | ------------------ |
| `-e, --env FILE` | load env-file    | `--env prod.env`   |
| `-H, --host`     | bind address     | `--host 127.0.0.1` |
| `-p, --port`     | listen port      | `--port 8080`      |
| `-w, --workers`  | gunicorn workers | `--workers 4`      |
| `-r, --reload`   | auto-reload      | `--reload`         |

### Manual (Uvicorn)

```bash
uvicorn mcpgateway.main:app --host 0.0.0.0 --port 4444 --workers 4
```

---

## Authentication examples

```bash
# Generate a JWT token using JWT_SECRET_KEY and export it as MCPGATEWAY_BEARER_TOKEN
# Note that the module needs to be installed. If running locally use:
export MCPGATEWAY_BEARER_TOKEN=$(JWT_SECRET_KEY=my-test-key python3 -m mcpgateway.utils.create_jwt_token)

# Use the JWT token in an API call
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/tools
```

---

## โ˜๏ธ AWS / Azure / OpenShift

Deployment details can be found in the GitHub Pages.

## โ˜๏ธ IBM Cloud Code Engine Deployment

This project supports deployment to [IBM Cloud Code Engine](https://cloud.ibm.com/codeengine) using the **ibmcloud** CLI and the IBM Container Registry.

<details>
<summary><strong>โ˜๏ธ IBM Cloud Code Engine Deployment</strong></summary>

### ๐Ÿ”ง Prerequisites

- Podman **or** Docker installed locally
- IBM Cloud CLI (use `make ibmcloud-cli-install` to install)
- An [IBM Cloud API key](https://cloud.ibm.com/iam/apikeys) with access to Code Engine & Container Registry
- Code Engine and Container Registry services **enabled** in your IBM Cloud account

---

### ๐Ÿ“ฆ Environment Variables

Create a **`.env`** file (or export the variables in your shell).
The first block is **required**; the second provides **tunable defaults** you can override:

```bash
# โ”€โ”€ Required โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
IBMCLOUD_REGION=us-south
IBMCLOUD_RESOURCE_GROUP=default
IBMCLOUD_PROJECT=my-codeengine-project
IBMCLOUD_CODE_ENGINE_APP=mcpgateway
IBMCLOUD_IMAGE_NAME=us.icr.io/myspace/mcpgateway:latest
IBMCLOUD_IMG_PROD=mcpgateway/mcpgateway
IBMCLOUD_API_KEY=your_api_key_here   # Optional - omit to use interactive `ibmcloud login --sso`

# โ”€โ”€ Optional overrides (sensible defaults provided) โ”€โ”€โ”€โ”€โ”€โ”€
IBMCLOUD_CPU=1                       # vCPUs for the app
IBMCLOUD_MEMORY=4G                   # Memory allocation
IBMCLOUD_REGISTRY_SECRET=my-regcred  # Name of the Container Registry secret
```

> โœ… **Quick check:** `make ibmcloud-check-env`

---

### ๐Ÿš€ Make Targets

| Target                      | Purpose                                                                   |
| --------------------------- | ------------------------------------------------------------------------- |
| `make ibmcloud-cli-install` | Install IBM Cloud CLI and required plugins                                |
| `make ibmcloud-login`       | Log in to IBM Cloud (API key or SSO)                                      |
| `make ibmcloud-ce-login`    | Select the Code Engine project & region                                   |
| `make ibmcloud-tag`         | Tag the local container image                                             |
| `make ibmcloud-push`        | Push the image to IBM Container Registry                                  |
| `make ibmcloud-deploy`      | **Create or update** the Code Engine application (uses CPU/memory/secret) |
| `make ibmcloud-ce-status`   | Show current deployment status                                            |
| `make ibmcloud-ce-logs`     | Stream logs from the running app                                          |
| `make ibmcloud-ce-rm`       | Delete the Code Engine application                                        |

---

### ๐Ÿ“ Example Workflow

```bash
make ibmcloud-check-env
make ibmcloud-cli-install
make ibmcloud-login
make ibmcloud-ce-login
make ibmcloud-tag
make ibmcloud-push
make ibmcloud-deploy
make ibmcloud-ce-status
make ibmcloud-ce-logs
```

</details>

---

## API Endpoints

You can test the API endpoints through curl, or Swagger UI, and check detailed documentation on ReDoc:

* **Swagger UI** โ†’ [http://localhost:4444/docs](http://localhost:4444/docs)
* **ReDoc**    โ†’ [http://localhost:4444/redoc](http://localhost:4444/redoc)

Generate an API Bearer token, and test the various API endpoints.

<details>
<summary><strong>๐Ÿ” Authentication & Health Checks</strong></summary>

```bash
# Generate a bearer token using the configured secret key (use the same as your .env)
export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token -u admin --secret my-test-key)
echo ${MCPGATEWAY_BEARER_TOKEN}

# Quickly confirm that authentication works and the gateway is healthy
curl -s -k -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" https://localhost:4444/health
# {"status":"healthy"}

# Quickly confirm the gateway version & DB connectivity
curl -s -k -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" https://localhost:4444/version | jq
```

</details>

---

<details>
<summary><strong>๐Ÿงฑ Protocol APIs (MCP) /protocol</strong></summary>

```bash
# Initialize MCP session
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
           "protocol_version":"2025-03-26",
           "capabilities":{},
           "client_info":{"name":"MyClient","version":"1.0.0"}
         }' \
     http://localhost:4444/protocol/initialize

# Ping (JSON-RPC style)
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":1,"method":"ping"}' \
     http://localhost:4444/protocol/ping

# Completion for prompt/resource arguments (not implemented)
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
           "ref":{"type":"ref/prompt","name":"example_prompt"},
           "argument":{"name":"topic","value":"py"}
         }' \
     http://localhost:4444/protocol/completion/complete

# Sampling (streaming) (not implemented)
curl -N -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
           "messages":[{"role":"user","content":{"type":"text","text":"Hello"}}],
           "maxTokens":16
         }' \
     http://localhost:4444/protocol/sampling/createMessage
```

</details>

---

<details>
<summary><strong>๐Ÿง  JSON-RPC Utility /rpc</strong></summary>

```bash
# Generic JSON-RPC calls (tools, gateways, roots, etc.)
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":1,"method":"list_tools"}' \
     http://localhost:4444/rpc
```

Handles any method name: `list_tools`, `list_gateways`, `prompts/get`, or invokes a tool if method matches a registered tool name .

</details>

---

<details>
<summary><strong>๐Ÿ”ง Tool Management /tools</strong></summary>


```bash
# Register a new tool
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
           "name":"clock_tool",
           "url":"http://localhost:9000/rpc",
           "description":"Returns current time",
           "input_schema":{
             "type":"object",
             "properties":{"timezone":{"type":"string"}},
             "required":[]
           }
         }' \
     http://localhost:4444/tools

# List tools
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/tools

# Get tool by ID
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/tools/1

# Update tool
curl -X PUT -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{ "description":"Updated desc" }' \
     http://localhost:4444/tools/1

# Toggle active status
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/tools/1/toggle?activate=false
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/tools/1/toggle?activate=true

# Delete tool
curl -X DELETE -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/tools/1
```

</details>

---

<details>
<summary><strong>๐ŸŒ Gateway Management /gateways</strong></summary>

```bash
# Register an MCP server as a new gateway provider
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"name":"peer_gateway","url":"http://peer:4444"}' \
     http://localhost:4444/gateways

# List gateways
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/gateways

# Get gateway by ID
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/gateways/1

# Update gateway
curl -X PUT -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"description":"New description"}' \
     http://localhost:4444/gateways/1

# Toggle active status
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/gateways/1/toggle?activate=false

# Delete gateway
curl -X DELETE -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/gateways/1
```

</details>

---

<details>
<summary><strong>๐Ÿ“ Resource Management /resources</strong></summary>


```bash
# Register resource
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
           "uri":"config://app/settings",
           "name":"App Settings",
           "content":"key=value"
         }' \
     http://localhost:4444/resources

# List resources
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/resources

# Read a resource
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/resources/config://app/settings

# Update resource
curl -X PUT -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"content":"new=value"}' \
     http://localhost:4444/resources/config://app/settings

# Delete resource
curl -X DELETE -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/resources/config://app/settings

# Subscribe to updates (SSE)
curl -N -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/resources/subscribe/config://app/settings
```

</details>

---

<details>
<summary><strong>๐Ÿ“ Prompt Management /prompts</strong></summary>

```bash
# Create prompt template
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
           "name":"greet",
           "template":"Hello, {{ user }}!",
           "argument_schema":{
             "type":"object",
             "properties":{"user":{"type":"string"}},
             "required":["user"]
           }
         }' \
     http://localhost:4444/prompts

# List prompts
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/prompts

# Get prompt (with args)
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"user":"Alice"}' \
     http://localhost:4444/prompts/greet

# Get prompt (no args)
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/prompts/greet

# Update prompt
curl -X PUT -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"template":"Hi, {{ user }}!"}' \
     http://localhost:4444/prompts/greet

# Toggle active
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/prompts/5/toggle?activate=false

# Delete prompt
curl -X DELETE -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/prompts/greet
```

</details>

---

<details>
<summary><strong>๐ŸŒฒ Root Management /roots</strong></summary>

```bash
# List roots
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/roots

# Add root
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"uri":"/data","name":"Data Root"}' \
     http://localhost:4444/roots

# Remove root
curl -X DELETE -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/roots/%2Fdata

# Subscribe to root changes (SSE)
curl -N -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/roots/changes
```

</details>

---

<details>
<summary><strong>๐Ÿ–ฅ๏ธ Server Management /servers</strong></summary>

```bash
# List servers
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/servers

# Get server
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/servers/UUID_OF_SERVER_1

# Create server
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"name":"db","description":"Database","associatedTools": ["1","2","3"]}' \
     http://localhost:4444/servers

# Update server
curl -X PUT -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"description":"Updated"}' \
     http://localhost:4444/servers/UUID_OF_SERVER_1

# Toggle active
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" \
     http://localhost:4444/servers/UUID_OF_SERVER_1/toggle?activate=false
```

</details>

---

<details>
<summary><strong>๐Ÿ“Š Metrics /metrics</strong></summary>

```bash
# Get aggregated metrics
curl -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/metrics

# Reset metrics (all or per-entity)
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/metrics/reset
curl -X POST -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/metrics/reset?entity=tool&id=1
```

</details>

---

<details>
<summary><strong>๐Ÿ“ก Events & Health</strong></summary>

```bash
# SSE: all events
curl -N -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN" http://localhost:4444/events

# WebSocket
wscat -c ws://localhost:4444/ws \
      -H "Authorization: Basic $(echo -n admin:changeme|base64)"

# Health check
curl http://localhost:4444/health
```

Full Swagger UI at `/docs`.

</details>

---

<details>
<summary><strong>๐Ÿ› ๏ธ Sample Tool</strong></summary>

```bash
uvicorn sample_tool.clock_tool:app --host 0.0.0.0 --port 9000
```

```bash
curl -X POST -H "Content-Type: application/json" \
     -d '{"jsonrpc":"2.0","id":1,"method":"get_time","params":{"timezone":"UTC"}}' \
     http://localhost:9000/rpc
```

</details>

---

## Testing

```bash
make test            # Run unit tests
make lint            # Run lint tools
```

---

## Project Structure

<details>
<summary><strong>๐Ÿ“ Directory and file structure for mcpgateway</strong></summary>

```bash
# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ CI / Quality & Meta-files โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ .bumpversion.cfg                # Automated semantic-version bumps
โ”œโ”€โ”€ .coveragerc                     # Coverage.py settings
โ”œโ”€โ”€ .darglint                       # Doc-string linter rules
โ”œโ”€โ”€ .dockerignore                   # Context exclusions for image builds
โ”œโ”€โ”€ .editorconfig                   # Consistent IDE / editor behaviour
โ”œโ”€โ”€ .env                            # Local runtime variables (git-ignored)
โ”œโ”€โ”€ .env.ce                         # IBM Code Engine runtime env (ignored)
โ”œโ”€โ”€ .env.ce.example                 # Sample env for IBM Code Engine
โ”œโ”€โ”€ .env.example                    # Generic sample env file
โ”œโ”€โ”€ .env.gcr                        # Google Cloud Run runtime env (ignored)
โ”œโ”€โ”€ .eslintrc.json                  # ESLint rules for JS / TS assets
โ”œโ”€โ”€ .flake8                         # Flake-8 configuration
โ”œโ”€โ”€ .gitattributes                  # Git attributes (e.g. EOL normalisation)
โ”œโ”€โ”€ .github                         # GitHub settings, CI/CD workflows & templates
โ”‚   โ”œโ”€โ”€ CODEOWNERS                  # Default reviewers
โ”‚   โ””โ”€โ”€ workflows/                  # Bandit, Docker, CodeQL, Python Package, Container Deployment, etc.
โ”œโ”€โ”€ .gitignore                      # Git exclusion rules
โ”œโ”€โ”€ .hadolint.yaml                  # Hadolint rules for Dockerfiles
โ”œโ”€โ”€ .htmlhintrc                     # HTMLHint rules
โ”œโ”€โ”€ .markdownlint.json              # Markdown-lint rules
โ”œโ”€โ”€ .pre-commit-config.yaml         # Pre-commit hooks (ruff, black, mypy, ...)
โ”œโ”€โ”€ .pycodestyle                    # PEP-8 checker settings
โ”œโ”€โ”€ .pylintrc                       # Pylint configuration
โ”œโ”€โ”€ .pyspelling.yml                 # Spell-checker dictionary & filters
โ”œโ”€โ”€ .ruff.toml                      # Ruff linter / formatter settings
โ”œโ”€โ”€ .spellcheck-en.txt              # Extra dictionary entries
โ”œโ”€โ”€ .stylelintrc.json               # Stylelint rules for CSS
โ”œโ”€โ”€ .travis.yml                     # Legacy Travis CI config (reference)
โ”œโ”€โ”€ .whitesource                    # WhiteSource security-scanning config
โ”œโ”€โ”€ .yamllint                       # yamllint ruleset

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Documentation & Guidance โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ CHANGELOG.md                    # Version-by-version change log
โ”œโ”€โ”€ CODE_OF_CONDUCT.md              # Community behaviour guidelines
โ”œโ”€โ”€ CONTRIBUTING.md                 # How to file issues & send PRs
โ”œโ”€โ”€ DEVELOPING.md                   # Contributor workflows & style guide
โ”œโ”€โ”€ LICENSE                         # Apache License 2.0
โ”œโ”€โ”€ README.md                       # Project overview & quick-start
โ”œโ”€โ”€ SECURITY.md                     # Security policy & CVE disclosure process
โ”œโ”€โ”€ TESTING.md                      # Testing strategy, fixtures & guidelines

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Containerisation & Runtime โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ Containerfile                   # OCI image build (Docker / Podman)
โ”œโ”€โ”€ Containerfile.lite              # FROM scratch UBI-Micro production build
โ”œโ”€โ”€ docker-compose.yml              # Local multi-service stack
โ”œโ”€โ”€ podman-compose-sonarqube.yaml   # One-liner SonarQube stack
โ”œโ”€โ”€ run-gunicorn.sh                 # Opinionated Gunicorn startup script
โ”œโ”€โ”€ run.sh                          # Uvicorn shortcut with arg parsing

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Build / Packaging / Tooling โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ MANIFEST.in                     # sdist inclusion rules
โ”œโ”€โ”€ Makefile                        # Dev & deployment targets
โ”œโ”€โ”€ package-lock.json               # Deterministic npm lock-file
โ”œโ”€โ”€ package.json                    # Front-end / docs tooling deps
โ”œโ”€โ”€ pyproject.toml                  # Poetry / PDM config & lint rules
โ”œโ”€โ”€ sonar-code.properties           # SonarQube analysis settings
โ”œโ”€โ”€ uv.lock                         # UV resolver lock-file

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Kubernetes & Helm Assets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ charts                          # Helm chart(s) for K8s / OpenShift
โ”‚   โ”œโ”€โ”€ mcp-stack                   # Umbrella chart
โ”‚   โ”‚   โ”œโ”€โ”€ Chart.yaml              # Chart metadata
โ”‚   โ”‚   โ”œโ”€โ”€ templates/...             # Manifest templates
โ”‚   โ”‚   โ””โ”€โ”€ values.yaml             # Default values
โ”‚   โ””โ”€โ”€ README.md                   # Install / upgrade guide
โ”œโ”€โ”€ k8s                             # Raw (non-Helm) K8s manifests
โ”‚   โ””โ”€โ”€ *.yaml                      # Deployment, Service, PVC resources

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Documentation Source โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ docs                            # MkDocs site source
โ”‚   โ”œโ”€โ”€ base.yml                    # MkDocs "base" configuration snippet (do not modify)
โ”‚   โ”œโ”€โ”€ mkdocs.yml                  # Site configuration (requires base.yml)
โ”‚   โ”œโ”€โ”€ requirements.txt            # Python dependencies for the MkDocs site
โ”‚   โ”œโ”€โ”€ Makefile                    # Make targets for building/serving the docs
โ”‚   โ””โ”€โ”€ theme                       # Custom MkDocs theme assets
โ”‚       โ””โ”€โ”€ logo.png                # Logo for the documentation theme
โ”‚   โ””โ”€โ”€ docs                        # Markdown documentation
โ”‚       โ”œโ”€โ”€ architecture/           # ADRs for the project
โ”‚       โ”œโ”€โ”€ articles/               # Long-form writeups
โ”‚       โ”œโ”€โ”€ blog/                   # Blog posts
โ”‚       โ”œโ”€โ”€ deployment/             # Deployment guides (AWS, Azure, etc.)
โ”‚       โ”œโ”€โ”€ development/            # Development workflows & CI docs
โ”‚       โ”œโ”€โ”€ images/                 # Diagrams & screenshots
โ”‚       โ”œโ”€โ”€ index.md                # Top-level docs landing page
โ”‚       โ”œโ”€โ”€ manage/                 # Management topics (backup, logging, tuning, upgrade)
โ”‚       โ”œโ”€โ”€ overview/               # Feature overviews & UI documentation
โ”‚       โ”œโ”€โ”€ security/               # Security guidance & policies
โ”‚       โ”œโ”€โ”€ testing/                # Testing strategy & fixtures
โ”‚       โ””โ”€โ”€ using/                  # User-facing usage guides (agents, clients, etc.)
โ”‚       โ”œโ”€โ”€ media/                  # Social media, press coverage, videos & testimonials
โ”‚       โ”‚   โ”œโ”€โ”€ press/              # Press articles and blog posts
โ”‚       โ”‚   โ”œโ”€โ”€ social/             # Tweets, LinkedIn posts, YouTube embeds
โ”‚       โ”‚   โ”œโ”€โ”€ testimonials/       # Customer quotes & community feedback
โ”‚       โ”‚   โ””โ”€โ”€ kit/                # Media kit & logos for bloggers & press
โ”œโ”€โ”€ dictionary.dic                  # Custom dictionary for spell-checker (make spellcheck)

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Application & Libraries โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ agent_runtimes                  # Configurable agentic frameworks converted to MCP Servers
โ”œโ”€โ”€ mcpgateway                      # โ† main application package
โ”‚   โ”œโ”€โ”€ __init__.py                 # Package metadata & version constant
โ”‚   โ”œโ”€โ”€ admin.py                    # FastAPI routers for Admin UI
โ”‚   โ”œโ”€โ”€ cache
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ”œโ”€โ”€ resource_cache.py       # LRU+TTL cache implementation
โ”‚   โ”‚   โ””โ”€โ”€ session_registry.py     # Session โ†” cache mapping
โ”‚   โ”œโ”€โ”€ config.py                   # Pydantic settings loader
โ”‚   โ”œโ”€โ”€ db.py                       # SQLAlchemy models & engine setup
โ”‚   โ”œโ”€โ”€ federation
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ”œโ”€โ”€ discovery.py            # Peer-gateway discovery
โ”‚   โ”‚   โ”œโ”€โ”€ forward.py              # RPC forwarding
โ”‚   โ”œโ”€โ”€ handlers
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ””โ”€โ”€ sampling.py             # Streaming sampling handler
โ”‚   โ”œโ”€โ”€ main.py                     # FastAPI app factory & startup events
โ”‚   โ”œโ”€โ”€ mcp.db                      # SQLite fixture for tests
โ”‚   โ”œโ”€โ”€ py.typed                    # PEP 561 marker (ships type hints)
โ”‚   โ”œโ”€โ”€ schemas.py                  # Shared Pydantic DTOs
โ”‚   โ”œโ”€โ”€ services
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ”œโ”€โ”€ completion_service.py   # Prompt / argument completion
โ”‚   โ”‚   โ”œโ”€โ”€ gateway_service.py      # Peer-gateway registry
โ”‚   โ”‚   โ”œโ”€โ”€ logging_service.py      # Central logging helpers
โ”‚   โ”‚   โ”œโ”€โ”€ prompt_service.py       # Prompt CRUD & rendering
โ”‚   โ”‚   โ”œโ”€โ”€ resource_service.py     # Resource registration & retrieval
โ”‚   โ”‚   โ”œโ”€โ”€ root_service.py         # File-system root registry
โ”‚   โ”‚   โ”œโ”€โ”€ server_service.py       # Server registry & monitoring
โ”‚   โ”‚   โ””โ”€โ”€ tool_service.py         # Tool registry & invocation
โ”‚   โ”œโ”€โ”€ static
โ”‚   โ”‚   โ”œโ”€โ”€ admin.css               # Styles for Admin UI
โ”‚   โ”‚   โ””โ”€โ”€ admin.js                # Behaviour for Admin UI
โ”‚   โ”œโ”€โ”€ templates
โ”‚   โ”‚   โ””โ”€โ”€ admin.html              # HTMX/Alpine Admin UI template
โ”‚   โ”œโ”€โ”€ transports
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ”œโ”€โ”€ base.py                 # Abstract transport interface
โ”‚   โ”‚   โ”œโ”€โ”€ sse_transport.py        # Server-Sent Events transport
โ”‚   โ”‚   โ”œโ”€โ”€ stdio_transport.py      # stdio transport for embedding
โ”‚   โ”‚   โ””โ”€โ”€ websocket_transport.py  # WS transport with ping/pong
โ”‚   โ”œโ”€โ”€ models.py                   # Core enums / type aliases
โ”‚   โ”œโ”€โ”€ utils
โ”‚   โ”‚   โ”œโ”€โ”€ create_jwt_token.py     # CLI & library for JWT generation
โ”‚   โ”‚   โ”œโ”€โ”€ services_auth.py        # Service-to-service auth dependency
โ”‚   โ”‚   โ””โ”€โ”€ verify_credentials.py   # Basic / JWT auth helpers
โ”‚   โ”œโ”€โ”€ validation
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ””โ”€โ”€ jsonrpc.py              # JSON-RPC 2.0 validation
โ”‚   โ””โ”€โ”€ version.py                  # Library version helper
โ”œโ”€โ”€ mcpgateway-wrapper              # Stdio client wrapper (PyPI)
โ”‚   โ”œโ”€โ”€ pyproject.toml
โ”‚   โ”œโ”€โ”€ README.md
โ”‚   โ””โ”€โ”€ src/mcpgateway_wrapper/
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ””โ”€โ”€ server.py               # Wrapper entry-point
โ”œโ”€โ”€ mcp-servers                     # Sample downstream MCP servers
โ”œโ”€โ”€ mcp.db                          # Default SQLite DB (auto-created)
โ”œโ”€โ”€ mcpgrid                         # Experimental grid client / PoC
โ”œโ”€โ”€ os_deps.sh                      # Installs system-level deps for CI

# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Tests & QA Assets โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โ”œโ”€โ”€ test_readme.py                  # Guard: README stays in sync
โ”œโ”€โ”€ tests
โ”‚   โ”œโ”€โ”€ conftest.py                 # Shared fixtures
โ”‚   โ”œโ”€โ”€ e2e/...                       # End-to-end scenarios
โ”‚   โ”œโ”€โ”€ hey/...                       # Load-test logs & helper script
โ”‚   โ”œโ”€โ”€ integration/...               # API-level integration tests
โ”‚   โ””โ”€โ”€ unit/...                      # Pure unit tests for business logic
```

</details>

---

## API Documentation

* **Swagger UI** โ†’ [http://localhost:4444/docs](http://localhost:4444/docs)
* **ReDoc**    โ†’ [http://localhost:4444/redoc](http://localhost:4444/redoc)
* **Admin Panel** โ†’ [http://localhost:4444/admin](http://localhost:4444/admin)

---

## Makefile targets

This project offer the following Makefile targets. Type `make` in the project root to show all targets.

<details>
<summary><strong>๐Ÿ”ง Available Makefile targets</strong></summary>

```bash
๐Ÿ MCP CONTEXT FORGE  (An enterprise-ready Model Context Protocol Gateway)
๐Ÿ”ง SYSTEM-LEVEL DEPENDENCIES (DEV BUILD ONLY)
os-deps              - Install Graphviz, Pandoc, Trivy, SCC used for dev docs generation and security scan
๐ŸŒฑ VIRTUAL ENVIRONMENT & INSTALLATION
venv                 - Create a fresh virtual environment with uv & friends
activate             - Activate the virtual environment in the current shell
install              - Install project into the venv
install-dev          - Install project (incl. dev deps) into the venv
install-db           - Install project (incl. postgres and redis) into venv
update               - Update all installed deps inside the venv
check-env            - Verify all required env vars in .env are present
โ–ถ๏ธ SERVE & TESTING
serve                - Run production Gunicorn server on :4444
certs                - Generate self-signed TLS cert & key in ./certs (won't overwrite)
serve-ssl            - Run Gunicorn behind HTTPS on :4444 (uses ./certs)
dev                  - Run fast-reload dev server (uvicorn)
run                  - Execute helper script ./run.sh
test                 - Run unit tests with pytest
test-curl            - Smoke-test API endpoints with curl script
pytest-examples      - Run README / examples through pytest-examples
clean                - Remove caches, build artefacts, virtualenv, docs, certs, coverage, SBOM, etc.
๐Ÿ“Š COVERAGE & METRICS
coverage             - Run tests with coverage, emit md/HTML/XML + badge
pip-licenses         - Produce dependency license inventory (markdown)
scc                  - Quick LoC/complexity snapshot with scc
scc-report           - Generate HTML LoC & per-file metrics with scc
๐Ÿ“š DOCUMENTATION & SBOM
docs                 - Build docs (graphviz + handsdown + images + SBOM)
images               - Generate architecture & dependency diagrams
๐Ÿ” LINTING & STATIC ANALYSIS
lint                 - Run the full linting suite (see targets below)
black                - Reformat code with black
autoflake            - Remove unused imports / variables with autoflake
isort                - Organise & sort imports with isort
flake8               - PEP-8 style & logical errors
pylint               - Pylint static analysis
markdownlint         - Lint Markdown files with markdownlint (requires markdownlint-cli)
mypy                 - Static type-checking with mypy
bandit               - Security scan with bandit
pydocstyle           - Docstring style checker
pycodestyle          - Simple PEP-8 checker
pre-commit           - Run all configured pre-commit hooks
ruff                 - Ruff linter + formatter
ty                   - Ty type checker from astral
pyright              - Static type-checking with Pyright
radon                - Code complexity & maintainability metrics
pyroma               - Validate packaging metadata
importchecker        - Detect orphaned imports
spellcheck           - Spell-check the codebase
fawltydeps           - Detect undeclared / unused deps
wily                 - Maintainability report
pyre                 - Static analysis with Facebook Pyre
depend               - List dependencies in โ‰ˆrequirements format
snakeviz             - Profile & visualise with snakeviz
pstats               - Generate PNG call-graph from cProfile stats
spellcheck-sort      - Sort local spellcheck dictionary
tox                  - Run tox across multi-Python versions
sbom                 - Produce a CycloneDX SBOM and vulnerability scan
pytype               - Flow-sensitive type checker
check-manifest       - Verify sdist/wheel completeness
yamllint            - Lint YAML files (uses .yamllint)
jsonlint            - Validate every *.json file with jq (--exit-status)
tomllint            - Validate *.toml files with tomlcheck
๐Ÿ•ธ๏ธ  WEBPAGE LINTERS & STATIC ANALYSIS (HTML/CSS/JS lint + security scans + formatting)
install-web-linters  - Install HTMLHint, Stylelint, ESLint, Retire.js & Prettier via npm
lint-web             - Run HTMLHint, Stylelint, ESLint, Retire.js and npm audit
format-web           - Format HTML, CSS & JS files with Prettier
osv-install          - Install/upgrade osv-scanner (Go)
osv-scan-source      - Scan source & lockfiles for CVEs
osv-scan-image       - Scan the built container image for CVEs
osv-scan             - Run all osv-scanner checks (source, image, licence)
๐Ÿ“ก SONARQUBE ANALYSIS
sonar-deps-podman    - Install podman-compose + supporting tools
sonar-deps-docker    - Install docker-compose + supporting tools
sonar-up-podman      - Launch SonarQube with podman-compose
sonar-up-docker      - Launch SonarQube with docker-compose
sonar-submit-docker  - Run containerised Sonar Scanner CLI with Docker
sonar-submit-podman  - Run containerised Sonar Scanner CLI with Podman
pysonar-scanner      - Run scan with Python wrapper (pysonar-scanner)
sonar-info           - How to create a token & which env vars to export
๐Ÿ›ก๏ธ SECURITY & PACKAGE SCANNING
trivy                - Scan container image for CVEs (HIGH/CRIT). Needs podman socket enabled
dockle               - Lint the built container image via tarball (no daemon/socket needed)
hadolint             - Lint Containerfile/Dockerfile(s) with hadolint
pip-audit            - Audit Python dependencies for published CVEs
๐Ÿ“ฆ DEPENDENCY MANAGEMENT
deps-update          - Run update-deps.py to update all dependencies in pyproject.toml and docs/requirements.txt
containerfile-update - Update base image in Containerfile to latest tag
๐Ÿ“ฆ PACKAGING & PUBLISHING
dist                 - Clean-build wheel *and* sdist into ./dist
wheel                - Build wheel only
sdist                - Build source distribution only
verify               - Build + twine + check-manifest + pyroma (no upload)
publish              - Verify, then upload to PyPI (needs TWINE_* creds)
๐Ÿฆญ PODMAN CONTAINER BUILD & RUN
podman-dev           - Build development container image
podman               - Build container image
podman-prod          - Build production container image (using ubi-micro โ†’ scratch). Not supported on macOS.
podman-run           - Run the container on HTTP  (port 4444)
podman-run-shell     - Run the container on HTTP  (port 4444) and start a shell
podman-run-ssl       - Run the container on HTTPS (port 4444, self-signed)
podman-run-ssl-host  - Run the container on HTTPS with --network=host (port 4444, self-signed)
podman-stop          - Stop & remove the container
podman-test          - Quick curl smoke-test against the container
podman-logs          - Follow container logs (โŒƒC to quit)
podman-stats         - Show container resource stats (if supported)
podman-top           - Show live top-level process info in container
podman-shell         - Open an interactive shell inside the Podman container
๐Ÿ‹ DOCKER BUILD & RUN
docker-dev           - Build development Docker image
docker               - Build production Docker image
docker-prod          - Build production container image (using ubi-micro โ†’ scratch). Not supported on macOS.
docker-run           - Run the container on HTTP  (port 4444)
docker-run-ssl       - Run the container on HTTPS (port 4444, self-signed)
docker-stop          - Stop & remove the container
docker-test          - Quick curl smoke-test against the container
docker-logs          - Follow container logs (โŒƒC to quit)
docker-stats         - Show container resource usage stats (non-streaming)
docker-top           - Show top-level process info in Docker container
docker-shell         - Open an interactive shell inside the Docker container
๐Ÿ› ๏ธ COMPOSE STACK     - Build / start / stop the multi-service stack
compose-up           - Bring the whole stack up (detached)
compose-restart      - Recreate changed containers, pulling / building as needed
compose-build        - Build (or rebuild) images defined in the compose file
compose-pull         - Pull the latest images only
compose-logs         - Tail logs from all services (Ctrl-C to exit)
compose-ps           - Show container status table
compose-shell        - Open an interactive shell in the "gateway" container
compose-stop         - Gracefully stop the stack (keep containers)
compose-down         - Stop & remove containers (keep named volumes)
compose-rm           - Remove *stopped* containers
compose-clean        - โœจ Down **and** delete named volumes (data-loss โš )
โ˜๏ธ IBM CLOUD CODE ENGINE
ibmcloud-check-env          - Verify all required IBM Cloud env vars are set
ibmcloud-cli-install        - Auto-install IBM Cloud CLI + required plugins (OS auto-detected)
ibmcloud-login              - Login to IBM Cloud CLI using IBMCLOUD_API_KEY (--sso)
ibmcloud-ce-login           - Set Code Engine target project and region
ibmcloud-list-containers    - List deployed Code Engine apps
ibmcloud-tag                - Tag container image for IBM Container Registry
ibmcloud-push               - Push image to IBM Container Registry
ibmcloud-deploy             - Deploy (or update) container image in Code Engine
ibmcloud-ce-logs            - Stream logs for the deployed application
ibmcloud-ce-status          - Get deployment status
ibmcloud-ce-rm              - Delete the Code Engine application
๐Ÿงช MINIKUBE LOCAL CLUSTER
minikube-install      - Install Minikube (macOS, Linux, or Windows via choco)
helm-install          - Install Helm CLI (macOS, Linux, or Windows)
minikube-start        - Start local Minikube cluster with Ingress + DNS + metrics-server
minikube-stop         - Stop the Minikube cluster
minikube-delete       - Delete the Minikube cluster
minikube-image-load   - Build and load ghcr.io/ibm/mcp-context-forge:latest into Minikube
minikube-k8s-apply    - Apply Kubernetes manifests from k8s/
minikube-status       - Show status of Minikube and ingress pods
๐Ÿ› ๏ธ HELM CHART TASKS
helm-lint            - Lint the Helm chart (static analysis)
helm-package         - Package the chart into dist/ as mcp-stack-<ver>.tgz
helm-deploy          - Upgrade/Install chart into Minikube (profile mcpgw)
helm-delete          - Uninstall the chart release from Minikube
๐Ÿ  LOCAL PYPI SERVER
local-pypi-install   - Install pypiserver for local testing
local-pypi-start     - Start local PyPI server on :8084 (no auth)
local-pypi-start-auth - Start local PyPI server with basic auth (admin/admin)
local-pypi-stop      - Stop local PyPI server
local-pypi-upload    - Upload existing package to local PyPI (no auth)
local-pypi-upload-auth - Upload existing package to local PyPI (with auth)
local-pypi-test      - Install package from local PyPI
local-pypi-clean     - Full cycle: build โ†’ upload โ†’ install locally
๐Ÿ  LOCAL DEVPI SERVER
devpi-install        - Install devpi server and client
devpi-init           - Initialize devpi server (first time only)
devpi-start          - Start devpi server
devpi-stop           - Stop devpi server
devpi-setup-user     - Create user and dev index
devpi-upload         - Upload existing package to devpi
devpi-test           - Install package from devpi
devpi-clean          - Full cycle: build โ†’ upload โ†’ install locally
devpi-status         - Show devpi server status
devpi-web            - Open devpi web interface
```
</details>

## ๐Ÿ” Troubleshooting

<details>
<summary><strong>Port publishing on WSL2 (rootless Podman & Docker Desktop)</strong></summary>

### Diagnose the listener

```bash
# Inside your WSL distro
ss -tlnp | grep 4444        # Use ss
netstat -anp | grep 4444    # or netstat
```

*Seeing `:::4444 LISTEN rootlessport` is normal* - the IPv6 wildcard
socket (`::`) also accepts IPv4 traffic **when**
`net.ipv6.bindv6only = 0` (default on Linux).

### Why localhost fails on Windows

WSL 2's NAT layer rewrites only the *IPv6* side of the dual-stack listener. From Windows, `http://127.0.0.1:4444` (or Docker Desktop's "localhost") therefore times-out.

#### Fix (Podman rootless)

```bash
# Inside the WSL distro
echo "wsl" | sudo tee /etc/containers/podman-machine
systemctl --user restart podman.socket
```

`ss` should now show `0.0.0.0:4444` instead of `:::4444`, and the
service becomes reachable from Windows *and* the LAN.

#### Fix (Docker Desktop > 4.19)

Docker Desktop adds a "WSL integration" switch per-distro.
Turn it **on** for your distro, restart Docker Desktop, then restart the
container:

```bash
docker restart mcpgateway
```

</details>

<details>
<summary><strong>Gateway starts but immediately exits ("Failed to read DATABASE_URL")</strong></summary>

Copy `.env.example` to `.env` first:

```bash
cp .env.example .env
```

Then edit `DATABASE_URL`, `JWT_SECRET_KEY`, `BASIC_AUTH_PASSWORD`, etc.
Missing or empty required vars cause a fast-fail at startup.

</details>

## Contributing

1. Fork the repo, create a feature branch.
2. Run `make lint` and fix any issues.
3. Keep `make test` green and 100% coverage.
4. Open a PR - describe your changes clearly.

See [CONTRIBUTING.md](CONTRIBUTING.md) for more details.
---

## Changelog

A complete changelog can be found here: [CHANGELOG.md](./CHANGELOG.md)

## License

Licensed under the **Apache License 2.0** - see [LICENSE](./LICENSE)


## Core Authors and Maintainers

- [Mihai Criveti](https://www.linkedin.com/in/crivetimihai) - Distinguished Engineer, Agentic AI

Special thanks to our contributors for helping us improve ContextForge MCP Gateway:

<a href="https://github.com/ibm/mcp-context-forge/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=ibm/mcp-context-forge&max=100&anon=0&columns=10" />
</a>

## Star History and Project Activity

[![Star History Chart](https://api.star-history.com/svg?repos=ibm/mcp-context-forge&type=Date)](https://www.star-history.com/#ibm/mcp-context-forge&Date)

<!-- === Usage Stats === -->
[![PyPi Downloads](https://static.pepy.tech/badge/mcp-contextforge-gateway/month)](https://pepy.tech/project/mcp-contextforge-gateway)&nbsp;
[![Stars](https://img.shields.io/github/stars/ibm/mcp-context-forge?style=social)](https://github.com/ibm/mcp-context-forge/stargazers)&nbsp;
[![Forks](https://img.shields.io/github/forks/ibm/mcp-context-forge?style=social)](https://github.com/ibm/mcp-context-forge/network/members)&nbsp;
[![Contributors](https://img.shields.io/github/contributors/ibm/mcp-context-forge)](https://github.com/ibm/mcp-context-forge/graphs/contributors)&nbsp;
[![Last Commit](https://img.shields.io/github/last-commit/ibm/mcp-context-forge)](https://github.com/ibm/mcp-context-forge/commits)&nbsp;
[![Open Issues](https://img.shields.io/github/issues/ibm/mcp-context-forge)](https://github.com/ibm/mcp-context-forge/issues)&nbsp;

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "mcp-contextforge-gateway",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.14,>=3.11",
    "maintainer_email": "Mihai Criveti <redacted@ibm.com>",
    "keywords": "MCP, API, gateway, proxy, tools, agents, agentic ai, model context protocol, multi-agent, fastapi, json-rpc, sse, websocket, federation, security, authentication",
    "author": null,
    "author_email": "Mihai Criveti <redacted@ibm.com>",
    "download_url": "https://files.pythonhosted.org/packages/e1/1e/8a30fb7a476dc481d4c9d99d1a574d80bcd5b40bb75a5f4643ad82d0d8d4/mcp_contextforge_gateway-0.3.1.tar.gz",
    "platform": null,
    "description": "# MCP Gateway\n\n> Model Context Protocol gateway & proxy - unify REST, MCP, and A2A with federation, virtual servers, retries, security, and an optional admin UI.\n\n![](docs/docs/images/contextforge-banner.png)\n\n<!-- === CI / Security / Build Badges === -->\n[![Build Python Package](https://github.com/IBM/mcp-context-forge/actions/workflows/python-package.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/python-package.yml)&nbsp;\n[![CodeQL](https://github.com/IBM/mcp-context-forge/actions/workflows/codeql.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/codeql.yml)&nbsp;\n[![Bandit Security](https://github.com/IBM/mcp-context-forge/actions/workflows/bandit.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/bandit.yml)&nbsp;\n[![Dependency Review](https://github.com/IBM/mcp-context-forge/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/dependency-review.yml)&nbsp;\n[![Tests & Coverage](https://github.com/IBM/mcp-context-forge/actions/workflows/pytest.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/pytest.yml)&nbsp;\n[![Lint & Static Analysis](https://github.com/IBM/mcp-context-forge/actions/workflows/lint.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/lint.yml)\n\n<!-- === Container Build & Deploy === -->\n[![Secure Docker Build](https://github.com/IBM/mcp-context-forge/actions/workflows/docker-image.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/docker-image.yml)&nbsp;\n[![Deploy to IBM Code Engine](https://github.com/IBM/mcp-context-forge/actions/workflows/ibm-cloud-code-engine.yml/badge.svg)](https://github.com/IBM/mcp-context-forge/actions/workflows/ibm-cloud-code-engine.yml)\n\n<!-- === Package / Container === -->\n[![Async](https://img.shields.io/badge/async-await-green.svg)](https://docs.python.org/3/library/asyncio.html)\n[![License](https://img.shields.io/github/license/ibm/mcp-context-forge)](LICENSE)&nbsp;\n[![PyPI](https://img.shields.io/pypi/v/mcp-contextforge-gateway)](https://pypi.org/project/mcp-contextforge-gateway/)&nbsp;\n[![Docker Image](https://img.shields.io/badge/docker-ghcr.io%2Fibm%2Fmcp--context--forge-blue)](https://github.com/ibm/mcp-context-forge/pkgs/container/mcp-context-forge)&nbsp;\n\n\nContextForge MCP Gateway is a feature-rich gateway, proxy and MCP Registry that federates MCP and REST services - unifying discovery, auth, rate-limiting, observability, virtual servers, multi-transport protocols, and an optional Admin UI into one clean endpoint for your AI clients. It runs as a fully compliant MCP server, deployable via PyPI or Docker, and scales to multi-cluster environments on Kubernetes with Redis-backed federation and caching.\n\n![MCP Gateway](https://ibm.github.io/mcp-context-forge/images/mcpgateway.gif)\n---\n\n## Table of Contents\n\n<!-- vscode-markdown-toc -->\n## Table of Contents\n\n* 1. [Table of Contents](#table-of-contents)\n* 2. [\ud83d\ude80 Overview & Goals](#-overview--goals)\n* 3. [Quick Start - PyPI](#quick-start---pypi)\n    * 3.1. [1 - Install & run (copy-paste friendly)](#1---install--run-copy-paste-friendly)\n* 4. [Quick Start - Containers](#quick-start---containers)\n    * 4.1. [\ud83d\udc33 Docker](#-docker)\n        * 4.1.1. [1 - Minimum viable run](#1---minimum-viable-run)\n        * 4.1.2. [2 - Persist the SQLite database](#2---persist-the-sqlite-database)\n        * 4.1.3. [3 - Local tool discovery (host network)](#3---local-tool-discovery-host-network)\n    * 4.2. [\ud83e\uddad Podman (rootless-friendly)](#-podman-rootless-friendly)\n        * 4.2.1. [1 - Basic run](#1---basic-run)\n        * 4.2.2. [2 - Persist SQLite](#2---persist-sqlite)\n        * 4.2.3. [3 - Host networking (rootless)](#3---host-networking-rootless)\n* 5. [Testing `mcpgateway.wrapper` by hand](#testing-mcpgatewaywrapper-by-hand)\n    * 5.1. [\ud83e\udde9 Running from an MCP Client (`mcpgateway.wrapper`)](#-running-from-an-mcp-client-mcpgatewaywrapper)\n        * 5.1.1. [1 - Install `uv` (`uvx` is an alias it provides)](#1---install-uv-uvx-is-an-alias-it-provides)\n        * 5.1.2. [2 - Create an on-the-spot venv & run the wrapper](#2---create-an-on-the-spot-venv--run-the-wrapper)\n        * 5.1.3. [Claude Desktop JSON (runs through **uvx**)](#claude-desktop-json-runs-through-uvx)\n    * 5.2. [\ud83d\ude80 Using with Claude Desktop (or any GUI MCP client)](#-using-with-claude-desktop-or-any-gui-mcp-client)\n* 6. [\ud83d\ude80 Quick Start: VS Code Dev Container](#-quick-start-vs-code-dev-container)\n    * 6.1. [1 - Clone & Open](#1---clone--open)\n    * 6.2. [2 - First-Time Build (Automatic)](#2---first-time-build-automatic)\n* 7. [Quick Start (manual install)](#quick-start-manual-install)\n    * 7.1. [Prerequisites](#prerequisites)\n    * 7.2. [One-liner (dev)](#one-liner-dev)\n    * 7.3. [Containerised (self-signed TLS)](#containerised-self-signed-tls)\n    * 7.4. [Smoke-test the API](#smoke-test-the-api)\n* 8. [Installation](#installation)\n    * 8.1. [Via Make](#via-make)\n    * 8.2. [UV (alternative)](#uv-alternative)\n    * 8.3. [pip (alternative)](#pip-alternative)\n    * 8.4. [Optional (PostgreSQL adapter)](#optional-postgresql-adapter)\n        * 8.4.1. [Quick Postgres container](#quick-postgres-container)\n* 9. [Configuration (`.env` or env vars)](#configuration-env-or-env-vars)\n    * 9.1. [Basic](#basic)\n    * 9.2. [Authentication](#authentication)\n    * 9.3. [UI Features](#ui-features)\n    * 9.4. [Security](#security)\n    * 9.5. [Logging](#logging)\n    * 9.6. [Transport](#transport)\n    * 9.7. [Federation](#federation)\n    * 9.8. [Resources](#resources)\n    * 9.9. [Tools](#tools)\n    * 9.10. [Prompts](#prompts)\n    * 9.11. [Health Checks](#health-checks)\n    * 9.12. [Database](#database)\n    * 9.13. [Cache Backend](#cache-backend)\n    * 9.14. [Development](#development)\n* 10. [Running](#running)\n    * 10.1. [Makefile](#makefile)\n    * 10.2. [Script helper](#script-helper)\n    * 10.3. [Manual (Uvicorn)](#manual-uvicorn)\n* 11. [Authentication examples](#authentication-examples)\n* 12. [\u2601\ufe0f AWS / Azure / OpenShift](#\ufe0f-aws--azure--openshift)\n* 13. [\u2601\ufe0f IBM Cloud Code Engine Deployment](#\ufe0f-ibm-cloud-code-engine-deployment)\n    * 13.1. [\ud83d\udd27 Prerequisites](#-prerequisites-1)\n    * 13.2. [\ud83d\udce6 Environment Variables](#-environment-variables)\n    * 13.3. [\ud83d\ude80 Make Targets](#-make-targets)\n    * 13.4. [\ud83d\udcdd Example Workflow](#-example-workflow)\n* 14. [API Endpoints](#api-endpoints)\n* 15. [Testing](#testing)\n* 16. [Project Structure](#project-structure)\n* 17. [API Documentation](#api-documentation)\n* 18. [Makefile targets](#makefile-targets)\n* 19. [\ud83d\udd0d Troubleshooting](#-troubleshooting)\n    * 19.1. [Diagnose the listener](#diagnose-the-listener)\n    * 19.2. [Why localhost fails on Windows](#why-localhost-fails-on-windows)\n        * 19.2.1. [Fix (Podman rootless)](#fix-podman-rootless)\n        * 19.2.2. [Fix (Docker Desktop > 4.19)](#fix-docker-desktop--419)\n* 20. [Contributing](#contributing)\n* 21. [Changelog](#changelog)\n* 22. [License](#license)\n* 23. [Core Authors and Maintainers](#core-authors-and-maintainers)\n* 24. [Star History and Project Activity](#star-history-and-project-activity)\n\n<!-- vscode-markdown-toc-config\n    numbering=true\n    autoSave=true\n    /vscode-markdown-toc-config -->\n<!-- /vscode-markdown-toc -->\n\n\n\n## \ud83d\ude80 Overview & Goals\n\n**ContextForge MCP Gateway** is a production-grade gateway, registry, and proxy that sits in front of any [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server or REST API-exposing a unified endpoint for all your AI clients.\n\nIt supports:\n\n* Federation across multiple MCP and REST services\n* Virtualization of legacy APIs as MCP-compliant tools and servers\n* Transport over HTTP, JSON-RPC, WebSocket, SSE, stdio and streamable-HTTP\n* An Admin UI for real-time management and configuration\n* Built-in auth, observability, retries, and rate-limiting\n* Scalable deployments via Docker or PyPI, Redis-backed caching, and multi-cluster federation\n\n![MCP Gateway Architecture](https://ibm.github.io/mcp-context-forge/images/mcpgateway.svg)\n\nFor a list of upcoming features, check out the [ContextForge MCP Gateway Roadmap](https://ibm.github.io/mcp-context-forge/architecture/roadmap/)\n\n---\n\n<details>\n<summary><strong>\ud83d\udd0c Gateway Layer with Protocol Flexibility</strong></summary>\n\n* Sits in front of any MCP server or REST API\n* Lets you choose your MCP protocol version (e.g., `2025-03-26`)\n* Exposes a single, unified interface for diverse backends\n\n</details>\n\n<details>\n<summary><strong>\ud83c\udf10 Federation of Peer Gateways (MCP Registry)</strong></summary>\n\n* Auto-discovers or configures peer gateways (via mDNS or manual)\n* Performs health checks and merges remote registries transparently\n* Supports Redis-backed syncing and fail-over\n\n</details>\n\n<details>\n<summary><strong>\ud83e\udde9 Virtualization of REST/gRPC Services</strong></summary>\n\n* Wraps non-MCP services as virtual MCP servers\n* Registers tools, prompts, and resources with minimal configuration\n\n</details>\n\n<details>\n<summary><strong>\ud83d\udd01 REST-to-MCP Tool Adapter</strong></summary>\n\n* Adapts REST APIs into tools with:\n\n  * Automatic JSON Schema extraction\n  * Support for headers, tokens, and custom auth\n  * Retry, timeout, and rate-limit policies\n\n</details>\n\n<details>\n<summary><strong>\ud83e\udde0 Unified Registries</strong></summary>\n\n* **Prompts**: Jinja2 templates, multimodal support, rollback/versioning\n* **Resources**: URI-based access, MIME detection, caching, SSE updates\n* **Tools**: Native or adapted, with input validation and concurrency controls\n\n</details>\n\n<details>\n<summary><strong>\ud83d\udcc8 Admin UI, Observability & Dev Experience</strong></summary>\n\n* Admin UI built with HTMX + Alpine.js\n* Auth: Basic, JWT, or custom schemes\n* Structured logs, health endpoints, metrics\n* 400+ tests, Makefile targets, live reload, pre-commit hooks\n\n</details>\n\n---\n\n## Quick Start - PyPI\n\nMCP Gateway is published on [PyPI](https://pypi.org/project/mcp-contextforge-gateway/) as `mcp-contextforge-gateway`.\n\n---\n\n<details>\n<summary><strong>\ud83d\udccb Prerequisites</strong></summary>\n\n* **Python \u2265 3.10** (3.11 recommended)\n* **curl + jq** - only for the last smoke-test step\n\n</details>\n\n### 1 - Install & run (copy-paste friendly)\n\n```bash\n# 1\ufe0f\u20e3  Isolated env + install from pypi\nmkdir mcpgateway && cd mcpgateway\npython3 -m venv .venv && source .venv/bin/activate\npip install --upgrade pip\npip install mcp-contextforge-gateway\n\n# 2\ufe0f\u20e3  Launch on all interfaces with custom creds & secret key\n# Enable the Admin API endpoints (true/false) - disabled by default\nexport MCPGATEWAY_UI_ENABLED=true\nexport MCPGATEWAY_ADMIN_API_ENABLED=true\n\nBASIC_AUTH_PASSWORD=pass JWT_SECRET_KEY=my-test-key \\\n  mcpgateway --host 0.0.0.0 --port 4444 &   # admin/pass\n\n# 3\ufe0f\u20e3  Generate a bearer token & smoke-test the API\nexport MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token \\\n    --username admin --exp 10080 --secret my-test-key)\n\ncurl -s -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://127.0.0.1:4444/version | jq\n```\n\n<details>\n<summary><strong>More configuration</strong></summary>\n\nCopy [.env.example](.env.example) to `.env` and tweak any of the settings (or use them as env variables).\n\n</details>\n\n<details>\n<summary><strong>\ud83d\ude80 End-to-end demo (register a local MCP server)</strong></summary>\n\n```bash\n# 1\ufe0f\u20e3  Spin up the sample GO MCP time server using mcpgateway.translate & docker\npython3 -m mcpgateway.translate \\\n     --stdio \"docker run --rm -i -p 8888:8080 ghcr.io/ibm/fast-time-server:latest -transport=stdio\" \\\n     --port 8003\n\n# Or using the official mcp-server-git using uvx:\npip install uv # to install uvx, if not already installed\npython3 -m mcpgateway.translate --stdio \"uvx mcp-server-git\" --port 9000\n\n# Alternative: running the local binary\n# cd mcp-servers/go/fast-time-server; make build\n# python3 -m mcpgateway.translate --stdio \"./dist/fast-time-server -transport=stdio\" --port 8002\n\n# 2\ufe0f\u20e3  Register it with the gateway\ncurl -s -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"name\":\"fast_time\",\"url\":\"http://localhost:9000/sse\"}' \\\n     http://localhost:4444/gateways\n\n# 3\ufe0f\u20e3  Verify tool catalog\ncurl -s -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/tools | jq\n\n# 4\ufe0f\u20e3  Create a *virtual server* bundling those tools. Use the ID of tools from the tool catalog (Step #3) and pass them in the associatedTools list.\ncurl -s -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"name\":\"time_server\",\"description\":\"Fast time tools\",\"associatedTools\":[<ID_OF_TOOLS>]}' \\\n     http://localhost:4444/servers | jq\n\n# Example curl\ncurl -s -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\"\n     -H \"Content-Type: application/json\"\n     -d '{\"name\":\"time_server\",\"description\":\"Fast time tools\",\"associatedTools\":[\"6018ca46d32a4ac6b4c054c13a1726a2\"]}' \\\n     http://localhost:4444/servers | jq\n\n# 5\ufe0f\u20e3  List servers (should now include the UUID of the newly created virtual server)\ncurl -s -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/servers | jq\n\n# 6\ufe0f\u20e3  Client SSE endpoint. Inspect it interactively with the MCP Inspector CLI (or use any MCP client)\nnpx -y @modelcontextprotocol/inspector\n# Transport Type: SSE, URL: http://localhost:4444/servers/UUID_OF_SERVER_1/sse,  Header Name: \"Authorization\", Bearer Token\n```\n\n</details>\n\n<details>\n<summary><strong>\ud83d\udda7 Using the stdio wrapper (mcpgateway-wrapper)</strong></summary>\n\n```bash\nexport MCP_AUTH_TOKEN=$MCPGATEWAY_BEARER_TOKEN\nexport MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1\npython3 -m mcpgateway.wrapper  # Ctrl-C to exit\n```\n\nYou can also run it with `uv` or inside Docker/Podman - see the *Containers* section above.\n\nIn MCP Inspector, define `MCP_AUTH_TOKEN` and `MCP_SERVER_CATALOG_URLS` env variables, and select `python3` as the Command, and `-m mcpgateway.wrapper` as Arguments.\n\n```bash\necho $PWD/.venv/bin/python3 # Using the Python3 full path ensures you have a working venv\nexport MCP_SERVER_CATALOG_URLS='http://localhost:4444/servers/UUID_OF_SERVER_1'\nexport MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN}\nnpx -y @modelcontextprotocol/inspector\n```\n\nWhen using a MCP Client such as Claude with stdio:\n\n```json\n{\n  \"mcpServers\": {\n    \"mcpgateway-wrapper\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"mcpgateway.wrapper\"],\n      \"env\": {\n        \"MCP_AUTH_TOKEN\": \"your-token-here\",\n        \"MCP_SERVER_CATALOG_URLS\": \"http://localhost:4444/servers/UUID_OF_SERVER_1\",\n        \"MCP_TOOL_CALL_TIMEOUT\": \"120\"\n      }\n    }\n  }\n}\n```\n\n</details>\n\n---\n\n## Quick Start - Containers\n\nUse the official OCI image from GHCR with **Docker** *or* **Podman**.\n\n---\n\n### \ud83d\udc33 Docker\n\n#### 1 - Minimum viable run\n\n```bash\ndocker run -d --name mcpgateway \\\n  -p 4444:4444 \\\n  -e HOST=0.0.0.0 \\\n  -e JWT_SECRET_KEY=my-test-key \\\n  -e BASIC_AUTH_USER=admin \\\n  -e BASIC_AUTH_PASSWORD=changeme \\\n  -e AUTH_REQUIRED=true \\\n  -e DATABASE_URL=sqlite:///./mcp.db \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1\n\n# Tail logs (Ctrl+C to quit)\ndocker logs -f mcpgateway\n\n# Generating an API key\ndocker run --rm -it ghcr.io/ibm/mcp-context-forge:0.3.1 \\\n  python -m mcpgateway.utils.create_jwt_token --username admin --exp 0 --secret my-test-key\n```\n\nBrowse to **[http://localhost:4444/admin](http://localhost:4444/admin)** (user `admin` / pass `changeme`).\n\n#### 2 - Persist the SQLite database\n\n```bash\nmkdir -p $(pwd)/data\n\ntouch $(pwd)/data/mcp.db\n\nsudo chown -R :docker $(pwd)/data\n\nchmod 777 $(pwd)/data\n\ndocker run -d --name mcpgateway \\\n  --restart unless-stopped \\\n  -p 4444:4444 \\\n  -v $(pwd)/data:/data \\\n  -e DATABASE_URL=sqlite:////data/mcp.db \\\n  -e HOST=0.0.0.0 \\\n  -e JWT_SECRET_KEY=my-test-key \\\n  -e BASIC_AUTH_USER=admin \\\n  -e BASIC_AUTH_PASSWORD=changeme \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1\n```\n\nSQLite now lives on the host at `./data/mcp.db`.\n\n#### 3 - Local tool discovery (host network)\n\n```bash\nmkdir -p $(pwd)/data\n\ntouch $(pwd)/data/mcp.db\n\nsudo chown -R :docker $(pwd)/data\n\nchmod 777 $(pwd)/data\n\ndocker run -d --name mcpgateway \\\n  --network=host \\\n  -e HOST=0.0.0.0 \\\n  -e PORT=4444 \\\n  -e DATABASE_URL=sqlite:////data/mcp.db \\\n  -v $(pwd)/data:/data \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1\n```\n\nUsing `--network=host` allows Docker to access the local network, allowing you to add MCP servers running on your host. See [Docker Host network driver documentation](https://docs.docker.com/engine/network/drivers/host/) for more details.\n\n---\n\n### \ud83e\uddad Podman (rootless-friendly)\n\n#### 1 - Basic run\n\n```bash\npodman run -d --name mcpgateway \\\n  -p 4444:4444 \\\n  -e HOST=0.0.0.0 \\\n  -e DATABASE_URL=sqlite:///./mcp.db \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1\n```\n\n#### 2 - Persist SQLite\n\n```bash\nmkdir -p $(pwd)/data\n\ntouch $(pwd)/data/mcp.db\n\nsudo chown -R :docker $(pwd)/data\n\nchmod 777 $(pwd)/data\n\npodman run -d --name mcpgateway \\\n  --restart=on-failure \\\n  -p 4444:4444 \\\n  -v $(pwd)/data:/data \\\n  -e DATABASE_URL=sqlite:////data/mcp.db \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1\n```\n\n#### 3 - Host networking (rootless)\n\n```bash\nmkdir -p $(pwd)/data\n\ntouch $(pwd)/data/mcp.db\n\nsudo chown -R :docker $(pwd)/data\n\nchmod 777 $(pwd)/data\n\npodman run -d --name mcpgateway \\\n  --network=host \\\n  -v $(pwd)/data:/data \\\n  -e DATABASE_URL=sqlite:////data/mcp.db \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1\n```\n\n---\n\n<details>\n<summary><strong>\u270f\ufe0f Docker/Podman tips</strong></summary>\n\n* **.env files** - Put all the `-e FOO=` lines into a file and replace them with `--env-file .env`. See the provided [.env.example](.env.example) for reference.\n* **Pinned tags** - Use an explicit version (e.g. `v0.3.1`) instead of `latest` for reproducible builds.\n* **JWT tokens** - Generate one in the running container:\n\n  ```bash\n  docker exec mcpgateway python3 -m mcpgateway.utils.create_jwt_token -u admin -e 10080 --secret my-test-key\n  ```\n* **Upgrades** - Stop, remove, and rerun with the same `-v $(pwd)/data:/data` mount; your DB and config stay intact.\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\ude91 Smoke-test the running container</strong></summary>\n\n```bash\ncurl -s -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/health | jq\ncurl -s -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/tools | jq\ncurl -s -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/version | jq\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udda7 Running the MCP Gateway stdio wrapper</strong></summary>\n\nThe `mcpgateway.wrapper` lets you connect to the gateway over **stdio** while keeping JWT authentication. You should run this from the MCP Client. The example below is just for testing.\n\n```bash\n# Set environment variables\nexport MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token --username admin --exp 10080 --secret my-test-key)\nexport MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN}\nexport MCP_SERVER_CATALOG_URLS='http://localhost:4444/servers/UUID_OF_SERVER_1'\nexport MCP_TOOL_CALL_TIMEOUT=120\nexport MCP_WRAPPER_LOG_LEVEL=DEBUG  # or OFF to disable logging\n\ndocker run --rm -i \\\n  -e MCP_AUTH_TOKEN=$MCPGATEWAY_BEARER_TOKEN \\\n  -e MCP_SERVER_CATALOG_URLS=http://host.docker.internal:4444/servers/UUID_OF_SERVER_1 \\\n  -e MCP_TOOL_CALL_TIMEOUT=120 \\\n  -e MCP_WRAPPER_LOG_LEVEL=DEBUG \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1 \\\n  python3 -m mcpgateway.wrapper\n```\n\n</details>\n\n---\n\n## Testing `mcpgateway.wrapper` by hand:\n\nBecause the wrapper speaks JSON-RPC over stdin/stdout, you can interact with it using nothing more than a terminal or pipes.\n\n```bash\n# Start the MCP Gateway Wrapper\nexport MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN}\nexport MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/YOUR_SERVER_UUID\npython3 -m mcpgateway.wrapper\n```\n\n<details>\n<summary><strong>Initialize the protocol</strong></summary>\n\n```json\n# Initialize the protocol\n{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"demo\",\"version\":\"0.0.1\"}}}\n\n# Then after the reply:\n{\"jsonrpc\":\"2.0\",\"method\":\"notifications/initialized\",\"params\":{}}\n\n# Get prompts\n{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"prompts/list\"}\n{\"jsonrpc\":\"2.0\",\"id\":5,\"method\":\"prompts/get\",\"params\":{\"name\":\"greeting\",\"arguments\":{\"user\":\"Bob\"}}}\n\n# Get resources\n{\"jsonrpc\":\"2.0\",\"id\":6,\"method\":\"resources/list\"}\n{\"jsonrpc\":\"2.0\",\"id\":7,\"method\":\"resources/read\",\"params\":{\"uri\":\"https://example.com/some.txt\"}}\n\n# Get / call tools\n{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}\n{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"get_system_time\",\"arguments\":{\"timezone\":\"Europe/Dublin\"}}}\n```\n\n</details>\n\n<details>\n<summary><strong>Expected responses from mcpgateway.wrapper</strong></summary>\n\n```json\n{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{\"experimental\":{},\"prompts\":{\"listChanged\":false},\"resources\":{\"subscribe\":false,\"listChanged\":false},\"tools\":{\"listChanged\":false}},\"serverInfo\":{\"name\":\"mcpgateway-wrapper\",\"version\":\"0.3.0\"}}}\n\n# When there's no tools\n{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":{\"tools\":[]}}\n\n# After you add some tools and create a virtual server\n{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":{\"tools\":[{\"annotations\":{\"readOnlyHint\":false,\"destructiveHint\":true,\"idempotentHint\":false,\"openWorldHint\":true},\"description\":\"Convert time between different timezones\",\"inputSchema\":{\"properties\":{\"source_timezone\":{\"description\":\"Source IANA timezone name\",\"type\":\"string\"},\"target_timezone\":{\"description\":\"Target IANA timezone name\",\"type\":\"string\"},\"time\":{\"description\":\"Time to convert in RFC3339 format or common formats like '2006-01-02 15:04:05'\",\"type\":\"string\"}},\"required\":[\"time\",\"source_timezone\",\"target_timezone\"],\"type\":\"object\"},\"name\":\"convert_time\"},{\"annotations\":{\"readOnlyHint\":false,\"destructiveHint\":true,\"idempotentHint\":false,\"openWorldHint\":true},\"description\":\"Get current system time in specified timezone\",\"inputSchema\":{\"properties\":{\"timezone\":{\"description\":\"IANA timezone name (e.g., 'America/New_York', 'Europe/London'). Defaults to UTC\",\"type\":\"string\"}},\"type\":\"object\"},\"name\":\"get_system_time\"}]}}\n\n# Running the time tool:\n{\"jsonrpc\":\"2.0\",\"id\":3,\"result\":{\"content\":[{\"type\":\"text\",\"text\":\"2025-07-09T00:09:45+01:00\"}]}}\n```\n\n</details>\n\n### \ud83e\udde9 Running from an MCP Client (`mcpgateway.wrapper`)\n\nThe `mcpgateway.wrapper` exposes everything your Gateway knows about over **stdio**, so any MCP client that *can't* (or *shouldn't*) open an authenticated SSE stream still gets full tool-calling power.\n\n> **Remember** to substitute your real Gateway URL (and server ID) for `http://localhost:4444/servers/UUID_OF_SERVER_1`.\n> When inside Docker/Podman, that often becomes `http://host.docker.internal:4444/servers/UUID_OF_SERVER_1` (macOS/Windows) or the gateway container's hostname (Linux).\n\n---\n\n<details>\n<summary><strong>\ud83d\udc33 Docker / Podman</strong></summary>\n\n```bash\ndocker run -i --rm \\\n  --network=host \\\n  -e MCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1 \\\n  -e MCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN} \\\n  -e MCP_TOOL_CALL_TIMEOUT=120 \\\n  ghcr.io/ibm/mcp-context-forge:0.3.1 \\\n  python3 -m mcpgateway.wrapper\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udce6 pipx (one-liner install &amp; run)</strong></summary>\n\n```bash\n# Install gateway package in its own isolated venv\npipx install --include-deps mcp-contextforge-gateway\n\n# Run the stdio wrapper\nMCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN} \\\nMCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1 \\\npython3 -m mcpgateway.wrapper\n# Alternatively with uv\nuv run --directory . -m mcpgateway.wrapper\n```\n\n**Claude Desktop JSON** (uses the host Python that pipx injected):\n\n```json\n{\n  \"mcpServers\": {\n    \"mcpgateway-wrapper\": {\n      \"command\": \"python3\",\n      \"args\": [\"-m\", \"mcpgateway.wrapper\"],\n      \"env\": {\n        \"MCP_AUTH_TOKEN\": \"<your-token>\",\n        \"MCP_SERVER_CATALOG_URLS\": \"http://localhost:4444/servers/UUID_OF_SERVER_1\",\n        \"MCP_TOOL_CALL_TIMEOUT\": \"120\"\n      }\n    }\n  }\n}\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\u26a1 uv / uvx (light-speed venvs)</strong></summary>\n\n#### 1 - Install <code>uv</code>  (<code>uvx</code> is an alias it provides)\n\n```bash\n# (a) official one-liner\ncurl -Ls https://astral.sh/uv/install.sh | sh\n\n# (b) or via pipx\npipx install uv\n```\n\n#### 2 - Create an on-the-spot venv & run the wrapper\n\n```bash\n# Create venv in ~/.venv/mcpgateway (or current dir if you prefer)\nuv venv ~/.venv/mcpgateway\nsource ~/.venv/mcpgateway/bin/activate\n\n# Install the gateway package using uv\nuv pip install mcp-contextforge-gateway\n\n# Launch wrapper\nMCP_AUTH_TOKEN=${MCPGATEWAY_BEARER_TOKEN} \\\nMCP_SERVER_CATALOG_URLS=http://localhost:4444/servers/UUID_OF_SERVER_1 \\\nuv run --directory . -m mcpgateway.wrapper # Use this just for testing, as the Client will run the uv command\n```\n\n#### Claude Desktop JSON (runs through **uvx**)\n\n```json\n{\n  \"mcpServers\": {\n    \"mcpgateway-wrapper\": {\n      \"command\": \"uvx\",\n      \"args\": [\n        \"run\",\n        \"--\",\n        \"python\",\n        \"-m\",\n        \"mcpgateway.wrapper\"\n      ],\n      \"env\": {\n        \"MCP_AUTH_TOKEN\": \"<your-token>\",\n        \"MCP_SERVER_CATALOG_URLS\": \"http://localhost:4444/servers/UUID_OF_SERVER_1\"\n    }\n  }\n}\n```\n\n</details>\n\n---\n\n### \ud83d\ude80 Using with Claude Desktop (or any GUI MCP client)\n\n1. **Edit Config** \u2192 `File \u25b8 Settings \u25b8 Developer \u25b8 Edit Config`\n2. Paste one of the JSON blocks above (Docker / pipx / uvx).\n3. Restart the app so the new stdio server is spawned.\n4. Open logs in the same menu to verify `mcpgateway-wrapper` started and listed your tools.\n\nNeed help? See:\n\n* **MCP Debugging Guide** - [https://modelcontextprotocol.io/docs/tools/debugging](https://modelcontextprotocol.io/docs/tools/debugging)\n\n---\n\n## \ud83d\ude80 Quick Start: VS Code Dev Container\n\nSpin up a fully-loaded dev environment (Python 3.11, Docker/Podman CLI, all project dependencies) in just two clicks.\n\n---\n\n<details>\n<summary><strong>\ud83d\udccb Prerequisites</strong></summary>\n\n* **VS Code** with the [Dev Containers extension](https://code.visualstudio.com/docs/devcontainers/containers)\n* **Docker** or **Podman** installed and running locally\n\n</details>\n\n<details>\n<summary><strong>\ud83e\uddf0 Setup Instructions</strong></summary>\n\n### 1 - Clone & Open\n\n```bash\ngit clone https://github.com/ibm/mcp-context-forge.git\ncd mcp-context-forge\ncode .\n```\n\nVS Code will detect the `.devcontainer` and prompt:\n**\"Reopen in Container\"**\n*or* manually run: <kbd>Ctrl/Cmd \u21e7 P</kbd> \u2192 **Dev Containers: Reopen in Container**\n\n---\n\n### 2 - First-Time Build (Automatic)\n\nThe container build will:\n\n* Install system packages & Python 3.11\n* Run `make install-dev` to pull all dependencies\n* Execute tests to verify the toolchain\n\nYou'll land in `/workspace` ready to develop.\n\n</details>\n\n<details>\n<summary><strong>\ud83d\udee0\ufe0f Daily Developer Workflow</strong></summary>\n\nCommon tasks inside the container:\n\n```bash\n# Start dev server (hot reload)\nmake dev            # http://localhost:4444\n\n# Run tests & linters\nmake test\nmake lint\n```\n\nOptional:\n\n* `make bash` - drop into an interactive shell\n* `make clean` - clear build artefacts & caches\n* Port forwarding is automatic (customize via `.devcontainer/devcontainer.json`)\n\n</details>\n\n<details>\n<summary><strong>\u2601\ufe0f GitHub Codespaces: 1-Click Cloud IDE</strong></summary>\n\nNo local Docker? Use Codespaces:\n\n1. Go to the repo \u2192 **Code \u25b8 Codespaces \u25b8 Create codespace on main**\n2. Wait for the container image to build in the cloud\n3. Develop using the same workflow above\n\n</details>\n\n---\n\n## Quick Start (manual install)\n\n### Prerequisites\n\n* **Python \u2265 3.10**\n* **GNU Make** (optional, but all common workflows are available as Make targets)\n* Optional: **Docker / Podman** for containerised runs\n\n### One-liner (dev)\n\n```bash\nmake venv install serve\n```\n\nWhat it does:\n\n1. Creates / activates a `.venv` in your home folder `~/.venv/mcpgateway`\n2. Installs the gateway and necessary dependencies\n3. Launches **Gunicorn** (Uvicorn workers) on [http://localhost:4444](http://localhost:4444)\n\nFor development, you can use:\n\n```bash\nmake install-dev # Install development dependencies, ex: linters and test harness\nmake lint          # optional: run style checks (ruff, mypy, etc.)\n```\n\n### Containerised (self-signed TLS)\n\n\n> You can use docker or podman, ex:\n\n```bash\nmake podman            # build production image\nmake podman-run-ssl    # run at https://localhost:4444\n# or listen on port 4444 on your host directly, adds --network=host to podman\nmake podman-run-ssl-host\n```\n\n### Smoke-test the API\n\n```bash\ncurl -k -sX GET \\\n     -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     https://localhost:4444/tools | jq\n```\n\nYou should receive `[]` until you register a tool.\n\n---\n\n## Installation\n\n### Via Make\n\n```bash\nmake venv install          # create .venv + install deps\nmake serve                 # gunicorn on :4444\n```\n\n### UV (alternative)\n\n```bash\nuv venv && source .venv/bin/activate\nuv pip install -e '.[dev]' # IMPORTANT: in zsh, quote to disable glob expansion!\n```\n\n### pip (alternative)\n\n```bash\npython3 -m venv .venv && source .venv/bin/activate\npip install -e \".[dev]\"\n```\n\n### Optional (PostgreSQL adapter)\n\nYou can configure the gateway with SQLite, PostgreSQL (or any other compatible database) in .env.\n\nWhen using PostgreSQL, you need to install `psycopg2` driver.\n\n```bash\nuv pip install psycopg2-binary   # dev convenience\n# or\nuv pip install psycopg2          # production build\n```\n\n#### Quick Postgres container\n\n```bash\ndocker run --name mcp-postgres \\\n  -e POSTGRES_USER=postgres \\\n  -e POSTGRES_PASSWORD=mysecretpassword \\\n  -e POSTGRES_DB=mcp \\\n  -p 5432:5432 -d postgres\n```\n\nA `make compose-up` target is provided along with a [docker-compose.yml](docker-compose.yml) file to make this process simpler.\n\n---\n\n## Configuration (`.env` or env vars)\n\n> \u26a0\ufe0f If any required `.env` variable is missing or invalid, the gateway will fail fast at startup with a validation error via Pydantic.\n\nYou can get started by copying the provided [.env.example](.env.example) to `.env` and making the necessary edits to fit your environment.\n\n<details>\n<summary><strong>\ud83d\udd27 Environment Configuration Variables</strong></summary>\n\n### Basic\n\n| Setting         | Description                              | Default                | Options                |\n| --------------- | ---------------------------------------- | ---------------------- | ---------------------- |\n| `APP_NAME`      | Gateway / OpenAPI title                  | `MCP Gateway`          | string                 |\n| `HOST`          | Bind address for the app                 | `0.0.0.0`              | IPv4/IPv6              |\n| `PORT`          | Port the server listens on               | `4444`                 | 1-65535                |\n| `DATABASE_URL`  | SQLAlchemy connection URL                | `sqlite:///./mcp.db`   | any SQLAlchemy dialect |\n| `APP_ROOT_PATH` | Subpath prefix for app (e.g. `/gateway`) | (empty)                | string                 |\n| `TEMPLATES_DIR` | Path to Jinja2 templates                 | `mcpgateway/templates` | path                   |\n| `STATIC_DIR`    | Path to static files                     | `mcpgateway/static`    | path                   |\n\n> \ud83d\udca1 Use `APP_ROOT_PATH=/foo` if reverse-proxying under a subpath like `https://host.com/foo/`.\n\n### Authentication\n\n| Setting               | Description                                                      | Default       | Options    |\n| --------------------- | ---------------------------------------------------------------- | ------------- | ---------- |\n| `BASIC_AUTH_USER`     | Username for Admin UI login and HTTP Basic authentication        | `admin`       | string     |\n| `BASIC_AUTH_PASSWORD` | Password for Admin UI login and HTTP Basic authentication        | `changeme`    | string     |\n| `AUTH_REQUIRED`       | Require authentication for all API routes                        | `true`        | bool       |\n| `JWT_SECRET_KEY`      | Secret key used to **sign JWT tokens** for API access            | `my-test-key` | string     |\n| `JWT_ALGORITHM`       | Algorithm used to sign the JWTs (`HS256` is default, HMAC-based) | `HS256`       | PyJWT algs |\n| `TOKEN_EXPIRY`        | Expiry of generated JWTs in minutes                              | `10080`       | int > 0    |\n| `AUTH_ENCRYPTION_SECRET` | Passphrase used to derive AES key for encrypting tool auth headers | `my-test-salt` | string |\n\n> \ud83d\udd10 `BASIC_AUTH_USER`/`PASSWORD` are used for:\n>\n> * Logging into the web-based Admin UI\n> * Accessing APIs via Basic Auth (`curl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\"`)\n>\n> \ud83d\udd11 `JWT_SECRET_KEY` is used to:\n>\n> * Sign JSON Web Tokens (`Authorization: Bearer <token>`)\n> * Generate tokens via:\n>\n>   ```bash\n>   export MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token --username admin --exp 0 --secret my-test-key)\n>   echo $MCPGATEWAY_BEARER_TOKEN\n>   ```\n> * Tokens allow non-interactive API clients to authenticate securely.\n>\n> \ud83e\uddea Set `AUTH_REQUIRED=false` during development if you want to disable all authentication (e.g. for local testing or open APIs) or clients that don't support SSE authentication.\n> In production, you should use the SSE to stdio `mcpgateway-wrapper` for such tools that don't support authenticated SSE, while still ensuring the gateway uses authentication.\n>\n> \ud83d\udd10 `AUTH_ENCRYPTION_SECRET` is used to encrypt and decrypt tool authentication credentials (`auth_value`).\n> You must set the same value across environments to decode previously stored encrypted auth values.\n> Recommended: use a long, random string.\n\n### UI Features\n\n| Setting                        | Description                            | Default | Options |\n| ------------------------------ | -------------------------------------- | ------- | ------- |\n| `MCPGATEWAY_UI_ENABLED`        | Enable the interactive Admin dashboard | `true`  | bool    |\n| `MCPGATEWAY_ADMIN_API_ENABLED` | Enable API endpoints for admin ops     | `true`  | bool    |\n\n> \ud83d\udda5\ufe0f Set both to `false` to disable management UI and APIs in production.\n\n### Security\n\n| Setting           | Description                    | Default                                        | Options    |\n| ----------------- | ------------------------------ | ---------------------------------------------- | ---------- |\n| `SKIP_SSL_VERIFY` | Skip upstream TLS verification | `false`                                        | bool       |\n| `ALLOWED_ORIGINS` | CORS allow-list                | `[\"http://localhost\",\"http://localhost:4444\"]` | JSON array |\n| `CORS_ENABLED`    | Enable CORS                    | `true`                                         | bool       |\n\n> Note: do not quote the ALLOWED_ORIGINS values, this needs to be valid JSON, such as: `ALLOWED_ORIGINS=[\"http://localhost\", \"http://localhost:4444\"]`\n\n### Logging\n\n| Setting      | Description       | Default | Options            |\n| ------------ | ----------------- | ------- | ------------------ |\n| `LOG_LEVEL`  | Minimum log level | `INFO`  | `DEBUG`...`CRITICAL` |\n| `LOG_FORMAT` | Log format        | `json`  | `json`, `text`     |\n| `LOG_FILE`   | Log output file   | (none)  | path or empty      |\n\n### Transport\n\n| Setting                   | Description                        | Default | Options                         |\n| ------------------------- | ---------------------------------- | ------- | ------------------------------- |\n| `TRANSPORT_TYPE`          | Enabled transports                 | `all`   | `http`,`ws`,`sse`,`stdio`,`all` |\n| `WEBSOCKET_PING_INTERVAL` | WebSocket ping (secs)              | `30`    | int > 0                         |\n| `SSE_RETRY_TIMEOUT`       | SSE retry timeout (ms)             | `5000`  | int > 0                         |\n| `USE_STATEFUL_SESSIONS`   | streamable http config             | `false` | bool                            |\n| `JSON_RESPONSE_ENABLED`   | json/sse streams (streamable http) | `true`  | bool                            |\n\n### Federation\n\n| Setting                    | Description            | Default | Options    |\n| -------------------------- | ---------------------- | ------- | ---------- |\n| `FEDERATION_ENABLED`       | Enable federation      | `true`  | bool       |\n| `FEDERATION_DISCOVERY`     | Auto-discover peers    | `false` | bool       |\n| `FEDERATION_PEERS`         | Comma-sep peer URLs    | `[]`    | JSON array |\n| `FEDERATION_TIMEOUT`       | Gateway timeout (secs) | `30`    | int > 0    |\n| `FEDERATION_SYNC_INTERVAL` | Sync interval (secs)   | `300`   | int > 0    |\n\n### Resources\n\n| Setting               | Description           | Default    | Options    |\n| --------------------- | --------------------- | ---------- | ---------- |\n| `RESOURCE_CACHE_SIZE` | LRU cache size        | `1000`     | int > 0    |\n| `RESOURCE_CACHE_TTL`  | Cache TTL (seconds)   | `3600`     | int > 0    |\n| `MAX_RESOURCE_SIZE`   | Max resource bytes    | `10485760` | int > 0    |\n| `ALLOWED_MIME_TYPES`  | Acceptable MIME types | see code   | JSON array |\n\n### Tools\n\n| Setting                 | Description                    | Default | Options |\n| ----------------------- | ------------------------------ | ------- | ------- |\n| `TOOL_TIMEOUT`          | Tool invocation timeout (secs) | `60`    | int > 0 |\n| `MAX_TOOL_RETRIES`      | Max retry attempts             | `3`     | int \u2265 0 |\n| `TOOL_RATE_LIMIT`       | Tool calls per minute          | `100`   | int > 0 |\n| `TOOL_CONCURRENT_LIMIT` | Concurrent tool invocations    | `10`    | int > 0 |\n\n### Prompts\n\n| Setting                 | Description                      | Default  | Options |\n| ----------------------- | -------------------------------- | -------- | ------- |\n| `PROMPT_CACHE_SIZE`     | Cached prompt templates          | `100`    | int > 0 |\n| `MAX_PROMPT_SIZE`       | Max prompt template size (bytes) | `102400` | int > 0 |\n| `PROMPT_RENDER_TIMEOUT` | Jinja render timeout (secs)      | `10`     | int > 0 |\n\n### Health Checks\n\n| Setting                 | Description                               | Default | Options |\n| ----------------------- | ----------------------------------------- | ------- | ------- |\n| `HEALTH_CHECK_INTERVAL` | Health poll interval (secs)               | `60`    | int > 0 |\n| `HEALTH_CHECK_TIMEOUT`  | Health request timeout (secs)             | `10`    | int > 0 |\n| `UNHEALTHY_THRESHOLD`   | Fail-count before peer deactivation,      | `3`     | int > 0 |\n|                         | Set to -1 if deactivation is not needed.  |         |         |\n\n### Database\n\n| Setting                 | Description                     | Default | Options |\n| ----------------------- | ------------------------------- | ------- | ------- |\n| `DB_POOL_SIZE`   .      | SQLAlchemy connection pool size | `200`   | int > 0 |\n| `DB_MAX_OVERFLOW`.      | Extra connections beyond pool   | `10`    | int \u2265 0 |\n| `DB_POOL_TIMEOUT`.      | Wait for connection (secs)      | `30`    | int > 0 |\n| `DB_POOL_RECYCLE`.      | Recycle connections (secs)      | `3600`  | int > 0 |\n| `DB_MAX_RETRIES` .      | Max Retry Attempts              | `3`     | int > 0 |\n| `DB_RETRY_INTERVAL_MS`  | Retry Interval (ms)             | `2000`  | int > 0 |\n\n### Cache Backend\n\n| Setting                   | Description                | Default  | Options                  |\n| ------------------------- | -------------------------- | -------- | ------------------------ |\n| `CACHE_TYPE`              | Backend (`memory`/`redis`) | `memory` | `none`, `memory`,`redis` |\n| `REDIS_URL`               | Redis connection URL       | (none)   | string or empty          |\n| `CACHE_PREFIX`            | Key prefix                 | `mcpgw:` | string                   |\n| `REDIS_MAX_RETRIES`       | Max Retry Attempts         | `3`      | int > 0                  |\n| `REDIS_RETRY_INTERVAL_MS` | Retry Interval (ms)        | `2000`   | int > 0                  |\n\n> \ud83e\udde0 `none` disables caching entirely. Use `memory` for dev, `database` for persistence, or `redis` for distributed caching.\n\n### Development\n\n| Setting    | Description            | Default | Options |\n| ---------- | ---------------------- | ------- | ------- |\n| `DEV_MODE` | Enable dev mode        | `false` | bool    |\n| `RELOAD`   | Auto-reload on changes | `false` | bool    |\n| `DEBUG`    | Debug logging          | `false` | bool    |\n\n</details>\n\n---\n\n## Running\n\n### Makefile\n\n```bash\n make serve               # Run production Gunicorn server on\n make serve-ssl           # Run Gunicorn behind HTTPS on :4444 (uses ./certs)\n```\n\n### Script helper\n\nTo run the development (uvicorn) server:\n\n```bash\nmake dev\n# or\n./run.sh --reload --log debug --workers 2\n```\n\n> `run.sh` is a wrapper around `uvicorn` that loads `.env`, supports reload, and passes arguments to the server.\n\nKey flags:\n\n| Flag             | Purpose          | Example            |\n| ---------------- | ---------------- | ------------------ |\n| `-e, --env FILE` | load env-file    | `--env prod.env`   |\n| `-H, --host`     | bind address     | `--host 127.0.0.1` |\n| `-p, --port`     | listen port      | `--port 8080`      |\n| `-w, --workers`  | gunicorn workers | `--workers 4`      |\n| `-r, --reload`   | auto-reload      | `--reload`         |\n\n### Manual (Uvicorn)\n\n```bash\nuvicorn mcpgateway.main:app --host 0.0.0.0 --port 4444 --workers 4\n```\n\n---\n\n## Authentication examples\n\n```bash\n# Generate a JWT token using JWT_SECRET_KEY and export it as MCPGATEWAY_BEARER_TOKEN\n# Note that the module needs to be installed. If running locally use:\nexport MCPGATEWAY_BEARER_TOKEN=$(JWT_SECRET_KEY=my-test-key python3 -m mcpgateway.utils.create_jwt_token)\n\n# Use the JWT token in an API call\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/tools\n```\n\n---\n\n## \u2601\ufe0f AWS / Azure / OpenShift\n\nDeployment details can be found in the GitHub Pages.\n\n## \u2601\ufe0f IBM Cloud Code Engine Deployment\n\nThis project supports deployment to [IBM Cloud Code Engine](https://cloud.ibm.com/codeengine) using the **ibmcloud** CLI and the IBM Container Registry.\n\n<details>\n<summary><strong>\u2601\ufe0f IBM Cloud Code Engine Deployment</strong></summary>\n\n### \ud83d\udd27 Prerequisites\n\n- Podman **or** Docker installed locally\n- IBM Cloud CLI (use `make ibmcloud-cli-install` to install)\n- An [IBM Cloud API key](https://cloud.ibm.com/iam/apikeys) with access to Code Engine & Container Registry\n- Code Engine and Container Registry services **enabled** in your IBM Cloud account\n\n---\n\n### \ud83d\udce6 Environment Variables\n\nCreate a **`.env`** file (or export the variables in your shell).\nThe first block is **required**; the second provides **tunable defaults** you can override:\n\n```bash\n# \u2500\u2500 Required \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nIBMCLOUD_REGION=us-south\nIBMCLOUD_RESOURCE_GROUP=default\nIBMCLOUD_PROJECT=my-codeengine-project\nIBMCLOUD_CODE_ENGINE_APP=mcpgateway\nIBMCLOUD_IMAGE_NAME=us.icr.io/myspace/mcpgateway:latest\nIBMCLOUD_IMG_PROD=mcpgateway/mcpgateway\nIBMCLOUD_API_KEY=your_api_key_here   # Optional - omit to use interactive `ibmcloud login --sso`\n\n# \u2500\u2500 Optional overrides (sensible defaults provided) \u2500\u2500\u2500\u2500\u2500\u2500\nIBMCLOUD_CPU=1                       # vCPUs for the app\nIBMCLOUD_MEMORY=4G                   # Memory allocation\nIBMCLOUD_REGISTRY_SECRET=my-regcred  # Name of the Container Registry secret\n```\n\n> \u2705 **Quick check:** `make ibmcloud-check-env`\n\n---\n\n### \ud83d\ude80 Make Targets\n\n| Target                      | Purpose                                                                   |\n| --------------------------- | ------------------------------------------------------------------------- |\n| `make ibmcloud-cli-install` | Install IBM Cloud CLI and required plugins                                |\n| `make ibmcloud-login`       | Log in to IBM Cloud (API key or SSO)                                      |\n| `make ibmcloud-ce-login`    | Select the Code Engine project & region                                   |\n| `make ibmcloud-tag`         | Tag the local container image                                             |\n| `make ibmcloud-push`        | Push the image to IBM Container Registry                                  |\n| `make ibmcloud-deploy`      | **Create or update** the Code Engine application (uses CPU/memory/secret) |\n| `make ibmcloud-ce-status`   | Show current deployment status                                            |\n| `make ibmcloud-ce-logs`     | Stream logs from the running app                                          |\n| `make ibmcloud-ce-rm`       | Delete the Code Engine application                                        |\n\n---\n\n### \ud83d\udcdd Example Workflow\n\n```bash\nmake ibmcloud-check-env\nmake ibmcloud-cli-install\nmake ibmcloud-login\nmake ibmcloud-ce-login\nmake ibmcloud-tag\nmake ibmcloud-push\nmake ibmcloud-deploy\nmake ibmcloud-ce-status\nmake ibmcloud-ce-logs\n```\n\n</details>\n\n---\n\n## API Endpoints\n\nYou can test the API endpoints through curl, or Swagger UI, and check detailed documentation on ReDoc:\n\n* **Swagger UI** \u2192 [http://localhost:4444/docs](http://localhost:4444/docs)\n* **ReDoc**    \u2192 [http://localhost:4444/redoc](http://localhost:4444/redoc)\n\nGenerate an API Bearer token, and test the various API endpoints.\n\n<details>\n<summary><strong>\ud83d\udd10 Authentication & Health Checks</strong></summary>\n\n```bash\n# Generate a bearer token using the configured secret key (use the same as your .env)\nexport MCPGATEWAY_BEARER_TOKEN=$(python3 -m mcpgateway.utils.create_jwt_token -u admin --secret my-test-key)\necho ${MCPGATEWAY_BEARER_TOKEN}\n\n# Quickly confirm that authentication works and the gateway is healthy\ncurl -s -k -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" https://localhost:4444/health\n# {\"status\":\"healthy\"}\n\n# Quickly confirm the gateway version & DB connectivity\ncurl -s -k -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" https://localhost:4444/version | jq\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83e\uddf1 Protocol APIs (MCP) /protocol</strong></summary>\n\n```bash\n# Initialize MCP session\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\n           \"protocol_version\":\"2025-03-26\",\n           \"capabilities\":{},\n           \"client_info\":{\"name\":\"MyClient\",\"version\":\"1.0.0\"}\n         }' \\\n     http://localhost:4444/protocol/initialize\n\n# Ping (JSON-RPC style)\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"ping\"}' \\\n     http://localhost:4444/protocol/ping\n\n# Completion for prompt/resource arguments (not implemented)\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\n           \"ref\":{\"type\":\"ref/prompt\",\"name\":\"example_prompt\"},\n           \"argument\":{\"name\":\"topic\",\"value\":\"py\"}\n         }' \\\n     http://localhost:4444/protocol/completion/complete\n\n# Sampling (streaming) (not implemented)\ncurl -N -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\n           \"messages\":[{\"role\":\"user\",\"content\":{\"type\":\"text\",\"text\":\"Hello\"}}],\n           \"maxTokens\":16\n         }' \\\n     http://localhost:4444/protocol/sampling/createMessage\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83e\udde0 JSON-RPC Utility /rpc</strong></summary>\n\n```bash\n# Generic JSON-RPC calls (tools, gateways, roots, etc.)\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"list_tools\"}' \\\n     http://localhost:4444/rpc\n```\n\nHandles any method name: `list_tools`, `list_gateways`, `prompts/get`, or invokes a tool if method matches a registered tool name .\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udd27 Tool Management /tools</strong></summary>\n\n\n```bash\n# Register a new tool\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\n           \"name\":\"clock_tool\",\n           \"url\":\"http://localhost:9000/rpc\",\n           \"description\":\"Returns current time\",\n           \"input_schema\":{\n             \"type\":\"object\",\n             \"properties\":{\"timezone\":{\"type\":\"string\"}},\n             \"required\":[]\n           }\n         }' \\\n     http://localhost:4444/tools\n\n# List tools\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/tools\n\n# Get tool by ID\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/tools/1\n\n# Update tool\ncurl -X PUT -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{ \"description\":\"Updated desc\" }' \\\n     http://localhost:4444/tools/1\n\n# Toggle active status\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/tools/1/toggle?activate=false\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/tools/1/toggle?activate=true\n\n# Delete tool\ncurl -X DELETE -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/tools/1\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83c\udf10 Gateway Management /gateways</strong></summary>\n\n```bash\n# Register an MCP server as a new gateway provider\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"name\":\"peer_gateway\",\"url\":\"http://peer:4444\"}' \\\n     http://localhost:4444/gateways\n\n# List gateways\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/gateways\n\n# Get gateway by ID\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/gateways/1\n\n# Update gateway\ncurl -X PUT -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"description\":\"New description\"}' \\\n     http://localhost:4444/gateways/1\n\n# Toggle active status\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/gateways/1/toggle?activate=false\n\n# Delete gateway\ncurl -X DELETE -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/gateways/1\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udcc1 Resource Management /resources</strong></summary>\n\n\n```bash\n# Register resource\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\n           \"uri\":\"config://app/settings\",\n           \"name\":\"App Settings\",\n           \"content\":\"key=value\"\n         }' \\\n     http://localhost:4444/resources\n\n# List resources\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/resources\n\n# Read a resource\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/resources/config://app/settings\n\n# Update resource\ncurl -X PUT -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"content\":\"new=value\"}' \\\n     http://localhost:4444/resources/config://app/settings\n\n# Delete resource\ncurl -X DELETE -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/resources/config://app/settings\n\n# Subscribe to updates (SSE)\ncurl -N -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/resources/subscribe/config://app/settings\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udcdd Prompt Management /prompts</strong></summary>\n\n```bash\n# Create prompt template\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\n           \"name\":\"greet\",\n           \"template\":\"Hello, {{ user }}!\",\n           \"argument_schema\":{\n             \"type\":\"object\",\n             \"properties\":{\"user\":{\"type\":\"string\"}},\n             \"required\":[\"user\"]\n           }\n         }' \\\n     http://localhost:4444/prompts\n\n# List prompts\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/prompts\n\n# Get prompt (with args)\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"user\":\"Alice\"}' \\\n     http://localhost:4444/prompts/greet\n\n# Get prompt (no args)\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/prompts/greet\n\n# Update prompt\ncurl -X PUT -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"template\":\"Hi, {{ user }}!\"}' \\\n     http://localhost:4444/prompts/greet\n\n# Toggle active\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/prompts/5/toggle?activate=false\n\n# Delete prompt\ncurl -X DELETE -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/prompts/greet\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83c\udf32 Root Management /roots</strong></summary>\n\n```bash\n# List roots\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/roots\n\n# Add root\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"uri\":\"/data\",\"name\":\"Data Root\"}' \\\n     http://localhost:4444/roots\n\n# Remove root\ncurl -X DELETE -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/roots/%2Fdata\n\n# Subscribe to root changes (SSE)\ncurl -N -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/roots/changes\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udda5\ufe0f Server Management /servers</strong></summary>\n\n```bash\n# List servers\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/servers\n\n# Get server\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/servers/UUID_OF_SERVER_1\n\n# Create server\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"name\":\"db\",\"description\":\"Database\",\"associatedTools\": [\"1\",\"2\",\"3\"]}' \\\n     http://localhost:4444/servers\n\n# Update server\ncurl -X PUT -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     -H \"Content-Type: application/json\" \\\n     -d '{\"description\":\"Updated\"}' \\\n     http://localhost:4444/servers/UUID_OF_SERVER_1\n\n# Toggle active\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" \\\n     http://localhost:4444/servers/UUID_OF_SERVER_1/toggle?activate=false\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udcca Metrics /metrics</strong></summary>\n\n```bash\n# Get aggregated metrics\ncurl -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/metrics\n\n# Reset metrics (all or per-entity)\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/metrics/reset\ncurl -X POST -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/metrics/reset?entity=tool&id=1\n```\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udce1 Events & Health</strong></summary>\n\n```bash\n# SSE: all events\ncurl -N -H \"Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN\" http://localhost:4444/events\n\n# WebSocket\nwscat -c ws://localhost:4444/ws \\\n      -H \"Authorization: Basic $(echo -n admin:changeme|base64)\"\n\n# Health check\ncurl http://localhost:4444/health\n```\n\nFull Swagger UI at `/docs`.\n\n</details>\n\n---\n\n<details>\n<summary><strong>\ud83d\udee0\ufe0f Sample Tool</strong></summary>\n\n```bash\nuvicorn sample_tool.clock_tool:app --host 0.0.0.0 --port 9000\n```\n\n```bash\ncurl -X POST -H \"Content-Type: application/json\" \\\n     -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"get_time\",\"params\":{\"timezone\":\"UTC\"}}' \\\n     http://localhost:9000/rpc\n```\n\n</details>\n\n---\n\n## Testing\n\n```bash\nmake test            # Run unit tests\nmake lint            # Run lint tools\n```\n\n---\n\n## Project Structure\n\n<details>\n<summary><strong>\ud83d\udcc1 Directory and file structure for mcpgateway</strong></summary>\n\n```bash\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 CI / Quality & Meta-files \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 .bumpversion.cfg                # Automated semantic-version bumps\n\u251c\u2500\u2500 .coveragerc                     # Coverage.py settings\n\u251c\u2500\u2500 .darglint                       # Doc-string linter rules\n\u251c\u2500\u2500 .dockerignore                   # Context exclusions for image builds\n\u251c\u2500\u2500 .editorconfig                   # Consistent IDE / editor behaviour\n\u251c\u2500\u2500 .env                            # Local runtime variables (git-ignored)\n\u251c\u2500\u2500 .env.ce                         # IBM Code Engine runtime env (ignored)\n\u251c\u2500\u2500 .env.ce.example                 # Sample env for IBM Code Engine\n\u251c\u2500\u2500 .env.example                    # Generic sample env file\n\u251c\u2500\u2500 .env.gcr                        # Google Cloud Run runtime env (ignored)\n\u251c\u2500\u2500 .eslintrc.json                  # ESLint rules for JS / TS assets\n\u251c\u2500\u2500 .flake8                         # Flake-8 configuration\n\u251c\u2500\u2500 .gitattributes                  # Git attributes (e.g. EOL normalisation)\n\u251c\u2500\u2500 .github                         # GitHub settings, CI/CD workflows & templates\n\u2502   \u251c\u2500\u2500 CODEOWNERS                  # Default reviewers\n\u2502   \u2514\u2500\u2500 workflows/                  # Bandit, Docker, CodeQL, Python Package, Container Deployment, etc.\n\u251c\u2500\u2500 .gitignore                      # Git exclusion rules\n\u251c\u2500\u2500 .hadolint.yaml                  # Hadolint rules for Dockerfiles\n\u251c\u2500\u2500 .htmlhintrc                     # HTMLHint rules\n\u251c\u2500\u2500 .markdownlint.json              # Markdown-lint rules\n\u251c\u2500\u2500 .pre-commit-config.yaml         # Pre-commit hooks (ruff, black, mypy, ...)\n\u251c\u2500\u2500 .pycodestyle                    # PEP-8 checker settings\n\u251c\u2500\u2500 .pylintrc                       # Pylint configuration\n\u251c\u2500\u2500 .pyspelling.yml                 # Spell-checker dictionary & filters\n\u251c\u2500\u2500 .ruff.toml                      # Ruff linter / formatter settings\n\u251c\u2500\u2500 .spellcheck-en.txt              # Extra dictionary entries\n\u251c\u2500\u2500 .stylelintrc.json               # Stylelint rules for CSS\n\u251c\u2500\u2500 .travis.yml                     # Legacy Travis CI config (reference)\n\u251c\u2500\u2500 .whitesource                    # WhiteSource security-scanning config\n\u251c\u2500\u2500 .yamllint                       # yamllint ruleset\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Documentation & Guidance \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 CHANGELOG.md                    # Version-by-version change log\n\u251c\u2500\u2500 CODE_OF_CONDUCT.md              # Community behaviour guidelines\n\u251c\u2500\u2500 CONTRIBUTING.md                 # How to file issues & send PRs\n\u251c\u2500\u2500 DEVELOPING.md                   # Contributor workflows & style guide\n\u251c\u2500\u2500 LICENSE                         # Apache License 2.0\n\u251c\u2500\u2500 README.md                       # Project overview & quick-start\n\u251c\u2500\u2500 SECURITY.md                     # Security policy & CVE disclosure process\n\u251c\u2500\u2500 TESTING.md                      # Testing strategy, fixtures & guidelines\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Containerisation & Runtime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 Containerfile                   # OCI image build (Docker / Podman)\n\u251c\u2500\u2500 Containerfile.lite              # FROM scratch UBI-Micro production build\n\u251c\u2500\u2500 docker-compose.yml              # Local multi-service stack\n\u251c\u2500\u2500 podman-compose-sonarqube.yaml   # One-liner SonarQube stack\n\u251c\u2500\u2500 run-gunicorn.sh                 # Opinionated Gunicorn startup script\n\u251c\u2500\u2500 run.sh                          # Uvicorn shortcut with arg parsing\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Build / Packaging / Tooling \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 MANIFEST.in                     # sdist inclusion rules\n\u251c\u2500\u2500 Makefile                        # Dev & deployment targets\n\u251c\u2500\u2500 package-lock.json               # Deterministic npm lock-file\n\u251c\u2500\u2500 package.json                    # Front-end / docs tooling deps\n\u251c\u2500\u2500 pyproject.toml                  # Poetry / PDM config & lint rules\n\u251c\u2500\u2500 sonar-code.properties           # SonarQube analysis settings\n\u251c\u2500\u2500 uv.lock                         # UV resolver lock-file\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Kubernetes & Helm Assets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 charts                          # Helm chart(s) for K8s / OpenShift\n\u2502   \u251c\u2500\u2500 mcp-stack                   # Umbrella chart\n\u2502   \u2502   \u251c\u2500\u2500 Chart.yaml              # Chart metadata\n\u2502   \u2502   \u251c\u2500\u2500 templates/...             # Manifest templates\n\u2502   \u2502   \u2514\u2500\u2500 values.yaml             # Default values\n\u2502   \u2514\u2500\u2500 README.md                   # Install / upgrade guide\n\u251c\u2500\u2500 k8s                             # Raw (non-Helm) K8s manifests\n\u2502   \u2514\u2500\u2500 *.yaml                      # Deployment, Service, PVC resources\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Documentation Source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 docs                            # MkDocs site source\n\u2502   \u251c\u2500\u2500 base.yml                    # MkDocs \"base\" configuration snippet (do not modify)\n\u2502   \u251c\u2500\u2500 mkdocs.yml                  # Site configuration (requires base.yml)\n\u2502   \u251c\u2500\u2500 requirements.txt            # Python dependencies for the MkDocs site\n\u2502   \u251c\u2500\u2500 Makefile                    # Make targets for building/serving the docs\n\u2502   \u2514\u2500\u2500 theme                       # Custom MkDocs theme assets\n\u2502       \u2514\u2500\u2500 logo.png                # Logo for the documentation theme\n\u2502   \u2514\u2500\u2500 docs                        # Markdown documentation\n\u2502       \u251c\u2500\u2500 architecture/           # ADRs for the project\n\u2502       \u251c\u2500\u2500 articles/               # Long-form writeups\n\u2502       \u251c\u2500\u2500 blog/                   # Blog posts\n\u2502       \u251c\u2500\u2500 deployment/             # Deployment guides (AWS, Azure, etc.)\n\u2502       \u251c\u2500\u2500 development/            # Development workflows & CI docs\n\u2502       \u251c\u2500\u2500 images/                 # Diagrams & screenshots\n\u2502       \u251c\u2500\u2500 index.md                # Top-level docs landing page\n\u2502       \u251c\u2500\u2500 manage/                 # Management topics (backup, logging, tuning, upgrade)\n\u2502       \u251c\u2500\u2500 overview/               # Feature overviews & UI documentation\n\u2502       \u251c\u2500\u2500 security/               # Security guidance & policies\n\u2502       \u251c\u2500\u2500 testing/                # Testing strategy & fixtures\n\u2502       \u2514\u2500\u2500 using/                  # User-facing usage guides (agents, clients, etc.)\n\u2502       \u251c\u2500\u2500 media/                  # Social media, press coverage, videos & testimonials\n\u2502       \u2502   \u251c\u2500\u2500 press/              # Press articles and blog posts\n\u2502       \u2502   \u251c\u2500\u2500 social/             # Tweets, LinkedIn posts, YouTube embeds\n\u2502       \u2502   \u251c\u2500\u2500 testimonials/       # Customer quotes & community feedback\n\u2502       \u2502   \u2514\u2500\u2500 kit/                # Media kit & logos for bloggers & press\n\u251c\u2500\u2500 dictionary.dic                  # Custom dictionary for spell-checker (make spellcheck)\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Application & Libraries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 agent_runtimes                  # Configurable agentic frameworks converted to MCP Servers\n\u251c\u2500\u2500 mcpgateway                      # \u2190 main application package\n\u2502   \u251c\u2500\u2500 __init__.py                 # Package metadata & version constant\n\u2502   \u251c\u2500\u2500 admin.py                    # FastAPI routers for Admin UI\n\u2502   \u251c\u2500\u2500 cache\n\u2502   \u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2502   \u251c\u2500\u2500 resource_cache.py       # LRU+TTL cache implementation\n\u2502   \u2502   \u2514\u2500\u2500 session_registry.py     # Session \u2194 cache mapping\n\u2502   \u251c\u2500\u2500 config.py                   # Pydantic settings loader\n\u2502   \u251c\u2500\u2500 db.py                       # SQLAlchemy models & engine setup\n\u2502   \u251c\u2500\u2500 federation\n\u2502   \u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2502   \u251c\u2500\u2500 discovery.py            # Peer-gateway discovery\n\u2502   \u2502   \u251c\u2500\u2500 forward.py              # RPC forwarding\n\u2502   \u251c\u2500\u2500 handlers\n\u2502   \u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2502   \u2514\u2500\u2500 sampling.py             # Streaming sampling handler\n\u2502   \u251c\u2500\u2500 main.py                     # FastAPI app factory & startup events\n\u2502   \u251c\u2500\u2500 mcp.db                      # SQLite fixture for tests\n\u2502   \u251c\u2500\u2500 py.typed                    # PEP 561 marker (ships type hints)\n\u2502   \u251c\u2500\u2500 schemas.py                  # Shared Pydantic DTOs\n\u2502   \u251c\u2500\u2500 services\n\u2502   \u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2502   \u251c\u2500\u2500 completion_service.py   # Prompt / argument completion\n\u2502   \u2502   \u251c\u2500\u2500 gateway_service.py      # Peer-gateway registry\n\u2502   \u2502   \u251c\u2500\u2500 logging_service.py      # Central logging helpers\n\u2502   \u2502   \u251c\u2500\u2500 prompt_service.py       # Prompt CRUD & rendering\n\u2502   \u2502   \u251c\u2500\u2500 resource_service.py     # Resource registration & retrieval\n\u2502   \u2502   \u251c\u2500\u2500 root_service.py         # File-system root registry\n\u2502   \u2502   \u251c\u2500\u2500 server_service.py       # Server registry & monitoring\n\u2502   \u2502   \u2514\u2500\u2500 tool_service.py         # Tool registry & invocation\n\u2502   \u251c\u2500\u2500 static\n\u2502   \u2502   \u251c\u2500\u2500 admin.css               # Styles for Admin UI\n\u2502   \u2502   \u2514\u2500\u2500 admin.js                # Behaviour for Admin UI\n\u2502   \u251c\u2500\u2500 templates\n\u2502   \u2502   \u2514\u2500\u2500 admin.html              # HTMX/Alpine Admin UI template\n\u2502   \u251c\u2500\u2500 transports\n\u2502   \u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2502   \u251c\u2500\u2500 base.py                 # Abstract transport interface\n\u2502   \u2502   \u251c\u2500\u2500 sse_transport.py        # Server-Sent Events transport\n\u2502   \u2502   \u251c\u2500\u2500 stdio_transport.py      # stdio transport for embedding\n\u2502   \u2502   \u2514\u2500\u2500 websocket_transport.py  # WS transport with ping/pong\n\u2502   \u251c\u2500\u2500 models.py                   # Core enums / type aliases\n\u2502   \u251c\u2500\u2500 utils\n\u2502   \u2502   \u251c\u2500\u2500 create_jwt_token.py     # CLI & library for JWT generation\n\u2502   \u2502   \u251c\u2500\u2500 services_auth.py        # Service-to-service auth dependency\n\u2502   \u2502   \u2514\u2500\u2500 verify_credentials.py   # Basic / JWT auth helpers\n\u2502   \u251c\u2500\u2500 validation\n\u2502   \u2502   \u251c\u2500\u2500 __init__.py\n\u2502   \u2502   \u2514\u2500\u2500 jsonrpc.py              # JSON-RPC 2.0 validation\n\u2502   \u2514\u2500\u2500 version.py                  # Library version helper\n\u251c\u2500\u2500 mcpgateway-wrapper              # Stdio client wrapper (PyPI)\n\u2502   \u251c\u2500\u2500 pyproject.toml\n\u2502   \u251c\u2500\u2500 README.md\n\u2502   \u2514\u2500\u2500 src/mcpgateway_wrapper/\n\u2502       \u251c\u2500\u2500 __init__.py\n\u2502       \u2514\u2500\u2500 server.py               # Wrapper entry-point\n\u251c\u2500\u2500 mcp-servers                     # Sample downstream MCP servers\n\u251c\u2500\u2500 mcp.db                          # Default SQLite DB (auto-created)\n\u251c\u2500\u2500 mcpgrid                         # Experimental grid client / PoC\n\u251c\u2500\u2500 os_deps.sh                      # Installs system-level deps for CI\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 Tests & QA Assets \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\u251c\u2500\u2500 test_readme.py                  # Guard: README stays in sync\n\u251c\u2500\u2500 tests\n\u2502   \u251c\u2500\u2500 conftest.py                 # Shared fixtures\n\u2502   \u251c\u2500\u2500 e2e/...                       # End-to-end scenarios\n\u2502   \u251c\u2500\u2500 hey/...                       # Load-test logs & helper script\n\u2502   \u251c\u2500\u2500 integration/...               # API-level integration tests\n\u2502   \u2514\u2500\u2500 unit/...                      # Pure unit tests for business logic\n```\n\n</details>\n\n---\n\n## API Documentation\n\n* **Swagger UI** \u2192 [http://localhost:4444/docs](http://localhost:4444/docs)\n* **ReDoc**    \u2192 [http://localhost:4444/redoc](http://localhost:4444/redoc)\n* **Admin Panel** \u2192 [http://localhost:4444/admin](http://localhost:4444/admin)\n\n---\n\n## Makefile targets\n\nThis project offer the following Makefile targets. Type `make` in the project root to show all targets.\n\n<details>\n<summary><strong>\ud83d\udd27 Available Makefile targets</strong></summary>\n\n```bash\n\ud83d\udc0d MCP CONTEXT FORGE  (An enterprise-ready Model Context Protocol Gateway)\n\ud83d\udd27 SYSTEM-LEVEL DEPENDENCIES (DEV BUILD ONLY)\nos-deps              - Install Graphviz, Pandoc, Trivy, SCC used for dev docs generation and security scan\n\ud83c\udf31 VIRTUAL ENVIRONMENT & INSTALLATION\nvenv                 - Create a fresh virtual environment with uv & friends\nactivate             - Activate the virtual environment in the current shell\ninstall              - Install project into the venv\ninstall-dev          - Install project (incl. dev deps) into the venv\ninstall-db           - Install project (incl. postgres and redis) into venv\nupdate               - Update all installed deps inside the venv\ncheck-env            - Verify all required env vars in .env are present\n\u25b6\ufe0f SERVE & TESTING\nserve                - Run production Gunicorn server on :4444\ncerts                - Generate self-signed TLS cert & key in ./certs (won't overwrite)\nserve-ssl            - Run Gunicorn behind HTTPS on :4444 (uses ./certs)\ndev                  - Run fast-reload dev server (uvicorn)\nrun                  - Execute helper script ./run.sh\ntest                 - Run unit tests with pytest\ntest-curl            - Smoke-test API endpoints with curl script\npytest-examples      - Run README / examples through pytest-examples\nclean                - Remove caches, build artefacts, virtualenv, docs, certs, coverage, SBOM, etc.\n\ud83d\udcca COVERAGE & METRICS\ncoverage             - Run tests with coverage, emit md/HTML/XML + badge\npip-licenses         - Produce dependency license inventory (markdown)\nscc                  - Quick LoC/complexity snapshot with scc\nscc-report           - Generate HTML LoC & per-file metrics with scc\n\ud83d\udcda DOCUMENTATION & SBOM\ndocs                 - Build docs (graphviz + handsdown + images + SBOM)\nimages               - Generate architecture & dependency diagrams\n\ud83d\udd0d LINTING & STATIC ANALYSIS\nlint                 - Run the full linting suite (see targets below)\nblack                - Reformat code with black\nautoflake            - Remove unused imports / variables with autoflake\nisort                - Organise & sort imports with isort\nflake8               - PEP-8 style & logical errors\npylint               - Pylint static analysis\nmarkdownlint         - Lint Markdown files with markdownlint (requires markdownlint-cli)\nmypy                 - Static type-checking with mypy\nbandit               - Security scan with bandit\npydocstyle           - Docstring style checker\npycodestyle          - Simple PEP-8 checker\npre-commit           - Run all configured pre-commit hooks\nruff                 - Ruff linter + formatter\nty                   - Ty type checker from astral\npyright              - Static type-checking with Pyright\nradon                - Code complexity & maintainability metrics\npyroma               - Validate packaging metadata\nimportchecker        - Detect orphaned imports\nspellcheck           - Spell-check the codebase\nfawltydeps           - Detect undeclared / unused deps\nwily                 - Maintainability report\npyre                 - Static analysis with Facebook Pyre\ndepend               - List dependencies in \u2248requirements format\nsnakeviz             - Profile & visualise with snakeviz\npstats               - Generate PNG call-graph from cProfile stats\nspellcheck-sort      - Sort local spellcheck dictionary\ntox                  - Run tox across multi-Python versions\nsbom                 - Produce a CycloneDX SBOM and vulnerability scan\npytype               - Flow-sensitive type checker\ncheck-manifest       - Verify sdist/wheel completeness\nyamllint            - Lint YAML files (uses .yamllint)\njsonlint            - Validate every *.json file with jq (--exit-status)\ntomllint            - Validate *.toml files with tomlcheck\n\ud83d\udd78\ufe0f  WEBPAGE LINTERS & STATIC ANALYSIS (HTML/CSS/JS lint + security scans + formatting)\ninstall-web-linters  - Install HTMLHint, Stylelint, ESLint, Retire.js & Prettier via npm\nlint-web             - Run HTMLHint, Stylelint, ESLint, Retire.js and npm audit\nformat-web           - Format HTML, CSS & JS files with Prettier\nosv-install          - Install/upgrade osv-scanner (Go)\nosv-scan-source      - Scan source & lockfiles for CVEs\nosv-scan-image       - Scan the built container image for CVEs\nosv-scan             - Run all osv-scanner checks (source, image, licence)\n\ud83d\udce1 SONARQUBE ANALYSIS\nsonar-deps-podman    - Install podman-compose + supporting tools\nsonar-deps-docker    - Install docker-compose + supporting tools\nsonar-up-podman      - Launch SonarQube with podman-compose\nsonar-up-docker      - Launch SonarQube with docker-compose\nsonar-submit-docker  - Run containerised Sonar Scanner CLI with Docker\nsonar-submit-podman  - Run containerised Sonar Scanner CLI with Podman\npysonar-scanner      - Run scan with Python wrapper (pysonar-scanner)\nsonar-info           - How to create a token & which env vars to export\n\ud83d\udee1\ufe0f SECURITY & PACKAGE SCANNING\ntrivy                - Scan container image for CVEs (HIGH/CRIT). Needs podman socket enabled\ndockle               - Lint the built container image via tarball (no daemon/socket needed)\nhadolint             - Lint Containerfile/Dockerfile(s) with hadolint\npip-audit            - Audit Python dependencies for published CVEs\n\ud83d\udce6 DEPENDENCY MANAGEMENT\ndeps-update          - Run update-deps.py to update all dependencies in pyproject.toml and docs/requirements.txt\ncontainerfile-update - Update base image in Containerfile to latest tag\n\ud83d\udce6 PACKAGING & PUBLISHING\ndist                 - Clean-build wheel *and* sdist into ./dist\nwheel                - Build wheel only\nsdist                - Build source distribution only\nverify               - Build + twine + check-manifest + pyroma (no upload)\npublish              - Verify, then upload to PyPI (needs TWINE_* creds)\n\ud83e\uddad PODMAN CONTAINER BUILD & RUN\npodman-dev           - Build development container image\npodman               - Build container image\npodman-prod          - Build production container image (using ubi-micro \u2192 scratch). Not supported on macOS.\npodman-run           - Run the container on HTTP  (port 4444)\npodman-run-shell     - Run the container on HTTP  (port 4444) and start a shell\npodman-run-ssl       - Run the container on HTTPS (port 4444, self-signed)\npodman-run-ssl-host  - Run the container on HTTPS with --network=host (port 4444, self-signed)\npodman-stop          - Stop & remove the container\npodman-test          - Quick curl smoke-test against the container\npodman-logs          - Follow container logs (\u2303C to quit)\npodman-stats         - Show container resource stats (if supported)\npodman-top           - Show live top-level process info in container\npodman-shell         - Open an interactive shell inside the Podman container\n\ud83d\udc0b DOCKER BUILD & RUN\ndocker-dev           - Build development Docker image\ndocker               - Build production Docker image\ndocker-prod          - Build production container image (using ubi-micro \u2192 scratch). Not supported on macOS.\ndocker-run           - Run the container on HTTP  (port 4444)\ndocker-run-ssl       - Run the container on HTTPS (port 4444, self-signed)\ndocker-stop          - Stop & remove the container\ndocker-test          - Quick curl smoke-test against the container\ndocker-logs          - Follow container logs (\u2303C to quit)\ndocker-stats         - Show container resource usage stats (non-streaming)\ndocker-top           - Show top-level process info in Docker container\ndocker-shell         - Open an interactive shell inside the Docker container\n\ud83d\udee0\ufe0f COMPOSE STACK     - Build / start / stop the multi-service stack\ncompose-up           - Bring the whole stack up (detached)\ncompose-restart      - Recreate changed containers, pulling / building as needed\ncompose-build        - Build (or rebuild) images defined in the compose file\ncompose-pull         - Pull the latest images only\ncompose-logs         - Tail logs from all services (Ctrl-C to exit)\ncompose-ps           - Show container status table\ncompose-shell        - Open an interactive shell in the \"gateway\" container\ncompose-stop         - Gracefully stop the stack (keep containers)\ncompose-down         - Stop & remove containers (keep named volumes)\ncompose-rm           - Remove *stopped* containers\ncompose-clean        - \u2728 Down **and** delete named volumes (data-loss \u26a0)\n\u2601\ufe0f IBM CLOUD CODE ENGINE\nibmcloud-check-env          - Verify all required IBM Cloud env vars are set\nibmcloud-cli-install        - Auto-install IBM Cloud CLI + required plugins (OS auto-detected)\nibmcloud-login              - Login to IBM Cloud CLI using IBMCLOUD_API_KEY (--sso)\nibmcloud-ce-login           - Set Code Engine target project and region\nibmcloud-list-containers    - List deployed Code Engine apps\nibmcloud-tag                - Tag container image for IBM Container Registry\nibmcloud-push               - Push image to IBM Container Registry\nibmcloud-deploy             - Deploy (or update) container image in Code Engine\nibmcloud-ce-logs            - Stream logs for the deployed application\nibmcloud-ce-status          - Get deployment status\nibmcloud-ce-rm              - Delete the Code Engine application\n\ud83e\uddea MINIKUBE LOCAL CLUSTER\nminikube-install      - Install Minikube (macOS, Linux, or Windows via choco)\nhelm-install          - Install Helm CLI (macOS, Linux, or Windows)\nminikube-start        - Start local Minikube cluster with Ingress + DNS + metrics-server\nminikube-stop         - Stop the Minikube cluster\nminikube-delete       - Delete the Minikube cluster\nminikube-image-load   - Build and load ghcr.io/ibm/mcp-context-forge:latest into Minikube\nminikube-k8s-apply    - Apply Kubernetes manifests from k8s/\nminikube-status       - Show status of Minikube and ingress pods\n\ud83d\udee0\ufe0f HELM CHART TASKS\nhelm-lint            - Lint the Helm chart (static analysis)\nhelm-package         - Package the chart into dist/ as mcp-stack-<ver>.tgz\nhelm-deploy          - Upgrade/Install chart into Minikube (profile mcpgw)\nhelm-delete          - Uninstall the chart release from Minikube\n\ud83c\udfe0 LOCAL PYPI SERVER\nlocal-pypi-install   - Install pypiserver for local testing\nlocal-pypi-start     - Start local PyPI server on :8084 (no auth)\nlocal-pypi-start-auth - Start local PyPI server with basic auth (admin/admin)\nlocal-pypi-stop      - Stop local PyPI server\nlocal-pypi-upload    - Upload existing package to local PyPI (no auth)\nlocal-pypi-upload-auth - Upload existing package to local PyPI (with auth)\nlocal-pypi-test      - Install package from local PyPI\nlocal-pypi-clean     - Full cycle: build \u2192 upload \u2192 install locally\n\ud83c\udfe0 LOCAL DEVPI SERVER\ndevpi-install        - Install devpi server and client\ndevpi-init           - Initialize devpi server (first time only)\ndevpi-start          - Start devpi server\ndevpi-stop           - Stop devpi server\ndevpi-setup-user     - Create user and dev index\ndevpi-upload         - Upload existing package to devpi\ndevpi-test           - Install package from devpi\ndevpi-clean          - Full cycle: build \u2192 upload \u2192 install locally\ndevpi-status         - Show devpi server status\ndevpi-web            - Open devpi web interface\n```\n</details>\n\n## \ud83d\udd0d Troubleshooting\n\n<details>\n<summary><strong>Port publishing on WSL2 (rootless Podman & Docker Desktop)</strong></summary>\n\n### Diagnose the listener\n\n```bash\n# Inside your WSL distro\nss -tlnp | grep 4444        # Use ss\nnetstat -anp | grep 4444    # or netstat\n```\n\n*Seeing `:::4444 LISTEN rootlessport` is normal* - the IPv6 wildcard\nsocket (`::`) also accepts IPv4 traffic **when**\n`net.ipv6.bindv6only = 0` (default on Linux).\n\n### Why localhost fails on Windows\n\nWSL 2's NAT layer rewrites only the *IPv6* side of the dual-stack listener. From Windows, `http://127.0.0.1:4444` (or Docker Desktop's \"localhost\") therefore times-out.\n\n#### Fix (Podman rootless)\n\n```bash\n# Inside the WSL distro\necho \"wsl\" | sudo tee /etc/containers/podman-machine\nsystemctl --user restart podman.socket\n```\n\n`ss` should now show `0.0.0.0:4444` instead of `:::4444`, and the\nservice becomes reachable from Windows *and* the LAN.\n\n#### Fix (Docker Desktop > 4.19)\n\nDocker Desktop adds a \"WSL integration\" switch per-distro.\nTurn it **on** for your distro, restart Docker Desktop, then restart the\ncontainer:\n\n```bash\ndocker restart mcpgateway\n```\n\n</details>\n\n<details>\n<summary><strong>Gateway starts but immediately exits (\"Failed to read DATABASE_URL\")</strong></summary>\n\nCopy `.env.example` to `.env` first:\n\n```bash\ncp .env.example .env\n```\n\nThen edit `DATABASE_URL`, `JWT_SECRET_KEY`, `BASIC_AUTH_PASSWORD`, etc.\nMissing or empty required vars cause a fast-fail at startup.\n\n</details>\n\n## Contributing\n\n1. Fork the repo, create a feature branch.\n2. Run `make lint` and fix any issues.\n3. Keep `make test` green and 100% coverage.\n4. Open a PR - describe your changes clearly.\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for more details.\n---\n\n## Changelog\n\nA complete changelog can be found here: [CHANGELOG.md](./CHANGELOG.md)\n\n## License\n\nLicensed under the **Apache License 2.0** - see [LICENSE](./LICENSE)\n\n\n## Core Authors and Maintainers\n\n- [Mihai Criveti](https://www.linkedin.com/in/crivetimihai) - Distinguished Engineer, Agentic AI\n\nSpecial thanks to our contributors for helping us improve ContextForge MCP Gateway:\n\n<a href=\"https://github.com/ibm/mcp-context-forge/graphs/contributors\">\n  <img src=\"https://contrib.rocks/image?repo=ibm/mcp-context-forge&max=100&anon=0&columns=10\" />\n</a>\n\n## Star History and Project Activity\n\n[![Star History Chart](https://api.star-history.com/svg?repos=ibm/mcp-context-forge&type=Date)](https://www.star-history.com/#ibm/mcp-context-forge&Date)\n\n<!-- === Usage Stats === -->\n[![PyPi Downloads](https://static.pepy.tech/badge/mcp-contextforge-gateway/month)](https://pepy.tech/project/mcp-contextforge-gateway)&nbsp;\n[![Stars](https://img.shields.io/github/stars/ibm/mcp-context-forge?style=social)](https://github.com/ibm/mcp-context-forge/stargazers)&nbsp;\n[![Forks](https://img.shields.io/github/forks/ibm/mcp-context-forge?style=social)](https://github.com/ibm/mcp-context-forge/network/members)&nbsp;\n[![Contributors](https://img.shields.io/github/contributors/ibm/mcp-context-forge)](https://github.com/ibm/mcp-context-forge/graphs/contributors)&nbsp;\n[![Last Commit](https://img.shields.io/github/last-commit/ibm/mcp-context-forge)](https://github.com/ibm/mcp-context-forge/commits)&nbsp;\n[![Open Issues](https://img.shields.io/github/issues/ibm/mcp-context-forge)](https://github.com/ibm/mcp-context-forge/issues)&nbsp;\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A production-grade MCP Gateway & Proxy built with FastAPI. Supports multi-server registration, virtual server composition, authentication, retry logic, observability, protocol translation, and a unified federated tool catalog.",
    "version": "0.3.1",
    "project_urls": {
        "Bug Tracker": "https://github.com/IBM/mcp-context-forge/issues",
        "Changelog": "https://github.com/IBM/mcp-context-forge/blob/main/CHANGELOG.md",
        "Documentation": "https://ibm.github.io/mcp-context-forge/",
        "Homepage": "https://ibm.github.io/mcp-context-forge/",
        "Repository": "https://github.com/IBM/mcp-context-forge"
    },
    "split_keywords": [
        "mcp",
        " api",
        " gateway",
        " proxy",
        " tools",
        " agents",
        " agentic ai",
        " model context protocol",
        " multi-agent",
        " fastapi",
        " json-rpc",
        " sse",
        " websocket",
        " federation",
        " security",
        " authentication"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "b201eb5abca4512ce20dbbca7f309275e3e7f1b322493b2ce8eb7b1854301435",
                "md5": "370226f22d2c5f3e09ab4ccd3a43ef4b",
                "sha256": "0c360103e83f5caf93b62a28a2d303668506ee1f732b6c1f0b887e32c6b8341e"
            },
            "downloads": -1,
            "filename": "mcp_contextforge_gateway-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "370226f22d2c5f3e09ab4ccd3a43ef4b",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.14,>=3.11",
            "size": 252701,
            "upload_time": "2025-07-11T03:26:40",
            "upload_time_iso_8601": "2025-07-11T03:26:40.738144Z",
            "url": "https://files.pythonhosted.org/packages/b2/01/eb5abca4512ce20dbbca7f309275e3e7f1b322493b2ce8eb7b1854301435/mcp_contextforge_gateway-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "e11e8a30fb7a476dc481d4c9d99d1a574d80bcd5b40bb75a5f4643ad82d0d8d4",
                "md5": "a64941ff85ef97d17fd0a095d4eafb8e",
                "sha256": "b91250975881b0565f579a4a8f508ff946c9b16e8ac56ade3231653cc8bdbd10"
            },
            "downloads": -1,
            "filename": "mcp_contextforge_gateway-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "a64941ff85ef97d17fd0a095d4eafb8e",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.14,>=3.11",
            "size": 3129664,
            "upload_time": "2025-07-11T03:26:52",
            "upload_time_iso_8601": "2025-07-11T03:26:52.109169Z",
            "url": "https://files.pythonhosted.org/packages/e1/1e/8a30fb7a476dc481d4c9d99d1a574d80bcd5b40bb75a5f4643ad82d0d8d4/mcp_contextforge_gateway-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-11 03:26:52",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "IBM",
    "github_project": "mcp-context-forge",
    "travis_ci": true,
    "coveralls": true,
    "github_actions": true,
    "tox": true,
    "lcname": "mcp-contextforge-gateway"
}
        
Elapsed time: 1.24907s