diff --git a/.github/workflows/docker_image_ci.yaml b/.github/workflows/docker_image_ci.yaml index b817c27f..62b15ef9 100644 --- a/.github/workflows/docker_image_ci.yaml +++ b/.github/workflows/docker_image_ci.yaml @@ -6,7 +6,7 @@ on: # tags: ["2.0.0"] env: - IMAGE_NAME: contextforge-gateway-rs + IMAGE_NAME: contextforge-data-plane jobs: @@ -21,17 +21,18 @@ jobs: id: set_version run: | CF_VERSION=$(grep -m 1 '^version' Cargo.toml | sed 's/version\s*=\s*"\(.*\)"/\1/') - echo "CF_VERSION=$CF_VERSION" >> $GITHUB_ENV + echo "CF_VERSION=${CF_VERSION}" >> "${GITHUB_ENV}" - name: Show version - run: echo $CF_VERSION + run: echo "${CF_VERSION}" - name: Build the Docker image - run: docker build . --file docker/Dockerfile --tag $IMAGE_NAME:latest + run: docker build . --file docker/Dockerfile --tag "${IMAGE_NAME}:latest" - name: Log in to registry - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin - name: Push image run: | - IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME - docker tag $IMAGE_NAME:latest $IMAGE_ID:$CF_VERSION - docker push $IMAGE_ID:$CF_VERSION - + IMAGE_ID="ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}" + docker tag "${IMAGE_NAME}:latest" "${IMAGE_ID}:v${CF_VERSION}" + docker tag "${IMAGE_NAME}:latest" "${IMAGE_ID}:latest" + docker push "${IMAGE_ID}:v${CF_VERSION}" + docker push "${IMAGE_ID}:latest" diff --git a/.gitignore b/.gitignore index c267df73..9e301cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ target **/mutants.out*/ # Generated by gateway local runs -contextforge-gateway-rs.log.* +contextforge-data-plane.log.* # Generated by mdBook docs/book/book/ diff --git a/AGENTS.md b/AGENTS.md index ef70deb7..a238e3a2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md -Guidance for agents working on `contextforge-gateway-rs`. +Guidance for agents working on `contextforge-data-plane`. This repo is the Rust dataplane part of ContextForge. It must stay compatible with the external ContextForge control plane in @@ -25,13 +25,13 @@ control-plane, UI, IAM, or metrics-storage app. ## Architecture -Architecture documentation lives in The ContextForge Gateway Book under +Architecture documentation lives in The ContextForge Data Plane Book under [docs/book](docs/book/README.md). Read the relevant page before changing the hot path: | Page | Read it for | | --- | --- | -| [What is ContextForge Gateway?](docs/book/src/what-is-contextforge-gateway.md) | Scope, boundaries, key terms, and the mental model. | +| [What is ContextForge Data Plane?](docs/book/src/what-is-contextforge-data-plane.md) | Scope, boundaries, key terms, and the mental model. | | [System Shape](docs/book/src/system-shape.md) | Crate layout, control-plane boundary, pipeline shape, state ownership, and module boundaries. | | [Request Flow](docs/book/src/request-flow.md) | Startup, middleware order, initialize fanout, authorized calls, and the response path. | | [Concurrency And Runtime Model](docs/book/src/concurrency-and-runtime.md) | Executor shapes, shared state and locks, fanout, and cancellation. | @@ -49,7 +49,7 @@ see [docs/book/README.md](docs/book/README.md) for build and validation steps. ## Working Rules -- Most product behavior belongs in `contextforge-gateway-rs-lib`; avoid adding +- Most product behavior belongs in `contextforge-data-plane-lib`; avoid adding dataplane logic to the binary crate. - Keep persistent config access behind `UserConfigStore`; do not push Redis details into routing code. diff --git a/Cargo.lock b/Cargo.lock index 6a7d8531..d0314ca8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -545,14 +545,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] -name = "contextforge-gateway-rs" +name = "contextforge-data-plane" version = "0.1.0" dependencies = [ "axum", "clap", - "contextforge-gateway-rs-apis", - "contextforge-gateway-rs-cpex", - "contextforge-gateway-rs-lib", + "contextforge-data-plane-apis", + "contextforge-data-plane-cpex", + "contextforge-data-plane-lib", "cpex-payload-marker", "cpex-secrets-detection", "cpex-text-prefixer", @@ -580,7 +580,7 @@ dependencies = [ ] [[package]] -name = "contextforge-gateway-rs-apis" +name = "contextforge-data-plane-apis" version = "0.1.0" dependencies = [ "cpex", @@ -591,12 +591,12 @@ dependencies = [ ] [[package]] -name = "contextforge-gateway-rs-cpex" +name = "contextforge-data-plane-cpex" version = "0.1.0" dependencies = [ "arc-swap", "async-trait", - "contextforge-gateway-rs-apis", + "contextforge-data-plane-apis", "cpex", "redis", "rmcp", @@ -608,7 +608,7 @@ dependencies = [ ] [[package]] -name = "contextforge-gateway-rs-lib" +name = "contextforge-data-plane-lib" version = "0.1.0" dependencies = [ "async-trait", @@ -617,8 +617,8 @@ dependencies = [ "axum-server", "chrono", "clap", - "contextforge-gateway-rs-apis", - "contextforge-gateway-rs-cpex", + "contextforge-data-plane-apis", + "contextforge-data-plane-cpex", "cpex", "cpex-secrets-detection", "futures", diff --git a/Cargo.toml b/Cargo.toml index c754f583..7ed72eb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [workspace] members = [ - "crates/contextforge-gateway-rs", - "crates/contextforge-gateway-rs-apis", - "crates/contextforge-gateway-rs-cpex", - "crates/contextforge-gateway-rs-lib", + "crates/contextforge-data-plane", + "crates/contextforge-data-plane-apis", + "crates/contextforge-data-plane-cpex", + "crates/contextforge-data-plane-lib", "crates/contextforge-load-test", "crates/plugins/cpex-secrets-detection", ] @@ -15,15 +15,15 @@ edition = "2024" rust-version = "1.96" license = "Apache-2.0" keywords = ["mcp", "gateway", "rust", "contextforge", "a2a", "ai", "llm"] -homepage = "https://github.com/contextforge-gateway-rs/contextforge-gateway-rs" +homepage = "https://github.com/contextforge-org/contextforge-data-plane" readme = "./README.md" -repository = "https://github.com/contextforge-gateway-rs/contextforge-gateway-rs" +repository = "https://github.com/contextforge-org/contextforge-data-plane" [workspace.dependencies] # Keep dependencies here only when at least two workspace members inherit them. -contextforge-gateway-rs-cpex = { path = "./crates/contextforge-gateway-rs-cpex" } -contextforge-gateway-rs-apis = { path = "./crates/contextforge-gateway-rs-apis"} +contextforge-data-plane-cpex = { path = "./crates/contextforge-data-plane-cpex" } +contextforge-data-plane-apis = { path = "./crates/contextforge-data-plane-apis"} rmcp = { version = "3.1.1", features = [ "server", "client", diff --git a/Makefile b/Makefile index 03a6f86e..655d37c6 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,12 @@ help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' -docker-prod: ## Build production Docker image (dataplane:latest) from docker/Dockerfile - docker build -t dataplane:latest -f docker/Dockerfile . +docker-prod: ## Build production Docker image (contextforge-data-plane:latest) from docker/Dockerfile + docker build -t contextforge-data-plane:latest -f docker/Dockerfile . testing-up: ## Launch testing stack: nginx, control plane, redis, postgres, pgbouncer, dataplane, fast_time_server - @docker image inspect dataplane:latest >/dev/null 2>&1 || { \ - echo "Image dataplane:latest not found. Run 'make docker-prod' first."; \ + @docker image inspect contextforge-data-plane:latest >/dev/null 2>&1 || { \ + echo "Image contextforge-data-plane:latest not found. Run 'make docker-prod' first."; \ exit 1; \ } docker compose -f docker/docker-compose.yml up -d nginx control-plane redis postgres pgbouncer data-plane fast_time_server register_fast_time diff --git a/README.md b/README.md index b7acc6f0..d29e29ae 100644 --- a/README.md +++ b/README.md @@ -1,195 +1,75 @@ -# ContextForge Dataplane +# ContextForge Data Plane -Architecture, configuration, and operations documentation lives in -[The ContextForge Gateway Book](docs/book/src/SUMMARY.md) under `docs/book`. -Build it locally with `mdbook serve docs/book`; see -[docs/book/README.md](docs/book/README.md) for details. +The Rust data plane for +[ContextForge](https://github.com/IBM/mcp-context-forge). It accepts modern MCP +traffic, loads control-plane-published configuration from Redis, and routes +authorized requests to configured MCP backends. -## Running -1. Start Redis and gateways -``` -docker compose -f docker/docker-compose-local.yaml up -d -``` - -Check Redis and backend status: -```bash -docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway-two -``` +Architecture, configuration, operations, and development documentation lives +in [The ContextForge Data Plane Book](docs/book/src/SUMMARY.md). Build it locally +with `mdbook serve docs/book`; see [docs/book/README.md](docs/book/README.md). -2. Run gateway -```bash - cargo run --bin contextforge-gateway-rs -- --address 0.0.0.0:8001 --redis-port 6379 --redis-address 127.0.0.1 --token-verification-public-key assets/jwt.key.pub --token-verification-private-key assets/jwt.key --number-of-cpus 16 --redis-mode=plain-text --upstream-connection-mode=plain-text-or-tls -``` +## Quick Start -This should spin up Redis instance and two mcp-gateways: a simple counter and a conformance test server from mcp-rust-sdk +Build the production image and start the supported control-plane + data-plane +test stack: -3. Get a test JWT token ```bash -USER_ID=11111111-1111-1111-1111-111111111111 -USER_EMAIL=admin@example.com - -curl --request GET \ - --url "http://127.0.0.1:8001/contextforge-rs/admin/tokens/${USER_ID}?email=${USER_EMAIL}" \ - --header 'accept: application/json' \ - --header 'content-type: application/json' +make docker-prod +make testing-up ``` -4. Use the token to add a test user to Redis +The stack uses the current `fast_time_server` backend and exercises config +publication through the external ContextForge control plane. Follow +[Local Docker Stack](docs/book/src/local-docker-stack.md) for the complete smoke +test, then stop it with: + ```bash -curl --request POST \ - --url "http://127.0.0.1:8001/contextforge-rs/admin/userconfigs/${USER_ID}" \ - --header 'authorization: Bearer {{token}}' \ - --header 'content-type: application/json' \ - --data '{ - "virtual_hosts": { - "c0ffee00f001f00lf00ldeadbeefdead": { - "backends": { - "gateway-one": { - "name": "gateway-one", - "url": "http://127.0.0.1:5555/mcp", - "transport": "STREAMABLEHTTP", - "passthrough_headers": [], - "allowed_tool_names": [], - "allowed_resource_names": [], - "allowed_prompt_names": [] - }, - "gateway-two": { - "name": "gateway-two", - "url": "http://127.0.0.1:5556/mcp", - "transport": "STREAMABLEHTTP", - "passthrough_headers": [], - "allowed_tool_names": [], - "allowed_resource_names": [], - "allowed_prompt_names": [] - } - } - } - } -}' +make testing-down ``` -6. Spin up MCP Inspector to test the calls +## Run the Binary from Cargo - -## Runtime CPEX Plugins - -Runtime CPEX plugins are disabled by default. Enable hook execution when starting the gateway: +For a lightweight host-development setup, start Redis and the MCP Rust SDK +counter and conformance fixtures: ```bash -cargo run --release \ - --bin contextforge-gateway-rs -- \ - --address 0.0.0.0:8001 \ - --redis-port 6379 \ - --redis-address 127.0.0.1 \ - --token-verification-public-key assets/jwt.key.pub \ - --token-verification-private-key assets/jwt.key \ - --number-of-cpus 16 \ - --redis-mode=plain-text \ - --upstream-connection-mode=plain-text-or-tls \ - --runtime-plugins-enabled true +docker compose -f docker/docker-compose-local.yaml up -d +docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway-two ``` -Plugin configuration is stored in Redis at key `ContextForgeGatewayRuntimePluginConfig`. The value can be JSON or MessagePack with `version: 1` and `cpex` containing the CPEX config. When runtime plugins are enabled with Redis config, this key must exist before startup. The gateway reloads that key while running, builds a new initialized CPEX runtime, and swaps the runtime registry to the new immutable `PluginManager`. The existing `PluginManager` is not mutated after initialization. +Then follow [Run the Gateway Locally](docs/book/src/running-the-gateway.md). + +## Runtime CPEX Plugins + +Runtime CPEX plugins are disabled by default. When enabled, the data plane loads +validated plugin configuration from Redis and supports the narrow hook surface +documented in [Plugins And Policy](docs/book/src/plugins-and-policy.md). -This integration currently passes only tool payloads. CPEX configs that enable route-based plugin selection, plugin directories, global policies/defaults, non-tool hooks, or plugin conditions are rejected in this PR. Redis write access to this key is a control-plane trust boundary because it controls which registered hooks run. +The optional demo plugin crates still come from their independently hosted +`cpex-plugins-rs` repository; they are unrelated to the retired MCP SDK fork. ### Experimental Secrets Detection Plugin The bundled secrets detection CPEX plugin is experimental. It is compiled into -the gateway with `contextforge-gateway-rs/plugins`; Redis config only activates -plugin factories that are already present in the binary. +the data plane with `contextforge-data-plane/plugins`; Redis config only +activates plugin factories that are already present in the binary. Activation requires all three pieces: -- Compile-time feature: `contextforge-gateway-rs/plugins` +- Compile-time feature: `contextforge-data-plane/plugins` - Runtime flag: `--runtime-plugins-enabled true` - Redis config key: `ContextForgeGatewayRuntimePluginConfig` -The plugin kind is `validator/secrets-detection`. The dataplane currently wires -only `cmf.tool_pre_invoke` and `cmf.tool_post_invoke`. +The plugin kind is `validator/secrets-detection`. The data plane currently +wires only `cmf.tool_pre_invoke` and `cmf.tool_post_invoke`. Example run command: ```bash cargo run --release \ - --features contextforge-gateway-rs/plugins \ - --bin contextforge-gateway-rs -- \ - --address 0.0.0.0:8001 \ - --redis-port 6379 \ - --redis-address 127.0.0.1 \ - --token-verification-public-key assets/jwt.key.pub \ - --token-verification-private-key assets/jwt.key \ - --number-of-cpus 16 \ - --redis-mode=plain-text \ - --upstream-connection-mode=plain-text-or-tls \ - --runtime-plugins-enabled true -``` - -### Payload Marker Demo - -This demo uses the `test-plugins` feature, which includes the demo plugin crates from `cpex-plugins-rs`. The plugin must be included in the gateway build before the gateway starts. Redis runtime registration activates already-registered factories; it does not load new Rust code into a running process. - -Build the gateway with the demo plugin factories: - -```bash -cargo check -p contextforge-gateway-rs --features test-plugins -``` - -The `test-plugins` feature registers those demo plugin factories through the gateway's generic CMF factory adapter. - -Start Redis and the sample MCP backends: - -```bash -GATEWAY_CPU_LIMIT=1 \ -GATEWAY_CPU_RESERVATION=0.5 \ -GATEWAY_MEM_LIMIT=1G \ -GATEWAY_MEM_RESERVATION=512M \ -docker compose -f docker/docker-compose-local.yaml up -d -``` - -Check Redis and backend status: -```bash -docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway-two -``` - -Register the payload marker config in Redis before starting the enabled gateway: - -```bash -docker compose -f docker/docker-compose-local.yaml exec -T redis redis-cli SET ContextForgeGatewayRuntimePluginConfig '{ - "version": 1, - "cpex": { - "plugins": [ - { - "name": "payload-marker", - "kind": "contextforge/payload-marker", - "hooks": ["cmf.tool_post_invoke"] - } - ] - } -}' -``` - -Run only one gateway process on port `8001` at a time. Stop the current gateway with `Ctrl-C` before switching between disabled and enabled plugin runs. - -Start the gateway with runtime plugins disabled for a baseline run: - -```bash -cargo run --release --features test-plugins --bin contextforge-gateway-rs -- \ - --address 0.0.0.0:8001 \ - --redis-port 6379 \ - --redis-address 127.0.0.1 \ - --token-verification-public-key assets/jwt.key.pub \ - --token-verification-private-key assets/jwt.key \ - --number-of-cpus 16 \ - --redis-mode=plain-text \ - --upstream-connection-mode=plain-text-or-tls \ - --runtime-plugins-enabled false -``` - -Start the gateway with runtime plugins enabled for the marker run: - -```bash -cargo run --release --features test-plugins --bin contextforge-gateway-rs -- \ + --features contextforge-data-plane/plugins \ + --bin contextforge-data-plane -- \ --address 0.0.0.0:8001 \ --redis-port 6379 \ --redis-address 127.0.0.1 \ @@ -201,132 +81,20 @@ cargo run --release --features test-plugins --bin contextforge-gateway-rs -- \ --runtime-plugins-enabled true ``` -Get a token: - -```bash -USER_ID=11111111-1111-1111-1111-111111111111 -USER_EMAIL=admin@example.com - -TOKEN=$(curl --silent --show-error --request GET \ - --url "http://127.0.0.1:8001/contextforge-rs/admin/tokens/${USER_ID}?email=${USER_EMAIL}" \ - --header 'accept: application/json' \ - --header 'content-type: application/json') -``` - -Create the gateway user config: - -```bash -curl --silent --show-error --request POST \ - --url "http://127.0.0.1:8001/contextforge-rs/admin/userconfigs/${USER_ID}" \ - --header "authorization: Bearer ${TOKEN}" \ - --header 'content-type: application/json' \ - --data '{ - "virtual_hosts": { - "c0ffee00f001f00lf00ldeadbeefdead": { - "backends": { - "gateway-one": { - "name": "gateway-one", - "url": "http://127.0.0.1:5555/mcp", - "transport": "STREAMABLEHTTP", - "passthrough_headers": [], - "allowed_tool_names": [], - "allowed_resource_names": [], - "allowed_prompt_names": [] - } - } - } - } - }' -``` - -Open an MCP session: - -```bash -INIT_HEADERS=$(mktemp) -``` - -```bash -curl --silent --show-error \ - --dump-header "${INIT_HEADERS}" \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header 'content-type: application/json' \ - --header 'accept: application/json, text/event-stream' \ - --data '{ - "jsonrpc": "2.0", - "id": 0, - "method": "initialize", - "params": { - "protocolVersion": "2025-11-25", - "capabilities": {}, - "clientInfo": { "name": "curl", "version": "0.1.0" } - } - }' -``` - -```bash -SESSION_ID=$(awk 'tolower($1) == "mcp-session-id:" { gsub("\r", "", $2); print $2 }' "${INIT_HEADERS}") -``` - -```bash -curl --silent --show-error \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header "mcp-session-id: ${SESSION_ID}" \ - --header 'mcp-protocol-version: 2025-11-25' \ - --header 'content-type: application/json' \ - --header 'accept: application/json, text/event-stream' \ - --data '{"jsonrpc":"2.0","method":"notifications/initialized"}' -``` +## Tracing and Metrics -Send a tool request: - -```bash -curl --silent --show-error \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header "mcp-session-id: ${SESSION_ID}" \ - --header 'mcp-protocol-version: 2025-11-25' \ - --header 'content-type: application/json' \ - --header 'accept: application/json, text/event-stream' \ - --data '{ - "jsonrpc": "2.0", - "id": 1, - "method": "tools/call", - "params": { - "name": "gateway-one-say_hello", - "arguments": {} - } - }' -``` - -With `--runtime-plugins-enabled false`, the response content should include only the backend tool result: - -```text -hello -``` - -With `--runtime-plugins-enabled true`, the response content should include the backend tool result plus an additional text part: - -```text -[cpex:payload-marker] -``` - -## Tracing & Metrics - -The gateway exports OTLP traces and metrics -(issue [#4721](https://github.com/IBM/mcp-context-forge/issues/4721)), and a -local verification stack (Langfuse + OTel Collector + Prometheus) ships as -compose overlays under `docker/`. The full walkthrough โ€” flags, stack setup, -starter PromQL queries, and a debugging checklist โ€” lives in the book: +The data plane exports OTLP traces and metrics. The local Langfuse, +OpenTelemetry Collector, and Prometheus overlays are documented in [Telemetry And Diagnostics](docs/book/src/telemetry-and-diagnostics.md). ## Performance Tests -As above and then run: -```bash -cargo run --release --bin contextforge-load-test -- --host 'http://127.0.0.1:8001' -r 40 -u 120 --run-time 120s --report-file report.html +With a configured data plane running on port `8001`: +```bash +cargo run --release --bin contextforge-load-test -- \ + --host http://127.0.0.1:8001 \ + -r 40 -u 120 --run-time 120s --report-file report.html ``` -[Performance reports](./reports) +Existing benchmark results are under [reports](reports). diff --git a/crates/contextforge-gateway-rs-apis/Cargo.toml b/crates/contextforge-data-plane-apis/Cargo.toml similarity index 79% rename from crates/contextforge-gateway-rs-apis/Cargo.toml rename to crates/contextforge-data-plane-apis/Cargo.toml index 478c6410..4440f6cf 100644 --- a/crates/contextforge-gateway-rs-apis/Cargo.toml +++ b/crates/contextforge-data-plane-apis/Cargo.toml @@ -1,11 +1,14 @@ [package] -name = "contextforge-gateway-rs-apis" +name = "contextforge-data-plane-apis" version.workspace = true edition.workspace = true rust-version.workspace = true license.workspace = true keywords.workspace = true +homepage.workspace = true +readme.workspace = true +repository.workspace = true [dependencies] diff --git a/crates/contextforge-gateway-rs-apis/src/lib.rs b/crates/contextforge-data-plane-apis/src/lib.rs similarity index 100% rename from crates/contextforge-gateway-rs-apis/src/lib.rs rename to crates/contextforge-data-plane-apis/src/lib.rs diff --git a/crates/contextforge-gateway-rs-apis/src/main.rs b/crates/contextforge-data-plane-apis/src/main.rs similarity index 91% rename from crates/contextforge-gateway-rs-apis/src/main.rs rename to crates/contextforge-data-plane-apis/src/main.rs index 97eba7e1..88ff3252 100644 --- a/crates/contextforge-gateway-rs-apis/src/main.rs +++ b/crates/contextforge-data-plane-apis/src/main.rs @@ -1,6 +1,6 @@ use std::fs; -use contextforge_gateway_rs_apis::{User, user_store}; +use contextforge_data_plane_apis::{User, user_store}; use schemars::SchemaGenerator; use user_store::UserConfig; #[allow(clippy::print_stdout)] diff --git a/crates/contextforge-gateway-rs-apis/src/runtime_plugin_config.rs b/crates/contextforge-data-plane-apis/src/runtime_plugin_config.rs similarity index 100% rename from crates/contextforge-gateway-rs-apis/src/runtime_plugin_config.rs rename to crates/contextforge-data-plane-apis/src/runtime_plugin_config.rs diff --git a/crates/contextforge-gateway-rs-apis/src/user.rs b/crates/contextforge-data-plane-apis/src/user.rs similarity index 100% rename from crates/contextforge-gateway-rs-apis/src/user.rs rename to crates/contextforge-data-plane-apis/src/user.rs diff --git a/crates/contextforge-gateway-rs-apis/src/user_store.rs b/crates/contextforge-data-plane-apis/src/user_store.rs similarity index 100% rename from crates/contextforge-gateway-rs-apis/src/user_store.rs rename to crates/contextforge-data-plane-apis/src/user_store.rs diff --git a/crates/contextforge-gateway-rs-cpex/Cargo.toml b/crates/contextforge-data-plane-cpex/Cargo.toml similarity index 73% rename from crates/contextforge-gateway-rs-cpex/Cargo.toml rename to crates/contextforge-data-plane-cpex/Cargo.toml index 5b373ec6..d74d69bd 100644 --- a/crates/contextforge-gateway-rs-cpex/Cargo.toml +++ b/crates/contextforge-data-plane-cpex/Cargo.toml @@ -1,10 +1,13 @@ [package] -name = "contextforge-gateway-rs-cpex" +name = "contextforge-data-plane-cpex" version.workspace = true edition.workspace = true rust-version.workspace = true license.workspace = true keywords.workspace = true +homepage.workspace = true +readme.workspace = true +repository.workspace = true [lib] doctest = false @@ -12,7 +15,7 @@ doctest = false [dependencies] arc-swap = "1.7" async-trait.workspace = true -contextforge-gateway-rs-apis.workspace = true +contextforge-data-plane-apis.workspace = true cpex.workspace = true redis.workspace = true rmcp.workspace = true diff --git a/crates/contextforge-gateway-rs-cpex/src/cmf.rs b/crates/contextforge-data-plane-cpex/src/cmf.rs similarity index 100% rename from crates/contextforge-gateway-rs-cpex/src/cmf.rs rename to crates/contextforge-data-plane-cpex/src/cmf.rs diff --git a/crates/contextforge-gateway-rs-cpex/src/config.rs b/crates/contextforge-data-plane-cpex/src/config.rs similarity index 97% rename from crates/contextforge-gateway-rs-cpex/src/config.rs rename to crates/contextforge-data-plane-cpex/src/config.rs index c5538ea1..4dc67006 100644 --- a/crates/contextforge-gateway-rs-cpex/src/config.rs +++ b/crates/contextforge-data-plane-cpex/src/config.rs @@ -7,7 +7,7 @@ use redis::{ use tokio::sync::Mutex; use crate::error::GatewayPluginRuntimeError; -use contextforge_gateway_rs_apis::runtime_plugin_config::{ +use contextforge_data_plane_apis::runtime_plugin_config::{ RUNTIME_PLUGIN_CONFIG_KEY, RUNTIME_PLUGIN_CONFIG_VERSION, RuntimePluginConfigDocument, }; use cpex::cpex_core::config::CpexConfig; @@ -86,7 +86,7 @@ pub(crate) fn decode_config_document(config: &[u8]) -> Result, pub(crate) config: Config, @@ -140,46 +140,46 @@ pub enum OtlpProtocol { } #[derive(Debug, Clone, Parser, Default)] -#[command(name = "contextforge-gateway-rs")] -#[command(about = "Minimal, fast and experimental Gateway/Dataplane for ContextForge")] +#[command(name = "contextforge-data-plane")] +#[command(about = "Minimal, fast, experimental data plane for ContextForge")] pub struct Config { - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_ADDRESS")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_ADDRESS")] pub address: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PUBLIC_KEY")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY")] pub token_verification_public_key: Option, #[cfg(feature = "with_tools")] - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PRIVATE_KEY")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY")] pub token_verification_private_key: PathBuf, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TOKEN_SECRET")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TOKEN_SECRET")] pub token_verification_secret: Option>, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_ENABLE_OPEN_TELEMETRY")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_ENABLE_OPEN_TELEMETRY")] pub enable_open_telemetry: Option, /// OTLP exporter endpoint. For `grpc` this is the collector address /// (e.g. `http://127.0.0.1:4317`). For `http-protobuf` this must be the /// full traces URL (e.g. `http://langfuse-web:3000/api/public/otel/v1/traces` /// for Langfuse, or `http://collector:4318/v1/traces` for the OTel Collector). - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_ENDPOINT")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_ENDPOINT")] pub otlp_endpoint: Option, /// OTLP wire protocol. Use `http-protobuf` when exporting directly to /// Langfuse (it does not accept gRPC). - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_PROTOCOL")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_PROTOCOL")] pub otlp_protocol: Option, /// Additional headers to attach to every OTLP request, formatted as /// `key1=value1,key2=value2`. Used to pass authentication (for example /// Langfuse's `Authorization=Basic `). - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_HEADERS")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_HEADERS")] pub otlp_headers: Option, /// Overrides the `service.name` OpenTelemetry resource attribute. - /// Defaults to `CONTEXTFORGE-GATEWAY-RS`. - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_OTEL_SERVICE_NAME")] + /// Defaults to `CONTEXTFORGE-DATA-PLANE`. + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_OTEL_SERVICE_NAME")] pub otlp_service_name: Option, /// Enables OTLP export of HTTP server metrics (request counts, latency @@ -187,7 +187,7 @@ pub struct Config { /// Independent from `enable_open_telemetry` so traces and metrics can be /// turned on individually. Langfuse does not ingest metrics, so this /// typically targets an OpenTelemetry Collector. - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_ENABLE_OTEL_METRICS")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_ENABLE_OTEL_METRICS")] pub enable_otel_metrics: Option, /// OTLP metrics endpoint. For `grpc` defaults to `http://127.0.0.1:4317`; @@ -195,67 +195,67 @@ pub struct Config { /// Kept separate from `otlp_endpoint` so traces and metrics can be routed /// to different backends (typical: traces to Langfuse, metrics to an /// OTel Collector). - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT")] pub otlp_metrics_endpoint: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_GATEWAY_CPUS")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_NUMBER_OF_CPUS")] pub number_of_cpus: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_SINGLE_RUNTIME")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_SINGLE_RUNTIME")] pub single_runtime: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_RUNTIME_PLUGINS_ENABLED")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_RUNTIME_PLUGINS_ENABLED")] pub runtime_plugins_enabled: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TLS_ADDRESS")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TLS_ADDRESS")] pub tls_address: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TLS_SERVER_PRIVATE_KEY")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TLS_SERVER_PRIVATE_KEY")] pub server_private_key: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TLS_SERVER_CERTIFICATE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TLS_SERVER_CERTIFICATE")] pub server_certificate: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE")] pub upstream_connection_mode: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TLS_UPSTREAM_PRIVATE_KEY")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TLS_UPSTREAM_PRIVATE_KEY")] pub upstream_private_key: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TLS_UPSTREAM_CERTIFICATE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TLS_UPSTREAM_CERTIFICATE")] pub upstream_certificate: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_TLS_UPSTREAM_TRUST_BUNDLE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_TLS_UPSTREAM_TRUST_BUNDLE")] pub upstream_trust_bundle: Option, /// Expiry in seconds for the in-process user config cache in front of /// Redis. The control-plane dataplane publisher rewrites UserConfig keys /// every 60s, so this bounds how stale a subject's config can get. /// 0 disables caching and reads Redis on every request. - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_USER_CONFIG_CACHE_EXPIRY_SECONDS", default_value_t = 60)] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_USER_CONFIG_CACHE_EXPIRY_SECONDS", default_value_t = 60)] pub user_config_cache_expiry_seconds: u64, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_REDIS_HOSTNAME")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_REDIS_HOSTNAME")] pub redis_address: String, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_REDIS_PORT")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_REDIS_PORT")] pub redis_port: u16, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_REDIS_CONNECTION_MODE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE")] pub redis_mode: RedisConnectionMode, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_REDIS_TLS_REDIS_TRUST_BUNDLE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_REDIS_TLS_REDIS_TRUST_BUNDLE")] pub redis_tls_trust_bundle: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_REDIS_TLS_REDIS_CLIENT_PRIVATE_KEY")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_REDIS_TLS_REDIS_CLIENT_PRIVATE_KEY")] pub redis_tls_client_private_key: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_RS_REDIS_TLS_REDIS_CLIENT_CERTIFICATE")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_REDIS_TLS_REDIS_CLIENT_CERTIFICATE")] pub redis_tls_client_certificate: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_LOG_NAME")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_LOG_NAME")] pub log_name: Option, - #[arg(long, env = "CONTEXTFORGE_GATEWAY_LOG_ROTATION")] + #[arg(long, env = "CONTEXTFORGE_DATA_PLANE_LOG_ROTATION")] pub log_rotation: Option, } diff --git a/crates/contextforge-gateway-rs-lib/src/const_values.rs b/crates/contextforge-data-plane-lib/src/const_values.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/const_values.rs rename to crates/contextforge-data-plane-lib/src/const_values.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/backend_client.rs b/crates/contextforge-data-plane-lib/src/gateway/backend_client.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/src/gateway/backend_client.rs rename to crates/contextforge-data-plane-lib/src/gateway/backend_client.rs index 7d9b2eb7..034bef24 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/backend_client.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/backend_client.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::Arc}; -use contextforge_gateway_rs_cpex::{GatewayPluginRuntimeHandle, RuntimeHookState}; +use contextforge_data_plane_cpex::{GatewayPluginRuntimeHandle, RuntimeHookState}; use rmcp::{ ClientHandler, Peer, RoleClient, RoleServer, model::{ diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/backend_transports.rs b/crates/contextforge-data-plane-lib/src/gateway/backend_transports.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/backend_transports.rs rename to crates/contextforge-data-plane-lib/src/gateway/backend_transports.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/identifier_routing.rs b/crates/contextforge-data-plane-lib/src/gateway/identifier_routing.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/src/gateway/identifier_routing.rs rename to crates/contextforge-data-plane-lib/src/gateway/identifier_routing.rs index 647e0793..ab94523e 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/identifier_routing.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/identifier_routing.rs @@ -1,4 +1,4 @@ -use contextforge_gateway_rs_apis::user_store::VirtualHost; +use contextforge_data_plane_apis::user_store::VirtualHost; use rmcp::{ErrorData, model::ErrorCode, service::ServiceError}; use tracing::{debug, warn}; diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/list_aggregation.rs b/crates/contextforge-data-plane-lib/src/gateway/list_aggregation.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/src/gateway/list_aggregation.rs rename to crates/contextforge-data-plane-lib/src/gateway/list_aggregation.rs index f9945f1d..001ea53f 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/list_aggregation.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/list_aggregation.rs @@ -3,7 +3,7 @@ use std::{ future::Future, }; -use contextforge_gateway_rs_apis::user_store::VirtualHost; +use contextforge_data_plane_apis::user_store::VirtualHost; use rmcp::{ ErrorData, model::{ diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_call_validator.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_call_validator.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_call_validator.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_call_validator.rs index 16b94ba2..026de314 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_call_validator.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/mcp_call_validator.rs @@ -1,4 +1,4 @@ -use contextforge_gateway_rs_apis::user_store::{UserConfig, VirtualHost}; +use contextforge_data_plane_apis::user_store::{UserConfig, VirtualHost}; use http::request::Parts; use rmcp::{ErrorData, RoleServer, model::ErrorCode, service::RequestContext}; use tracing::debug; diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_service.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_service.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_service.rs index 564da261..452a4669 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/mcp_service.rs @@ -4,7 +4,7 @@ mod prompts; mod resources; mod tools; -use contextforge_gateway_rs_cpex::GatewayPluginRuntimeHandle; +use contextforge_data_plane_cpex::GatewayPluginRuntimeHandle; use rmcp::{ ErrorData, RoleServer, ServerHandler, model::{ diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/completion.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/completion.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/completion.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_service/completion.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/initialization.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/initialization.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/initialization.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_service/initialization.rs index 60331220..3370cac6 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/initialization.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/initialization.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, sync::Arc}; -use contextforge_gateway_rs_apis::user_store::BackendMCPGateway; +use contextforge_data_plane_apis::user_store::BackendMCPGateway; use http::request::Parts; use rmcp::{ ErrorData, RoleClient, RoleServer, ServiceExt, @@ -275,7 +275,7 @@ fn is_protected_header(name: &http::HeaderName) -> bool { #[cfg(test)] mod tests { - use contextforge_gateway_rs_apis::user_store::Transport; + use contextforge_data_plane_apis::user_store::Transport; use super::*; diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/prompts.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/prompts.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/prompts.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_service/prompts.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/resources.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/resources.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/resources.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_service/resources.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/tools.rs b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/tools.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/tools.rs rename to crates/contextforge-data-plane-lib/src/gateway/mcp_service/tools.rs index 903eb43e..b442fb7d 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/tools.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/mcp_service/tools.rs @@ -1,4 +1,4 @@ -use contextforge_gateway_rs_cpex::ToolPreCallResult; +use contextforge_data_plane_cpex::ToolPreCallResult; use rmcp::{ ErrorData, RoleServer, model::{CallToolRequestParams, CallToolResponse, ErrorCode, ListToolsResult, PaginatedRequestParams}, diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/mod.rs b/crates/contextforge-data-plane-lib/src/gateway/mod.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/mod.rs rename to crates/contextforge-data-plane-lib/src/gateway/mod.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/session_manager.rs b/crates/contextforge-data-plane-lib/src/gateway/session_manager.rs similarity index 97% rename from crates/contextforge-gateway-rs-lib/src/gateway/session_manager.rs rename to crates/contextforge-data-plane-lib/src/gateway/session_manager.rs index af361e72..20aa828a 100644 --- a/crates/contextforge-gateway-rs-lib/src/gateway/session_manager.rs +++ b/crates/contextforge-data-plane-lib/src/gateway/session_manager.rs @@ -1,4 +1,4 @@ -use contextforge_gateway_rs_apis::user_store::VirtualHost; +use contextforge_data_plane_apis::user_store::VirtualHost; use tracing::{debug, info}; use super::backend_transports::{BackendTransportKey, BackendTransports, ServiceHolder}; diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/session_store/local_session_store.rs b/crates/contextforge-data-plane-lib/src/gateway/session_store/local_session_store.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/session_store/local_session_store.rs rename to crates/contextforge-data-plane-lib/src/gateway/session_store/local_session_store.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/session_store/mod.rs b/crates/contextforge-data-plane-lib/src/gateway/session_store/mod.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/session_store/mod.rs rename to crates/contextforge-data-plane-lib/src/gateway/session_store/mod.rs diff --git a/crates/contextforge-gateway-rs-lib/src/gateway/session_store/redis_session_store.rs b/crates/contextforge-data-plane-lib/src/gateway/session_store/redis_session_store.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/gateway/session_store/redis_session_store.rs rename to crates/contextforge-data-plane-lib/src/gateway/session_store/redis_session_store.rs diff --git a/crates/contextforge-gateway-rs-lib/src/layers/claims_id.rs b/crates/contextforge-data-plane-lib/src/layers/claims_id.rs similarity index 95% rename from crates/contextforge-gateway-rs-lib/src/layers/claims_id.rs rename to crates/contextforge-data-plane-lib/src/layers/claims_id.rs index 365b8df2..02ff0488 100644 --- a/crates/contextforge-gateway-rs-lib/src/layers/claims_id.rs +++ b/crates/contextforge-data-plane-lib/src/layers/claims_id.rs @@ -8,7 +8,7 @@ use http::{StatusCode, header}; use jsonwebtoken::Validation; use crate::{ - common::{ContextForgeClaims, ContextForgeGatewayAppState}, + common::{ContextForgeClaims, ContextForgeDataPlaneAppState}, const_values::{CONTEXT_FORGE_GATEWAY_AUDIENCE, CONTEXT_FORGE_GATEWAY_ISSUER}, }; @@ -21,7 +21,7 @@ fn unauthorized_response() -> Response { } pub async fn claims_layer( - State(state): State, + State(state): State, request: http::Request, next: Next, ) -> Response { @@ -79,7 +79,7 @@ mod test { use async_trait::async_trait; use axum::{Router, body::Body, middleware, response::Response, routing::get}; use chrono::Duration; - use contextforge_gateway_rs_apis::{User, user_store::UserConfig}; + use contextforge_data_plane_apis::{User, user_store::UserConfig}; use http::{HeaderMap, Request, StatusCode}; use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, encode}; use tower::ServiceExt; @@ -87,7 +87,7 @@ mod test { use crate::{ Config, - common::{self, ContextForgeClaims, ContextForgeGatewayAppState, JwtTokenDecoders, Scopes}, + common::{self, ContextForgeClaims, ContextForgeDataPlaneAppState, JwtTokenDecoders, Scopes}, const_values::{CONTEXT_FORGE_GATEWAY_AUDIENCE, CONTEXT_FORGE_GATEWAY_ISSUER}, layers::claims_id::claims_layer, user_config_store::{ConfigStoreError, UserConfigStore}, @@ -165,7 +165,7 @@ mod test { let decoding_key = DecodingKey::from_secret(HMAC_SECRET); - let state = ContextForgeGatewayAppState { + let state = ContextForgeDataPlaneAppState { jwt_token_decoding_keys: JwtTokenDecoders { rs: None, hmac_sha: Some(decoding_key) }, config_store: Arc::new(MockedUserConfigStore {}), config: Config::default(), @@ -200,7 +200,7 @@ mod test { let decoding_key = DecodingKey::from_secret(HMAC_SECRET); - let state = ContextForgeGatewayAppState { + let state = ContextForgeDataPlaneAppState { jwt_token_decoding_keys: JwtTokenDecoders { rs: None, hmac_sha: Some(decoding_key) }, config_store: Arc::new(MockedUserConfigStore {}), config: Config::default(), @@ -242,7 +242,7 @@ mod test { let decoding_key = DecodingKey::from_secret(HMAC_SECRET); - let state = ContextForgeGatewayAppState { + let state = ContextForgeDataPlaneAppState { jwt_token_decoding_keys: JwtTokenDecoders { rs: None, hmac_sha: Some(decoding_key) }, config_store: Arc::new(MockedUserConfigStore {}), config: Config::default(), @@ -277,7 +277,7 @@ mod test { let decoding_key = DecodingKey::from_secret(HMAC_SECRET); - let state = ContextForgeGatewayAppState { + let state = ContextForgeDataPlaneAppState { jwt_token_decoding_keys: JwtTokenDecoders { rs: None, hmac_sha: Some(decoding_key) }, config_store: Arc::new(MockedUserConfigStore {}), config: Config::default(), diff --git a/crates/contextforge-gateway-rs-lib/src/layers/mod.rs b/crates/contextforge-data-plane-lib/src/layers/mod.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/layers/mod.rs rename to crates/contextforge-data-plane-lib/src/layers/mod.rs diff --git a/crates/contextforge-gateway-rs-lib/src/layers/session_id.rs b/crates/contextforge-data-plane-lib/src/layers/session_id.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/layers/session_id.rs rename to crates/contextforge-data-plane-lib/src/layers/session_id.rs diff --git a/crates/contextforge-gateway-rs-lib/src/layers/user_config_store.rs b/crates/contextforge-data-plane-lib/src/layers/user_config_store.rs similarity index 94% rename from crates/contextforge-gateway-rs-lib/src/layers/user_config_store.rs rename to crates/contextforge-data-plane-lib/src/layers/user_config_store.rs index 80ba5ad2..4d5804c2 100644 --- a/crates/contextforge-gateway-rs-lib/src/layers/user_config_store.rs +++ b/crates/contextforge-data-plane-lib/src/layers/user_config_store.rs @@ -1,16 +1,16 @@ use axum::{body::Body, extract::State, middleware::Next, response::Response}; -use contextforge_gateway_rs_apis::User; +use contextforge_data_plane_apis::User; use http::{StatusCode, header}; //use openid::Claims; use tracing::{debug, info, warn}; use crate::{ - common::{ContextForgeClaims, ContextForgeGatewayAppState}, + common::{ContextForgeClaims, ContextForgeDataPlaneAppState}, user_config_store::ConfigStoreError, }; pub async fn user_config_store_layer( - State(state): State, + State(state): State, mut request: http::Request, next: Next, ) -> Response { diff --git a/crates/contextforge-gateway-rs-lib/src/layers/virtual_host_config.rs b/crates/contextforge-data-plane-lib/src/layers/virtual_host_config.rs similarity index 96% rename from crates/contextforge-gateway-rs-lib/src/layers/virtual_host_config.rs rename to crates/contextforge-data-plane-lib/src/layers/virtual_host_config.rs index ce1c2044..7634e58d 100644 --- a/crates/contextforge-gateway-rs-lib/src/layers/virtual_host_config.rs +++ b/crates/contextforge-data-plane-lib/src/layers/virtual_host_config.rs @@ -1,5 +1,5 @@ use axum::{body::Body, middleware::Next, response::Response}; -use contextforge_gateway_rs_apis::user_store::UserConfig; +use contextforge_data_plane_apis::user_store::UserConfig; use http::{StatusCode, header}; use tracing::debug; @@ -42,7 +42,7 @@ mod tests { use std::collections::HashMap; use axum::{Router, body::to_bytes, middleware, routing::get}; - use contextforge_gateway_rs_apis::user_store::VirtualHost; + use contextforge_data_plane_apis::user_store::VirtualHost; use http::Request; use tower::ServiceExt; diff --git a/crates/contextforge-gateway-rs-lib/src/layers/virtual_host_id.rs b/crates/contextforge-data-plane-lib/src/layers/virtual_host_id.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/layers/virtual_host_id.rs rename to crates/contextforge-data-plane-lib/src/layers/virtual_host_id.rs diff --git a/crates/contextforge-gateway-rs-lib/src/lib.rs b/crates/contextforge-data-plane-lib/src/lib.rs similarity index 96% rename from crates/contextforge-gateway-rs-lib/src/lib.rs rename to crates/contextforge-data-plane-lib/src/lib.rs index 07104aef..3f71ef6a 100644 --- a/crates/contextforge-gateway-rs-lib/src/lib.rs +++ b/crates/contextforge-data-plane-lib/src/lib.rs @@ -2,7 +2,7 @@ use std::{fs, sync::Arc}; use axum::middleware; use axum_otel_metrics::HttpMetricsLayerBuilder; -use contextforge_gateway_rs_cpex::GatewayPluginRuntimeHandle; +use contextforge_data_plane_cpex::GatewayPluginRuntimeHandle; use futures::FutureExt; use jsonwebtoken::DecodingKey; use rmcp::transport::{ @@ -36,7 +36,7 @@ pub type Error = Box; pub type Result = std::result::Result; use crate::{ - common::{ContextForgeGatewayAppState, JwtTokenDecoders}, + common::{ContextForgeDataPlaneAppState, JwtTokenDecoders}, gateway::LocalUserSessionStore, layers::{ claims_id::claims_layer, @@ -115,7 +115,7 @@ impl Gateway { Ok(key) }); - let mcp_add_state: ContextForgeGatewayAppState = ContextForgeGatewayAppState { + let mcp_add_state: ContextForgeDataPlaneAppState = ContextForgeDataPlaneAppState { jwt_token_decoding_keys: JwtTokenDecoders { rs: rs_decoding_key.transpose()?, hmac_sha: config diff --git a/crates/contextforge-gateway-rs-lib/src/telemetry.rs b/crates/contextforge-data-plane-lib/src/telemetry.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/telemetry.rs rename to crates/contextforge-data-plane-lib/src/telemetry.rs diff --git a/crates/contextforge-gateway-rs-lib/src/tools.rs b/crates/contextforge-data-plane-lib/src/tools.rs similarity index 92% rename from crates/contextforge-gateway-rs-lib/src/tools.rs rename to crates/contextforge-data-plane-lib/src/tools.rs index 6bf71eb2..87ab7f41 100644 --- a/crates/contextforge-gateway-rs-lib/src/tools.rs +++ b/crates/contextforge-data-plane-lib/src/tools.rs @@ -8,14 +8,14 @@ use axum::{ routing::{Router, get, post}, }; use chrono::Duration; -use contextforge_gateway_rs_apis::{User as CFUser, user_store::UserConfig}; +use contextforge_data_plane_apis::{User as CFUser, user_store::UserConfig}; use http::{StatusCode, header}; use serde::Deserialize; use uuid::Uuid; //use tracing::debug; use crate::{ - common::{ContextForgeClaims, ContextForgeGatewayAppState, Scopes, User}, + common::{ContextForgeClaims, ContextForgeDataPlaneAppState, Scopes, User}, const_values::{CONTEXT_FORGE_GATEWAY_AUDIENCE, CONTEXT_FORGE_GATEWAY_ISSUER}, }; @@ -58,7 +58,7 @@ impl ContextForgeClaims { } } -pub fn add_tools(router: Router) -> Router { +pub fn add_tools(router: Router) -> Router { router .route("/admin/tokens/{user_id}", get(get_token)) .route("/admin/userconfigs/{user_id}", post(configure_user)) @@ -74,7 +74,7 @@ pub async fn health() -> Response { } pub async fn get_token( - State(state): State, + State(state): State, Path(user_id): Path, Query(query): Query, ) -> Response { @@ -95,7 +95,7 @@ pub async fn get_token( //#[debug_handler] pub async fn configure_user( Path(user_id): Path, - State(state): State, + State(state): State, Json(user_config): Json, ) -> Response { if state.config_store.set_config(&CFUser::new(&user_id), &user_config).await.is_ok() { diff --git a/crates/contextforge-gateway-rs-lib/src/transports/mod.rs b/crates/contextforge-data-plane-lib/src/transports/mod.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/transports/mod.rs rename to crates/contextforge-data-plane-lib/src/transports/mod.rs diff --git a/crates/contextforge-gateway-rs-lib/src/transports/tcp.rs b/crates/contextforge-data-plane-lib/src/transports/tcp.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/transports/tcp.rs rename to crates/contextforge-data-plane-lib/src/transports/tcp.rs diff --git a/crates/contextforge-gateway-rs-lib/src/transports/tls.rs b/crates/contextforge-data-plane-lib/src/transports/tls.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/src/transports/tls.rs rename to crates/contextforge-data-plane-lib/src/transports/tls.rs diff --git a/crates/contextforge-gateway-rs-lib/src/user_config_store/mod.rs b/crates/contextforge-data-plane-lib/src/user_config_store/mod.rs similarity index 92% rename from crates/contextforge-gateway-rs-lib/src/user_config_store/mod.rs rename to crates/contextforge-data-plane-lib/src/user_config_store/mod.rs index b7d5bc4d..647e2a88 100644 --- a/crates/contextforge-gateway-rs-lib/src/user_config_store/mod.rs +++ b/crates/contextforge-data-plane-lib/src/user_config_store/mod.rs @@ -1,6 +1,6 @@ mod redis_config_store; use async_trait::async_trait; -use contextforge_gateway_rs_apis::{User, user_store::UserConfig}; +use contextforge_data_plane_apis::{User, user_store::UserConfig}; pub use redis_config_store::RedisUserConfigStore; use serde::{Deserialize, Serialize}; diff --git a/crates/contextforge-gateway-rs-lib/src/user_config_store/redis_config_store.rs b/crates/contextforge-data-plane-lib/src/user_config_store/redis_config_store.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/src/user_config_store/redis_config_store.rs rename to crates/contextforge-data-plane-lib/src/user_config_store/redis_config_store.rs index 75491b1c..442675bb 100644 --- a/crates/contextforge-gateway-rs-lib/src/user_config_store/redis_config_store.rs +++ b/crates/contextforge-data-plane-lib/src/user_config_store/redis_config_store.rs @@ -4,7 +4,7 @@ use std::{ }; use async_trait::async_trait; -use contextforge_gateway_rs_apis::{User, user_store::UserConfig}; +use contextforge_data_plane_apis::{User, user_store::UserConfig}; use lru_time_cache::LruCache; use redis::{ AsyncCommands, RedisError, diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_completions.rs b/crates/contextforge-data-plane-lib/tests/gateway_completions.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/tests/gateway_completions.rs rename to crates/contextforge-data-plane-lib/tests/gateway_completions.rs index 3872f739..4cd2f68c 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_completions.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_completions.rs @@ -1,6 +1,6 @@ mod support; -use contextforge_gateway_rs_lib::Result; +use contextforge_data_plane_lib::Result; use tracing::info; use support::{ diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_list_tools.rs b/crates/contextforge-data-plane-lib/tests/gateway_list_tools.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/tests/gateway_list_tools.rs rename to crates/contextforge-data-plane-lib/tests/gateway_list_tools.rs index f4e3c74f..04a77859 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_list_tools.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_list_tools.rs @@ -2,7 +2,7 @@ mod support; use std::{fs::File, io::Read}; -use contextforge_gateway_rs_lib::{Config, Result, UpstreamConnectionMode}; +use contextforge_data_plane_lib::{Config, Result, UpstreamConnectionMode}; use futures::{FutureExt, future::BoxFuture}; use rustls::crypto; use tracing::{info, warn}; diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_pagination.rs b/crates/contextforge-data-plane-lib/tests/gateway_pagination.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/tests/gateway_pagination.rs rename to crates/contextforge-data-plane-lib/tests/gateway_pagination.rs index 4f4679d3..f4324ae9 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_pagination.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_pagination.rs @@ -2,11 +2,11 @@ mod support; use std::{collections::HashMap, sync::Arc}; -use contextforge_gateway_rs_apis::{ +use contextforge_data_plane_apis::{ User, user_store::{BackendMCPGateway, Transport, UserConfig, VirtualHost}, }; -use contextforge_gateway_rs_lib::{Config, Gateway, Result, UserConfigStore, UserConfigStoreType}; +use contextforge_data_plane_lib::{Config, Gateway, Result, UserConfigStore, UserConfigStoreType}; use rmcp::{ model::PaginatedRequestParams, transport::{ diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_plugins.rs b/crates/contextforge-data-plane-lib/tests/gateway_plugins.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/tests/gateway_plugins.rs rename to crates/contextforge-data-plane-lib/tests/gateway_plugins.rs index 18c4b206..beea51ac 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_plugins.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_plugins.rs @@ -2,7 +2,7 @@ mod support; use std::sync::{Arc, Mutex as StdMutex}; -use contextforge_gateway_rs_cpex::CpexRuntimeRegistry; +use contextforge_data_plane_cpex::CpexRuntimeRegistry; use cpex::cpex_core::cmf::Role; use cpex::cpex_core::config::CpexConfig; use cpex::cpex_core::hooks::types::cmf_hook_names; diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_prompts.rs b/crates/contextforge-data-plane-lib/tests/gateway_prompts.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/tests/gateway_prompts.rs rename to crates/contextforge-data-plane-lib/tests/gateway_prompts.rs index 500114e5..53b022a3 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_prompts.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_prompts.rs @@ -1,6 +1,6 @@ mod support; -use contextforge_gateway_rs_lib::{Config, Result, UpstreamConnectionMode}; +use contextforge_data_plane_lib::{Config, Result, UpstreamConnectionMode}; use rmcp::model::GetPromptRequestParams; use serde_json::json; use tracing::{info, warn}; diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_resource_templates.rs b/crates/contextforge-data-plane-lib/tests/gateway_resource_templates.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/tests/gateway_resource_templates.rs rename to crates/contextforge-data-plane-lib/tests/gateway_resource_templates.rs index 9cc9a8e4..9ae3284a 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_resource_templates.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_resource_templates.rs @@ -1,6 +1,6 @@ mod support; -use contextforge_gateway_rs_lib::{Config, Result, UpstreamConnectionMode}; +use contextforge_data_plane_lib::{Config, Result, UpstreamConnectionMode}; use rmcp::model::{ReadResourceRequestParams, ResourceContents}; use tracing::{info, warn}; diff --git a/crates/contextforge-gateway-rs-lib/tests/gateway_subscriptions.rs b/crates/contextforge-data-plane-lib/tests/gateway_subscriptions.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/tests/gateway_subscriptions.rs rename to crates/contextforge-data-plane-lib/tests/gateway_subscriptions.rs index b710baea..e7372f42 100644 --- a/crates/contextforge-gateway-rs-lib/tests/gateway_subscriptions.rs +++ b/crates/contextforge-data-plane-lib/tests/gateway_subscriptions.rs @@ -6,7 +6,7 @@ use std::{ time::Instant, }; -use contextforge_gateway_rs_lib::Result; +use contextforge_data_plane_lib::Result; use futures::future::try_join_all; use rmcp::{ ClientHandler, diff --git a/crates/contextforge-gateway-rs-lib/tests/support/auth.rs b/crates/contextforge-data-plane-lib/tests/support/auth.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/tests/support/auth.rs rename to crates/contextforge-data-plane-lib/tests/support/auth.rs diff --git a/crates/contextforge-gateway-rs-lib/tests/support/client.rs b/crates/contextforge-data-plane-lib/tests/support/client.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/tests/support/client.rs rename to crates/contextforge-data-plane-lib/tests/support/client.rs index 135e84a2..d0d7e59c 100644 --- a/crates/contextforge-gateway-rs-lib/tests/support/client.rs +++ b/crates/contextforge-data-plane-lib/tests/support/client.rs @@ -1,6 +1,6 @@ use std::time::{Duration, Instant}; -use contextforge_gateway_rs_lib::Result; +use contextforge_data_plane_lib::Result; use http::{HeaderMap, HeaderValue}; use rmcp::{ ServiceExt, diff --git a/crates/contextforge-gateway-rs-lib/tests/support/list_tools_gateway.rs b/crates/contextforge-data-plane-lib/tests/support/list_tools_gateway.rs similarity index 99% rename from crates/contextforge-gateway-rs-lib/tests/support/list_tools_gateway.rs rename to crates/contextforge-data-plane-lib/tests/support/list_tools_gateway.rs index b7062a0f..af41eb78 100644 --- a/crates/contextforge-gateway-rs-lib/tests/support/list_tools_gateway.rs +++ b/crates/contextforge-data-plane-lib/tests/support/list_tools_gateway.rs @@ -1,10 +1,10 @@ use std::{collections::HashMap, net::SocketAddr, sync::Arc}; -use contextforge_gateway_rs_apis::{ +use contextforge_data_plane_apis::{ User, user_store::{BackendMCPGateway, Transport, UserConfig, VirtualHost}, }; -use contextforge_gateway_rs_lib::{ +use contextforge_data_plane_lib::{ Config, Gateway, Result, UpstreamConnectionMode, UserConfigStore, UserConfigStoreType, }; use futures::{FutureExt, future::BoxFuture}; diff --git a/crates/contextforge-gateway-rs-lib/tests/support/mock_counter.rs b/crates/contextforge-data-plane-lib/tests/support/mock_counter.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/tests/support/mock_counter.rs rename to crates/contextforge-data-plane-lib/tests/support/mock_counter.rs diff --git a/crates/contextforge-gateway-rs-lib/tests/support/mod.rs b/crates/contextforge-data-plane-lib/tests/support/mod.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/tests/support/mod.rs rename to crates/contextforge-data-plane-lib/tests/support/mod.rs diff --git a/crates/contextforge-gateway-rs-lib/tests/support/paginating_mock.rs b/crates/contextforge-data-plane-lib/tests/support/paginating_mock.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/tests/support/paginating_mock.rs rename to crates/contextforge-data-plane-lib/tests/support/paginating_mock.rs diff --git a/crates/contextforge-gateway-rs-lib/tests/support/plugin.rs b/crates/contextforge-data-plane-lib/tests/support/plugin.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/tests/support/plugin.rs rename to crates/contextforge-data-plane-lib/tests/support/plugin.rs diff --git a/crates/contextforge-gateway-rs-lib/tests/support/plugin_gateway.rs b/crates/contextforge-data-plane-lib/tests/support/plugin_gateway.rs similarity index 98% rename from crates/contextforge-gateway-rs-lib/tests/support/plugin_gateway.rs rename to crates/contextforge-data-plane-lib/tests/support/plugin_gateway.rs index edf75a58..0bc90bdd 100644 --- a/crates/contextforge-gateway-rs-lib/tests/support/plugin_gateway.rs +++ b/crates/contextforge-data-plane-lib/tests/support/plugin_gateway.rs @@ -4,12 +4,12 @@ use std::{ time::{Duration, Instant}, }; -use contextforge_gateway_rs_apis::{ +use contextforge_data_plane_apis::{ User, user_store::{BackendMCPGateway, Transport, UserConfig, VirtualHost}, }; -use contextforge_gateway_rs_cpex::CpexRuntimeRegistry; -use contextforge_gateway_rs_lib::{Config, Gateway, UpstreamConnectionMode, UserConfigStore, UserConfigStoreType}; +use contextforge_data_plane_cpex::CpexRuntimeRegistry; +use contextforge_data_plane_lib::{Config, Gateway, UpstreamConnectionMode, UserConfigStore, UserConfigStoreType}; use futures::FutureExt; use http::{HeaderMap, HeaderValue}; use rmcp::{ @@ -159,7 +159,7 @@ pub(crate) struct RunningGateway { pub(crate) backend_state: BackendState, pub(crate) backend_name: String, gateway_url: String, - handle: Option>>>, + handle: Option>>>, } impl RunningGateway { diff --git a/crates/contextforge-gateway-rs-lib/tests/support/runtime.rs b/crates/contextforge-data-plane-lib/tests/support/runtime.rs similarity index 96% rename from crates/contextforge-gateway-rs-lib/tests/support/runtime.rs rename to crates/contextforge-data-plane-lib/tests/support/runtime.rs index 5a6f463c..83d9b3dd 100644 --- a/crates/contextforge-gateway-rs-lib/tests/support/runtime.rs +++ b/crates/contextforge-data-plane-lib/tests/support/runtime.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use contextforge_gateway_rs_cpex::CpexRuntimeRegistry; +use contextforge_data_plane_cpex::CpexRuntimeRegistry; use cpex::cpex_core::config::CpexConfig; use serde_json::json; diff --git a/crates/contextforge-gateway-rs-lib/tests/support/tool.rs b/crates/contextforge-data-plane-lib/tests/support/tool.rs similarity index 100% rename from crates/contextforge-gateway-rs-lib/tests/support/tool.rs rename to crates/contextforge-data-plane-lib/tests/support/tool.rs diff --git a/crates/contextforge-gateway-rs-lib/tests/support/user_config_store.rs b/crates/contextforge-data-plane-lib/tests/support/user_config_store.rs similarity index 84% rename from crates/contextforge-gateway-rs-lib/tests/support/user_config_store.rs rename to crates/contextforge-data-plane-lib/tests/support/user_config_store.rs index 38b499b3..eac5eeca 100644 --- a/crates/contextforge-gateway-rs-lib/tests/support/user_config_store.rs +++ b/crates/contextforge-data-plane-lib/tests/support/user_config_store.rs @@ -1,8 +1,8 @@ use std::{collections::HashMap, sync::Arc}; use async_trait::async_trait; -use contextforge_gateway_rs_apis::{User, user_store::UserConfig}; -use contextforge_gateway_rs_lib::{ConfigStoreError, UserConfigStore}; +use contextforge_data_plane_apis::{User, user_store::UserConfig}; +use contextforge_data_plane_lib::{ConfigStoreError, UserConfigStore}; use tokio::sync::Mutex; #[derive(Clone, Default)] diff --git a/crates/contextforge-gateway-rs/Cargo.toml b/crates/contextforge-data-plane/Cargo.toml similarity index 81% rename from crates/contextforge-gateway-rs/Cargo.toml rename to crates/contextforge-data-plane/Cargo.toml index 66e231d1..d287c2ba 100644 --- a/crates/contextforge-gateway-rs/Cargo.toml +++ b/crates/contextforge-data-plane/Cargo.toml @@ -1,15 +1,19 @@ [package] -name = "contextforge-gateway-rs" +name = "contextforge-data-plane" version.workspace = true edition.workspace = true rust-version.workspace = true license.workspace = true keywords.workspace = true +homepage.workspace = true +readme.workspace = true +repository.workspace = true [dependencies] -contextforge-gateway-rs-cpex.workspace = true -contextforge-gateway-rs-lib = { path = "../contextforge-gateway-rs-lib" } +contextforge-data-plane-cpex.workspace = true +contextforge-data-plane-lib = { path = "../contextforge-data-plane-lib" } +# These demo plugins remain in their independently hosted legacy repository. cpex-payload-marker = { git = "https://github.com/contextforge-gateway-rs/cpex-plugins-rs", rev = "ab47801daccfbba44ea07b033034a347e7b5afdd", optional = true } cpex-text-prefixer = { git = "https://github.com/contextforge-gateway-rs/cpex-plugins-rs", rev = "ab47801daccfbba44ea07b033034a347e7b5afdd", optional = true } cpex-tool-namespace = { git = "https://github.com/contextforge-gateway-rs/cpex-plugins-rs", rev = "ab47801daccfbba44ea07b033034a347e7b5afdd", optional = true } @@ -35,7 +39,7 @@ test-plugins = ["dep:cpex-payload-marker", "dep:cpex-text-prefixer", "dep:cpex-t [dev-dependencies] axum.workspace = true -contextforge-gateway-rs-apis.workspace = true +contextforge-data-plane-apis.workspace = true http.workspace = true jsonwebtoken.workspace = true openport.workspace = true diff --git a/crates/contextforge-gateway-rs/src/logging.rs b/crates/contextforge-data-plane/src/logging.rs similarity index 98% rename from crates/contextforge-gateway-rs/src/logging.rs rename to crates/contextforge-data-plane/src/logging.rs index e05dfea9..a695f7f8 100644 --- a/crates/contextforge-gateway-rs/src/logging.rs +++ b/crates/contextforge-data-plane/src/logging.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use contextforge_gateway_rs_lib::{Config, LogRotation, OtlpProtocol}; +use contextforge_data_plane_lib::{Config, LogRotation, OtlpProtocol}; use opentelemetry::global; use opentelemetry::trace::TracerProvider; use opentelemetry_otlp::{MetricExporter, Protocol, SpanExporter, WithExportConfig, WithHttpConfig, WithTonicConfig}; @@ -26,7 +26,7 @@ pub struct Guard { meter_provider: Option, } -const CONTROLLER_NAME: &str = "CONTEXTFORGE-GATEWAY-RS"; +const CONTROLLER_NAME: &str = "CONTEXTFORGE-DATA-PLANE"; const DEFAULT_GRPC_TRACES_ENDPOINT: &str = "http://127.0.0.1:4317"; const DEFAULT_GRPC_METRICS_ENDPOINT: &str = "http://127.0.0.1:4317"; const DEFAULT_HTTP_TRACES_ENDPOINT: &str = "http://127.0.0.1:4318/v1/traces"; @@ -36,7 +36,7 @@ const METRICS_EXPORT_INTERVAL: std::time::Duration = std::time::Duration::from_s pub fn init_tracing_logging(configuration: &Config) -> Result> { let registry = Registry::default(); - let log_name = configuration.log_name.clone().unwrap_or("contextforge-gateway-rs.log".to_owned()); + let log_name = configuration.log_name.clone().unwrap_or("contextforge-data-plane.log".to_owned()); let file_appender = match configuration.log_rotation.clone().unwrap_or_default() { LogRotation::Minutely => tracing_appender::rolling::minutely(".", log_name), diff --git a/crates/contextforge-gateway-rs/src/main.rs b/crates/contextforge-data-plane/src/main.rs similarity index 94% rename from crates/contextforge-gateway-rs/src/main.rs rename to crates/contextforge-data-plane/src/main.rs index bfa7c498..9af223e2 100644 --- a/crates/contextforge-gateway-rs/src/main.rs +++ b/crates/contextforge-data-plane/src/main.rs @@ -6,8 +6,8 @@ mod test_plugins; use std::sync::Arc; use clap::Parser; -use contextforge_gateway_rs_cpex::CpexRuntimeRegistry; -use contextforge_gateway_rs_lib::{Config, Gateway, RedisClient, RedisConfig, UserConfigStoreType}; +use contextforge_data_plane_cpex::CpexRuntimeRegistry; +use contextforge_data_plane_lib::{Config, Gateway, RedisClient, RedisConfig, UserConfigStoreType}; use rmcp::transport::streamable_http_server::session::local::LocalSessionManager; use rustls::crypto; use tikv_jemallocator::Jemalloc; @@ -31,7 +31,7 @@ fn main() -> Result<(), Box> { otel_metrics_enabled = config.enable_otel_metrics.unwrap_or(false), single_runtime = config.single_runtime.unwrap_or(true), configured_cpus = ?config.number_of_cpus, - "starting contextforge-gateway-rs" + "starting contextforge-data-plane" ); let runtime = runtime::Runtime::from(&config); diff --git a/crates/contextforge-gateway-rs/src/runtime.rs b/crates/contextforge-data-plane/src/runtime.rs similarity index 91% rename from crates/contextforge-gateway-rs/src/runtime.rs rename to crates/contextforge-data-plane/src/runtime.rs index bb90386c..71e87b55 100644 --- a/crates/contextforge-gateway-rs/src/runtime.rs +++ b/crates/contextforge-data-plane/src/runtime.rs @@ -3,8 +3,8 @@ use std::{ thread, }; -use contextforge_gateway_rs_cpex::CpexRuntimeRegistry; -use contextforge_gateway_rs_lib::{Config, Gateway}; +use contextforge_data_plane_cpex::CpexRuntimeRegistry; +use contextforge_data_plane_lib::{Config, Gateway}; use tokio::runtime::{Builder, LocalOptions}; use tokio::task::JoinHandle; use tracing::{debug, error, info, warn}; @@ -38,7 +38,7 @@ impl Default for Runtime { global_queue_interval: Option::default(), event_interval: Option::default(), max_io_events_per_tick: Option::default(), - thread_name: "mcp-gateway-rs-runtime".to_owned(), + thread_name: "contextforge-data-plane-runtime".to_owned(), } } } @@ -69,7 +69,7 @@ impl Runtime { self, gateway: Gateway, cpex_runtime: Option>, - ) -> contextforge_gateway_rs_lib::Result<()> { + ) -> contextforge_data_plane_lib::Result<()> { if self.single_runtime { let mut builder = Builder::new_multi_thread(); self.configure_builder(&mut builder, self.thread_name.clone()); @@ -115,7 +115,7 @@ impl Runtime { gateway: Gateway, cpex_runtime: Option>, init_sender: Option>>, - ) -> std::io::Result>> { + ) -> std::io::Result>> { thread::Builder::new().name(thread_name.clone()).spawn(move || { let mut builder = Builder::new_current_thread(); Self::configure_single_thread_builder(&mut builder, thread_name); @@ -123,7 +123,7 @@ impl Runtime { Ok(runtime) => runtime, Err(error) => { warn!("Can't build thread {error:?}"); - return Err::<(), contextforge_gateway_rs_lib::Error>(error.into()); + return Err::<(), contextforge_data_plane_lib::Error>(error.into()); }, }; @@ -148,7 +148,7 @@ impl Runtime { async fn initialize_cpex_runtime( cpex_runtime: Option>, - ) -> contextforge_gateway_rs_lib::Result>> { + ) -> contextforge_data_plane_lib::Result>> { let Some(cpex_runtime) = cpex_runtime else { return Ok(None); }; @@ -168,7 +168,7 @@ impl Runtime { } } - async fn run_gateway(gateway: Gateway) -> contextforge_gateway_rs_lib::Result<()> { + async fn run_gateway(gateway: Gateway) -> contextforge_data_plane_lib::Result<()> { let res = gateway.run_gateway().await; if res.is_ok() { debug!("Gateway process terminated"); diff --git a/crates/contextforge-gateway-rs/src/test_plugins.rs b/crates/contextforge-data-plane/src/test_plugins.rs similarity index 90% rename from crates/contextforge-gateway-rs/src/test_plugins.rs rename to crates/contextforge-data-plane/src/test_plugins.rs index 2a39628f..ee816617 100644 --- a/crates/contextforge-gateway-rs/src/test_plugins.rs +++ b/crates/contextforge-data-plane/src/test_plugins.rs @@ -1,4 +1,4 @@ -use contextforge_gateway_rs_cpex::{CmfPluginFactory, CpexRuntimeRegistry}; +use contextforge_data_plane_cpex::{CmfPluginFactory, CpexRuntimeRegistry}; pub fn register(runtime: &mut CpexRuntimeRegistry) -> Result<(), Box> { runtime.register_factory( diff --git a/crates/contextforge-gateway-rs/tests/secrets_detection_e2e.rs b/crates/contextforge-data-plane/tests/secrets_detection_e2e.rs similarity index 98% rename from crates/contextforge-gateway-rs/tests/secrets_detection_e2e.rs rename to crates/contextforge-data-plane/tests/secrets_detection_e2e.rs index bf8203e4..af1554be 100644 --- a/crates/contextforge-gateway-rs/tests/secrets_detection_e2e.rs +++ b/crates/contextforge-data-plane/tests/secrets_detection_e2e.rs @@ -13,7 +13,7 @@ use std::{ time::{Duration, Instant, SystemTime, UNIX_EPOCH}, }; -use contextforge_gateway_rs_apis::{ +use contextforge_data_plane_apis::{ User, runtime_plugin_config::{RUNTIME_PLUGIN_CONFIG_KEY, RUNTIME_PLUGIN_CONFIG_VERSION}, user_store::{BackendMCPGateway, Transport, UserConfig, VirtualHost}, @@ -174,7 +174,7 @@ struct E2eEnvironment { } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -#[ignore = "spawns redis-server and the contextforge-gateway-rs binary"] +#[ignore = "spawns redis-server and the contextforge-data-plane binary"] async fn binary_e2e_redacts_tool_arguments_and_results() { let backend = start_backend().await; let env = start_environment( @@ -212,7 +212,7 @@ async fn binary_e2e_redacts_tool_arguments_and_results() { } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -#[ignore = "spawns redis-server and the contextforge-gateway-rs binary"] +#[ignore = "spawns redis-server and the contextforge-data-plane binary"] async fn binary_e2e_blocks_tool_arguments_before_backend_call() { let backend = start_backend().await; let env = start_environment( @@ -294,7 +294,7 @@ async fn start_backend() -> RunningBackend { } fn start_gateway_process(gateway_port: u16, redis_port: u16) -> ChildProcess { - let binary = env!("CARGO_BIN_EXE_contextforge-gateway-rs"); + let binary = env!("CARGO_BIN_EXE_contextforge-data-plane"); let child = Command::new(binary) .current_dir(env!("CARGO_MANIFEST_DIR")) .args([ @@ -318,8 +318,8 @@ fn start_gateway_process(gateway_port: u16, redis_port: u16) -> ChildProcess { .stdout(Stdio::null()) .stderr(Stdio::null()) .spawn() - .expect("contextforge-gateway-rs binary starts"); - ChildProcess::new("contextforge-gateway-rs", child) + .expect("contextforge-data-plane binary starts"); + ChildProcess::new("contextforge-data-plane", child) } async fn wait_for_redis(port: u16, child: &mut ChildProcess) { diff --git a/crates/plugins/cpex-secrets-detection/README.md b/crates/plugins/cpex-secrets-detection/README.md index a36bcf9b..d77b96f2 100644 --- a/crates/plugins/cpex-secrets-detection/README.md +++ b/crates/plugins/cpex-secrets-detection/README.md @@ -72,8 +72,8 @@ From the workspace root: ```bash cargo +1.96 test -p cpex-secrets-detection -cargo +1.96 check -p contextforge-gateway-rs --features plugins -cargo +1.96 test -p contextforge-gateway-rs-cpex -cargo +1.96 test -p contextforge-gateway-rs-lib --test gateway_plugins -- --nocapture -cargo +1.96 test -p contextforge-gateway-rs --features plugins --test secrets_detection_e2e -- --ignored --nocapture +cargo +1.96 check -p contextforge-data-plane --features plugins +cargo +1.96 test -p contextforge-data-plane-cpex +cargo +1.96 test -p contextforge-data-plane-lib --test gateway_plugins -- --nocapture +cargo +1.96 test -p contextforge-data-plane --features plugins --test secrets_detection_e2e -- --ignored --nocapture ``` diff --git a/deny.toml b/deny.toml index f8397108..af2927a8 100644 --- a/deny.toml +++ b/deny.toml @@ -323,7 +323,8 @@ allow-registry = ["https://github.com/rust-lang/crates.io-index"] allow-git = [] [sources.allow-org] -# github.com organizations to allow git sources for +# github.com organizations to allow git sources for. The legacy organization +# still hosts the demo CPEX plugins used by the optional test feature. github = ["contextforge-gateway-rs"] # gitlab.com organizations to allow git sources for gitlab = [] diff --git a/docker/Dockerfile b/docker/Dockerfile index 408275e3..adc76db1 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -7,12 +7,12 @@ apt install -y ca-certificates protobuf-compiler EOF COPY . . -RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \ - --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git \ +RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry,sharing=locked \ + --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git,sharing=locked \ cargo fetch --locked -RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry \ - --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git \ - cargo build --release --features "contextforge-gateway-rs-lib/with_tools contextforge-gateway-rs/plugins" +RUN --mount=type=cache,id=cargo,target=/usr/local/cargo/registry,sharing=locked \ + --mount=type=cache,id=cargo-git,target=/usr/local/cargo/git,sharing=locked \ + cargo build --release --features "contextforge-data-plane-lib/with_tools contextforge-data-plane/plugins" FROM debian:trixie-slim RUN < --requirepass ${LANGFUSE_REDIS_AUTH:-langfuse-redis-secret} --maxmemory-policy noeviction diff --git a/docker/docker-compose-local.yaml b/docker/docker-compose-local.yaml index 33736793..a8b60ded 100644 --- a/docker/docker-compose-local.yaml +++ b/docker/docker-compose-local.yaml @@ -1,9 +1,9 @@ #version: "3.9" # Supported by both podman-compose and Docker Compose v2+ -name: mcp-gatewys +name: contextforge-data-plane-local networks: - gateways-net: # Single user-defined bridge network keeps traffic private + contextforge-data-plane-net: # Single user-defined bridge network keeps traffic private driver: bridge ############################################################################### @@ -15,7 +15,7 @@ services: build: dockerfile: mcp_counter.Dockerfile - networks: [gateways-net] + networks: [contextforge-data-plane-net] ports: [5555:5555] environment: @@ -48,7 +48,7 @@ services: image: mcp_conformance build: dockerfile: mcp_conformance.Dockerfile - networks: [gateways-net] + networks: [contextforge-data-plane-net] ports: [5556:5556] environment: @@ -124,7 +124,7 @@ services: - ../assets/contextforgeCA/:/tls_config:z - networks: [gateways-net] + networks: [contextforge-data-plane-net] deploy: resources: limits: diff --git a/docker/docker-compose-otel-collector.yaml b/docker/docker-compose-otel-collector.yaml index d07bdf88..098538bd 100644 --- a/docker/docker-compose-otel-collector.yaml +++ b/docker/docker-compose-otel-collector.yaml @@ -1,4 +1,4 @@ -# ContextForge Gateway (Rust) + OpenTelemetry Collector overlay for local +# ContextForge Data Plane + OpenTelemetry Collector overlay for local # metrics verification (issue #4721 follow-up). # # Langfuse only ingests traces (see docker-compose-langfuse.yaml). To verify @@ -26,7 +26,7 @@ # Inspect: # docker logs otel-collector --tail 200 # -# Reuses `gateways-net` already declared by docker-compose-local.yaml. +# Reuses `contextforge-data-plane-net` from docker-compose-local.yaml. services: otel-collector: @@ -42,7 +42,7 @@ services: # Prometheus-text endpoint exposed by the `prometheus` exporter, # scraped by the prometheus service below. - "8889:8889" - networks: [gateways-net] + networks: [contextforge-data-plane-net] prometheus: image: docker.io/prom/prometheus:v2.55.0 @@ -58,4 +58,4 @@ services: - "9090:9090" depends_on: - otel-collector - networks: [gateways-net] + networks: [contextforge-data-plane-net] diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 5f821f3e..918e3aaf 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,8 +1,8 @@ #version: "3.9" # Supported by both podman-compose and Docker Compose v2+ -name: mcp-gateway-rs +name: contextforge-data-plane networks: - contextforge-gateway-net: + contextforge-stack-net: # Single user-defined bridge network keeps traffic private driver: bridge @@ -25,7 +25,7 @@ services: ports: - "8080:80" - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] dns: - 127.0.0.11 command: [nginx, '-g', 'daemon off;'] @@ -57,25 +57,25 @@ services: memory: 128M # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - # mcp-gateway-rs + # contextforge-data-plane # # # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ data-plane: labels: - name: dataplane - image: ${IMAGE_LOCAL:-dataplane:latest} - networks: [contextforge-gateway-net] + name: contextforge-data-plane + image: ${IMAGE_LOCAL:-contextforge-data-plane:latest} + networks: [contextforge-stack-net] environment: - - CONTEXTFORGE_GATEWAY_RS_ADDRESS=0.0.0.0:4445 - - CONTEXTFORGE_GATEWAY_RS_REDIS_HOSTNAME=redis - - CONTEXTFORGE_GATEWAY_RS_REDIS_PORT=6379 - - CONTEXTFORGE_GATEWAY_RS_REDIS_CONNECTION_MODE=plain-text - - CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE=plain-text-or-tls - - CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub - - CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key + - CONTEXTFORGE_DATA_PLANE_ADDRESS=0.0.0.0:4445 + - CONTEXTFORGE_DATA_PLANE_REDIS_HOSTNAME=redis + - CONTEXTFORGE_DATA_PLANE_REDIS_PORT=6379 + - CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE=plain-text + - CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE=plain-text-or-tls + - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub + - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key - RUST_LOG=debug sysctls: @@ -129,20 +129,20 @@ services: volumes: - ../assets/:/keys:z # mount catalog configuration - contextforge-gateway-one: - image: ${IMAGE_LOCAL:-dataplane:latest} - container_name: contextforge-gateway-one - networks: [contextforge-gateway-net] + contextforge-data-plane-one: + image: ${IMAGE_LOCAL:-contextforge-data-plane:latest} + container_name: contextforge-data-plane-one + networks: [contextforge-stack-net] ports: [5551:4445] environment: - - CONTEXTFORGE_GATEWAY_RS_ADDRESS=0.0.0.0:4445 - - CONTEXTFORGE_GATEWAY_RS_REDIS_HOSTNAME=redis - - CONTEXTFORGE_GATEWAY_RS_REDIS_PORT=6379 - - CONTEXTFORGE_GATEWAY_RS_REDIS_CONNECTION_MODE=plain-text - - CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE=plain-text-or-tls - - CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub - - CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key + - CONTEXTFORGE_DATA_PLANE_ADDRESS=0.0.0.0:4445 + - CONTEXTFORGE_DATA_PLANE_REDIS_HOSTNAME=redis + - CONTEXTFORGE_DATA_PLANE_REDIS_PORT=6379 + - CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE=plain-text + - CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE=plain-text-or-tls + - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub + - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key - RUST_LOG=debug sysctls: @@ -173,20 +173,20 @@ services: volumes: - ../assets/:/keys:z # mount catalog configuration - contextforge-gateway-two: - image: ${IMAGE_LOCAL:-dataplane:latest} - container_name: contextforge-gateway-two - networks: [contextforge-gateway-net] + contextforge-data-plane-two: + image: ${IMAGE_LOCAL:-contextforge-data-plane:latest} + container_name: contextforge-data-plane-two + networks: [contextforge-stack-net] ports: [5552:4445] environment: - - CONTEXTFORGE_GATEWAY_RS_ADDRESS=0.0.0.0:4445 - - CONTEXTFORGE_GATEWAY_RS_REDIS_HOSTNAME=redis - - CONTEXTFORGE_GATEWAY_RS_REDIS_PORT=6379 - - CONTEXTFORGE_GATEWAY_RS_REDIS_CONNECTION_MODE=plain-text - - CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE=plain-text-or-tls - - CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub - - CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key + - CONTEXTFORGE_DATA_PLANE_ADDRESS=0.0.0.0:4445 + - CONTEXTFORGE_DATA_PLANE_REDIS_HOSTNAME=redis + - CONTEXTFORGE_DATA_PLANE_REDIS_PORT=6379 + - CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE=plain-text + - CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE=plain-text-or-tls + - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY=/keys/jwt.key.pub + - CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY=/keys/jwt.key - RUST_LOG=debug sysctls: @@ -220,7 +220,7 @@ services: mcp-counter-tool-one: image: ghcr.io/mcp-counter-tool:latest container_name: mcp-counter-tool-one - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] ports: [5601:5555] environment: @@ -250,7 +250,7 @@ services: mcp-counter-tool-two: image: ghcr.io/mcp-counter-tool:latest container_name: mcp-counter-tool-two - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] ports: [5602:5555] environment: @@ -310,7 +310,7 @@ services: start_period: 10s ports: - "6379:6379" # expose only if you want host access - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] deploy: resources: limits: @@ -342,7 +342,7 @@ services: depends_on: postgres: condition: service_healthy - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] restart: "no" ############################################################################### @@ -354,7 +354,7 @@ services: image: ghcr.io/ibm/mcp-context-forge:d24df05e7985787bfa3264ab45cee411e308a111 container_name: control-plane restart: unless-stopped - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] ports: - "4444:4444" environment: @@ -461,7 +461,7 @@ services: - POSTGRES_DB=mcp volumes: - pgdata:/var/lib/postgresql - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"] interval: 30s @@ -481,7 +481,7 @@ services: image: edoburu/pgbouncer:latest container_name: pgbouncer restart: unless-stopped - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] ulimits: nofile: soft: 65536 @@ -535,7 +535,7 @@ services: image: ghcr.io/ibm/cfex-mcp-fast-time-server:latest container_name: fast_time_server restart: unless-stopped - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] ports: - "8880:8880" environment: @@ -574,7 +574,7 @@ services: register_fast_time: image: ghcr.io/ibm/mcp-context-forge:d24df05e7985787bfa3264ab45cee411e308a111 container_name: register_fast_time - networks: [contextforge-gateway-net] + networks: [contextforge-stack-net] depends_on: control-plane: condition: service_healthy diff --git a/docker/mcp_conformance.Dockerfile b/docker/mcp_conformance.Dockerfile index 57350e51..a53d268c 100644 --- a/docker/mcp_conformance.Dockerfile +++ b/docker/mcp_conformance.Dockerfile @@ -29,6 +29,6 @@ EOF WORKDIR / COPY --from=builder /tmp/rust-sdk/target/release/conformance-server /conformance-server -LABEL org.opencontainers.image.source=https://github.com/contextforge-gateway-rs/contextforge-gateway-rs +LABEL org.opencontainers.image.source=https://github.com/contextforge-org/contextforge-data-plane LABEL org.opencontainers.image.description="Mcp-conformance" ENTRYPOINT ["/conformance-server"] diff --git a/docker/mcp_counter.Dockerfile b/docker/mcp_counter.Dockerfile index d7038dcb..f5f9af6e 100644 --- a/docker/mcp_counter.Dockerfile +++ b/docker/mcp_counter.Dockerfile @@ -29,6 +29,6 @@ EOF WORKDIR / COPY --from=builder /tmp/rust-sdk/target/release/examples/servers_counter_streamhttp /servers_counter_streamhttp -LABEL org.opencontainers.image.source=https://github.com/contextforge-gateway-rs/contextforge-gateway-rs +LABEL org.opencontainers.image.source=https://github.com/contextforge-org/contextforge-data-plane LABEL org.opencontainers.image.description="Mcp-conformance" ENTRYPOINT ["/servers_counter_streamhttp"] diff --git a/docker/nginx.conf b/docker/nginx.conf index 205956cd..a48ac408 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -158,7 +158,7 @@ http { # Dynamic backend URLs. Using variables keeps Docker DNS re-resolution active # across gateway container churn. - map "" $contextforge_gateway_backend_url { + map "" $contextforge_data_plane_backend_url { default "http://data-plane:4445"; } @@ -251,7 +251,7 @@ http { # ============================================================ - # contextforge-gateway-rs + # contextforge-data-plane # ============================================================ location ^~ /contextforge-rs { # Rate limiting: 20000 r/s sustained, burst=20000 for load testing spikes @@ -259,7 +259,7 @@ http { limit_req zone=api_limit burst=20000 nodelay; limit_conn conn_limit 20000; - proxy_pass $contextforge_gateway_backend_url; + proxy_pass $contextforge_data_plane_backend_url; proxy_cache off; @@ -318,7 +318,7 @@ http { # Health Check - No rate limiting (for monitoring during load tests) # ============================================================ location = /health { - proxy_pass $contextforge_gateway_backend_url/contextforge-rs/health; + proxy_pass $contextforge_data_plane_backend_url/contextforge-rs/health; proxy_set_header Host $http_host; proxy_set_header Connection ""; proxy_http_version 1.1; diff --git a/docker/otel-collector-config.yaml b/docker/otel-collector-config.yaml index 6e321359..bbbea9f9 100644 --- a/docker/otel-collector-config.yaml +++ b/docker/otel-collector-config.yaml @@ -1,7 +1,7 @@ # OpenTelemetry Collector configuration for local metrics verification # (issue #4721 follow-up). # -# Receives OTLP/HTTP from the host-side ContextForge Gateway and dumps +# Receives OTLP/HTTP from the host-side ContextForge Data Plane and dumps # everything to stdout via the `debug` exporter so we can eyeball the # semantic-convention HTTP metrics emitted by axum-otel-metrics: # - http.server.active_requests diff --git a/docs/book/README.md b/docs/book/README.md index ebafcbdf..558e6073 100644 --- a/docs/book/README.md +++ b/docs/book/README.md @@ -1,6 +1,6 @@ -# Developing The ContextForge Gateway Book +# Developing The ContextForge Data Plane Book -This directory contains the mdBook source for The ContextForge Gateway Book. +This directory contains the mdBook source for The ContextForge Data Plane Book. The rendered book also documents its own publishing path in [Publishing This Book](src/publishing-this-book.md); keep the two in sync when the workflow or mdBook version changes. diff --git a/docs/book/book.toml b/docs/book/book.toml index 2884cafd..554b6372 100644 --- a/docs/book/book.toml +++ b/docs/book/book.toml @@ -1,10 +1,10 @@ [book] -authors = ["ContextForge Gateway maintainers"] +authors = ["ContextForge Data Plane maintainers"] language = "en" src = "src" -title = "The ContextForge Gateway Book" -description = "Architecture, configuration, and operations guide for contextforge-gateway-rs, the Rust MCP dataplane that presents many backend MCP servers as one gateway endpoint." +title = "The ContextForge Data Plane Book" +description = "Architecture, configuration, and operations guide for contextforge-data-plane, the Rust MCP dataplane that presents many backend MCP servers as one gateway endpoint." [output.html] -git-repository-url = "https://github.com/contextforge-gateway-rs/contextforge-gateway-rs" -edit-url-template = "https://github.com/contextforge-gateway-rs/contextforge-gateway-rs/edit/main/docs/book/{path}" +git-repository-url = "https://github.com/contextforge-org/contextforge-data-plane" +edit-url-template = "https://github.com/contextforge-org/contextforge-data-plane/edit/main/docs/book/{path}" diff --git a/docs/book/src/SUMMARY.md b/docs/book/src/SUMMARY.md index 2dbacabe..05c1583a 100644 --- a/docs/book/src/SUMMARY.md +++ b/docs/book/src/SUMMARY.md @@ -1,6 +1,6 @@ -# The ContextForge Gateway Book +# The ContextForge Data Plane Book -- [๐ŸŒ‰ What is ContextForge Gateway?](what-is-contextforge-gateway.md) +- [๐ŸŒ‰ What is ContextForge Data Plane?](what-is-contextforge-data-plane.md) - [๐Ÿš€ Getting Started](usage.md) - [Run the Gateway Locally](running-the-gateway.md) - [Configuration Reference](gateway-options.md) diff --git a/docs/book/src/architectural-choices.md b/docs/book/src/architectural-choices.md index 55a0307f..ae804b3a 100644 --- a/docs/book/src/architectural-choices.md +++ b/docs/book/src/architectural-choices.md @@ -111,7 +111,7 @@ The downstream client should reason about one MCP server: ```text client - -> ContextForge Gateway + -> ContextForge Data Plane -> merged tools/resources/prompts ``` diff --git a/docs/book/src/assets/gateway-overview.svg b/docs/book/src/assets/gateway-overview.svg index b7c523c1..3bb1ec1f 100644 --- a/docs/book/src/assets/gateway-overview.svg +++ b/docs/book/src/assets/gateway-overview.svg @@ -1,6 +1,6 @@ - ContextForge Gateway request and response path - An MCP client sends streamable HTTP traffic to the ContextForge Gateway. The gateway validates the caller, loads runtime configuration, calls backend MCP servers, receives backend responses, merges them, and returns one MCP response or stream to the client. + ContextForge Data Plane request and response path + An MCP client sends streamable HTTP traffic to the ContextForge Data Plane. The data plane validates the caller, loads runtime configuration, calls backend MCP servers, receives backend responses, merges them, and returns one MCP response or stream to the client. @@ -38,7 +38,7 @@ - ContextForge Gateway + ContextForge Data Plane validate caller diff --git a/docs/book/src/assets/request-flow.svg b/docs/book/src/assets/request-flow.svg index 71c0bc32..573ed4d9 100644 --- a/docs/book/src/assets/request-flow.svg +++ b/docs/book/src/assets/request-flow.svg @@ -1,5 +1,5 @@ - ContextForge Gateway request flow + ContextForge Data Plane request flow A normal MCP HTTP request enters the TCP or TLS listener, passes through metrics, tracing, the contextforge nested router, CORS, virtual host extraction, claims validation, session extraction, user config lookup, a virtual host config check, and RMCP. RMCP then follows either initialize handling or authorized MCP method handling, calls backend MCP servers as needed, and returns the response through the same stack. diff --git a/docs/book/src/assets/system-shape.svg b/docs/book/src/assets/system-shape.svg index 8daebed6..f783a1c6 100644 --- a/docs/book/src/assets/system-shape.svg +++ b/docs/book/src/assets/system-shape.svg @@ -1,5 +1,5 @@ - ContextForge Gateway system shape + ContextForge Data Plane system shape The ContextForge control plane writes runtime config into Redis. MCP clients call the Rust gateway dataplane. The gateway loads config, validates identity, calls backend MCP servers, receives backend responses, merges them, and returns one downstream response. diff --git a/docs/book/src/capability-flow.md b/docs/book/src/capability-flow.md index 0551a81e..f38b0ae0 100644 --- a/docs/book/src/capability-flow.md +++ b/docs/book/src/capability-flow.md @@ -21,7 +21,7 @@ families the gateway can route. ## Initialize Sequence `McpService::initialize` in -`crates/contextforge-gateway-rs-lib/src/gateway/mcp_service/initialization.rs` +`crates/contextforge-data-plane-lib/src/gateway/mcp_service/initialization.rs` runs this capability-related flow: 1. The gateway validates the call and resolves the selected virtual host. diff --git a/docs/book/src/contributing.md b/docs/book/src/contributing.md index d6bf4bef..08812431 100644 --- a/docs/book/src/contributing.md +++ b/docs/book/src/contributing.md @@ -8,10 +8,10 @@ | Change | Home | | --- | --- | -| Dataplane behavior: routing, middleware, sessions, transports | `contextforge-gateway-rs-lib` โ€” almost everything goes here. | -| Process shell: CLI flags, logging, runtime shape, exporters | `contextforge-gateway-rs` (the binary crate). Do not add dataplane logic here. | -| Shared config shapes (`UserConfig`, `User`, plugin config document) | `contextforge-gateway-rs-apis`. Regenerate the JSON schemas after any change: `cargo run -p contextforge-gateway-rs-apis` (see [Control-Plane Integration](control-plane-integration.md)). | -| Plugin integration | `contextforge-gateway-rs-cpex`. | +| Dataplane behavior: routing, middleware, sessions, transports | `contextforge-data-plane-lib` โ€” almost everything goes here. | +| Process shell: CLI flags, logging, runtime shape, exporters | `contextforge-data-plane` (the binary crate). Do not add dataplane logic here. | +| Shared config shapes (`UserConfig`, `User`, plugin config document) | `contextforge-data-plane-apis`. Regenerate the JSON schemas after any change: `cargo run -p contextforge-data-plane-apis` (see [Control-Plane Integration](control-plane-integration.md)). | +| Plugin integration | `contextforge-data-plane-cpex`. | | Load generation | `contextforge-load-test`. | Inside the library crate, keep the module boundaries from @@ -68,7 +68,7 @@ Expectations by change type: | Change type | Minimum validation | | --- | --- | | Docs only | `mdbook build docs/book` and `mdbook test docs/book`. | -| Routing or session behavior | New or updated integration tests under `crates/contextforge-gateway-rs-lib/tests/` against the mock backends. | +| Routing or session behavior | New or updated integration tests under `crates/contextforge-data-plane-lib/tests/` against the mock backends. | | Config shape | Schema regeneration plus a control-plane compatibility check. | | Plugin behavior | `gateway_plugins.rs` coverage for the new hook path. | | Performance-sensitive paths | A [load-test run](performance.md) before and after. | diff --git a/docs/book/src/control-plane-integration.md b/docs/book/src/control-plane-integration.md index 9a157d09..ee60ef08 100644 --- a/docs/book/src/control-plane-integration.md +++ b/docs/book/src/control-plane-integration.md @@ -49,12 +49,12 @@ disable the cache; production keeps both at 60. ## Schema Generation -`contextforge-gateway-rs-apis` is the single source of truth for the shared +`contextforge-data-plane-apis` is the single source of truth for the shared config shapes. It generates the JSON Schemas the control plane can validate against: ```bash -cargo run -p contextforge-gateway-rs-apis +cargo run -p contextforge-data-plane-apis ``` This writes `schemas/user.json` and `schemas/user_config.json`. Regenerate and @@ -71,7 +71,7 @@ control-plane paths and does not enter the dataplane. ## Verifying The Integration -The [`cf-integration`](https://github.com/contextforge-gateway-rs/cf-integration) +The [`cf-integration`](https://github.com/contextforge-org/contextforge-dev-tools) harness tests exactly this surface: it runs the stock upstream control-plane stack with the nginx split and the dataplane publisher enabled, then drives probe, live-test, and load lanes through the public route. When the diff --git a/docs/book/src/deployment-notes.md b/docs/book/src/deployment-notes.md index 4293f7f8..7105ff34 100644 --- a/docs/book/src/deployment-notes.md +++ b/docs/book/src/deployment-notes.md @@ -24,7 +24,7 @@ compile it out. Use TCP-level checks or the exported metrics for liveness until a real health endpoint exists. (The reference nginx config's `location = /health` predates this and does not match the gateway's route.) -The [`cf-integration`](https://github.com/contextforge-gateway-rs/cf-integration) +The [`cf-integration`](https://github.com/contextforge-org/contextforge-dev-tools) harness runs the same split with the stock upstream control-plane stack and rewrites public `/servers/{id}/mcp` to `/contextforge-rs/servers/{id}/mcp`. @@ -64,9 +64,11 @@ returns `400` until Redis returns. ## Images And Sizing - CI builds `docker/Dockerfile` (a `rust:1.96.1` builder stage) on every push - to `main` and pushes `ghcr.io//contextforge-gateway-rs:`, - where the tag is the Cargo package version. There is no `latest` tag โ€” - pin the version. + to `main` and pushes both + `ghcr.io//contextforge-data-plane:v` and + `ghcr.io//contextforge-data-plane:latest`, where `` is the + Cargo package version. There is no unprefixed version tag. Pin the + `v`-prefixed tag for reproducible deployments; `latest` tracks `main`. - The reference Compose stack runs the gateway with raised limits worth copying to real deployments: `nofile` 65535 and TCP tuning (`tcp_fin_timeout=15`, widened local port range) for high connection churn. diff --git a/docs/book/src/gateway-options.md b/docs/book/src/gateway-options.md index c0d924f5..26e77e9d 100644 --- a/docs/book/src/gateway-options.md +++ b/docs/book/src/gateway-options.md @@ -8,7 +8,7 @@ a flag and an environment variable at the same time, the command-line flag wins. For the always-current list, ask the binary directly: ```bash -cargo run -p contextforge-gateway-rs --bin contextforge-gateway-rs -- --help +cargo run -p contextforge-data-plane --bin contextforge-data-plane -- --help ``` The sections below group the options by concern: listeners, JWT, Redis, upstream @@ -40,10 +40,10 @@ cannot pass the claims layer. | Flag | Env var | Required | Meaning | | --- | --- | --- | --- | -| `--address ` | `CONTEXTFORGE_GATEWAY_RS_ADDRESS` | No | Plain HTTP listener. Omit it when serving only TLS. | -| `--tls-address ` | `CONTEXTFORGE_GATEWAY_RS_TLS_ADDRESS` | No | TLS listener address. Requires certificate and private key. | -| `--server-certificate ` | `CONTEXTFORGE_GATEWAY_RS_TLS_SERVER_CERTIFICATE` | With `--tls-address` | PEM certificate chain for downstream TLS. | -| `--server-private-key ` | `CONTEXTFORGE_GATEWAY_RS_TLS_SERVER_PRIVATE_KEY` | With `--tls-address` | PEM private key for downstream TLS. | +| `--address ` | `CONTEXTFORGE_DATA_PLANE_ADDRESS` | No | Plain HTTP listener. Omit it when serving only TLS. | +| `--tls-address ` | `CONTEXTFORGE_DATA_PLANE_TLS_ADDRESS` | No | TLS listener address. Requires certificate and private key. | +| `--server-certificate ` | `CONTEXTFORGE_DATA_PLANE_TLS_SERVER_CERTIFICATE` | With `--tls-address` | PEM certificate chain for downstream TLS. | +| `--server-private-key ` | `CONTEXTFORGE_DATA_PLANE_TLS_SERVER_PRIVATE_KEY` | With `--tls-address` | PEM private key for downstream TLS. | `--address` and `--tls-address` may both be configured, but they must not use the same socket address. @@ -52,9 +52,9 @@ the same socket address. | Flag | Env var | Required | Meaning | | --- | --- | --- | --- | -| `--token-verification-public-key ` | `CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PUBLIC_KEY` | For RSA tokens | RSA public key used for `RS256`, `RS384`, or `RS512` tokens. | -| `--token-verification-secret ` | `CONTEXTFORGE_GATEWAY_RS_TOKEN_SECRET` | For HMAC tokens | Shared secret used for `HS256`, `HS384`, or `HS512` tokens. | -| `--token-verification-private-key ` | `CONTEXTFORGE_GATEWAY_RS_TOKEN_VERIFICATION_PRIVATE_KEY` | Local tools only | RSA private key used by the optional local token helper. Present only when `contextforge-gateway-rs-lib/with_tools` is enabled. | +| `--token-verification-public-key ` | `CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PUBLIC_KEY` | For RSA tokens | RSA public key used for `RS256`, `RS384`, or `RS512` tokens. | +| `--token-verification-secret ` | `CONTEXTFORGE_DATA_PLANE_TOKEN_SECRET` | For HMAC tokens | Shared secret used for `HS256`, `HS384`, or `HS512` tokens. | +| `--token-verification-private-key ` | `CONTEXTFORGE_DATA_PLANE_TOKEN_VERIFICATION_PRIVATE_KEY` | Local tools only | RSA private key used by the optional local token helper. Present only when `contextforge-data-plane-lib/with_tools` is enabled. | The claims layer validates issuer, audience, and expiration: @@ -71,13 +71,13 @@ then selects one virtual host inside that config. | Flag | Env var | Required | Meaning | | --- | --- | --- | --- | -| `--redis-address ` | `CONTEXTFORGE_GATEWAY_RS_REDIS_HOSTNAME` | Yes | Redis host name or IP. | -| `--redis-port ` | `CONTEXTFORGE_GATEWAY_RS_REDIS_PORT` | Yes | Redis port. | -| `--redis-mode ` | `CONTEXTFORGE_GATEWAY_RS_REDIS_CONNECTION_MODE` | Yes | Redis connection mode: `plain-text`, `tls`, or `mtls`. | -| `--redis-tls-trust-bundle ` | `CONTEXTFORGE_GATEWAY_RS_REDIS_TLS_REDIS_TRUST_BUNDLE` | TLS and mTLS | PEM trust bundle for Redis TLS. | -| `--redis-tls-client-certificate ` | `CONTEXTFORGE_GATEWAY_RS_REDIS_TLS_REDIS_CLIENT_CERTIFICATE` | mTLS | PEM client certificate for Redis mTLS. | -| `--redis-tls-client-private-key ` | `CONTEXTFORGE_GATEWAY_RS_REDIS_TLS_REDIS_CLIENT_PRIVATE_KEY` | mTLS | PEM client private key for Redis mTLS. | -| `--user-config-cache-expiry-seconds ` | `CONTEXTFORGE_GATEWAY_RS_USER_CONFIG_CACHE_EXPIRY_SECONDS` | No, default `60` | Expiry for the in-process user config cache in front of Redis. `0` disables caching and reads Redis on every request. | +| `--redis-address ` | `CONTEXTFORGE_DATA_PLANE_REDIS_HOSTNAME` | Yes | Redis host name or IP. | +| `--redis-port ` | `CONTEXTFORGE_DATA_PLANE_REDIS_PORT` | Yes | Redis port. | +| `--redis-mode ` | `CONTEXTFORGE_DATA_PLANE_REDIS_CONNECTION_MODE` | Yes | Redis connection mode: `plain-text`, `tls`, or `mtls`. | +| `--redis-tls-trust-bundle ` | `CONTEXTFORGE_DATA_PLANE_REDIS_TLS_REDIS_TRUST_BUNDLE` | TLS and mTLS | PEM trust bundle for Redis TLS. | +| `--redis-tls-client-certificate ` | `CONTEXTFORGE_DATA_PLANE_REDIS_TLS_REDIS_CLIENT_CERTIFICATE` | mTLS | PEM client certificate for Redis mTLS. | +| `--redis-tls-client-private-key ` | `CONTEXTFORGE_DATA_PLANE_REDIS_TLS_REDIS_CLIENT_PRIVATE_KEY` | mTLS | PEM client private key for Redis mTLS. | +| `--user-config-cache-expiry-seconds ` | `CONTEXTFORGE_DATA_PLANE_USER_CONFIG_CACHE_EXPIRY_SECONDS` | No, default `60` | Expiry for the in-process user config cache in front of Redis. `0` disables caching and reads Redis on every request. | Local Compose exposes plain Redis on `127.0.0.1:6379`, so local runs normally use: @@ -95,10 +95,10 @@ for config, not the routing model itself. | Flag | Env var | Required | Meaning | | --- | --- | --- | --- | -| `--upstream-connection-mode ` | `CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE` | No | Controls whether backend MCP URLs may be HTTP, HTTPS, or mTLS. | -| `--upstream-trust-bundle ` | `CONTEXTFORGE_GATEWAY_RS_TLS_UPSTREAM_TRUST_BUNDLE` | No | Additional PEM trust bundle for HTTPS upstreams. | -| `--upstream-certificate ` | `CONTEXTFORGE_GATEWAY_RS_TLS_UPSTREAM_CERTIFICATE` | mTLS modes | PEM client certificate for upstream mTLS. | -| `--upstream-private-key ` | `CONTEXTFORGE_GATEWAY_RS_TLS_UPSTREAM_PRIVATE_KEY` | mTLS modes | PEM client private key for upstream mTLS. | +| `--upstream-connection-mode ` | `CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE` | No | Controls whether backend MCP URLs may be HTTP, HTTPS, or mTLS. | +| `--upstream-trust-bundle ` | `CONTEXTFORGE_DATA_PLANE_TLS_UPSTREAM_TRUST_BUNDLE` | No | Additional PEM trust bundle for HTTPS upstreams. | +| `--upstream-certificate ` | `CONTEXTFORGE_DATA_PLANE_TLS_UPSTREAM_CERTIFICATE` | mTLS modes | PEM client certificate for upstream mTLS. | +| `--upstream-private-key ` | `CONTEXTFORGE_DATA_PLANE_TLS_UPSTREAM_PRIVATE_KEY` | mTLS modes | PEM client private key for upstream mTLS. | Connection modes: @@ -116,28 +116,28 @@ before reaching that backend because the reqwest client is HTTPS-only. | Flag | Env var | Default | Meaning | | --- | --- | --- | --- | -| `--number-of-cpus ` | `CONTEXTFORGE_GATEWAY_RS_GATEWAY_CPUS` | Host CPU count | Worker thread count for the Tokio runtime shape. | -| `--single-runtime ` | `CONTEXTFORGE_GATEWAY_RS_SINGLE_RUNTIME` | `true` | `true` uses one multi-thread runtime. `false` starts multiple current-thread runtimes. | -| `--runtime-plugins-enabled ` | `CONTEXTFORGE_GATEWAY_RS_RUNTIME_PLUGINS_ENABLED` | `false` | Enables CPEX runtime plugin execution and Redis plugin config loading. | +| `--number-of-cpus ` | `CONTEXTFORGE_DATA_PLANE_NUMBER_OF_CPUS` | Host CPU count | Worker thread count for the Tokio runtime shape. | +| `--single-runtime ` | `CONTEXTFORGE_DATA_PLANE_SINGLE_RUNTIME` | `true` | `true` uses one multi-thread runtime. `false` starts multiple current-thread runtimes. | +| `--runtime-plugins-enabled ` | `CONTEXTFORGE_DATA_PLANE_RUNTIME_PLUGINS_ENABLED` | `false` | Enables CPEX runtime plugin execution and Redis plugin config loading. | When runtime plugins are enabled, plugin config is read from Redis key `ContextForgeGatewayRuntimePluginConfig`. That key is a control-plane trust boundary because it decides which registered hooks run. The flag only enables execution for plugin factories compiled into the binary. For the experimental secrets detection plugin, also build the gateway with -`contextforge-gateway-rs/plugins`. +`contextforge-data-plane/plugins`. ## Telemetry Options | Flag | Env var | Default | Meaning | | --- | --- | --- | --- | -| `--enable-open-telemetry ` | `CONTEXTFORGE_GATEWAY_RS_ENABLE_OPEN_TELEMETRY` | `false` | Enables trace export. | -| `--enable-otel-metrics ` | `CONTEXTFORGE_GATEWAY_RS_ENABLE_OTEL_METRICS` | `false` | Enables HTTP server metric export. | -| `--otlp-protocol ` | `CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_PROTOCOL` | `grpc` | `grpc` or `http-protobuf`. | -| `--otlp-endpoint ` | `CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_ENDPOINT` | Protocol-specific | Trace export endpoint. | -| `--otlp-metrics-endpoint ` | `CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | Protocol-specific | Metrics export endpoint. | -| `--otlp-headers ` | `CONTEXTFORGE_GATEWAY_RS_OTEL_EXPORTER_OTLP_HEADERS` | none | Comma-separated `key=value` headers for OTLP export. | -| `--otlp-service-name ` | `CONTEXTFORGE_GATEWAY_RS_OTEL_SERVICE_NAME` | `CONTEXTFORGE-GATEWAY-RS` | OpenTelemetry `service.name`. | +| `--enable-open-telemetry ` | `CONTEXTFORGE_DATA_PLANE_ENABLE_OPEN_TELEMETRY` | `false` | Enables trace export. | +| `--enable-otel-metrics ` | `CONTEXTFORGE_DATA_PLANE_ENABLE_OTEL_METRICS` | `false` | Enables HTTP server metric export. | +| `--otlp-protocol ` | `CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_PROTOCOL` | `grpc` | `grpc` or `http-protobuf`. | +| `--otlp-endpoint ` | `CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_ENDPOINT` | Protocol-specific | Trace export endpoint. | +| `--otlp-metrics-endpoint ` | `CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` | Protocol-specific | Metrics export endpoint. | +| `--otlp-headers ` | `CONTEXTFORGE_DATA_PLANE_OTEL_EXPORTER_OTLP_HEADERS` | none | Comma-separated `key=value` headers for OTLP export. | +| `--otlp-service-name ` | `CONTEXTFORGE_DATA_PLANE_OTEL_SERVICE_NAME` | `CONTEXTFORGE-DATA-PLANE` | OpenTelemetry `service.name`. | Default endpoints: @@ -157,8 +157,8 @@ RUST_TRACE_LOG=debug | Flag or env var | Default | Meaning | | --- | --- | --- | -| `--log-name` / `CONTEXTFORGE_GATEWAY_LOG_NAME` | `contextforge-gateway-rs.log` | File log name in the current working directory. | -| `--log-rotation` / `CONTEXTFORGE_GATEWAY_LOG_ROTATION` | `hourly` | Rotation mode: `minutely`, `hourly`, `daily`, or `never`. | +| `--log-name` / `CONTEXTFORGE_DATA_PLANE_LOG_NAME` | `contextforge-data-plane.log` | File log name in the current working directory. | +| `--log-rotation` / `CONTEXTFORGE_DATA_PLANE_LOG_ROTATION` | `hourly` | Rotation mode: `minutely`, `hourly`, `daily`, or `never`. | | `RUST_LOG` | `debug` | Console event filter. | | `RUST_FILE_LOG` | `debug` | File event filter. | | `RUST_TRACE_LOG` | `info` | OpenTelemetry span filter. | @@ -189,7 +189,7 @@ You may combine this with `--address` to expose both HTTP and HTTPS listeners. ### HMAC Token Verification ```bash ---token-verification-secret "${CONTEXTFORGE_GATEWAY_RS_TOKEN_SECRET}" +--token-verification-secret "${CONTEXTFORGE_DATA_PLANE_TOKEN_SECRET}" ``` Use this only when downstream JWTs are signed with an `HS*` algorithm. RSA diff --git a/docs/book/src/local-docker-stack.md b/docs/book/src/local-docker-stack.md index 06f9de10..7d0d11f4 100644 --- a/docs/book/src/local-docker-stack.md +++ b/docs/book/src/local-docker-stack.md @@ -13,7 +13,7 @@ make docker-prod make testing-up ``` -`make docker-prod` builds `dataplane:latest` from `docker/Dockerfile`; +`make docker-prod` builds `contextforge-data-plane:latest` from `docker/Dockerfile`; `testing-up` refuses to start if this image doesn't exist yet. `testing-up` starts: `nginx`, `control-plane`, `redis`, `postgres`, `pgbouncer`, `data-plane`, `fast_time_server`, `register_fast_time` (see `Makefile`). @@ -109,5 +109,5 @@ Stops the stack (containers/volumes kept; rerun `testing-up` to resume). | --- | --- | --- | | `403 {"detail":"Token is invalid: User is no longer a member of the associated team"}` | Hit control-plane instead of dataplane โ€” URL missing `/contextforge-rs` prefix. | Use `/contextforge-rs/servers//mcp`. | | `400 "Problem occurred retrieving the configuration"` | Dataplane has no `UserConfig` yet for the token's subject (`register_fast_time`/publisher hasn't run or synced). | Re-check config propagation above; confirm `register_fast_time` logs completed successfully and wait out the publisher interval. | -| `tools/list` returns `{"tools": [], "resultType": "complete"}` | Dataplane resolved the `UserConfig` fine, but couldn't connect to a declared backend. | `docker compose logs data-plane \| grep -i "worker quit\|BadScheme\|backend"`. A `BadScheme` error means `CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE` isn't set to `plain-text-or-tls` for a plain-`http://` backend. | +| `tools/list` returns `{"tools": [], "resultType": "complete"}` | Dataplane resolved the `UserConfig` fine, but couldn't connect to a declared backend. | `docker compose logs data-plane \| grep -i "worker quit\|BadScheme\|backend"`. A `BadScheme` error means `CONTEXTFORGE_DATA_PLANE_UPSTREAM_CONNECTION_MODE` isn't set to `plain-text-or-tls` for a plain-`http://` backend. | | `401` on every request | Bad/expired token, or control-plane and dataplane are signing/verifying with different keys or algorithms. | Confirm both sides have matching `JWT_ALGORITHM`/key config โ€” see [Control-Plane Integration](control-plane-integration.md). | diff --git a/docs/book/src/performance.md b/docs/book/src/performance.md index 879484fb..e9a4871e 100644 --- a/docs/book/src/performance.md +++ b/docs/book/src/performance.md @@ -1,7 +1,7 @@ # Performance > โšก **Two load paths:** `contextforge-load-test` measures the Rust dataplane -> alone, and the [`cf-integration`](https://github.com/contextforge-gateway-rs/cf-integration) +> alone, and the [`cf-integration`](https://github.com/contextforge-org/contextforge-dev-tools) > harness measures the full nginx-to-control-plane-to-dataplane stack with > Locust. Use the first to profile gateway changes and the second to measure > what users would see. diff --git a/docs/book/src/plugins-and-policy.md b/docs/book/src/plugins-and-policy.md index ee0f21e5..e6e647ad 100644 --- a/docs/book/src/plugins-and-policy.md +++ b/docs/book/src/plugins-and-policy.md @@ -7,10 +7,10 @@ payloads, so the gateway keeps the supported hook surface narrow and explicit. Runtime plugins are disabled by default. Enablement has two stages: -1. Compile concrete Rust plugin factories into the gateway binary with Cargo +1. Compile concrete Rust plugin factories into the data-plane binary with Cargo features. -2. Start the gateway with runtime plugins enabled and provide plugin config in - Redis. +2. Start the data plane with runtime plugins enabled and provide plugin config + in Redis. The runtime flag activates already-registered factories; it does not load new Rust code into a running process. When enabled, the binary creates a CPEX @@ -25,11 +25,66 @@ ContextForgeGatewayRuntimePluginConfig The runtime registry builds an initialized immutable plugin manager from that configuration. Reloading swaps the manager instead of mutating a live one. -The bundled secrets detection plugin is experimental. Compile it into the -gateway with `contextforge-gateway-rs/plugins`, enable runtime plugins with +The bundled secrets detection plugin is experimental. Compile it into the data +plane with `contextforge-data-plane/plugins`, enable runtime plugins with `--runtime-plugins-enabled true`, and configure the plugin kind `validator/secrets-detection` in the Redis document. +## Built-In Demo Factories + +The optional `test-plugins` feature compiles three demo factories from the +independently hosted `cpex-plugins-rs` repository. Redis configuration activates +factories already present in the binary; it never loads new Rust code into a +running process. + +Start the lightweight dependencies: + +```bash +docker compose -f docker/docker-compose-local.yaml up -d redis gateway-one gateway-two +``` + +Register the payload-marker configuration before starting the data plane: + +```bash +docker compose -f docker/docker-compose-local.yaml exec -T redis \ + redis-cli SET ContextForgeGatewayRuntimePluginConfig '{ + "version": 1, + "cpex": { + "plugins": [ + { + "name": "payload-marker", + "kind": "contextforge/payload-marker", + "hooks": ["cmf.tool_post_invoke"] + } + ] + } + }' +``` + +Build and run with the demo factories and runtime execution enabled: + +```bash +cargo run -p contextforge-data-plane \ + --features 'contextforge-data-plane-lib/with_tools,test-plugins' \ + --bin contextforge-data-plane -- \ + --address 127.0.0.1:8001 \ + --redis-address 127.0.0.1 \ + --redis-port 6379 \ + --redis-mode plain-text \ + --token-verification-public-key assets/jwt.key.pub \ + --token-verification-private-key assets/jwt.key \ + --upstream-connection-mode plain-text-or-tls \ + --runtime-plugins-enabled true +``` + +Startup should log successful CPEX initialization. The payload marker appends +`[cpex:payload-marker]` to successful tool results. The supported hook path is +also covered by: + +```bash +cargo nextest run --locked -p contextforge-data-plane-lib --test gateway_plugins +``` + ## Supported Hooks The supported surface is deliberately narrow: diff --git a/docs/book/src/request-flow.md b/docs/book/src/request-flow.md index f4320b1d..de553445 100644 --- a/docs/book/src/request-flow.md +++ b/docs/book/src/request-flow.md @@ -30,7 +30,7 @@ follow [Run the Gateway Locally](running-the-gateway.md) alongside this page. ## Startup Path -Startup begins in `crates/contextforge-gateway-rs/src/main.rs`: +Startup begins in `crates/contextforge-data-plane/src/main.rs`: ```text install rustls crypto provider @@ -53,7 +53,7 @@ and then calls `gateway.run_gateway()`. ## HTTP Stack Order -`Gateway::run_gateway` builds the service stack in `crates/contextforge-gateway-rs-lib/src/lib.rs`. +`Gateway::run_gateway` builds the service stack in `crates/contextforge-data-plane-lib/src/lib.rs`. Tower layers execute from the outside in, so a normal MCP request reaches the handler in this order: diff --git a/docs/book/src/running-the-gateway.md b/docs/book/src/running-the-gateway.md index d4d9f392..c57bdd70 100644 --- a/docs/book/src/running-the-gateway.md +++ b/docs/book/src/running-the-gateway.md @@ -1,70 +1,69 @@ # Run the Gateway Locally -This page walks through a local run that proves the dataplane can authenticate a -caller, load runtime config from Redis, initialize backend MCP sessions, and -return merged MCP results to a downstream client. +Use one of the two local workflows below. The end-to-end stack uses the current +Fast Time MCP backend, while the lightweight stack uses counter and conformance +test fixtures. -The local flow uses the repository's Docker Compose stack for Redis and two -sample backend MCP servers: - -| Service | Local port | Role | -| --- | --- | --- | -| `redis` | `6379` | Runtime config store for user config. | -| `gateway-one` | `5555` | Sample counter MCP backend. | -| `gateway-two` | `5556` | Sample conformance MCP backend. | -| `contextforge-gateway-rs` | `8001` | Rust dataplane process you run with Cargo. | +## Prerequisites -> ๐Ÿงช The token and user-config endpoints below are local bootstrap helpers. They -> are compiled with `contextforge-gateway-rs-lib/with_tools`. In a real -> deployment, the external ContextForge control plane mints tokens and writes -> config to Redis. +- Docker Compose. +- A Rust toolchain matching the workspace `rust-version` for the host workflow. +- Test keys at `assets/jwt.key` and `assets/jwt.key.pub` for the host workflow. +- Free local ports `6379`, `16379`, `5555`, `5556`, and `8001`. -Run the numbered steps in order, in the same terminal. Later steps reuse shell -variables such as `${TOKEN}` and `${SESSION_ID}` that earlier steps set, so a -fresh shell will not have them. +## Recommended End-to-End Stack -## Prerequisites +The supported smoke environment includes the external ContextForge control +plane, Redis, PostgreSQL, PgBouncer, the Rust data plane, and +`fast_time_server`: -- Rust toolchain matching the workspace `rust-version`. -- Docker Compose. -- Free local ports: `6379`, `16379`, `5555`, `5556`, and `8001`. The Compose - stack maps both plain (`6379`) and TLS (`16379`) Redis ports. -- Test keys under `assets/`: `jwt.key` and `jwt.key.pub`. +```bash +make docker-prod +make testing-up +``` -## 1. Start Redis and Backend MCP Servers +Confirm the services and one-shot registration job: ```bash -docker compose -f docker/docker-compose-local.yaml up -d +docker compose -f docker/docker-compose.yml ps -a +docker compose -f docker/docker-compose.yml logs register_fast_time ``` -The sample backends default to a CPU limit of `8` and a reservation of `4`, -which Docker rejects on hosts with fewer CPUs -(`range of CPUs is from 0.01 to ...`). On smaller machines, override the -sizing knobs: +Continue with [Local Docker Stack](local-docker-stack.md) for token creation, +config propagation, and an MCP smoke test through the complete control-plane to +data-plane path. + +Stop the stack without deleting its containers or volumes: ```bash -GATEWAY_CPU_LIMIT=2 GATEWAY_CPU_RESERVATION=0.5 \ - docker compose -f docker/docker-compose-local.yaml up -d +make testing-down ``` -Check that the local dependencies are running: +## Run the Rust Binary from Cargo + +For debugger, profiler, or rapid host-development loops, start Redis and the +counter and conformance fixtures: ```bash +docker compose -f docker/docker-compose-local.yaml up -d docker compose -f docker/docker-compose-local.yaml ps redis gateway-one gateway-two ``` -The backends listen on the host so the gateway can reach them at -`http://127.0.0.1:5555/mcp` and `http://127.0.0.1:5556/mcp`. +The services are available at: -## 2. Start the Gateway +| Service | Local endpoint | Role | +| --- | --- | --- | +| `redis` | `127.0.0.1:6379` | Runtime configuration store. | +| `gateway-one` | `http://127.0.0.1:5555/mcp` | MCP Rust SDK counter fixture. | +| `gateway-two` | `http://127.0.0.1:5556/mcp` | MCP Rust SDK conformance fixture. | -For the local bootstrap flow, run the binary with the `with_tools` dependency -feature so the admin token and config endpoints are available: +Run the binary with the local bootstrap helpers when direct token/config setup +is needed during development: ```bash -cargo run -p contextforge-gateway-rs \ - --features contextforge-gateway-rs-lib/with_tools \ - --bin contextforge-gateway-rs -- \ +cargo run -p contextforge-data-plane \ + --features contextforge-data-plane-lib/with_tools \ + --bin contextforge-data-plane -- \ --address 127.0.0.1:8001 \ --redis-address 127.0.0.1 \ --redis-port 6379 \ @@ -75,15 +74,18 @@ cargo run -p contextforge-gateway-rs \ --number-of-cpus 4 ``` -Keep this process running. The gateway exposes MCP traffic under: +The client-facing route is: ```text http://127.0.0.1:8001/contextforge-rs/servers/{virtual_host_id}/mcp ``` +Keep the data-plane process running. Use another terminal for the remaining +steps. + Runtime CPEX plugins need both a compile-time feature and runtime config. To try the experimental secrets detection plugin locally, build with -`contextforge-gateway-rs/plugins`, start the gateway with +`contextforge-data-plane/plugins`, start the data plane with `--runtime-plugins-enabled true`, and write the Redis plugin config before startup. @@ -91,9 +93,10 @@ The local command uses `--upstream-connection-mode plain-text-or-tls` because the sample backend URLs are plain HTTP. Without that option, the default upstream client is HTTPS-only. -## 3. Mint a Test Token +### Mint a Local Test Token -In another terminal, request a JWT for the test subject: +The local token helper signs an RS256 token with `assets/jwt.key`. Its `sub` +claim becomes the Redis user-config key. ```bash USER_ID=11111111-1111-1111-1111-111111111111 @@ -101,25 +104,21 @@ USER_EMAIL=admin@example.com TOKEN=$(curl --silent --show-error \ --url "http://127.0.0.1:8001/contextforge-rs/admin/tokens/${USER_ID}?email=${USER_EMAIL}") - -printf '%s\n' "${TOKEN}" ``` -The token's `sub` claim is the UUID in `USER_ID`. The gateway uses that subject -as the Redis user-config key; email metadata, when present, is not used for MCP -routing. +### Seed Local Runtime Configuration -## 4. Write User Config - -Seed Redis with one virtual host and two backend MCP servers: +Create a virtual host that points at both lightweight MCP fixtures: ```bash +VIRTUAL_HOST_ID=c0ffee00f001f00df00ddeadbeefdead + curl --silent --show-error --request POST \ --url "http://127.0.0.1:8001/contextforge-rs/admin/userconfigs/${USER_ID}" \ --header 'content-type: application/json' \ --data '{ "virtual_hosts": { - "c0ffee00f001f00lf00ldeadbeefdead": { + "c0ffee00f001f00df00ddeadbeefdead": { "backends": { "gateway-one": { "name": "gateway-one", @@ -145,135 +144,69 @@ curl --silent --show-error --request POST \ }' ``` -The important relationship is: +The identity and routing relationship is: ```text -JWT subject 11111111-1111-1111-1111-111111111111 - -> Redis user config - -> virtual host c0ffee00f001f00lf00ldeadbeefdead - -> backend MCP URLs +JWT subject + -> Redis UserConfig + -> virtual host id + -> configured backend MCP URLs ``` -## 5. Temporary Legacy Smoke Flow +### Verify Modern Protocol Discovery -> This section exercises the current migration-era implementation. It is not -> the supported downstream client contract. New clients must target MCP -> `2026-07-28` over Streamable HTTP with `server/discover` and per-request -> client context. Legacy clients and SSE remain on control-plane routes and do -> not use this dataplane endpoint; this smoke flow will be replaced as the -> dataplane migration lands. - -Open a streamable HTTP MCP session and save the returned `mcp-session-id` -header: +Probe the client-facing route with MCP `2026-07-28`. Modern requests carry the +protocol version, client identity, and client capabilities in `_meta` on every +request: ```bash -INIT_HEADERS=$(mktemp) - curl --silent --show-error \ - --dump-header "${INIT_HEADERS}" \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ + --url "http://127.0.0.1:8001/contextforge-rs/servers/${VIRTUAL_HOST_ID}/mcp" \ --header "authorization: Bearer ${TOKEN}" \ --header 'content-type: application/json' \ --header 'accept: application/json, text/event-stream' \ + --header 'mcp-protocol-version: 2026-07-28' \ + --header 'mcp-method: server/discover' \ --data '{ "jsonrpc": "2.0", - "id": 0, - "method": "initialize", + "id": 1, + "method": "server/discover", "params": { - "protocolVersion": "2025-11-25", - "capabilities": {}, - "clientInfo": { "name": "curl", "version": "0.1.0" } - } - }' - -SESSION_ID=$(awk 'tolower($1) == "mcp-session-id:" { gsub("\r", "", $2); print $2 }' "${INIT_HEADERS}") -printf '%s\n' "${SESSION_ID}" -``` - -During `initialize`, the gateway opens upstream MCP client sessions to the -configured backends and stores them under the downstream session id. - -Send the MCP initialized notification: - -```bash -curl --silent --show-error \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header "mcp-session-id: ${SESSION_ID}" \ - --header 'mcp-protocol-version: 2025-11-25' \ - --header 'content-type: application/json' \ - --header 'accept: application/json, text/event-stream' \ - --data '{"jsonrpc":"2.0","method":"notifications/initialized"}' -``` - -## 6. List Tools - -```bash -curl --silent --show-error \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header "mcp-session-id: ${SESSION_ID}" \ - --header 'mcp-protocol-version: 2025-11-25' \ - --header 'content-type: application/json' \ - --header 'accept: application/json, text/event-stream' \ - --data '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' -``` - -The response should contain tool names prefixed with their backend name, such as -`gateway-one-increment`. That prefix is the routing contract for later -`tools/call` requests. - -## 7. Call a Tool - -```bash -curl --silent --show-error \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header "mcp-session-id: ${SESSION_ID}" \ - --header 'mcp-protocol-version: 2025-11-25' \ - --header 'content-type: application/json' \ - --header 'accept: application/json, text/event-stream' \ - --data '{ - "jsonrpc": "2.0", - "id": 2, - "method": "tools/call", - "params": { - "name": "gateway-one-increment", - "arguments": {} + "_meta": { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": { + "name": "curl", + "version": "0.1.0" + }, + "io.modelcontextprotocol/clientCapabilities": {} + } } }' ``` -The gateway strips `gateway-one-`, forwards `increment` to the `gateway-one` -backend session, and returns the backend result to the client. +The response should advertise `2026-07-28` in `supportedVersions`. This probe +validates the modern HTTP envelope plus authentication, user-config lookup, and +virtual-host selection. Use the [recommended end-to-end stack](local-docker-stack.md) +for the complete backend tool-call smoke test. -## 8. End the Session - -```bash -curl --silent --show-error --request DELETE \ - --url http://127.0.0.1:8001/contextforge-rs/servers/c0ffee00f001f00lf00ldeadbeefdead/mcp \ - --header "authorization: Bearer ${TOKEN}" \ - --header "mcp-session-id: ${SESSION_ID}" -``` - -The gateway removes local session state and backend transports for that user -and MCP session id. +The target downstream contract is MCP `2026-07-28` over Streamable HTTP using +`server/discover` and per-request client metadata. Older protocol versions, +legacy session initialization, and SSE remain control-plane responsibilities; +see [MCP Behavior](mcp-behavior.md) and +[Control-Plane Integration](control-plane-integration.md). ## Troubleshooting -| Symptom | Likely boundary | +| Symptom | Likely cause | | --- | --- | -| `401 Unauthorized` | Missing bearer token, invalid signature, expired token, wrong issuer, wrong audience, or no configured decoder key. | -| `400 Problem occurred retrieving the configuration` | Redis has no config for the JWT subject, or the Redis lookup returned no data. | -| `500 Problem occurred retrieving the configuration` | The stored config could not be decoded, the Redis key could not be encoded, or another non-missing config-store error occurred. | -| `404` with `{"detail":"Server not found"}` | The path virtual host id is not present in that user's config. | -| MCP session id is empty | The `initialize` call failed before RMCP created a downstream session. | -| Backend calls fail | Backend URL is wrong, backend process is down, or `--upstream-connection-mode` rejects the URL scheme. | -| Calls fail after gateway restart | Backend MCP session state is local process state today. Re-run `initialize`. | - -## Tear Down - -Stop the gateway with `Ctrl-C`, then stop local dependencies: +| `401 Unauthorized` | Missing bearer token, invalid signature, expired token, or mismatched issuer/audience. | +| `400 Problem occurred retrieving the configuration` | Redis has no `UserConfig` for the token subject. Re-run the config POST with the same `USER_ID`. | +| `500 Problem occurred retrieving the configuration` | Redis access or stored config decoding failed; inspect data-plane and Redis logs. | +| `404` with `{"detail":"Server not found"}` | The URL virtual-host id does not exist in that user's config. | +| `400` mentioning request metadata | The MCP protocol header and `_meta` version differ, or required per-request client metadata is missing. | +| Backend calls fail | A backend URL is wrong, a fixture is down, or `--upstream-connection-mode` rejects plain HTTP. | + +Stop the host process with `Ctrl-C`, then remove the lightweight dependencies: ```bash docker compose -f docker/docker-compose-local.yaml down diff --git a/docs/book/src/runtime-configuration.md b/docs/book/src/runtime-configuration.md index 93eeeb6e..01b1ad1c 100644 --- a/docs/book/src/runtime-configuration.md +++ b/docs/book/src/runtime-configuration.md @@ -14,7 +14,7 @@ parts of the dataplane. | Surface | Source | Loaded | Main user | | --- | --- | --- | --- | -| Process `Config` | CLI flags and `CONTEXTFORGE_GATEWAY_RS_*` env vars parsed by `clap`. | Startup. | Listener setup, JWT decoder keys, Redis connection, upstream HTTP client, telemetry, runtime shape. | +| Process `Config` | CLI flags and `CONTEXTFORGE_DATA_PLANE_*` env vars parsed by `clap`. | Startup. | Listener setup, JWT decoder keys, Redis connection, upstream HTTP client, telemetry, runtime shape. | | `UserConfig` | `UserConfigStore`, currently Redis through `RedisUserConfigStore`. | Per request after JWT validation. | Virtual host and backend selection. | | `RuntimePluginConfigDocument` | Redis key `ContextForgeGatewayRuntimePluginConfig` when runtime plugins are enabled. | Startup and watcher reload. | CPEX tool pre/post hooks. | @@ -140,7 +140,7 @@ RuntimePluginConfigDocument Runtime config activates plugin factories that were compiled into the gateway binary; it does not load new Rust code. The experimental secrets detection -plugin is included with the `contextforge-gateway-rs/plugins` Cargo feature and +plugin is included with the `contextforge-data-plane/plugins` Cargo feature and activated with plugin kind `validator/secrets-detection`. The plugin config loader accepts JSON bytes or MessagePack bytes. It rejects diff --git a/docs/book/src/security-model.md b/docs/book/src/security-model.md index d1643a7a..e6dfb034 100644 --- a/docs/book/src/security-model.md +++ b/docs/book/src/security-model.md @@ -55,7 +55,7 @@ apply, but expect this to tighten as policy work lands. ## Local Bootstrap Helpers -The `contextforge-gateway-rs-lib/with_tools` feature compiles in +The `contextforge-data-plane-lib/with_tools` feature compiles in `/contextforge-rs/admin/tokens/{user}`, `/contextforge-rs/admin/userconfigs/{user}`, and `/contextforge-rs/health`. These routes are registered outside the authentication middleware, so token diff --git a/docs/book/src/system-shape.md b/docs/book/src/system-shape.md index ee0f7566..717dcfe1 100644 --- a/docs/book/src/system-shape.md +++ b/docs/book/src/system-shape.md @@ -10,7 +10,7 @@ ![System shape](assets/system-shape.svg) -The ContextForge Gateway is the Rust dataplane process for MCP traffic. It is +The ContextForge Data Plane is the Rust dataplane process for MCP traffic. It is not a second ContextForge application. It accepts downstream streamable HTTP MCP requests, builds request context, loads runtime config, opens or reuses backend MCP client sessions, and returns one merged MCP server view to the caller. @@ -35,7 +35,7 @@ In text form, the same model is: ContextForge control plane -> writes runtime config and owns management workflows -contextforge-gateway-rs process +contextforge-data-plane process -> authenticates, loads config, routes, fans out, applies hooks, emits signals backend MCP servers @@ -81,7 +81,7 @@ server. Internally, it is a focused proxy, fanout, policy, and merge dataplane. ## Process Assembly -Startup begins in `crates/contextforge-gateway-rs/src/main.rs`. The binary crate +Startup begins in `crates/contextforge-data-plane/src/main.rs`. The binary crate does process-level assembly: ```text @@ -114,7 +114,7 @@ logging, trace export, and metrics export setup. ## Gateway Assembly -`crates/contextforge-gateway-rs-lib/src/lib.rs` builds the dataplane stack in +`crates/contextforge-data-plane-lib/src/lib.rs` builds the dataplane stack in `Gateway::run_gateway`: ```text @@ -146,10 +146,10 @@ The repository is a Cargo workspace with narrow responsibilities: | Crate | Responsibility | | --- | --- | -| `contextforge-gateway-rs` | Process shell: CLI config, logging, telemetry exporters, Tokio runtime, allocator, plugin registry startup, gateway construction. | -| `contextforge-gateway-rs-lib` | Dataplane library: Axum stack, request middleware, config lookup, MCP fanout/routing, backend sessions, upstream clients, downstream transports. | -| `contextforge-gateway-rs-apis` | Shared contract: `UserConfig`, `VirtualHost`, `BackendMCPGateway`, Redis user key, plugin config document, schema generation. | -| `contextforge-gateway-rs-cpex` | Plugin integration: CPEX runtime registry, Redis plugin config loading, supported tool pre/post hooks, stream event adaptation. | +| `contextforge-data-plane` | Process shell: CLI config, logging, telemetry exporters, Tokio runtime, allocator, plugin registry startup, gateway construction. | +| `contextforge-data-plane-lib` | Dataplane library: Axum stack, request middleware, config lookup, MCP fanout/routing, backend sessions, upstream clients, downstream transports. | +| `contextforge-data-plane-apis` | Shared contract: `UserConfig`, `VirtualHost`, `BackendMCPGateway`, Redis user key, plugin config document, schema generation. | +| `contextforge-data-plane-cpex` | Plugin integration: CPEX runtime registry, Redis plugin config loading, supported tool pre/post hooks, stream event adaptation. | | `contextforge-load-test` | Performance harness: end-to-end MCP traffic driver. | Keep those boundaries stable. Adding dataplane behavior to the binary crate @@ -219,7 +219,7 @@ state in separate ownership scopes. The current ownership model is: | State | Owner | Lifetime | | --- | --- | --- | | CLI `Config` | Binary startup and `Gateway` | Process lifetime. | -| JWT decoders | `ContextForgeGatewayAppState` | Process lifetime. | +| JWT decoders | `ContextForgeDataPlaneAppState` | Process lifetime. | | User config | `UserConfigStore`, currently Redis plus in-process LRU | Control-plane authored, request-path consumed. | | Request identity | Request extensions | One HTTP request. | | Virtual host id | Request extensions | One HTTP request. | diff --git a/docs/book/src/telemetry-and-diagnostics.md b/docs/book/src/telemetry-and-diagnostics.md index 04af6a29..73b15c87 100644 --- a/docs/book/src/telemetry-and-diagnostics.md +++ b/docs/book/src/telemetry-and-diagnostics.md @@ -18,7 +18,7 @@ All export settings are process config; see the telemetry section of the ## Logging Console and file logging are always on. The file appender writes -`contextforge-gateway-rs.log` (configurable with `--log-name`) in the current +`contextforge-data-plane.log` (configurable with `--log-name`) in the current working directory and rotates hourly by default (`--log-rotation`). Three environment filters control verbosity independently: @@ -63,7 +63,7 @@ A complete local pipeline ships under `docker/` as overlays on top of the | Component | Role | Endpoint | | --- | --- | --- | -| Langfuse | Trace backend and span viewer. | UI at `http://localhost:3100`, login `admin@example.com` / `changeme`, project `ContextForge Gateway (Rust)`. | +| Langfuse | Trace backend and span viewer. | UI at `http://localhost:3100`, login `admin@example.com` / `changeme`, project `ContextForge Data Plane`. | | OTel Collector | Receives OTLP from the gateway, fans traces and metrics out. | OTLP/HTTP on `:4318`, Prometheus exposition on `:8889`, raw dumps via `docker logs otel-collector`. | | Prometheus | Scrapes the collector for browsable PromQL. | UI at `http://localhost:9090`. | @@ -83,7 +83,7 @@ Re-run with `ps` instead of `up -d` and wait until every container is healthy. ```bash RUST_TRACE_LOG=debug \ -cargo run --release --bin contextforge-gateway-rs -- \ +cargo run --release --bin contextforge-data-plane -- \ --address 0.0.0.0:8001 \ --redis-port 6379 --redis-address 127.0.0.1 --redis-mode=plain-text \ --token-verification-public-key assets/jwt.key.pub \ @@ -95,7 +95,7 @@ cargo run --release --bin contextforge-gateway-rs -- \ --otlp-endpoint http://127.0.0.1:3100/api/public/otel/v1/traces \ --otlp-headers "Authorization=Basic cGstbGYtY29udGV4dGZvcmdlOnNrLWxmLWNvbnRleHRmb3JnZQ==" \ --otlp-metrics-endpoint http://127.0.0.1:4318/v1/metrics \ - --otlp-service-name contextforge-gateway-rs + --otlp-service-name contextforge-data-plane ``` The `Authorization` header is Basic auth for the seeded Langfuse project keys diff --git a/docs/book/src/testing.md b/docs/book/src/testing.md index 0b071fe7..4f804860 100644 --- a/docs/book/src/testing.md +++ b/docs/book/src/testing.md @@ -28,7 +28,7 @@ migration inventory and should be replaced as the modern implementation lands. ## In-Repo Integration Tests -`crates/contextforge-gateway-rs-lib/tests/` exercises the gateway against +`crates/contextforge-data-plane-lib/tests/` exercises the gateway against in-process mock MCP backends (shared helpers live in `tests/support/`): | Test file | Covers | @@ -42,7 +42,7 @@ These run in `cargo nextest run` with no Docker dependencies. ## Full-Stack Integration Harness -[`cf-integration`](https://github.com/contextforge-gateway-rs/cf-integration) +[`cf-integration`](https://github.com/contextforge-org/contextforge-dev-tools) wires the external ContextForge control plane (`cf-controlplane`) to this dataplane the way production intends: the stock upstream Compose stack, plus exactly two intentional differences โ€” nginx routes only diff --git a/docs/book/src/what-is-contextforge-gateway.md b/docs/book/src/what-is-contextforge-data-plane.md similarity index 97% rename from docs/book/src/what-is-contextforge-gateway.md rename to docs/book/src/what-is-contextforge-data-plane.md index 1d692cb5..7404fdac 100644 --- a/docs/book/src/what-is-contextforge-gateway.md +++ b/docs/book/src/what-is-contextforge-data-plane.md @@ -1,8 +1,8 @@ -# What is ContextForge Gateway? +# What is ContextForge Data Plane? -Welcome to the ContextForge Gateway book. +Welcome to the ContextForge Data Plane book. -`contextforge-gateway-rs` is the Rust **dataplane** for ContextForge: a single +`contextforge-data-plane` is the Rust **data plane** for ContextForge: a single MCP entry point that sits in front of many backend MCP servers and makes them look like one. If you have used an API gateway or reverse proxy for HTTP APIs, this is the same idea for the Model Context Protocol (MCP).