Plugin catalog

95 plugins, every one searchable.

The MCPG gateway is a thin shell — the power lives in plugins. Each entry below carries what it does, what it costs you in licence terms, where its source lives, and a configuration fragment that boots as written.

62 plugins are Apache-2.0. 33 enterprise plugins are source-available under BUSL-1.1 — read the source, run them in non-production freely, and license production use via agent@mcpg.dev or mcpg.cloud.

Before the catalog

What the gateway is configured with

One YAML document, 6 worked examples, smallest first.

An MCPG gateway is one YAML document. It has fourteen top-level blocks — mcp, governance, gateway, observability, plugins, cluster, storage, credentials, schema_registry, feature_flags, debug, license, cloud, usage_reporting — and nothing else. The root is deny_unknown_fields: a misspelled key is a boot failure, not a warning, so a config that starts is a config the gateway fully understood.

Two rules explain the shape of every example below.

The gateway links almost nothing in. There are no built-in backends and no built-in metrics or trace exporters. backend: { kind: http } resolves only because a plugins[] entry declares the HTTP backend artefact; metrics.sinks[].kind exports only because a plugins[] entry supplies that cdylib. Naming a capability requests it — a plugins[] entry provides it. The published images bake nine of these at /usr/local/lib/mcpg/plugins/<id>/plugin.so, so most deployments point source.path there and never touch a registry.

Capabilities and their governance sit together. A tool is declared once, under mcp.capabilities.tools[], carrying its own trust floor, scope requirements, quota references and backend wiring. You read one entry to know who may call a tool and what it does when they do.

1. Minimal The smallest thing that boots and serves a tool.

This is a complete, loadable document. It declares one backend plugin and binds one tool to it; every other block takes its default, which means the listener comes up on 127.0.0.1:8787 at /mcp and the compliance audit trail writes to ./mcpg-audit.log in the working directory.

The one line that is not obvious is minimum_trust: unauthenticated. A binding’s trust floor defaults to header_asserted, and this config configures no identity source — so at the default floor an anonymous caller sits below the bar and the tool is filtered out of tools/list entirely. The gateway would boot and serve nothing.

yaml
plugins:
  - id: dev.mcpg.backend.mock
    class: backend
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.mock/plugin.so

mcp:
  capabilities:
    tools:
      - name: ping
        description: Return a fixed JSON payload so a client can prove the
          gateway is reachable end to end.
        governance:
          minimum_trust: unauthenticated
        backend:
          kind: mock
          response:
            ok: true
2. A real backend HTTP, with retry and argument substitution.

Swapping mock for http changes only the plugins[] source and the binding’s backend: block. ${arguments.account_id} interpolates the caller’s tool argument into the URL and ${env.…} pulls the upstream credential from the process environment at config load, so the token never appears in the document.

retry is a first-class per-binding block rather than something the backend invents, and the response guards — expected_status_codes, require_json_response, max_response_bytes — turn a misbehaving upstream into a clean tool error instead of an unbounded read.

yaml
gateway:
  server:
    bind_address: "0.0.0.0:8787"
    mcp_path: /mcp
    health_path: /health
    allowed_origins:
      - "https://console.example.com"
    request_timeout_ms: 30000

plugins:
  - id: dev.mcpg.backend.http
    class: backend
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so

mcp:
  capabilities:
    tools:
      - name: accounts.lookup
        title: Look up an account
        description: Fetch one account record from the corporate accounts API
          by its identifier.
        input_schema:
          type: object
          properties:
            account_id:
              type: string
          required: [account_id]
        governance:
          minimum_trust: unauthenticated
        retry:
          max_attempts: 3
          initial_backoff_ms: 200
          retry_on_status_codes: [429, 502, 503, 504]
          retry_on_transport_error: true
        backend:
          kind: http
          url: "https://api.example.com/v1/accounts/${arguments.account_id}"
          method: get
          timeout_ms: 5000
          expected_status_codes: [200]
          require_json_response: true
          max_response_bytes: 65536
          headers:
            Authorization: "Bearer ${env.ACCOUNTS_API_TOKEN}"

One guard to know about: the HTTP backend resolves DNS itself and refuses any address in a private range unless the binding sets allow_private_backends: true in its backend: block. A tool pointed at https://accounts.internal/… or a cluster-local service fails closed until you opt in. That is deliberate — it is the SSRF guard — but it surprises people wiring their first internal upstream.

3. Identity and authorization An OIDC issuer and a trust floor.

governance.access.oidc_oauth is one of the few things handled in-process: the gateway builds the JWKS-backed verifier itself, so unlike a backend or a metrics sink this block needs no plugins[] entry. providers is a list, so a second issuer is a second entry. verification.kind selects oidc_jwks, oauth_introspection, or hybrid.

With an issuer configured, minimum_trust: verified becomes meaningful: only a caller presenting a token that verified against that issuer’s keys reaches the tool, and required_scopes adds an OAuth scope check that answers a short-scoped caller with a step-up challenge naming what is missing, rather than a bare 403.

yaml
gateway:
  server:
    bind_address: "0.0.0.0:8787"
    allowed_origins:
      - "https://console.example.com"

governance:
  access:
    oidc_oauth:
      token_source:
        kind: authorization_bearer
      providers:
        - issuer: "https://example.okta.com"
          audiences: ["mcpg-gateway"]
          clock_skew_secs: 60
          verification:
            kind: oidc_jwks
            allowed_algs: ["RS256"]
            refresh_interval_secs: 300
            max_staleness_secs: 3600
  policy:
    tool_access:
      default_minimum_trust: verified

plugins:
  - id: dev.mcpg.backend.http
    class: backend
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so

mcp:
  capabilities:
    tools:
      - name: accounts.lookup
        description: Fetch one account record. Requires a verified caller.
        governance:
          minimum_trust: verified
          required_scopes: ["accounts:read"]
        backend:
          kind: http
          url: "https://api.example.com/v1/accounts/${arguments.account_id}"
          method: get
          timeout_ms: 5000
          expected_status_codes: [200]

Note that both floors are set here, and that is not redundant. Every declared binding injects its own trust rule keyed by its name, and that rule wins over default_minimum_trust — including when the binding simply left the field at its default header_asserted. Raising governance.policy.tool_access.default_minimum_trust on its own therefore does not lift the floor on tools you declared; it governs surfaces that have no binding rule of their own. Set the floor on the binding.

4. Governance Quotas, a CEL guard, and a required audit trail.

Rate limits, budgets and concurrency caps are a built-in registry, not a plugin. You declare named policies under governance.quotas and bindings reference them by id, so one SLA tier is defined once and attached to many tools. scope: per_identity requires an identity_claim naming the JWT claim the bucket keys on; global and per_session reject that field.

allow_if is a CEL expression evaluated per call against the resolved identity — the tool disappears for everyone outside the group. Audit is the block worth reading twice: it is enabled and required by default, meaning a stock gateway refuses to start unless a sink is actually serving. on_failure: fail_closed is the compliance posture — no action without a durable record.

yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://example.okta.com"
          audiences: ["mcpg-gateway"]
          verification:
            kind: oidc_jwks
            allowed_algs: ["RS256"]

  quotas:
    store:
      kind: cluster
    on_error: deny
    rate_limits:
      - id: per-caller-standard
        kind: token_bucket
        scope: per_identity
        identity_claim: sub
        rate:
          calls_per_minute: 600
        burst: 50
        on_exceeded: deny
    budgets:
      - id: per-caller-daily-calls
        kind: call_count
        scope: per_identity
        identity_claim: sub
        cap_calls: 20000
        window: 1d
    concurrency:
      - id: writes-in-flight
        scope: global
        max_concurrent: 8

  audit:
    enabled: true
    required: true
    on_failure: fail_closed
    emit_tool_call_allowed: true
    emit_tool_call_completed: true
    sinks:
      - kind: dev.mcpg.builtin.audit.local-file
        config:
          path: /var/log/mcpg/audit.log

plugins:
  - id: dev.mcpg.backend.http
    class: backend
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so

mcp:
  capabilities:
    tools:
      - name: accounts.close
        description: Close an account. Restricted, rate limited, and audited.
        governance:
          minimum_trust: verified
          required_scopes: ["accounts:write"]
          allow_if: '"account_admins" in identity.groups'
        quotas:
          rate_limit: per-caller-standard
          budget: per-caller-daily-calls
          concurrency: writes-in-flight
        backend:
          kind: http
          url: "https://api.example.com/v1/accounts/${arguments.account_id}/close"
          method: post
          timeout_ms: 10000
          expected_status_codes: [200, 204]

The local-file audit sink is genuinely built in — dev.mcpg.builtin.* ids need no plugins[] entry. That is the exception, and the next example is the rule.

5. Observability Every sink needs two entries.

This is the single most common misconfiguration, so it gets its own example. Only stderr, stdout and file are built-in sink kinds. prometheus and otlp are not keywords; they are plugin ids, and a sink naming one exports nothing unless a matching plugins[] entry loads that cdylib. The gateway logs a warning and keeps running — metrics land nowhere and /metrics returns an empty payload, with no boot failure to tell you.

So each signal below appears twice: once in plugins[] to load the exporter, once in observability to route the signal to it. Note also that traces.enabled defaults to false — the triad is not symmetrical, and traces must be switched on explicitly.

yaml
plugins:
  - id: dev.mcpg.backend.http
    class: backend
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so

  # Without these two entries the sinks below are silently inert.
  - id: dev.mcpg.observability.prometheus
    class: metrics_sink
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.observability.prometheus/plugin.so
    config:
      namespace: mcpg
      global_labels:
        env: production
        region: eu-west-1

  - id: dev.mcpg.observability.otlp
    class: telemetry_sink
    source:
      path: /usr/local/lib/mcpg/plugins/dev.mcpg.observability.otlp/plugin.so
    config:
      url: "http://otel-collector.observability.svc.cluster.local:4317"
      service_name: mcpg-gateway
      resource_attributes:
        deployment.environment: production
      batch_export_timeout_ms: 30000

observability:
  enabled: true
  logs:
    enabled: true
    level: info
    sinks:
      - kind: stderr
        config:
          format: json
  metrics:
    enabled: true
    sinks:
      - kind: dev.mcpg.observability.prometheus
        config:
          path: /metrics
  traces:
    enabled: true
    service_name: mcpg-gateway
    propagate_context: true
    sinks:
      - kind: dev.mcpg.observability.otlp

mcp:
  capabilities:
    tools:
      - name: accounts.lookup
        description: Fetch one account record from the accounts API.
        governance:
          minimum_trust: unauthenticated
        backend:
          kind: http
          url: "https://api.example.com/v1/accounts/${arguments.account_id}"
          method: get
          timeout_ms: 5000
          expected_status_codes: [200]

The two config: blocks are not the same object and are not interchangeable. plugins[].config is the plugin’s own configuration — the Prometheus exporter validates it strictly and refuses to load on an unknown key. The sink’s config: is read by the gateway only, for two things: path (the HTTP route /metrics is served on, and the audit file path) and format for log sinks. /metrics is served on the gateway’s main listener; there is no separate metrics port.

6. Production shape Clustering and plugin integrity.

Multi-replica deployments swap cluster.kind from the default single_node to a real coordinator, which then backs sessions, tasks, quotas and delivery across every replica. The transport guard refuses a plaintext coordinator URL, since it carries all shared state; readiness_gate: fail ties /ready to coordinator health so a load balancer drains a replica that has lost it, and state_encryption_key_env names the environment variable holding the key that seals capability state at rest.

On the supply-chain side, signature verification is already enforce by default — a stock gateway loads only signed plugins. What production adds is require_integrity_anchor: true, which refuses any oci:-sourced plugin pulled by bare tag, forcing every entry to carry a digest pin, an artefact hash, or its own trusted keys.

yaml
gateway:
  server:
    bind_address: "0.0.0.0:8787"
    allowed_origins:
      - "https://gateway.example.com"
    request_timeout_ms: 30000
    session_idle_timeout_ms: 900000
    shutdown_timeout_ms: 30000
    tls:
      cert_path: /etc/mcpg/certs/server.crt
      key_path: /etc/mcpg/certs/server.key
      min_tls_version: "1.3"

  plugin_registry:
    default_signature_policy: enforce
    require_integrity_anchor: true

cluster:
  kind: redis
  url: "${env.MCPG_REDIS_URL}"          # rediss:// — plaintext is refused
  password: "${env.MCPG_REDIS_PASSWORD}"
  key_prefix: "mcpg:prod"
  pool_size: 16
  readiness_gate: fail
  state_encryption_key_env: MCPG_CLUSTER_STATE_KEY

governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://example.okta.com"
          audiences: ["mcpg-gateway"]
          verification:
            kind: oidc_jwks
            allowed_algs: ["RS256"]
  audit:
    enabled: true
    required: true
    on_failure: fail_closed
    sinks:
      - kind: dev.mcpg.builtin.audit.local-file
        config:
          path: /var/log/mcpg/audit.log

plugins:
  - id: dev.mcpg.backend.http
    class: backend
    source:
      # Digest-pinned: satisfies require_integrity_anchor. Replace with
      # the digest of the artefact you actually ship.
      oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-http@sha256:0000000000000000000000000000000000000000000000000000000000000000"
    signature:
      policy: enforce

mcp:
  capabilities:
    tools:
      - name: accounts.lookup
        description: Fetch one account record from the accounts API.
        governance:
          minimum_trust: verified
        backend:
          kind: http
          url: "https://api.example.com/v1/accounts/${arguments.account_id}"
          method: get
          timeout_ms: 5000
          expected_status_codes: [200]

A non-digest OCI reference is resolved per platform: the gateway appends its own os/arch/libc suffix, so you write backend-http:1.0.0, never backend-http:1.0.0-linux-amd64.

Where the older reference disagrees with the code

Every key above was checked against apps/gateway/src/config/ and the generated config.schema.json, and all six documents validate against that schema. In four places the shipped prose is wrong and the code is authoritative.

default_signature_policy defaults to warn.
It defaults to enforce. The SignaturePolicy enum carries #[default] on Enforce and the generated schema emits "default": "enforce", so signature enforcement is on out of the box.
otlp and prometheus are built-in sink kinds.
BUILTIN_SINK_KINDS is stderr, stdout and file only. Both are plugin ids needing a plugins[] entry; a missing entry produces a warning and a silently unexported signal.
bind: on a metrics sink chooses a port.
Nothing reads bind. /metrics is served on the gateway’s main listener, not a separate port — only path is consumed.
config: { path: … } belongs to the Prometheus plugin.
It belongs to the sink. PrometheusSinkConfig is deny_unknown_fields over namespace and global_labels only, so copying path or bind into the plugin entry’s config refuses the plugin at load.

Showing 95 of 95 plugins.

Backends & Connectors

33 plugins
dev.mcpg.backend.amqpAMQP Binding
Backend
alpha
v0.1.0-alpha.17

Reaches a RabbitMQ / AMQP 0.9.1 broker as three per-binding operations: publish a message whose body is the tool’s arguments JSON, run request/reply RPC (publishing with reply_to plus a correlation id and awaiting the correlated reply on a private exclusive queue), or pull one message off a queue. Publisher confirms and the mandatory-routing flag turn an unroutable message into a tool error rather than a silent drop.

Use it to Let an agent enqueue a background job on RabbitMQ.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    # An identity source is what raises the gateway's reachable trust ceiling
    # to `verified`. Without one the tool below never reaches tools/list.
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.amqp
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-amqp:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: jobs.enqueue
        title: "Enqueue job"
        description: Enqueue a background job on the work queue.
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            task: { type: string }
            payload: { type: object }
          required: [task]
        backend:
          kind: amqp
          uri: "amqps://mcpg:${env.RABBIT_PASSWORD}@rabbit.internal:5671/%2f"
          op: publish
          routing_key: "jobs"
          content_type: application/json
          timeout_ms: 10000
dev.mcpg.backend.bigqueryBigQuery Binding
Backend
alpha
v0.1.0-alpha.17

Runs one operator-fixed Standard-SQL statement against Google BigQuery over the REST jobs.query API and returns rows as JSON typed by the result schema, authenticating with a GCP service-account key resolved from the gateway secret-resolver. Caller values never reach the SQL text — they bind as positional query parameters — and a read-only guard, a row cap and a maximum_bytes_billed cost cap bound the query, with query.dry_run turning the same binding into a no-charge bytes/USD cost estimator.

Use it to Expose a costed, read-only warehouse query to an agent.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    # Raises the reachable trust ceiling to `header_asserted`. Without it the
    # ceiling is `unauthenticated` and the tool below is filtered out.
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.bigquery
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-bigquery:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: analytics.daily_signups
        title: "Daily signups"
        description: Daily signup counts since a given date.
        annotations: { read_only: true, open_world: false }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            since: { type: string }
          required: [since]
        backend:
          kind: bigquery
          project_id: "acme-analytics"
          dataset: "analytics"
          location: "EU"
          auth:
            mode: service_account
            credentials_json: "${env.BIGQUERY_SA_KEY}"
          query:
            read_only: true
            max_rows: 1000
            maximum_bytes_billed: 1073741824   # 1 GiB cost cap
            timeout_ms: 60000
          statement: "SELECT day, count(*) AS signups FROM `acme-analytics.analytics.events` WHERE day >= ? GROUP BY day ORDER BY day"
          params: ["arguments.since"]
dev.mcpg.backend.clickhouseClickHouse Binding
Backend
alpha
v0.1.0-alpha.17

Runs an operator-fixed analytical statement against a ClickHouse server (OSS, Cloud, or Altinity) over its HTTP interface and returns JSONEachRow rows as JSON, with `?` placeholders filled from CEL expressions that the driver escapes and serialises as ClickHouse SQL literals rather than concatenating raw. A read-only keyword guard plus dispatch over HTTP GET — which ClickHouse itself treats as read-only at the server — fence the query, and operator-fixed query.settings (max_execution_time, max_threads, max_memory_usage) cap each call.

Use it to Query an event-analytics ClickHouse cluster from an agent.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.clickhouse
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-clickhouse:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: events.by_user
        title: "Recent user events"
        description: Recent events for a user.
        annotations: { read_only: true, open_world: false }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            user_id: { type: string }
          required: [user_id]
        backend:
          kind: clickhouse
          url: "https://ch.internal:8443"
          database: analytics
          auth:
            username: reader
            password: "${env.CLICKHOUSE_READER_PASSWORD}"
          statement: "SELECT event, ts FROM events WHERE user_id = ? ORDER BY ts DESC LIMIT 100"
          params: ["arguments.user_id"]
          query:
            read_only: true
            max_execution_time_ms: 30000
            max_result_rows: 10000
dev.mcpg.backend.commandCommand Binding
Backend
alpha
v0.1.0-alpha.17

Turns an existing local CLI, script, or batch job into an MCP surface by spawning the operator-configured process, writing the call arguments to its stdin as one JSON document, and capturing stdout and stderr under byte and wall-clock caps. The executable path is fixed in config and never derived from a request, only args[] entries are CEL-templated from caller values, and the substitution never re-enters a shell — but the child inherits the gateway’s uid and environment, so confine it with OS-level controls rather than with plugin capabilities.

Use it to Expose an internal CLI as a governed MCP tool.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.backend.command
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.command/plugin.so }

mcp:
  capabilities:
    tools:
      - name: docs.render
        title: "Render document"
        description: Render a document with the local renderer CLI.
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            id: { type: string }
          required: [id]
        backend:
          kind: command
          command: /usr/local/bin/render
          args: ["--format", "json", "--id", "${arguments.id}"]
          timeout_ms: 5000
          max_output_bytes: 65536
          require_json_stdout: true
dev.mcpg.backend.duckdbDuckDB Binding
Backend
alpha
v0.1.0-alpha.17

Runs operator-fixed analytical SQL against an embedded DuckDB engine — no server to run — over an in-memory or file database, local Parquet and CSV, and S3 or HTTP object stores when the httpfs extension is enabled. Caller values bind as `?` parameters rather than being interpolated, external filesystem and network access is default-deny until the operator opts in, and read_only opens file databases read-only on top of a read-only statement guard.

Use it to Query a Parquet data lake without standing up a warehouse.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.duckdb
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-duckdb:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: analytics.region_revenue
        title: "Region revenue"
        description: Quarterly revenue by region from the Parquet lake.
        annotations: { read_only: true, open_world: false }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            quarter: { type: string }
          required: [quarter]
        backend:
          kind: duckdb
          database: ":memory:"
          read_only: true
          allow_external_access: true
          init_sql:
            - "INSTALL httpfs; LOAD httpfs;"
            - "CREATE SECRET s3 (TYPE S3, KEY_ID '${env.AWS_LAKE_ACCESS_KEY_ID}', SECRET '${env.AWS_LAKE_SECRET_ACCESS_KEY}', REGION 'eu-west-1')"
          statement: "SELECT region, sum(amount) AS revenue FROM read_parquet('s3://acme-lake/sales/*.parquet') WHERE quarter = ? GROUP BY region"
          params: ["arguments.quarter"]
          query:
            statement_timeout_ms: 60000
            max_rows: 10000
dev.mcpg.backend.dynamodbDynamoDB Binding
Backend
alpha
v0.1.0-alpha.17

Exposes Amazon DynamoDB as MCP tools, one operator-fixed table plus one operation (get_item, put_item, delete_item, update_item, query, scan, batch_get, batch_write) per binding, over the modern aws-lc-rs/rustls AWS client using static keys or the default credential chain (IRSA, instance role, env, profile). The table is never caller-supplied, keys are validated against the declared key schema, CEL params bind expression placeholders server-side as ExpressionAttributeValues, and mutating operations are flagged as aws.mutates on the audit record.

Use it to Read and update an orders table from an agent.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.dynamodb
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-dynamodb:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      # No hand-written input_schema: the plugin derives one that marks
      # `key_condition_expression` required, and a hand-written `required`
      # array would REPLACE that wholesale and advertise a call shape that
      # errors on every invocation.
      - name: orders.by_customer
        title: "Orders by customer"
        description: >-
          Query a customer's orders by status. Call with
          key_condition_expression: "customer_id = :cid AND #s = :status".
        annotations: { read_only: true, open_world: false }
        governance:
          minimum_trust: verified
        backend:
          kind: dynamodb
          region: us-east-1
          table: orders
          operation: query
          partition_key: { name: customer_id, type: S }
          sort_key: { name: status, type: S }
          # Operator-fixed placeholders; bound server-side, never interpolated.
          params:
            ":cid": "arguments.customer_id"
            ":status": "arguments.status"
          limits:
            max_page_size: 100
            timeout_ms: 8000
dev.mcpg.backend.elasticsearchElasticsearch Binding
Backend
alpha
v0.1.0-alpha.17

Reaches an Elasticsearch or OpenSearch cluster over the REST API, one operation per binding — search, count, get, index, delete, bulk, msearch, or a vector knn nearest-neighbour search over a dense_vector field for RAG. The index arrives as an allowlisted, path-injection-guarded argument, write operations stay closed until allow_writes is set, scripting is default-deny, and API-key, basic, or bearer auth resolves per caller without ever appearing in logs or the response envelope.

Use it to Semantic and full-text search over an application log index.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.elasticsearch
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-elasticsearch:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: logs.search
        title: "Search logs"
        description: Full-text search over the application logs.
        annotations: { read_only: true, open_world: false }
        governance:
          minimum_trust: header_asserted
        backend:
          kind: elasticsearch
          urls: ["https://es.internal:9200"]
          operation: search
          index_allowlist: ["logs-*"]
          default_index: logs-app
          max_size: 200
          operation_timeout_ms: 30000
          auth:
            kind: api_key
            api_key: "${env.ES_API_KEY}"

      - name: logs.index_event
        title: "Index log event"
        description: Index a structured log document.
        governance:
          minimum_trust: verified
        backend:
          kind: elasticsearch
          urls: ["https://es.internal:9200"]
          operation: index
          index_allowlist: ["logs-app"]
          default_index: logs-app
          allow_writes: true
          auth:
            kind: basic
            username: ingest
            password: "${env.ES_INGEST_PASSWORD}"
dev.mcpg.backend.emailEmail Binding
Backend
alpha
v0.1.0-alpha.17

Sends mail through an SMTP server and reads a mailbox over IMAP, one operation per binding: op: send builds a message from the call’s to / subject / body arguments and delivers it, op: read fetches the most recent messages as envelope plus text body using BODY.PEEK so it never marks anything as seen. TLS is rustls (STARTTLS or implicit) and the login password resolves through the gateway secret-resolver rather than living in config.

Use it to Send alert mail and triage a shared support inbox.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.email
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-email:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: alerts.notify
        title: "Send alert email"
        description: Send an alert email.
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            to: { type: string }
            subject: { type: string }
            body: { type: string }
          required: [to, subject, body]
        backend:
          kind: email
          op: send
          host: "smtp.corp.example.com"
          port: 587
          tls: starttls
          username: "svc-mcpg"
          password: "${env.SMTP_PASSWORD}"
          from: "alerts@corp.example.com"
          timeout_ms: 15000

      - name: inbox.recent
        title: "Recent inbox mail"
        description: Read the most recent messages from the shared inbox.
        annotations: { read_only: true }
        governance:
          minimum_trust: verified
        backend:
          kind: email
          op: read
          host: "imap.corp.example.com"
          port: 993
          tls: implicit
          username: "shared-inbox@corp.example.com"
          password: "${env.IMAP_PASSWORD}"
          mailbox: INBOX
          limit: 20
dev.mcpg.backend.ftpFTP Binding
Backend
alpha
v0.1.0-alpha.17

Lists a directory, reads a file, or writes a file on an FTP / FTPS server — the classic partner drop-directory integration — as tools or as MCP resources, with explicit FTPS (AUTH TLS) required by default over a pure-Rust rustls stack. The caller’s path is joined under an operator-configured base directory and any `..` segment is rejected before a single FTP command is sent, with a byte cap on every read and write.

Use it to Pick up partner CSV drops from an FTPS directory.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.ftp
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-ftp:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: dropbox.read
        title: "Read partner file"
        description: Read a file from the partner drop directory.
        annotations: { read_only: true }
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            path: { type: string }
          required: [path]
        backend:
          kind: ftp
          op: get
          host: "ftp.partner.example.com"
          port: 21
          user: "svc-mcpg"
          password: "${env.FTP_PASSWORD}"
          tls: true                 # require FTPS (default)
          path: "/outbound"
          max_bytes: 10485760
          timeout_ms: 15000
dev.mcpg.backend.graphqlGraphQL Binding
Backend
alpha
v0.1.0-alpha.17

Fronts a GraphQL endpoint by POSTing a standard { query, variables } document: the operator pins one query or mutation at config time and the caller’s arguments become the variables, so a client gets one governed operation instead of an open GraphQL endpoint. A 200 response carrying a non-empty errors array is surfaced as a tool error, and a DNS-rebinding guard pins the validated address for the life of the cached client.

Use it to Expose one catalog GraphQL query as a governed tool.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.backend.graphql
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.graphql/plugin.so }
    granted_capabilities:
      - network_outbound

mcp:
  capabilities:
    tools:
      - name: catalog.list_products
        title: "List products"
        description: List products from the catalog service.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            limit: { type: integer }
        backend:
          kind: graphql
          url: "https://catalog.internal/graphql"
          operation: "query($limit: Int) { products(limit: $limit) { id name } }"
          timeout_ms: 2000
          max_response_bytes: 65536
          headers:
            authorization: "Bearer ${env.CATALOG_API_TOKEN}"
dev.mcpg.backend.grpcgRPC Binding
Backend
Enterprise
alpha
v0.1.0-alpha.17

Calls one RPC method on a gRPC service through its JSON transcoding surface (grpc-gateway, the Envoy gRPC-JSON filter, Connect, or equivalent), POSTing the caller’s arguments to {origin}/{service}/{method}. The URL, service, and method are transport-only routing facts and a credential reference in any of them is rejected at registration; credentials belong in header values, behind the same DNS-rebinding guard and per-credential client cache as the HTTP binding.

Use it to Expose one internal gRPC method as an MCP tool.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.backend.grpc
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.grpc/plugin.so }
    granted_capabilities:
      - network_outbound

mcp:
  capabilities:
    tools:
      - name: users.get
        title: "Get user"
        description: Look up a user record.
        annotations: { read_only: true }
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            id: { type: string }
          required: [id]
        backend:
          kind: grpc
          url: "https://users.internal:8443"
          service: user.v1.UserService
          method: GetUser
          timeout_ms: 2000
          max_response_bytes: 65536
          headers:
            authorization: "Bearer ${env.USERS_API_TOKEN}"
dev.mcpg.backend.hanaSAP HANA Binding
Backend
alpha
v0.1.0-alpha.17

Runs an operator-fixed statement against a SAP HANA database over its native HDB SQL protocol using the pure-Rust hdbconnect_async driver with rustls TLS and a lazy bb8 pool that opens no socket until the first call. Caller values bind as server-side prepared-statement parameters rather than being interpolated, a read-only keyword guard fences the statement, and list_tables / list_columns operations let an agent discover the schema from SYS.TABLES and SYS.TABLE_COLUMNS without writing SQL.

Use it to Read SAP business data from HANA inside an agent workflow.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.hana
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-hana:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: sap.order_lookup
        title: "Look up SAP order"
        description: Look up a sales order in SAP HANA by id.
        annotations: { read_only: true, open_world: false }
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            order_id: { type: string }
          required: [order_id]
        backend:
          kind: hana
          host: "hana.corp.example.com"
          port: 39015
          user: "MCPG_READER"
          password: "${env.HANA_READER_PASSWORD}"
          database: "HXE"
          use_tls: true
          tls_verify_peer: true
          operation: query
          read_only: true
          query: "SELECT ORDER_ID, CUSTOMER, TOTAL FROM SALES.ORDERS WHERE ORDER_ID = ?"
          params: ["arguments.order_id"]
          pool_max_size: 6
          timeout_ms: 5000
          max_rows: 1000
dev.mcpg.backend.httpHTTP Binding
Backend
alpha
v0.1.0-alpha.17

The general-purpose binding for any REST/JSON API: a POST binding sends the caller’s arguments as a JSON body, a GET binding renders them into a deterministic sorted query string, and the response is checked against expected_status_codes and optional JSON parseability. The URL and every header value are CEL templates that resolve `${cred://issuer/target}` per caller identity at dispatch time, with one cached client per resolved-credential bundle, a DNS-rebinding guard that pins the validated address, and streaming progress chunks when the upstream streams.

Use it to Front any existing internal REST API as a governed tool.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities:
      - network_outbound

  # A `cred://` reference resolves per request against a registered
  # credential_issuer. Naming an issuer that no plugins[] entry declares
  # fails EVERY call with "unknown credential_issuer plugin".
  - id: dev.mcpg.credential.static
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-static:protocol-1" }
    config:
      targets:
        orders-api:
          value: "${env.ORDERS_API_TOKEN}"
          ttl_seconds: 3600

mcp:
  capabilities:
    tools:
      - name: orders.fetch
        title: "Fetch order"
        description: Fetch an order by id.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            id: { type: string }
          required: [id]
        backend:
          kind: http
          url: "https://orders.internal/v1/orders/${arguments.id}"
          method: get
          timeout_ms: 2000
          max_response_bytes: 65536
          expected_status_codes: [200]
          require_json_response: true
          headers:
            authorization: "Bearer ${cred://dev.mcpg.credential.static/orders-api}"
dev.mcpg.backend.kafkaKafka Binding
Backend
Enterprise
alpha
v0.1.0-alpha.18

Turns a Kafka consumer group into a synchronous MCP tool: the call payload is produced to a request topic with a unique correlation_id header and the first reply on the response topic carrying that id is returned, with non-matching messages skipped rather than consumed. It forwards W3C trace context and idempotency headers as record headers, resolves SASL credentials (PLAIN, SCRAM-SHA-256/512, OAUTHBEARER — enough for Confluent Cloud and AWS MSK), and ships a second entity that turns any message on a topic into a resource-change notification.

Use it to Call an event-driven worker as if it were an API.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.kafka
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-kafka:protocol-1" }
    granted_capabilities:
      - network_outbound
    config:
      bootstrap_servers: "kafka-1:9092,kafka-2:9092"
      group_id: mcpg

mcp:
  capabilities:
    tools:
      - name: events.enrich
        title: "Enrich event"
        description: Enrich an event through the enrichment worker.
        governance:
          minimum_trust: verified
        backend:
          kind: kafka
          request_topic: enrich.requests
          response_topic: enrich.responses
          timeout_ms: 10000
          max_response_bytes: 65536
          security_protocol: SASL_SSL
          sasl_mechanism: SCRAM-SHA-256
          sasl_username: "${env.KAFKA_USERNAME}"
          sasl_password: "${env.KAFKA_PASSWORD}"
dev.mcpg.backend.ldapLDAP Binding
Backend
Enterprise
alpha
v0.1.0-alpha.17

Binds a service account against LDAP or Active Directory over LDAP/LDAPS and runs directory searches — people, groups, org structure — returning the matched entries as JSON. The search filter is CEL-templated from the tool arguments with every interpolated string RFC 4515 LDAP-escaped, so a caller cannot break out of the filter.

Use it to Let an agent look up staff and group membership in AD.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.ldap
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-ldap:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: directory.search_people
        title: "Search directory"
        description: Find people in the corporate directory.
        annotations: { read_only: true }
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            q: { type: string }
          required: [q]
        backend:
          kind: ldap
          url: "ldaps://dc1.corp.example.com:636"
          bind_dn: "cn=svc-mcpg,ou=svc,dc=corp,dc=example,dc=com"
          bind_password: "${env.LDAP_SVC_PASSWORD}"
          base_dn: "ou=people,dc=corp,dc=example,dc=com"
          scope: subtree
          filter: "(&(objectClass=person)(|(cn=*${arguments.q}*)(mail=*${arguments.q}*)))"
          attributes: [cn, mail, department, manager, memberOf]
          size_limit: 100
          timeout_ms: 10000
dev.mcpg.backend.llm.anthropicAnthropic Messages API Backend
Backend
alpha
v0.1.0-alpha.17

Puts the Anthropic Messages API behind a governed MCP tool (backend.kind: anthropic_chat) instead of handing an API key to every client: a binding pins one model, one system/user prompt template pair rendered over the caller’s arguments, and one execution policy, returning free-form text or JSON validated against the binding’s output_schema via the forced-tool pattern. It runs a bounded agentic loop over an explicit allowlist of other tools in the same gateway, streams tokens over SSE, and enforces per-binding token and daily-USD budget caps before spending.

Use it to Offer Claude to internal clients under a spend cap.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.llm.anthropic
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-llm-anthropic:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: incident.summarize
        title: "Summarise incident"
        description: Summarise an incident report into a structured verdict.
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            report: { type: string }
          required: [report]
        backend:
          kind: anthropic_chat
          api_key: "${env.ANTHROPIC_API_KEY}"
          model: claude-sonnet-4-5
          prompt:
            system: You are a terse incident analyst. Answer only as JSON.
            user: "Summarise this report:\n{{ input.report }}"
          sampling:
            temperature: 0
            max_completion_tokens: 1024
          response_format:
            mode: json_schema
            on_mismatch: retry_once
          budget:
            usd_daily_cap: 25
          output_schema:
            type: object
            properties:
              severity: { type: string }
              summary:  { type: string }
            required: [severity, summary]
dev.mcpg.backend.llm.compatOpenAI-Compatible Backends
Backend
alpha
v0.1.0-alpha.17

Reaches any endpoint that speaks the OpenAI /chat/completions and /embeddings wire format but is not OpenAI — vLLM, LocalAI, Together, Groq, OpenRouter, llama.cpp’s OpenAI server, or Vertex AI’s OpenAI compatibility surface — through two backend kinds, compat_chat and compat_embedding. The operator supplies base_url and the API key is optional, so unauthenticated self-hosted servers work unmodified, and structured output is validated binding-side so an endpoint with weak native JSON-schema support still gets a hard contract.

Use it to Govern a self-hosted vLLM deployment like a hosted provider.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.llm.compat
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-llm-compat:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: local.chat
        title: "Local model chat"
        description: Chat with the in-cluster vLLM deployment.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            question: { type: string }
          required: [question]
        backend:
          kind: compat_chat
          base_url: "http://vllm.internal.svc:8000/v1"   # required
          # api_key omitted — this vLLM endpoint accepts unauthenticated requests
          model: meta-llama/Llama-3.1-8B-Instruct
          prompt:
            system: You are a concise assistant.
            user: "{{ input.question }}"
          response_format:
            mode: text
          sampling:
            temperature: 0.2
            max_completion_tokens: 1024

      - name: local.embed
        title: "Embed passages"
        description: Embed passages against the local inference server.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        backend:
          kind: compat_embedding
          base_url: "http://vllm.internal.svc:8000/v1"
          model: BAAI/bge-large-en-v1.5
          max_batch_size: 64
          cache: { enabled: true }
dev.mcpg.backend.llm.geminiGoogle Gemini Backends
Backend
alpha
v0.1.0-alpha.17

Reaches Google’s AI Studio API — Gemini chat, embeddings and Imagen image generation — as three backend kinds in one artifact, so the API key stays in the gateway instead of being distributed to every client. Prompts are templates over the caller’s arguments, replies are re-validated against a JSON schema, and per-binding token and daily-USD caps stop a runaway loop before it spends.

Use it to Give agents Gemini access without handing every client an API key.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.llm.gemini
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-llm-gemini:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: page.extract
        description: Extract structured order details from a screenshot.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            shot: { type: string, description: "image URL or mcpg-resource:// URI" }
          required: [shot]
        backend:
          kind: gemini_chat
          api_key: "${env.GEMINI_API_KEY}"
          model: gemini-2.0-flash
          prompt:
            system: You read screenshots and answer only as JSON.
            user: Extract the visible order details.
            image_inputs: [shot]
          sampling: { temperature: 0 }
          response_format: { mode: json_schema }
          output_schema:
            type: object
            properties:
              order_id: { type: string }
              total: { type: string }
            required: [order_id]
          budget: { usd_daily_cap: 25 }
dev.mcpg.backend.llm.openaiOpenAI + Azure OpenAI Backends
Backend
alpha
v0.1.0-alpha.17

Reaches OpenAI and Azure OpenAI as ten backend kinds in one artifact — chat, embeddings, image, text-to-speech and speech-to-text, each in a public-API and an Azure-deployment flavour. A chat binding can run a bounded tool loop over other bindings in the same gateway, refusing any tool the model invents outside the configured allowlist before the call leaves the plugin.

Use it to Route GPT calls through the gateway with per-binding spend caps.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.llm.openai
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-llm-openai:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: ticket.classify
        description: Classify a support ticket into a category and urgency.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            body: { type: string }
          required: [body]
        backend:
          kind: openai_chat            # or azure_openai_chat with a full base_url
          api_key: "${env.OPENAI_API_KEY}"
          model: gpt-4o-mini
          prompt:
            system: You classify support tickets. Answer only as JSON.
            user: "{{ input.body }}"
          sampling: { temperature: 0 }
          response_format: { mode: json_schema }
          output_schema:
            type: object
            properties:
              category: { type: string }
              urgency: { type: string }
            required: [category, urgency]
          budget: { usd_daily_cap: 50 }

      - name: docs.embed
        description: Embed one or more passages.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: openai_embedding
          api_key: "${env.OPENAI_API_KEY}"
          model: text-embedding-3-small
          dimensions: 512
          cache: { enabled: true }
dev.mcpg.backend.llm.stabilityStability AI Image Generation Backend
Backend
alpha
v0.1.0-alpha.17

Reaches Stability AI’s Stable Image API — the Core, SD3 and Ultra SKUs, selected through the binding’s model field — and pushes the generated bytes into the gateway content store, returning an mcpg-resource:// URI the client fetches through an ordinary MCP resource read. A content-filtered response surfaces as a clear error rather than an empty success, and a per-call timeout plus a retry policy — not a spend cap — bound the binding.

Use it to Let an agent generate product images without handing out a Stability API key.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.llm.stability
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-llm-stability:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: art.generate
        description: Generate an illustration from a prompt.
        annotations: { read_only: false, open_world: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            prompt: { type: string }
            size: { type: string, description: "WxH pixels or a W:H ratio" }
          required: [prompt]
        backend:
          kind: stability_image
          api_key: "${env.STABILITY_API_KEY}"
          model: core                 # core | sd3 | ultra
          timeout_ms: 60000
          defaults:
            size: "1024x1024"
            output_format: webp
            negative_prompt: "blurry, low quality"
dev.mcpg.backend.markdownMarkdown Conversion
Backend
alpha
v0.1.0-alpha.3

Converts documents — DOCX, PPTX, XLSX, PDF, HTML, EPUB, Outlook .msg, ZIP archives, images, audio, CSV, JSON, XML, feeds and Jupyter notebooks — into LLM-friendly Markdown, shipping both an MCP tool the model can call and a transform entity that converts a document already in flight through a pipeline. It never reads the local filesystem and declares no filesystem capability: bytes arrive inline, from the gateway content store, or over HTTPS only when the operator opts in.

Use it to Turn a customer’s uploaded DOCX or PDF into agent-readable text.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.markdown
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-markdown:protocol-1" }
    # Declared because the opt-in `sources.url` mode can open a socket; the
    # grant is fail-closed, so the entry must carry it either way.
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: convert_to_markdown
        description: Convert a document (DOCX, PDF, XLSX, EPUB, .msg, ...) to Markdown.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: markdown
          limits:
            # Byte ceilings are plain integers — there is no human-size parser,
            # and a "20Mi" string fails registration. Omitted keys take the
            # engine defaults (20 MiB in, 4 MiB out, 200 MiB expanded).
            max_depth: 3
            max_embedded_documents: 64
            max_table_rows: 5000
            timeout_ms: 30000
          output:
            front_matter: yaml            # none | yaml | toml
            tables: gfm                   # gfm | html | csv
          formats:
            enable: [text, csv, json, ipynb, xml, feed, html,
                     docx, pptx, spreadsheet, epub, zip, pdf,
                     image, audio, msg]
          sources:
            inline: true                  # `content` (base64) or `text` argument
            resource: true                # mcpg-resource:// from the content store
            url: false                    # https:// fetch stays off unless opted in
dev.mcpg.backend.mockMock Binding
Backend
alpha
v0.1.0-alpha.17

Answers a tool, prompt or resource call with a response the operator wrote in config — no network, no filesystem, no subprocess — with optional simulated latency, a simulated error mode, and a passthrough mode that emits a literal CallToolResult so a binding can return image, audio or embedded-resource content. Use it to stand up a tool contract before the real system exists and to keep contract tests and offline demos deterministic.

Use it to Ship a tool contract before the backing service exists.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.backend.mock
    class: backend
    kind: native
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.mock/plugin.so }
    # No granted_capabilities: the plugin declares no required capabilities.

mcp:
  capabilities:
    tools:
      - name: dev.echo
        description: Returns a fixed fixture response for local development.
        input_schema:
          type: object
          properties:
            query: { type: string }
        backend:
          kind: mock
          response: { status: ok, items: [{ id: item-1, label: First item }] }
          delay_ms: 0
          error: false
          passthrough: false
        governance:
          minimum_trust: unauthenticated

      - name: dev.error_scenario
        description: Simulates an upstream failure so error handling can be tested.
        backend:
          kind: mock
          response: null
          error: true
          error_message: "simulated upstream timeout"
        governance:
          minimum_trust: unauthenticated
dev.mcpg.backend.mssqlMSSQL Binding
Backend
Enterprise
alpha
v0.1.0-alpha.17

Dispatches tool calls to Microsoft SQL Server over TDS on a pooled, rustls-encrypted connection, binding @P1, @P2, … placeholders from an ordered list of CEL expressions evaluated against the tool arguments. The statement text is operator-fixed and values cross the wire as TDS parameters, so caller input cannot alter the query; op: query returns rows and op: execute returns rows-affected.

Use it to Expose an on-prem SQL Server HR table as a read-only tool.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.mssql
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-mssql:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: directory.find_employee
        description: Look up an employee by id.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { id: { type: integer } }
          required: [id]
        backend:
          kind: mssql
          host: "sql1.corp.example.com"
          port: 1433
          database: "HR"
          user: "svc_mcpg"
          password: "${env.MSSQL_HR_PASSWORD}"
          encryption: required
          trust_server_certificate: true
          op: query
          query: "SELECT id, full_name, email FROM dbo.employees WHERE id = @P1"
          params: ["arguments.id"]       # bound to @P1 as a TDS parameter
          size_limit: 100
          pool_max_size: 8
          timeout_ms: 10000
dev.mcpg.backend.natsNATS Binding
Backend
alpha
v0.1.0-alpha.18

Dispatches tool calls as NATS request/reply on an operator-fixed subject and turns the reply into the tool result, so a service that already answers on NATS needs no HTTP front end. Inbound trace headers propagate to the responder, oversized replies are truncated and flagged, and the same artifact ships a nats_topic watch strategy that turns messages on a subject into resources/updated notifications.

Use it to Front an existing NATS request/reply worker as an MCP tool.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.nats
    class: backend
    kind: native
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-nats:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: pricing.quote
        description: Request a price quote from the pricing worker over NATS.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { sku: { type: string } }
          required: [sku]
        backend:
          kind: nats
          url: "nats://nats.internal:4222"
          subject: pricing.quote
          timeout_ms: 2000
          max_response_bytes: 65536
          # credentials_path: /etc/mcpg/nats.creds

    resources:
      # The same artifact ships the `nats_topic` watch strategy, so a resource
      # can be invalidated by a message on a subject.
      - name: catalog.snapshot
        description: The product catalog.
        uri: "catalog://snapshot"
        governance:
          minimum_trust: header_asserted
        backend: { kind: nats, url: "nats://nats.internal:4222", subject: catalog.read }
        watch:
          strategy:
            type: nats_topic
            subject: catalog.changed
dev.mcpg.backend.odbcODBC Binding
Backend
alpha
v0.1.0-alpha.16

Reaches any database with an installed unixODBC driver — Teradata, Sybase, Informix, IBM Db2, Vertica, SAP HANA and the rest of the long tail — running an operator-fixed statement whose ? placeholders are bound server-side via SQLBindParameter, behind a read-only keyword guard. Two catalog operations (SQLTables and SQLColumns) let an agent discover tables and columns without writing SQL, with every filter passed as an argument rather than interpolated.

Use it to Reach a Teradata or Db2 warehouse that has no native driver.

Licence
Apache-2.0 (plugin source). The artifact bundles LGPL unixODBC C sources; redistribution terms for the bundled driver are not yet decided, and the crate is deliberately held back from the public mirror.
Capabilities
network_outbound
Source
not mirrored publicly
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.odbc
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-odbc:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: orders.by_customer
        description: Recent orders for a customer, from the Teradata warehouse.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { customer_id: { type: integer } }
          required: [customer_id]
        backend:
          kind: odbc
          connection_string: "Driver={Teradata};DBCName=tdprod;UID=svc;PWD=${env.TERADATA_PASSWORD}"
          driver_label: teradata
          query: "SELECT order_id, total FROM orders WHERE customer_id = ? ORDER BY order_id"
          params: ["arguments.customer_id"]   # bound via SQLBindParameter
          read_only: true
          max_rows: 500
          timeout_ms: 15000

      # Schema discovery without writing SQL: the filters are passed as
      # arguments to the SQLTables catalog function, never interpolated.
      - name: db.list_tables
        description: List the tables an agent may query.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        backend:
          kind: odbc
          connection_string: "Driver={Teradata};DBCName=tdprod;UID=svc;PWD=${env.TERADATA_PASSWORD}"
          driver_label: teradata
          operation: list_tables
          schema_arg: schema
          table_type: "TABLE,VIEW"
dev.mcpg.backend.openapiOpenAPI Binding
Backend
alpha
v0.1.0-alpha.17

Turns an OpenAPI 3.0/3.1 document into MCP tools: you register the spec once as a named source on the plugin entry, and each operation becomes a tool whose input and output schemas are derived from its parameters, request body and responses — nobody hand-writes a schema or a URL. Calls dispatch as outbound HTTP behind the DNS-rebinding guard with credentials injected exactly as the spec’s securitySchemes describe, and a whole spec can be bulk-exposed under a configurable capability ceiling.

Use it to Publish an existing REST API as tools without hand-writing schemas.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.backend.openapi
    class: backend
    kind: native
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.openapi/plugin.so }
    granted_capabilities: [network_outbound]
    # Unusually for a backend, the spec registry lives on the PLUGIN entry;
    # a binding then names only the source and the operation.
    config:
      sources:
        - name: petstore
          spec: "file:///etc/mcpg/specs/petstore.yaml"
          base_url: https://api.petstore.example.com
          headers:
            User-Agent: mcpg-gateway
          auth:
            # Key is the securityScheme name declared in the spec.
            api_key: "${cred://dev.mcpg.credential.static/petstore}"
          response:
            max_response_bytes: 1048576
            timeout_ms: 8000

  # The issuer the auth block above names. Without this entry every call
  # fails with "unknown credential_issuer plugin".
  - id: dev.mcpg.credential.static
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-static:protocol-1" }
    config:
      targets:
        petstore:
          value: "${env.PETSTORE_API_KEY}"
          ttl_seconds: 3600

mcp:
  capabilities:
    tools:
      # inputSchema / outputSchema are derived from the operation — no
      # hand-written schema, no hand-written URL.
      - name: petstore.adopt
        description: Adopt a pet.
        governance:
          minimum_trust: header_asserted
        backend: { kind: openapi, source: petstore, operation: adoptPet }
dev.mcpg.backend.oracleOracle Binding
Backend
Enterprise
alpha
v0.1.0-alpha.17

Dispatches tool calls to Oracle Database through rust-oracle/ODPI-C on a pooled connection, binding :1, :2, … placeholders from CEL expressions over the tool arguments so an operator-fixed SQL or PL/SQL statement cannot be altered by the caller. It also introspects the data dictionary (ALL_TABLES / ALL_TAB_COLUMNS, needing no DBA privilege) so an agent can discover a schema, and polls a scalar high-water query to drive resource-change notifications.

Use it to Query an Oracle ERP schema from an agent, injection-safe.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.oracle
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-oracle:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: directory.find_employee
        description: Look up an employee by id.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { id: { type: integer } }
          required: [id]
        backend:
          kind: oracle
          dsn: "//ora1.corp.example.com:1521/HRPDB1"
          username: "svc_mcpg"
          password: "${env.ORACLE_HR_PASSWORD}"
          op: query
          query: "SELECT id, full_name, email FROM employees WHERE id = :1"
          params: ["arguments.id"]        # bound to :1 as an Oracle bind variable

      # Data-dictionary discovery through ALL_TAB_COLUMNS — no DBA_* grant.
      - name: directory.list_columns
        description: List the columns of a table in the HR schema.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        backend:
          kind: oracle
          dsn: "//ora1.corp.example.com:1521/HRPDB1"
          username: "svc_mcpg"
          password: "${env.ORACLE_HR_PASSWORD}"
          operation: list_columns
          owner: "HR"                     # bound as :owner
          table_arg: "table"              # arguments.table bound as :tbl
dev.mcpg.backend.sftpSFTP Binding
Backend
alpha
v0.1.0-alpha.17

Lists a directory, reads a file, or writes a file over SSH file transfer using pure-Rust russh crypto (no OpenSSL), exposed either as list/get/put tools or as a files-as-resources surface where resources/list enumerates a directory and resources/read fetches a file. Caller paths join under an operator-configured root with `..` rejected before any SSH call, and host-key verification fails closed unless a SHA-256 fingerprint is pinned or unknown keys are explicitly accepted.

Use it to Read partner drop files from an SFTP server as a tool.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.sftp
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-sftp:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: dropbox.read
        description: Read a file from the partner drop directory.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { path: { type: string } }
          required: [path]
        backend:
          kind: sftp
          op: get                              # list | get | put
          host: "sftp.partner.example.com"
          port: 22
          username: "svc-mcpg"
          password: "${env.SFTP_PASSWORD}"
          host_key_sha256: "SHA256:2xUBM/..."  # host-key check fails closed
          root: "/outbound"                    # caller paths join under this; `..` rejected
          max_bytes: 10485760
          timeout_ms: 15000
dev.mcpg.backend.smbSMB Binding
Backend
alpha
v0.1.0-alpha.17

Lists a directory, reads a file, or writes a file on an SMB/CIFS share through the system libsmbclient, exposed either as list/get/put tools or as a files-as-resources surface with one MCP resource per file under the configured path. Caller paths join under an operator-configured base with `..` rejected, and a polling watcher fingerprints the directory listing so an added, removed, resized or re-touched file fires resources/updated.

Use it to Give an agent scoped read access to a corporate file share.

Licence
Apache-2.0 (plugin source). The artifact links copyleft libsmbclient C sources; redistribution terms for the bundled driver are not yet decided, and the crate is deliberately held back from the public mirror.
Capabilities
network_outbound
Source
not mirrored publicly
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.smb
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-smb:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: fileshare.read
        description: Read a file from the corporate SMB share.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { path: { type: string } }
          required: [path]
        backend:
          kind: smb
          op: get                       # list | get | put
          host: "fileserver.corp"
          share: "shared"
          user: "svc-mcpg"
          password: "${env.SMB_PASSWORD}"
          domain: "CORP"
          path: "/outbound"             # caller paths join under this; `..` rejected
dev.mcpg.backend.snowflakeSnowflake Binding
Backend
alpha
v0.1.0-alpha.17

Runs an operator-fixed analytical statement against a Snowflake warehouse over the REST API, decoding Arrow result sets into JSON rows, with key-pair JWT or password auth resolved at config load. A read-only keyword guard and a max_rows cap bound every statement, caller arguments are never templated into the SQL, and a result_scan operation re-fetches a prior query’s result set by its Snowflake query id for pagination.

Use it to Answer analytics questions from a Snowflake warehouse, read-only and row-capped.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.snowflake
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-snowflake:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: analytics.daily_signups
        description: Daily signup counts for the last 30 days.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        input_schema: { type: object, properties: {} }
        backend:
          kind: snowflake
          account: "xy12345.eu-central-1"
          warehouse: "ANALYTICS_WH"
          database: "PROD"
          schema: "PUBLIC"
          role: "REPORTER"
          auth:
            mode: key_pair              # key_pair | password
            username: "svc_mcpg"
            private_key_pem: "${env.SNOWFLAKE_PRIVATE_KEY}"
          query:
            read_only: true             # rejects anything but SELECT/WITH/SHOW/DESCRIBE/EXPLAIN
            max_rows: 1000
          statement: >
            SELECT day, count(*) AS signups
            FROM events WHERE day >= dateadd(day, -30, current_date())
            GROUP BY day ORDER BY day
dev.mcpg.backend.soapSOAP Binding
Backend
Enterprise
alpha
v0.1.0-alpha.17

Dispatches tool calls as SOAP 1.1/1.2 envelopes over outbound HTTP, so a legacy WSDL service becomes an MCP tool with no bridge service in between. Tool arguments are CEL-interpolated and XML-escaped into an operator-supplied body template before the envelope is POSTed, and a <soap:Fault> is parsed into a structured application error with retry guidance rather than surfaced as an opaque HTTP 500.

Use it to Wrap a legacy WSDL service as an MCP tool.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.soap
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-soap:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: GetWeather
        description: Current weather for a city via the legacy SOAP service.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties: { city: { type: string } }
          required: [city]
        backend:
          kind: soap
          endpoint: https://weather.example.com/ws/WeatherService
          soap_version: "1.1"
          soap_action: "http://weather.example.com/GetWeather"
          body_template: |
            <wsx:GetWeather xmlns:wsx="http://weather.example.com/">
              <City>${arguments.city}</City>
            </wsx:GetWeather>
          headers:
            Authorization: "Bearer ${env.WEATHER_API_TOKEN}"
dev.mcpg.backend.sqlSQL Binding
Backend
alpha
v0.1.0-alpha.17

Dispatches tool calls to PostgreSQL, MySQL/MariaDB or SQLite over a pooled connection, with named placeholders always bound as parameters and seven row modes including a keyset-paged stream envelope whose cursor is HMAC-SHA-256 signed and bound to its binding name. The same artifact ships interval-polling and LISTEN/NOTIFY watch strategies for resource-change notifications.

Use it to Query a tenant-scoped Postgres table with a server-side row cap.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.backend.sql
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-sql:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: orders.lookup_by_tenant
        title: Lookup Orders by Tenant
        description: Return recent orders for a tenant.
        annotations: { read_only: true }
        governance:
          minimum_trust: header_asserted
        backend:
          kind: sql
          driver: postgres                 # postgres | mysql | mariadb | sqlite
          url: "postgres://app:${env.ORDERS_DB_PW}@db:5432/orders"
          pool: { max_connections: 10, min_idle: 1 }
          query:
            sql: "SELECT id, total, placed_at FROM orders WHERE tenant_id = :tenant ORDER BY placed_at DESC LIMIT :effective_limit"
            params: ["tenant", "effective_limit"]
            param_exprs:
              # Server-side cap: param_exprs override caller values of the same
              # name, so the ceiling is not spoofable by the client.
              effective_limit: "arguments.limit < 200 ? arguments.limit : 200"
            row_mode: many                 # single | many | scalar | affected_rows | resource_contents | stream | result_sets
            timeout_ms: 3000
          schema: { derive: input }
dev.mcpg.backend.twilioTwilio SMS + Voice Binding
Backend
alpha
v0.1.0-alpha.18

Proxies the Twilio REST API for SMS and MMS, voice calls, recordings, number lookup and Verify OTP as operation-discriminated MCP tools, and mounts an HTTP route that receives Twilio’s inbound SMS, voice, gather and status webhooks — validating X-Twilio-Signature with a constant-time HMAC before any side effect — and answers with TwiML. Inbound events push resources/updated to subscribed MCP clients in-process, with no webhook round-trip.

Use it to Let an agent send SMS and answer inbound calls.

Licence
Apache-2.0
Capabilities
network_outbound, http_route_serve
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.backend.twilio
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-twilio:protocol-1" }
    # The grant is fail-closed and must cover every capability the descriptor
    # requires — the http_route entity below opens a listener.
    granted_capabilities: [network_outbound, http_route_serve]
    # This `config:` block belongs to the http_route entity that receives
    # Twilio's inbound webhooks. It is resolved at CONFIG LOAD, where only
    # `${env.X}` and bound secret-provider URIs expand — a `cred://` ref
    # would arrive as a literal string and break every signature check.
    config:
      account_sid: "${env.TWILIO_ACCOUNT_SID}"
      # Webhook signatures are ALWAYS keyed by the Account Auth Token.
      auth_token: "${env.TWILIO_AUTH_TOKEN}"
      public_base_url: "https://mcpg.example.com"
      validate_signature: true
      max_body_bytes: 65536
      inbound_sms:
        auto_reply: "Thanks - an agent will follow up shortly."

mcp:
  capabilities:
    tools:
      - name: twilio.send_sms
        title: "Send SMS"
        description: "Send an SMS (or MMS via media_url) from the configured number."
        annotations: { read_only: false, idempotent: false }
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          required: [to, body]
          properties:
            to: { type: string, description: "E.164 destination, e.g. +14155551212" }
            body: { type: string }
            media_url: { type: array, items: { type: string } }
          additionalProperties: false
        backend:
          kind: twilio
          operation: send_sms
          account_sid: "${env.TWILIO_ACCOUNT_SID}"
          # Prefer a scoped, revocable API Key over the root Auth Token.
          api_key_sid: "${env.TWILIO_API_KEY_SID}"
          api_key_secret: "${env.TWILIO_API_KEY_SECRET}"
          from: "+14155550100"

Cache

2 plugins
dev.mcpg.cache.memoryIn-Memory Cache
Cache
alpha
v0.1.0-alpha.17

Keeps cache namespaces inside the gateway process as a bounded moka LRU with a per-entry TTL and atomic per-key counters, so response caches, JWKS documents and rate-limit counters work on a single instance with no external service. Every operation is local CPU — no socket, no capability grant, and nothing that can fail transiently.

Use it to Single-instance gateway caching without operating a Redis.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.cache.memory
    class: cache
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/cache-memory:protocol-1"
    config:
      max_capacity: 50000
dev.mcpg.cache.redisRedis Cache
Cache
alpha
v0.1.0-alpha.17

Puts cache namespaces in Redis under a `{key_prefix}:{namespace}:{key}` layout over a deadpool connection pool with per-operation deadlines, so a response cache, a JWKS document or a rate-limit counter is shared across gateway replicas instead of rebuilt in each one. `incr` runs as a server-side Lua script so the increment and its TTL apply atomically, and namespace invalidation walks SCAN + batched DEL rather than FLUSHDB.

Use it to Share rate-limit counters across replicated gateway pods.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.cache.redis
    class: cache
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/cache-redis:protocol-1"
    granted_capabilities:
      - network_outbound
    config:
      url: ${env.REDIS_URL}      # redis://user:pass@redis-primary.internal:6379/0
      key_prefix: mcpg
      connection:
        pool_size: 16
        connect_timeout_ms: 1000
        operation_timeout_ms: 5000

Catalog

1 plugin
dev.mcpg.catalog.builtinBuiltin Catalog Provider
Catalog provider
alpha
v0.1.0-alpha.17

Turns a block of YAML into a governed tool catalogue: it annotates every `tools/list` response with owner, tags, docs URL, maturity and approval flags under `_meta.mcpg.catalog`, drops tools marked hidden, and removes any tool whose required trust exceeds the caller’s. It is a pure offline lookup with no catalogue service to stand up, and it filters at presentation only — pair it with a policy engine or tool gate when the tool must also be refused at dispatch.

Use it to Show each caller only the tools its trust level clears.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.catalog.builtin
    class: catalog_provider
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/catalog-builtin:protocol-1"
    config:
      tools:
        orders.search:
          owner: platform-team <platform@example.com>
          tags: [read-only, orders]
          doc_url: https://docs.example.com/tools/orders-search
          maturity: stable
          trust_required: verified
          sample_arguments:
            query: "status:open"
        internal.health:
          hide: true
      defaults:
        hide_unknown: false
        require_verified_for_unknown: false
      global_defaults:
        owner: platform-team
        maturity: stable

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: orders.search
        description: Search open orders.
        governance:
          minimum_trust: verified
        backend:
          kind: http
          url: https://orders.internal/search
          method: get

Clustering & HA

4 plugins
dev.mcpg.cluster.consulConsul Cluster Coordinator
Cluster coordinator
Enterprise
alpha
v0.1.0-alpha.17

Coordinates a multi-replica gateway fleet through the HashiCorp Consul HTTP API — peers from the catalog service, leadership and distributed locks from Consul Sessions with KV compare-and-swap supplying the fencing token, cross-replica notifications over the Events API, and a durable key/value store for capability state. Consul KV has no per-key TTL, so key/value expiry is carried in each value’s envelope and applied lazily on read.

Use it to Cluster gateway replicas where Consul already does service discovery.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
cluster:
  kind: consul
  address: https://consul.service.internal:8501
  service_name: mcpg-gateway
  kv_prefix: mcpg/prod/
  token: ${env.CONSUL_TOKEN}
  datacenter: eu-west-1
  node_id: ${env.HOSTNAME}
  subscribe_wait_sec: 30
  lease_renew_before_expiry_percent: 30

plugins:
  # No `config:` block — the `cluster:` block above is the single source
  # of truth for this coordinator's runtime config.
  - id: dev.mcpg.cluster.consul
    class: cluster
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/cluster-consul:protocol-1"
    granted_capabilities:
      - network_outbound
dev.mcpg.cluster.etcdetcd Cluster Coordinator
Cluster coordinator
Enterprise
alpha
v0.1.0-alpha.17

Coordinates a gateway fleet against etcd v3 over gRPC: native lease grant and lock for leadership and distributed locks, the KV API with Txn compare-and-swap for shared state, and Watch streams for pub/sub that stay durable and replayable inside the retention window. Peer discovery reads and watches the `peers/` prefix but registers nothing itself, so membership must be populated externally.

Use it to Leader election for a gateway fleet already running etcd.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
cluster:
  kind: etcd
  endpoints:
    - https://etcd-0.internal:2379
    - https://etcd-1.internal:2379
  key_prefix: /mcpg/           # must end in '/'
  tls:
    # Transport is fail-closed: an https:// endpoint with no tls: block,
    # mixed schemes, or auth over plaintext is rejected at boot.
    ca_cert: /etc/mcpg/certs/etcd-ca.pem
  node_id: ${env.HOSTNAME}
  event_ttl_secs: 60
  lease_renew_before_expiry_percent: 30

plugins:
  - id: dev.mcpg.cluster.etcd
    class: cluster
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/cluster-etcd:protocol-1"
    granted_capabilities:
      - network_outbound
dev.mcpg.cluster.natsNATS JetStream Cluster Coordinator
Cluster coordinator
Enterprise
alpha
v0.1.0-alpha.17

Coordinates a gateway fleet on NATS JetStream: KV buckets hold leases, locks, CAS-guarded fencing counters and shared capability state, while subjects carry peer heartbeats and cross-replica notifications. It implements all four coordinator primitives — key/value store, pub/sub bus, lease, and key watch — so sessions, tasks, subscriptions, delivery and cancellation state become durable and replicated with no further wiring, and a peer silent past `node.peer_expiry_sec` is evicted with a leave event.

Use it to Share session and delivery state across replicas over NATS.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
cluster:
  kind: nats
  servers:
    - tls://nats-0.internal:4222
    - tls://nats-1.internal:4222
  node:
    id: ${env.HOSTNAME}
    heartbeat_interval_sec: 10
    peer_expiry_sec: 30
  auth:
    method: credentials_file
    path: /etc/mcpg/nats.creds
  tls:
    ca_cert: /etc/mcpg/certs/nats-ca.pem
    require_tls: true
  jetstream:
    replicas: 3
    storage: file
  lease:
    default_ttl_sec: 30
    renew_before_expiry_percent: 50

plugins:
  - id: dev.mcpg.cluster.nats
    class: cluster
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/cluster-nats:protocol-1"
    granted_capabilities:
      - network_outbound
dev.mcpg.cluster.redisRedis Cluster Coordinator
Cluster coordinator
Enterprise
alpha
v0.1.0-alpha.17

Supplies the whole coordination surface for a multi-replica gateway over one Redis instance — key/value store, pub/sub, leases carrying monotonic fence tokens, key-change watch, and TTL’d peer presence that expires a dead replica on its own — so replicas share sessions, bundle-reload events and approval notifications. Leases are a Lua `SET NX PX` plus an `INCR` on a sibling fence key, and key-change watch reads a Redis Stream the KV store appends to on every write.

Use it to Cluster a gateway fleet on Redis you already run.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
cluster:
  kind: redis
  url: ${env.REDIS_URL}             # rediss:// in production
  password: ${env.REDIS_PASSWORD}
  key_prefix: "mcpg:cluster:"       # one namespace per deployment
  lease_ttl_ms: 30000
  peer_ttl_ms: 60000
  service_name: mcpg
  lease_renew_before_expiry_percent: 80

plugins:
  - id: dev.mcpg.cluster.redis
    class: cluster
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/cluster-redis:protocol-1"
    granted_capabilities:
      - network_outbound

Credential Issuers

9 plugins
dev.mcpg.credential.aws-stsAWS STS AssumeRole Credentials
Credential issuer
Enterprise
alpha
v0.1.0-alpha.17

Issues short-lived AWS credentials per request by calling STS AssumeRole from the gateway’s own IAM principal (IRSA, instance role, or static keys), picking the target role from the caller’s identity via a static ARN, subject id, first role, or a template. The caller’s subject is stamped into the RoleSessionName so CloudTrail attributes every assumed-role action to the real caller, and identity-derived ARNs are honoured only for a Verified principal that passes an ARN shape check and an optional allowlist.

Use it to Give each analyst their own AWS role, attributed in CloudTrail.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.credential.aws-sts
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-aws-sts:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      region: us-east-1
      # base_credentials omitted in production: run as an IAM principal (IRSA / instance role)
      targets:
        per-team:                         # -> cred://dev.mcpg.credential.aws-sts/per-team
          identity_mapping: template
          role_arn_template: "arn:aws:iam::123456789012:role/mcpg-${identity.attributes.team}"
          allowed_role_arns:
            - "arn:aws:iam::123456789012:role/mcpg-data"
            - "arn:aws:iam::123456789012:role/mcpg-platform"
          session_name_prefix: mcpg
          duration_seconds: 3600
          max_cache_ttl_ms: 3600000

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: datalake.query
        description: Query the internal data lake with the caller's own assumed AWS role.
        governance:
          minimum_trust: verified        # identity-derived role ARNs require Verified
        backend:
          kind: http
          method: post
          url: https://datalake.internal/query
          headers:
            X-Amz-Access-Key-Id: "${cred://dev.mcpg.credential.aws-sts/per-team#access_key_id}"
            X-Amz-Secret-Access-Key: "${cred://dev.mcpg.credential.aws-sts/per-team#secret_access_key}"
            X-Amz-Security-Token: "${cred://dev.mcpg.credential.aws-sts/per-team#session_token}"
dev.mcpg.credential.azure-identityAzure Entra Workload-Identity Credentials
Credential issuer
Enterprise
alpha
v0.1.0-alpha.17

Issues Azure Entra (Azure AD) bearer tokens for a named downstream resource, with the gateway proving its own workload identity through an AKS federated credential, an IMDS managed identity, or a client secret. The requested scope is operator-fixed by default, or derived from the caller’s identity via a template that is honoured only for a Verified principal, https-shape-checked, and optionally allowlisted.

Use it to Call Microsoft Graph from AKS without a stored client secret.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.credential.azure-identity
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-azure-identity:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      targets:
        graph:                            # -> cred://dev.mcpg.credential.azure-identity/graph
          base_auth: { mode: workload_identity }   # reads AZURE_FEDERATED_TOKEN_FILE
          tenant_id: contoso.onmicrosoft.com
          client_id: "00000000-0000-0000-0000-000000000000"
          scope: "https://graph.microsoft.com/.default"
          max_cache_ttl_ms: 1800000
        storage:
          base_auth: { mode: managed_identity }    # IMDS
          resource: "https://storage.azure.com"

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: directory.find_user
        description: Look up a user in Microsoft Graph by user principal name.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            upn: { type: string, description: User principal name }
          required: [upn]
        backend:
          kind: http
          method: get
          url: "https://graph.microsoft.com/v1.0/users/${arguments.upn}"
          headers:
            Authorization: "Bearer ${cred://dev.mcpg.credential.azure-identity/graph}"
dev.mcpg.credential.gcp-impersonationGCP Service-Account Impersonation
Credential issuer
Enterprise
alpha
v0.1.0-alpha.17

Mints short-lived GCP OAuth2 access tokens or OIDC ID tokens per request by impersonating a target service account through the IAM Credentials REST API, with the gateway authenticating from GKE Workload Identity or the GCE metadata server. The target service account can be fixed by the operator or derived from the caller’s identity, in which case it requires a Verified principal, a valid *.gserviceaccount.com shape, and an optional allowlist.

Use it to Run BigQuery jobs as a per-team service account, not one shared identity.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.credential.gcp-impersonation
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-gcp-impersonation:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      # base_auth defaults to the GKE Workload Identity metadata server
      targets:
        bq-reader:                        # -> cred://dev.mcpg.credential.gcp-impersonation/bq-reader
          token_kind: access_token
          service_account: "bq-reader@my-proj.iam.gserviceaccount.com"
          scopes: ["https://www.googleapis.com/auth/bigquery.readonly"]
          lifetime_seconds: 3600
        per-team:
          identity_mapping: template
          service_account_template: "mcpg-${identity.attributes.team}@my-proj.iam.gserviceaccount.com"
          allowed_service_accounts:
            - "mcpg-data@my-proj.iam.gserviceaccount.com"
          scopes: ["https://www.googleapis.com/auth/cloud-platform"]

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: bq.run_query
        description: Run a BigQuery job as the impersonated read-only service account.
        governance:
          minimum_trust: verified
        backend:
          kind: http
          method: post
          url: "https://bigquery.googleapis.com/bigquery/v2/projects/my-proj/queries"
          headers:
            Authorization: "Bearer ${cred://dev.mcpg.credential.gcp-impersonation/bq-reader}"
dev.mcpg.credential.jwt-mintJWT Minting Credential Issuer
Credential issuer
alpha
v0.1.0-alpha.18

Mints a freshly signed HS256, RS256, or EdDSA JWT per request that asserts the caller’s identity to a downstream service, using per-target profiles for issuer, audience, TTL, static claims, and claims projected from the caller’s roles, groups, or attributes. Signing keys are parsed once at boot and each call is pure CPU crypto with no outbound network; reserved registered claims cannot be overridden, and a per-target rule decides who may mint.

Use it to Assert the caller’s identity to a partner API as a 5-minute signed JWT.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.credential.jwt-mint
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-jwt-mint:protocol-1" }
    config:
      targets:
        partner-api:                      # -> cred://dev.mcpg.credential.jwt-mint/partner-api
          algorithm: EdDSA
          signing_key: "${env.PARTNER_JWT_ED25519_PEM}"
          issuer: https://gateway.example.com
          audience: ["https://partner.example/api"]
          ttl_seconds: 300
          kid: partner-2026
          claim_mappings:
            roles: roles
            tenant: attributes.tenant
          authorize: { kind: roles, roles: ["partner"] }

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: partner.create_order
        description: Create an order at the partner API, asserting the caller in a minted JWT.
        governance:
          minimum_trust: verified        # roles/groups/subjects rules require a Verified identity
        backend:
          kind: http
          method: post
          url: https://partner.example/api/orders
          headers:
            Authorization: "Bearer ${cred://dev.mcpg.credential.jwt-mint/partner-api}"
dev.mcpg.credential.oauth-client-credentialsOAuth 2.0 Client Credentials Issuer
Credential issuer
alpha
v0.1.0-alpha.17

Fetches and refreshes outbound OAuth 2.0 access tokens with the client_credentials grant (RFC 6749 §4.4) for named providers, so the gateway owns the machine-to-machine refresh loop instead of each binding holding a long-lived secret. Refresh runs ahead of expiry behind a per-provider mutex to avoid a thundering herd, a stale token serves for a short grace window through a transient token-endpoint outage, and only the standard RFC error code is ever echoed into logs.

Use it to Call a billing API that issues short-lived service tokens.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.credential.oauth-client-credentials
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-oauth-client-credentials:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      providers:
        billing-api:                      # -> cred://dev.mcpg.credential.oauth-client-credentials/billing-api
          token_url: https://auth.example.com/oauth/token
          client_id: mcpg-gateway
          client_secret: "${env.BILLING_CLIENT_SECRET}"
          scopes: ["invoices.read", "invoices.write"]
          refresh_buffer_ms: 60000
          timeout_ms: 5000

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: billing.get_invoice
        description: Fetch an invoice from the billing API.
        governance:
          minimum_trust: header_asserted
        input_schema:
          type: object
          properties:
            invoice_id: { type: string }
          required: [invoice_id]
        backend:
          kind: http
          method: get
          url: "https://api.example.com/invoices/${arguments.invoice_id}"
          headers:
            Authorization: "Bearer ${cred://dev.mcpg.credential.oauth-client-credentials/billing-api}"
dev.mcpg.credential.oauth-id-jagOAuth Cross-App Access (ID-JAG) Issuer
Credential issuer
Enterprise
alpha
v0.1.0-alpha.17

Runs the OAuth Cross-App Access two-hop flow per provider: it exchanges the caller’s subject token at the enterprise IdP for an ID Assertion Grant scoped to an upstream resource server (RFC 8693), then redeems that assertion at the upstream authorization server (RFC 7523) for the access token a federated MCP server will accept. Issuance requires a Verified caller, nothing is cached in-plugin because tokens are per-caller, and a target_template can derive a provider for a whole allowlisted fleet of registry servers from one config block.

Use it to Reach a federated MCP server as the end user, not as the gateway.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  # An identity_provider entry is what makes callers Verified — ID-JAG
  # issuance refuses anything less.
  - id: dev.mcpg.identity.oidc
    class: identity_provider
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.identity.oidc/plugin.so }
    granted_capabilities: [network_outbound]
    config:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

  - id: dev.mcpg.credential.oauth-id-jag
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-oauth-id-jag:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      providers:
        drive:
          idp_token_url: https://idp.example.com/oauth2/token          # hop 1 (enterprise IdP)
          client_id: mcpg-gateway
          client_secret: "${env.IDP_CLIENT_SECRET}"
          audience: https://drive-mcp.example.com                      # upstream AS
          resource: https://drive-mcp.example.com/mcp
          scopes: [read]
          redeem_token_url: https://drive-mcp.example.com/oauth2/token  # hop 2 (upstream AS)

mcp:
  federations:
    - name: drive
      upstream:
        url: https://drive-mcp.example.com/mcp
        auth:
          mode: oauth_impersonation
          credential: "cred://dev.mcpg.credential.oauth-id-jag/drive"
dev.mcpg.credential.oauth-token-exchangeOAuth 2.0 Token Exchange Issuer
Credential issuer
Enterprise
alpha
v0.1.0-alpha.17

Exchanges the caller’s own subject token at an STS token endpoint (RFC 8693) for a downstream access token, so upstream calls carry the end user’s identity instead of one shared service account. The subject token is read from the resolved identity and never logged, nothing is cached in-plugin because each caller yields a distinct exchange, and a target_template covers a fleet of upstreams behind one STS from a single config block.

Use it to Call a search service on behalf of the end user, with their scopes.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.credential.oauth-token-exchange
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-oauth-token-exchange:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      providers:
        search:                           # -> cred://dev.mcpg.credential.oauth-token-exchange/search
          token_url: https://sts.example.com/oauth/token
          client_id: mcpg-gateway
          client_secret: "${env.STS_CLIENT_SECRET}"
          audience: https://search.example.com
          scopes: ["search.read"]
          timeout_ms: 5000

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: search.query
        description: Query the search service on behalf of the calling user.
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            index: { type: string }
          required: [index]
        backend:
          kind: http
          method: post
          url: "https://search.example.com/v1/${arguments.index}/query"
          headers:
            Authorization: "Bearer ${cred://dev.mcpg.credential.oauth-token-exchange/search}"
dev.mcpg.credential.staticStatic Credential Issuer
Credential issuer
alpha
v0.1.0-alpha.17

Hands out operator-declared credentials to bindings through cred:// references — either a single value such as a bearer token, or named parts such as a username and password addressed with #part. Each target carries its own authorization rule (any authenticated caller, or a role, group, or subject allowlist that additionally requires a Verified identity), so one shared gateway can hand different targets to different callers with no external secret infrastructure and no outbound network.

Use it to Dev, lab, and partner integrations where the secret is genuinely static.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.credential.static
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-static:protocol-1" }
    config:
      targets:
        orders-pg:                        # -> .../orders-pg#username, .../orders-pg#password
          parts:
            username: orders_ro
            password: "${env.ORDERS_PG_PASSWORD}"
          ttl_seconds: 600
          authorize: { kind: roles, roles: ["analyst"] }

  # The binding below names `kind: sql`, so the SQL backend artifact has to
  # be declared. Boot fails outright on a binding whose backend kind has no
  # registered plugin.
  - id: dev.mcpg.backend.sql
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-sql:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: orders.recent
        description: List the most recent orders.
        governance:
          minimum_trust: verified        # the roles rule requires a Verified identity
        backend:
          kind: sql
          driver: postgres
          url: "postgres://${cred://dev.mcpg.credential.static/orders-pg#username}:${cred://dev.mcpg.credential.static/orders-pg#password}@db.internal/orders?sslmode=require"
          query:
            sql: "SELECT id, total FROM orders ORDER BY created_at DESC LIMIT 20"
            params: []
            row_mode: many
dev.mcpg.credential.vault-dynamic-dbVault Dynamic Database Credentials
Credential issuer
Enterprise
alpha
v0.1.0-alpha.17

Mints a fresh database username and password per request from HashiCorp Vault’s database secrets engine, mapping the caller’s identity to a Vault role by a fixed name, the subject id, the caller’s first role, or a template. Cache TTL is capped at the Vault lease duration and the plugin revokes the lease when the gateway evicts the credential rather than waiting for Vault to expire it, authenticating by token or AppRole with Vault Enterprise namespaces supported.

Use it to Per-caller Postgres logins so DB row-level security does the gating.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.credential.vault-dynamic-db
    class: credential_issuer
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/credential-vault-dynamic-db:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      url: "https://vault.example.com:8200"
      db_mount: database
      auth:
        method: token                    # token | approle
        token: "${env.VAULT_TOKEN}"
      targets:
        orders:                          # -> cred://dev.mcpg.credential.vault-dynamic-db/orders
          identity_mapping: from_role    # identity.roles[0] selects the Vault role
          vault_role: orders-readonly    # fallback when the caller carries no role
          max_cache_ttl_ms: 3600000
          revoke_on_evict: true
      connection:
        connect_timeout_ms: 5000
        operation_timeout_ms: 10000

  - id: dev.mcpg.backend.sql
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-sql:protocol-1" }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: orders.lookup
        description: Look up an order using a per-caller Vault-issued database credential.
        governance:
          minimum_trust: verified
        input_schema:
          type: object
          properties:
            order_id: { type: string }
          required: [order_id]
        backend:
          kind: sql
          driver: postgres
          url: "postgres://${cred://dev.mcpg.credential.vault-dynamic-db/orders#username}:${cred://dev.mcpg.credential.vault-dynamic-db/orders#password}@db.internal/orders?sslmode=require"
          query:
            sql: "SELECT id, status, total FROM orders WHERE id = :order_id"
            params: [order_id]
            row_mode: single

Identity & SSO

11 plugins
dev.mcpg.identity.aauthAAuth Agent Identity Resolver
Identity provider
alpha
v0.1.0-alpha.17

Gives each calling AI agent a cryptographic identity instead of a shared API key: it verifies the RFC 9421 HTTP Message Signature on every request, checks the presented `aa-agent+jwt` token against the issuing Agent Provider’s published JWKS (SSRF-admitted fetch, cached), enforces the proof-of-possession binding so the token’s `cnf.jwk` must be the key that signed the request, and resolves the stable principal `aauth:local@domain`. Opt-in person tokens add the human an agent acts for, and opt-in auth tokens carry the granted `scope` into gateway scopes.

Use it to Admit third-party AI agents without provisioning them credentials.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.aauth
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-aauth:protocol-1" }
    granted_capabilities:
      - network_outbound
    config:
      # Agent Providers this gateway trusts (exact `iss` match). An empty list
      # without `allow_any_issuer` refuses to load.
      trusted_issuers:
        - https://ap.example
      signature_window_secs: 60
      expected_authority: gw.example       # pin @authority when a proxy rewrites Host
      person_tokens:
        enabled: true
        resource_identifier: https://gw.example
        trusted_person_servers:
          - https://sandbox.personserver.dev
      auth_tokens:
        enabled: true
      resolution:
        trust_level: verified
        auth_provider_label: aauth
dev.mcpg.identity.api-keyStatic API-Key Identity Resolver
Identity provider
alpha
v0.1.0-alpha.17

Resolves the caller from a static, operator-declared API-key registry: it takes the key from `Authorization: Bearer` or any named header, SHA-256s it and constant-time-compares against every registry digest, then stamps the matched entry’s roles, groups, scopes and attributes on the identity. Keys support soft revocation and RFC 3339 expiry and are referenced through the gateway secret resolver (`${env.X}`, `vault://…`, `file:///…`) rather than pasted into config — fully offline, with no external identity provider.

Use it to Service-to-service auth for internal callers with no IdP.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.api-key
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-api-key:protocol-1" }
    config:
      token_sources:
        - { kind: bearer }                       # Authorization: Bearer <token>
        - { kind: header, header: X-Api-Key }
      keys:
        - key_id: service-orders                 # becomes subject_id
          secret: "${env.MCPG_APIKEY_ORDERS}"    # >= 16 bytes after resolution
          roles: ["service"]
          groups: ["internal-services"]
          scopes: ["orders.read", "orders.write"]
          attributes: { tenant_id: acme }
        - key_id: partner-acme
          secret: "vault://secret/data/api-keys#acme"
          enabled: true                          # false soft-revokes
          expires_at: "2026-12-31T00:00:00Z"
          roles: ["partner"]
      resolution:
        trust_level: verified
        auth_provider_label: api-key
dev.mcpg.identity.basicHTTP Basic Identity Resolver
Identity provider
alpha
v0.1.0-alpha.17

Authenticates `Authorization: Basic` callers against an operator-declared user registry, verifying the supplied password against a stored argon2 or bcrypt PHC hash — MD5 htpasswd entries are rejected at load — and stamping that user’s roles, groups, scopes and attributes on the identity. Hashes are generated out of band and referenced through the secret resolver so plaintext never appears in config, and per-user `enabled` / `expires_at` time-box an account without deleting it.

Use it to Authenticated callers on a small deployment with no IdP.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.basic
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-basic:protocol-1" }
    config:
      username_case: insensitive
      users:
        - username: alice
          password_hash: "${env.ALICE_PASSWORD_HASH}"   # argon2 or bcrypt PHC string
          roles: ["operator"]
          groups: ["sre"]
          scopes: ["admin.read"]
          attributes: { tenant: acme }
          enabled: true
          expires_at: "2027-01-01T00:00:00Z"
      resolution:
        trust_level: verified
        auth_provider_label: basic
dev.mcpg.identity.jwtGeneric JWT Identity Resolver
Identity provider
alpha
v0.1.0-alpha.18

Verifies bearer JWTs from issuers that are not full OIDC providers, using operator-supplied static keys — an HS shared secret, an RS/ES/EdDSA public-key PEM, or a pinned JWKS document — and checks `exp`/`nbf`/`iss`/`aud` before mapping claims to subject, roles, groups, scopes and attributes. No discovery, no JWKS fetch, no introspection, so there is no outbound network on the auth path, and bad config refuses to load rather than running unenforced.

Use it to Accept a partner’s signed JWTs with no live JWKS endpoint.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.jwt
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-jwt:protocol-1" }
    config:
      token_source:
        kind: authorization_bearer
      issuers:
        - issuer: https://auth.partner.example
          audiences: ["https://gateway.mcpg.dev"]
          algorithms: ["EdDSA"]
          clock_skew_secs: 60
          key:
            kind: ed_pem
            pem: ${env.PARTNER_JWT_ED25519_PUBLIC_PEM}
          claim_mappings:
            subject_claim: sub
            role_claim_paths: ["realm_access.roles"]
            scope_claim_paths: ["scope"]
            attribute_claim_mappings: { tenant: "tenant" }
      resolution:
        trust_level: verified
        auth_provider_label: jwt
dev.mcpg.identity.kerberosKerberos / SPNEGO Identity Resolver
Identity provider
Enterprise
alpha
v0.1.0-alpha.18

Accepts HTTP Negotiate / SPNEGO callers (RFC 4559) by feeding the `Authorization: Negotiate` GSSAPI token to MIT GSSAPI `accept_sec_context` against the gateway’s service keytab — a purely local cryptographic check, since the keytab decrypts the service ticket and the KDC is never contacted. Roles and groups come back empty: AD group membership rides in the ticket’s PAC, which this version does not decode.

Use it to Desktop SSO for AD-joined users, no second credential issued.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.kerberos
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-kerberos:protocol-1" }
    config:
      keytab: "${env.MCPG_KEYTAB}"                      # e.g. /etc/mcpg/http.keytab
      service_name: "HTTP@gateway.corp.example.com"     # omit to accept any principal in the keytab
      strip_realm: true                                 # alice@CORP.EXAMPLE.COM -> alice
      resolution:
        trust_level: verified
        auth_provider_label: kerberos
dev.mcpg.identity.ldapLDAP / Active Directory Identity Resolver
Identity provider
Enterprise
alpha
v0.1.0-alpha.17

Verifies `Authorization: Basic` credentials by binding to an LDAP or Active Directory server as the caller — the directory itself is the password oracle, so the gateway never holds a password or hash — then reads the caller’s `memberOf` entries and projects group DNs into groups and their CNs into roles. Two modes: template the user’s DN directly, or bind a service account, search for the user (the AD `sAMAccountName` case), and re-bind as the matched DN.

Use it to Gate tools on existing AD group membership for corporate users.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.ldap
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-ldap:protocol-1" }
    granted_capabilities:
      - network_outbound
    config:
      url: "ldaps://dc1.corp.example.com:636"
      bind:
        mode: search
        bind_dn: "cn=svc-mcpg,ou=svc,dc=corp,dc=example,dc=com"
        bind_password: "${env.LDAP_SVC_PASSWORD}"
        base_dn: "ou=people,dc=corp,dc=example,dc=com"
        user_filter: "(sAMAccountName={username})"
      subject_attribute: sAMAccountName
      group_attribute: memberOf
      roles_from_group_cn: true
      attributes: [mail, displayName, department]
      timeout_ms: 10000
      resolution:
        trust_level: verified
        auth_provider_label: ldap
dev.mcpg.identity.mtlsmTLS Identity Resolver (header-injection)
Identity provider
alpha
v0.1.0-alpha.17

Turns the client-certificate details a TLS terminator forwards in HTTP headers — an Envoy/Istio `X-Forwarded-Client-Cert` chain, an nginx-style `X-SSL-Client-S-DN`, or any cloud load-balancer header — into a caller identity keyed on the subject CN, the whole DN, or a SHA-256 fingerprint, with per-subject roles and scopes. It reads headers only and never validates a peer certificate itself, so it defaults to the lower `header_asserted` trust level until a trusted proxy is known to strip inbound copies of those headers.

Use it to Honour Istio sidecar mTLS identity already terminated in front.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.mtls
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-mtls:protocol-1" }
    config:
      sources:
        - { kind: xfcc, header: X-Forwarded-Client-Cert, chain_position: first }
        - { kind: dn_string, header: X-SSL-Client-S-DN }
        - { kind: custom_header, header: X-Client-Fingerprint, extraction_hint: fingerprint }
      extraction:
        mode: subject_cn
        case_sensitive: false
      identities:
        orders-svc:
          roles: ["service"]
          scopes: ["orders.read"]
          attributes: { tenant: acme }
      resolution:
        # Raise to `verified` only when a trusted proxy terminates mTLS AND
        # strips any inbound copy of these headers before injecting its own.
        trust_level: header_asserted
        auth_provider_label: mtls
dev.mcpg.identity.oidcOIDC/OAuth Identity Resolver
Identity provider
alpha
v0.1.0-alpha.17

Validates OIDC/OAuth bearer tokens against one or more configured issuers — JWKS signature verification via discovery, RFC 7662 opaque-token introspection, or both — enforcing audience, clock skew and an allowed-algorithm list. Claims map to the subject, roles, groups, scopes and attributes that downstream policy and audit see, and every discovery/JWKS/introspection fetch runs behind an SSRF guard.

Use it to Workforce SSO from Okta or Keycloak into MCP tools.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.identity.oidc
    class: identity_provider
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.identity.oidc/plugin.so }
    granted_capabilities:
      - network_outbound
    config:
      token_source:
        kind: authorization_bearer
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg"]
          clock_skew_secs: 60
          allow_private_issuer: false
          verification:
            kind: oidc_jwks
            allowed_algs: ["RS256"]
            refresh_interval_secs: 300
            timeout_ms: 2000
            allow_hmac: false
          claim_mappings:
            subject_claim: sub
            group_claim_paths: ["groups"]
            role_claim_paths: ["realm_access/roles"]
            scope_claim_paths: ["scope", "scp"]
            attribute_claim_mappings: { tenant: "tenant_id" }
dev.mcpg.identity.pasetoPASETO Identity Resolver
Identity provider
Enterprise
alpha
v0.1.0-alpha.17

Verifies PASETO v4 tokens against operator-supplied static keys — `v4.public` Ed25519 signatures checked with a public key, or `v4.local` XChaCha20-Poly1305 tokens decrypted with a shared symmetric key — validates `exp` (always required) plus `iss` and `aud` when configured, and maps claims to subject, roles, groups, scopes and attributes. Pure synchronous compute with no network: the PASETO sibling of the static-key JWT resolver.

Use it to Accept PASETO-issuing services without adopting JWT.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.paseto
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-paseto:protocol-1" }
    config:
      token_source:
        kind: authorization_bearer
      issuers:
        - issuer: https://auth.partner.example
          audiences: ["https://gateway.mcpg.dev"]
          key:
            kind: public_hex                            # v4.public (Ed25519)
            hex: ${env.PARTNER_PASETO_V4_PUBLIC_HEX}
          claim_mappings:
            subject_claim: sub
            role_claim_paths: ["roles"]
            attribute_claim_mappings: { tenant: "tenant" }
      resolution:
        trust_level: verified
        auth_provider_label: paseto
dev.mcpg.identity.samlSAML 2.0 Identity Resolver
Identity provider
Enterprise
alpha
v0.1.0-alpha.17

Verifies a SAML 2.0 assertion carried in a header against the operator-configured IdP certificate — never the certificate embedded in the message — using libxml2 exclusive-C14N with pure-Rust RSA, then validates `Conditions` (time window and audience) and `Issuer` and maps the NameID and attributes to subject, roles and groups. Signature-wrapping defenses require exactly one assertion, a direct-child signature, and a verified signature covering that assertion’s ID — all checked locally, with no outbound call.

Use it to Bridge an existing enterprise SAML IdP to MCP tool access.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.saml
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-saml:protocol-1" }
    config:
      idp_certificate: "file:///etc/mcpg/idp.crt"          # PEM trust anchor
      idp_entity_id: "https://idp.corp.example.com/saml2"
      audience: "mcpg-gateway"
      assertion_header: X-SAML-Assertion
      role_attribute: "http://schemas.example.com/role"
      group_attribute: "memberOf"
      clock_skew_secs: 120
      resolution:
        trust_level: verified
        auth_provider_label: saml
dev.mcpg.identity.workloadSPIFFE Workload Identity Resolver
Identity provider
Enterprise
alpha
v0.1.0-alpha.17

Resolves SPIFFE workload identity from either an X.509-SVID (chain-validated against the trust bundle’s CA roots, SPIFFE URI read from the leaf SAN) or a JWT-SVID (validated against the bundle’s JWKS), enforcing the trust domain, the JWT-SVID audience and an optional SPIFFE-ID allowlist. Trust bundles come from a file with hot-reload or a live gRPC stream off the SPIRE agent’s Workload API socket, so SPIRE key rotation needs no restart.

Use it to Only SPIRE-attested mesh workloads may call payment tools.

Licence
BUSL-1.1
Capabilities
transport_listen, network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.identity.workload
    class: identity_provider
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/identity-workload:protocol-1" }
    granted_capabilities:
      - transport_listen
      - network_outbound
    config:
      trust_domain: example.org
      bundle:
        kind: workload_api
        socket_path: unix:/run/spire/sockets/agent.sock
      sources:
        - { kind: x509_svid }
        - { kind: jwt_svid_bearer }
      audiences: ["https://gateway.example.org"]
      mode: allowlist
      allowlist:
        - "spiffe://example.org/ns/payments/sa/orders"
      identities:
        "spiffe://example.org/ns/payments/sa/orders":
          roles: ["service"]
          scopes: ["orders.read", "orders.write"]
      resolution:
        trust_level: verified
        auth_provider_label: spiffe-workload

Integration

1 plugin
dev.mcpg.webhookWebhook Notifications
Tool gate
alpha
v0.1.0-alpha.17

POSTs a JSON event to your own HTTP receivers — a chat channel, an on-call pager, a SIEM collector — when a tool call completes, returns an error, or exceeds a per-endpoint slow threshold. Delivery runs on a bounded background queue with retry backoff, a per-endpoint circuit breaker, and an SSRF guard that pins the resolved address and refuses private ranges, so a slow receiver never delays a tool call.

Use it to Page on-call when a production tool call errors.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.webhook
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/webhook:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      max_retries: 3
      retry_backoff_ms: 1000
      timeout_ms: 5000
      buffer_size: 1024
      circuit_breaker:
        consecutive_5xx_threshold: 5
        open_duration_ms: 30000
        half_open_probe_count: 1
      endpoints:
        - url: https://hooks.example.com/mcpg
          events: ["error", "slow_response"]   # completed | error | slow_response | all
          slow_threshold_ms: 2000
          headers:
            Authorization: "Bearer ${env.HOOK_TOKEN}"

Observability

7 plugins
dev.mcpg.audit.s3-wormS3 Object-Lock (WORM) Audit Sink
Audit sink
Enterprise
alpha
v0.1.0-alpha.17

Writes every audit event as one JSON object into an S3 Object-Lock bucket under a governance- or compliance-mode retention header that S3 itself enforces, so the object cannot be overwritten or deleted before its retention date — the write-once-read-many evidence SOC 2, HIPAA and PCI-DSS ask for. It honours the synchronous-durable audit contract: emit returns only after the PutObject completes, and the receipt carries the SHA-256 over the exact stored bytes so an auditor can re-derive the hash chain from any S3-API bucket that had Object Lock enabled at creation.

Use it to Retain seven years of tamper-proof tool-call records for a SOC 2 audit.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.audit.s3-worm
    kind: native
    class: audit_sink
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/audit-s3-worm:protocol-1"
    granted_capabilities:
      - network_outbound
    config:
      bucket: acme-mcpg-audit-worm   # must be created with Object Lock enabled
      region: us-east-1
      prefix: gateway-prod
      retention_mode: compliance     # governance | compliance
      retention_days: 2555           # 7 years
      request_timeout_ms: 10000
      # credentials omitted: run as an IAM principal (IRSA / instance role)

# Listing the id under governance.audit.sinks[] is what routes events to
# it; replacing the default entry retires the built-in local-file sink.
governance:
  audit:
    enabled: true
    required: true          # refuse to start with no audit sink
    on_failure: fail_closed
    sinks:
      - kind: dev.mcpg.audit.s3-worm
dev.mcpg.auditAudit Log
Tool gate
alpha
v0.1.0-alpha.17

Writes one append-only JSON record per tool call — caller identity, tool, surface, transport, a SHA-256 argument digest, a result summary, timing, and a monotonic sequence number — to stdout or an append-only file. It always allows the call, and records drain on a dedicated writer thread so a slow or broken sink degrades logging rather than traffic.

Use it to Keep a forensic record of who called which tool.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.audit
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/audit:protocol-1" }
    config:
      sink:
        kind: file                       # stdout (default) | file
        path: /var/log/mcpg/audit.jsonl  # rotate externally, e.g. logrotate
      include_arguments: false
      include_arguments_hash: true
      include_results: false
      include_result_summary: true
      include_result_meta: true
      tools_filter: ["orders.*", "admin.*"]
      buffer_size: 8192
dev.mcpg.call-loggerCall Logger
Tool gate
alpha
v0.1.0-alpha.17

Emits a structured start and end tracing event for every tool call — request id, tool, transport, caller identity, duration, and, when you opt in, the redacted and size-capped arguments and result — into whatever log sink the gateway already writes to. Redaction covers operator-named fields, known credential keys, and credential-shaped values such as Bearer tokens, sk_/AKIA/ghp_ prefixes, PEM headers, and JWTs.

Use it to Debug what a client actually sends and a backend returns.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.call-logger
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/call-logger:protocol-1" }
    config:
      sample_rate: 1.0                 # 1.0 logs both halves of every call
      log_arguments: true
      log_results: true
      max_argument_bytes: 4096
      max_result_bytes: 8192
      redact_fields: ["ssn", "date_of_birth"]
dev.mcpg.observability.otlpOpenTelemetry OTLP Exporter
Telemetry sink
alpha
v0.1.0-alpha.17

Reassembles the gateway’s span start/end events into OpenTelemetry spans — name, kind, timestamps, status and both attribute sets — and ships them over OTLP/gRPC to an OpenTelemetry Collector or any OTLP backend such as Datadog, Honeycomb, Grafana Tempo or New Relic. Delivery runs through the OTel SDK’s batch span processor, so a slow collector never back-pressures the request path; this plugin exports traces only, and metric and log events that reach it are ignored.

Use it to See gateway request traces beside backend service spans in Grafana Tempo.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.observability.otlp
    kind: native
    class: telemetry_sink
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.observability.otlp/plugin.so }
    granted_capabilities:
      - network_outbound
    config:
      url: http://otel-collector:4317
      service_name: mcpg
      service_version: "2.4.0"
      resource_attributes:
        deployment.environment: prod
      batch_export_timeout_ms: 30000

observability:
  enabled: true
  traces:
    # traces.enabled defaults to FALSE — the signal triad is not symmetrical.
    enabled: true
    service_name: mcpg
    propagate_context: true
    sinks:
      - kind: dev.mcpg.observability.otlp
dev.mcpg.observability.prometheusPrometheus Metrics Exporter
Metrics sink
alpha
v0.1.0-alpha.17

Accumulates the counters, gauges and histograms the gateway records into an in-memory registry keyed by (name, labels) and renders it in Prometheus text-exposition format on the gateway’s own /metrics route. It is the sink the default config already names, so loading this plugin is the only step a scrape needs — without it /metrics answers empty — and it holds no I/O of its own; a sample whose kind disagrees with an established series is dropped and counted rather than corrupting the family.

Use it to Scrape gateway request latency and call counts into an existing Prometheus stack.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  # Baked into the published image, so no registry pull is needed.
  - id: dev.mcpg.observability.prometheus
    kind: native
    class: metrics_sink
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.observability.prometheus/plugin.so }
    config:
      namespace: mcpg
      global_labels:
        env: production
        region: us-east-1

# The plugins[] entry loads the artifact and holds the config block.
# The sinks list is the routing allow-list: without the id here the
# signal goes nowhere. This plugin is already the default entry, so
# the block below is only needed to run it alongside another sink.
observability:
  enabled: true
  metrics:
    enabled: true
    sinks:
      - kind: dev.mcpg.observability.prometheus
dev.mcpg.metrics.statsdStatsD Metrics Sink
Metrics sink
alpha
v0.1.0-alpha.17

Formats each metric point the gateway records as a statsd or DogStatsD line — counters as name:value|c, gauges as |g, histograms as one |h, |ms or |d sample per observation — and writes it to a UDP collector such as statsd, the Datadog Agent or Telegraf, or to stdout/stderr. Labels become DogStatsD tags, and metric names, tag keys and tag values are sanitised so nothing in a label can corrupt the wire format.

Use it to Push gateway metrics to an existing Datadog Agent over UDP.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.metrics.statsd
    kind: native
    class: metrics_sink
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/metrics-statsd:protocol-1"
    granted_capabilities:
      - network_outbound
    config:
      destination:
        kind: udp            # udp | stdout | stderr
        address: "127.0.0.1:8125"
      prefix: mcpg
      emit_tags: true
      histogram_type: distribution   # histogram | timing | distribution

observability:
  enabled: true
  metrics:
    enabled: true
    sinks:
      - kind: dev.mcpg.metrics.statsd
dev.mcpg.log.syslogSyslog Log Sink
Log sink
alpha
v0.1.0-alpha.17

Renders each gateway and plugin log record as an RFC 5424 (or RFC 3164) syslog line and sends it over UDP or TCP to rsyslog, syslog-ng, Fluent Bit or any syslog collector, with configurable facility, app-name, hostname, severity floor and structured-field inclusion. TCP is newline-framed and reconnects after a failed write; delivery is best-effort, so a failed write drops the record rather than blocking the caller.

Use it to Ship gateway logs into the corporate rsyslog estate without running a sidecar.

Licence
Apache-2.0
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.log.syslog
    kind: native
    class: log_sink
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/log-syslog:protocol-1"
    granted_capabilities:
      - network_outbound
    config:
      destination:
        kind: udp            # udp | tcp | stdout | stderr
        address: "10.0.0.5:514"
      format: rfc5424        # rfc5424 | rfc3164
      facility: 1            # 0-23; 1 = user-level
      app_name: mcpg-gateway
      hostname: gw-1
      min_level: info
      include_fields: true

observability:
  enabled: true
  logs:
    enabled: true
    level: info
    sinks:
      - kind: stderr
        config:
          format: json
      - kind: dev.mcpg.log.syslog

Agentic Payments

4 plugins
dev.mcpg.payment.acpAgentic Commerce Protocol (ACP)
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Puts a tool behind a real purchase at a merchant implementing the Agentic Checkout specification: it opens a checkout session, returns the merchant’s session and payment handlers to the agent as an HTTP 402 challenge, and lets the tool run only when the merchant reports status completed — re-challenging on 3D Secure or any other status. The gateway holds the merchant bearer token, each session is bound to the principal that opened it, and a stable idempotency key means a retried completion replays instead of charging twice.

Use it to Let an agent buy from an ACP merchant with a gateway-held credential.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.payment.acp
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/payment-acp:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      config:
        default_api_version: "2026-01-30"
        session_ttl_ms: 3600000         # 1 hour (the default is 3600 ms)
        http_timeout_ms: 30000          # the default is 30 ms — always set this
      tools:
        store.buy:
          merchant_base_url: https://merchant.example/agentic_commerce
          auth_token: ${env.ACP_MERCHANT_TOKEN}
          agent_capabilities:
            interventions:
              supported: ["3ds"]
              display_context: webview

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: store.buy
        description: Purchase an item from the merchant catalogue.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: http
          url: https://orders.internal/confirm
          method: post
          timeout_ms: 10000
dev.mcpg.payment.mppMachine Payment Protocol (MPP)
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Charges per call on priced tools using the Machine Payment Protocol: it issues an HMAC-signed, single-use 402 challenge bound to the tool and a random nonce, then admits the call only after an Ed25519 proof of payment verifies against the configured settlement-authority public key. Per-tool charges may be a literal decimal or a CEL expression, and with no settlement key configured the gate denies every paid call rather than falling open.

Use it to Charge per call on a premium tool with signed settlement proofs.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.payment.mpp
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/payment-mpp:protocol-1" }
    config:
      enabled: true
      secret_key: ${env.MPP_SECRET_KEY}     # HMAC secret for challenge integrity
      realm: mcpg-gateway
      recipient: "acct:platform"
      challenge_timeout_seconds: 300
      # Ed25519 settlement-authority public key (64 hex chars).
      # Unset => the gate fails closed and denies every paid call.
      settlement_public_key: ${env.MPP_SETTLEMENT_PUBKEY}
      tools:
        ai.premium_query:
          charge: "0.10"
          currency: USDC

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: ai.premium_query
        description: Run a premium inference query.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: http
          url: https://inference.internal/query
          method: post
          timeout_ms: 30000
dev.mcpg.payment.ucpUniversal Commerce Protocol (UCP)
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Lets an agent buy from a UCP-compatible merchant: it reads the merchant’s /.well-known/ucp profile to find the checkout endpoint, checks the profile advertises every capability the tool requires, opens a checkout, hands the agent its state as an HTTP 402 challenge, and releases the tool only when the merchant reports the checkout completed. The discovered endpoint must be HTTPS and same-origin with the configured merchant URL unless you list the origin explicitly.

Use it to Buy from a discovery-driven storefront under an origin allowlist.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.payment.ucp
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/payment-ucp:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      config:
        platform_profile_url: https://gateway.example/.well-known/ucp
        session_ttl_ms: 3600000         # 1 hour (the default is 3600 ms)
        discovery_cache_ttl_ms: 3600000
        http_timeout_ms: 30000          # the default is 30 ms — always set this
      tools:
        store.checkout:
          merchant_url: https://merchant.example
          capabilities: ["dev.ucp.shopping.checkout"]
          transport: rest               # mcp | rest
          allowed_endpoint_origins:     # empty = same-origin only
            - https://api.merchant.example
          auth_token: ${env.UCP_MERCHANT_TOKEN}

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: store.checkout
        description: Place an order with the merchant.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: http
          url: https://orders.internal/place
          method: post
          timeout_ms: 10000
dev.mcpg.payment.x402x402 Crypto Micropayments
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Charges stablecoin per call on priced tools over the x402 protocol: an unpaid call is answered with HTTP 402 carrying machine-readable payment requirements (network, asset, amount, recipient), and a call presenting a credential runs only once an x402 facilitator answers valid: true. It is stateless — no cart, no session, no account system — and attaches the facilitator’s transaction receipt to the allowed call.

Use it to Bill an agent ten cents in USDC per premium query.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.payment.x402
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/payment-x402:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      config:
        facilitator_url: https://x402.org/facilitator
        recipient_address: "0x5f3a9C1b7E2d48Aa10bC93f4e6D75B802a1cE9F4"
        http_timeout_ms: 10000        # the default is 10 ms — always set this
      tools:
        premium.query:
          charge: "0.10"              # per call
          currency: USDC
          chain_id: "eip155:8453"     # Base mainnet

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: premium.query
        description: Run a premium inference query.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: http
          url: https://inference.internal/query
          method: post
          timeout_ms: 30000

Reliability

3 plugins
dev.mcpg.circuit-breakerCircuit Breaker
Tool gate
alpha
v0.1.0-alpha.17

Counts consecutive failed tool results per tool and, once one crosses its failure threshold, stops dispatching to it entirely — answering a fast HTTP 503 instead of another doomed backend round-trip — until a cooldown elapses and a single half-open probe proves the backend healthy again. Thresholds and cooldowns can be overridden per tool.

Use it to Stop burning latency and pool slots on a downed backend.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.circuit-breaker
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/circuit-breaker:protocol-1" }
    config:
      failure_threshold: 5            # consecutive failures that trip the circuit
      cooldown_ms: 30000              # open -> half-open delay
      half_open_max_inflight: 1       # concurrent probes while half-open
      per_tool:
        - tool: "billing.charge"      # exact tool name, not a glob
          failure_threshold: 2
          cooldown_ms: 60000
dev.mcpg.rate-limitRate Limiter
Tool gate
alpha
v0.1.0-alpha.17

Token-bucket throttling for tool calls, where each rule picks its own bucket key: per calling principal, per tool, per principal-and-tool pair, per MCP session, or one global bucket. A drained bucket is denied with HTTP 429 and a retry_after_secs hint instead of reaching the backend.

Use it to Cap one noisy agent to 10 calls a minute on expensive tools.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.rate-limit
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/rate-limit:protocol-1" }
    config:
      default_limit: 100              # tokens per window for unmatched tools
      default_window_ms: 60000
      default_burst: 150              # headroom above the steady rate
      cleanup_interval_ms: 300000     # idle threshold for bucket eviction
      rules:
        - tools: ["expensive.*", "admin.*"]   # globs, first match wins
          scope: per_principal                 # per_principal | per_tool | per_principal_tool | per_session | global
          limit: 10
          window_ms: 60000
          burst: 20
dev.mcpg.response-cacheResponse Cache
Tool gate
alpha
v0.1.0-alpha.17

Serves a repeated tool call from a short-lived in-memory cache keyed on the MCP surface, the tool name, and a canonicalised hash of the arguments, so a hit skips the backend entirely. Errors are never cached, a request can opt out with _meta.no_cache, TTLs are overridable per tool by glob, and cache_scope: per_identity keys entries per caller.

Use it to Skip a slow, per-request-billed API on repeat calls.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.response-cache
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/response-cache:protocol-1" }
    config:
      default_ttl_ms: 300000          # 5 minutes
      max_entries: 10000
      cache_scope: shared             # shared | per_identity
      per_tool:
        - tools: ["catalog.*"]        # glob patterns
          ttl_ms: 60000
        - tools: ["live.*", "*.stream"]
          ttl_ms: 0                   # never cache these

Secret Providers

1 plugin
dev.mcpg.secret.vaultHashiCorp Vault Secret Provider
Secret provider
Enterprise
alpha
v0.1.0-alpha.17

Resolves `vault://<path>#<field>` references against HashiCorp Vault at config load, so the gateway config names its secrets instead of carrying them; it reads KV v2 and the dynamic engines (database credentials, PKI, AWS STS) and authenticates by static token, AppRole, userpass or Kubernetes ServiceAccount. It then keeps watching: each renewable lease is renewed at half its TTL, and a rotation event is emitted when a secret changes, either by polling KV v2 version metadata or over Vault’s `sys/events/subscribe` WebSocket stream.

Use it to Keep upstream API tokens in Vault, not in the config file.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  # Registering the entry binds the `vault://` scheme — there is no
  # separate binding block.
  - id: dev.mcpg.secret.vault
    class: secret_provider
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/secret-vault:protocol-1"
    granted_capabilities:
      - network_outbound
    config:
      url: https://vault.example:8200
      auth:
        method: approle
        role_id: ${env.VAULT_ROLE_ID}
        secret_id: ${env.VAULT_SECRET_ID}
      default_field: value
      watch:
        strategy: poll
        poll_interval_ms: 30000
      connection:
        connect_timeout_ms: 5000
        operation_timeout_ms: 10000

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: billing.charge
        description: Charge a customer.
        governance:
          minimum_trust: verified
        backend:
          kind: http
          url: https://billing.internal/charge
          method: post
          headers:
            authorization: vault://secret/data/billing#token

Security & Policy

10 plugins
dev.mcpg.tool-gate.dlpData-Loss-Prevention Gate
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Scans tool arguments before dispatch and results after it for secrets and personal data — AWS keys, JWTs, emails, Luhn-checked card numbers, generic API keys, URL credentials, plus your own named regexes — and either denies the call (HTTP 403 / -32050) or redacts the matches in place. The matched value never reaches the deny message, error data, logs, or metric labels; only detector names and counts do.

Use it to Stop an agent leaking an AWS key through a tool argument.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.tool-gate.dlp
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/tool-gate-dlp:protocol-1" }
    config:
      pre_execution: true
      post_execution: true
      action: redact                  # block | redact
      detectors: [aws_access_key, jwt, email, credit_card, url_credentials]
      custom_patterns:
        - { name: employee_id, regex: "EMP-[0-9]{6}" }
      redact_placeholder: "[REDACTED]"
      validate_credit_card_luhn: true
      tools: ["*"]
      exclude_tools: ["debug.*"]
dev.mcpg.tool-gate.field-cryptoField-Level Crypto Gate
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Encrypts named argument fields with XChaCha20-Poly1305 before a call reaches its backend and decrypts named result fields on the way back, so the downstream system stores ciphertext it can never read. Each envelope is bound to its own JSON Pointer path as additional authenticated data, so a ciphertext lifted from /ssn fails to open at any other field.

Use it to Let a SaaS backend hold an SSN it cannot decrypt.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.tool-gate.field-crypto
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/tool-gate-field-crypto:protocol-1" }
    config:
      key_hex: ${env.MCPG_FIELD_CRYPTO_KEY_HEX}   # 64 hex chars = 32 bytes
      encrypt_fields: ["/ssn", "/card/number"]
      decrypt_fields: ["/ssn"]
      fail_closed: true
      tools: ["records.*"]
dev.mcpg.guardrailsHTTP Guardrail Hooks
Tool gate
Enterprise
alpha
v0.1.0-alpha.17

Calls your own external HTTP services before and after tool dispatch — a content scanner, a policy decision point, a budget enforcer, a commercial DLP product — and applies the allow or deny they return, optionally letting them rewrite arguments or results. Each hook is scoped by tool-name glob and an optional CEL trigger, and chooses for itself whether a timeout fails closed or open.

Use it to Route tool arguments through an existing enterprise PDP.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.guardrails
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/guardrails:protocol-1" }
    granted_capabilities: ["network_outbound"]
    config:
      apply_to_non_tool_surfaces: false
      allow_private_backends: false
      pre_execution:
        - name: pii-scanner
          url: https://scanner.svc/scan
          timeout_ms: 5000
          max_response_bytes: 65536
          on_error: deny                # deny (fail-closed) | allow
          allow_mutation: true
          tools: ["orders.*"]
          exclude_tools: ["orders.debug_*"]
          trigger_cel: 'trust_level == "verified"'
          headers: { Authorization: "Bearer ${env.SCANNER_TOKEN}" }
      post_execution: []
dev.mcpg.ip-allowlistIP Allowlist
Tool gate
alpha
v0.1.0-alpha.17

Admits a tool call only when the caller’s IP — read from a configurable forwarded-for header — falls inside one of the CIDR ranges you list, and denies with HTTP 403 otherwise, including when no address can be resolved at all. Covers IPv4 and IPv6, normalising IPv4-mapped addresses so a dual-stack hop cannot slip past an IPv4 range.

Use it to Confine a tool to office and VPN egress ranges.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.ip-allowlist
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/ip-allowlist:protocol-1" }
    config:
      allow:
        - "10.0.0.0/8"
        - "192.168.1.0/24"
        - "::1/128"
      ip_header: x-forwarded-for
      tools: []          # empty = gate every tool
dev.mcpg.policy.casbinCasbin Policy Engine
Policy engine
Enterprise
alpha
v0.1.0-alpha.17

Embedded Casbin authorization engine: you supply a model .conf (request shape, policy shape, matcher) and a policy .csv, and the plugin compiles an enforcer at boot that answers every gateway authorization question in-process. Because the access-control model lives in the model file, one artifact expresses ACL, RBAC, RBAC-with-domains or ABAC, and a matched deny reports the matching policy lines as the reason.

Use it to Reuse existing Casbin RBAC or ABAC rules to gate tool calls.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.policy.casbin
    class: policy_engine
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/policy-casbin:protocol-1" }
    config:
      model_path: /etc/mcpg/casbin/model.conf     # r = sub, obj, act
      policy_path: /etc/mcpg/casbin/policy.csv    # p, alice, billing.charge, tool.call.pre
      translation:
        request_fields:                           # one entry per model request column, in order
          - { source: identity_subject_id, fallback: anonymous }
          - { source: context, field: tool_name }
          - { source: decision_point }
      evaluation:
        on_default_deny: not_applicable
      reload:
        enabled: true
        check_interval_sec: 60

governance:
  policy:
    engine:
      - kind: casbin       # short alias for dev.mcpg.policy.casbin
dev.mcpg.policy.cedarCedar Policy Engine
Policy engine
Enterprise
alpha
v0.1.0-alpha.17

Embedded AWS Cedar authorization engine: it aggregates every .cedar file under policy_dir into one PolicySet at boot and evaluates typed principal x action x resource requests in-process, with no external decision server. Operator translation rules map the gateway’s (decision_point, input, context) envelope onto Cedar entity types, and @advice / @redact annotations on a matched policy surface as obligations and redactions on the decision.

Use it to Typed permit/forbid authz on every tool call, hot-reloaded.

Licence
BUSL-1.1
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.policy.cedar
    class: policy_engine
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/policy-cedar:protocol-1" }
    config:
      policy_dir: /etc/mcpg/cedar/policies          # required; walked recursively
      schema_path: /etc/mcpg/cedar/schema.cedarschema
      entities_path: /etc/mcpg/cedar/entities.json
      include_input_as_context: true
      translation:
        principal_type: User
        action_namespace: Action
        anonymous_principal_id: anonymous
        resource_types:
          - { decision_point: "tool.call.pre", resource_type: Tool, resource_id_path: "/tool" }
          - { decision_point: "*", resource_type: Resource, resource_id_path: "/id" }
      evaluation:
        on_default_deny: not_applicable            # "deny" makes this the sole authority
      reload:
        enabled: true
        check_interval_sec: 60

governance:
  policy:
    engine:
      - kind: cedar        # short alias for dev.mcpg.policy.cedar
dev.mcpg.policy.opaOPA Policy Engine
Policy engine
Enterprise
alpha
v0.1.0-alpha.17

Open Policy Agent engine in two modes: remote POSTs each evaluation envelope to a standalone OPA server’s REST Data API at /v1/data/<package>, while embedded verifies a Rego-compiled WASM bundle against its expected SHA-256 and evaluates it in-process via wasmtime with no egress. An OPA 404 maps to NotApplicable so the next engine in the chain gets a turn; every other failure fails closed to Deny.

Use it to Authorize tool calls with Rego your platform team already maintains.

Licence
BUSL-1.1
Capabilities
network_outbound
Configuration sample
yaml
plugins:
  - id: dev.mcpg.policy.opa
    class: policy_engine
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/policy-opa:protocol-1" }
    granted_capabilities: ["network_outbound"]     # remote mode only
    config:
      mode: remote
      remote:
        url: "https://opa.svc.cluster.local:8181"
        package: "mcpg/allow"                      # POSTs to /v1/data/mcpg/allow
        timeout_ms: 500
        tls:
          ca_cert: /etc/mcpg/opa-ca.pem
          verify_peer: true

  # Air-gapped alternative — same plugin, no egress:
  # config:
  #   mode: embedded
  #   policy_bundle:
  #     source_path: /etc/mcpg/policy.wasm
  #     sha256: "3f5a..."
  #     entrypoint: "mcpg/allow"
  #     reload: { enabled: true, check_interval_sec: 60 }

governance:
  policy:
    engine:
      - kind: opa          # short alias for dev.mcpg.policy.opa
dev.mcpg.tool-gate.business-hoursBusiness Hours Gate
Tool gate
alpha
v0.1.0-alpha.17

Admits a tool call only inside weekly time windows you define, evaluated as wall-clock time in a chosen IANA timezone, and refuses anything outside every window or on a listed blackout date before the backend runs. The timezone database is compiled into the artifact, so windows hold their wall-clock position across daylight-saving transitions with no I/O and no clock service.

Use it to Block a payroll run outside 09:00-17:00 New York.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
plugins:
  - id: dev.mcpg.tool-gate.business-hours
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/tool-gate-business-hours:protocol-1" }
    config:
      timezone: America/New_York
      windows:
        - { days: [mon, tue, wed, thu, fri], start: "09:00", end: "12:00" }
        - { days: [mon, tue, wed, thu, fri], start: "13:00", end: "17:00" }
      blackout_dates: ["2026-12-25", "2027-01-01"]
      deny_http_status: 403
      deny_code: -32030
dev.mcpg.tool-gate.schemaJSON Schema Contract Gate
Tool gate
alpha
v0.1.0-alpha.17

Validates tool-call arguments against an inline JSON Schema you supply and rejects a malformed call with a precise 4xx — JSON-RPC -32602 over HTTP 400 by default — before it reaches a backend. The schema compiles once at load and resolves only in-document $ref, so there is no outbound dependency, and a schema that fails to compile refuses the boot rather than running unenforced.

Use it to Enforce a contract stricter than a tool’s advertised input schema.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.tool-gate.schema
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/tool-gate-schema:protocol-1" }
    config:
      schema:
        type: object
        required: ["query"]
        properties:
          query: { type: string, minLength: 1 }
          limit: { type: integer, maximum: 100 }
      max_errors: 8
      http_status: 400
      code: -32602

  # HTTP is a runtime-loaded cdylib, not linked into the gateway. Without
  # this entry the tool below lists fine and fails on every call with
  # "HTTP backend plugin not registered".
  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    tools:
      - name: search.documents
        description: Search the document index.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: http
          url: https://search.internal/query
          method: post
          timeout_ms: 5000
dev.mcpg.tool-gate-slack-approvalSlack Tool-Gate Approval
Tool gate
alpha
v0.1.0-alpha.18

Parks a tool call matching your regex rules until a named human clicks Approve on an interactive Slack Block Kit message. One cdylib carries all three pieces — the gate that suspends the call, the notifier that posts to the channel, and the HTTP route that verifies Slack’s request signature and resolves the approval — and the resolution POST is confined to an operator-declared origin allowlist.

Use it to Hold a production refund until an engineer approves it in Slack.

Licence
Apache-2.0
Capabilities
network_outbound, http_route_serve
Configuration sample
yaml
governance:
  approvals:
    # the gateway mints the signed callback URL from this base
    callback_base_url: https://gw.example.com

plugins:
  - id: dev.mcpg.tool-gate-slack-approval
    class: tool_gate
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/tool-gate-slack-approval:protocol-1" }
    granted_capabilities: ["network_outbound", "http_route_serve"]
    config:
      bot_token: ${env.SLACK_BOT_TOKEN}
      signing_secret: ${env.SLACK_SIGNING_SECRET}
      default_channel: "#mcp-approvals"
      interactive_path: /slack/interactive
      callback_allowed_origins:
        - https://gw.example.com
      rules:
        - tool_pattern: '^prod\.'
          summary_template: "Approve {tool} for {subject}?"
          deadline_secs: 300
          channel: "#prod-approvals"

Transforms

7 plugins
dev.mcpg.transform.csvCSV Transform
Transform
alpha
v0.1.0-alpha.17

Converts between delimited text and JSON in either direction: csv_to_json parses a CSV, TSV or other single-byte-delimited string into an array of row objects (with a header row) or arrays, and json_to_csv serialises an array back to delimited text with RFC 4180 quoting. An optional JSON Pointer confines the conversion to one sub-field so the rest of the tool payload passes through untouched.

Use it to A tool speaks CSV; the MCP client needs structured rows.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.transform.csv
    class: transform
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/transform-csv:protocol-1" }
    config:
      direction: csv_to_json           # csv_to_json | json_to_csv
      phase: result
      pointer: /structuredContent/report
      delimiter: ";"
      has_headers: true
      max_output_bytes: 1048576

  - id: dev.mcpg.backend.graphql
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.graphql/plugin.so }
    granted_capabilities: [network_outbound]

# Or the reverse direction as a pipeline step:
mcp:
  capabilities:
    tools:
      - name: orders.report
        description: Fetch the vendor's orders and hand them back as a CSV table.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: pipeline
          steps:
            - kind: graphql
              id: fetch
              url: https://vendor.example.com/graphql
              operation: "query { orders { id total } }"
            - kind: plugin_transform
              id: table
              plugin: dev.mcpg.transform.csv
              config:
                direction: json_to_csv
                pointer: /steps/fetch/output/orders
dev.mcpg.transform.json-schemaJSON Schema Validation Transform
Transform
alpha
v0.1.0-alpha.17

Validates a JSON value against an operator-supplied inline JSON Schema: a valid value passes through byte-identical, an invalid one raises a transform error naming each failing instance path, capped by max_errors. Validation runs fully offline because the validator is compiled without an HTTP resolver, so only in-document $ref resolves and a schema holding a remote $ref cannot make the gateway call out.

Use it to Refuse to continue when a backend’s response breaks its contract.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.transform.json-schema
    class: transform
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/transform-json-schema:protocol-1" }
    config:
      phase: arguments
      max_errors: 32
      schema:
        type: object
        required: [query]
        properties:
          query: { type: string, minLength: 1 }
          limit: { type: integer, maximum: 100 }

  - id: dev.mcpg.backend.graphql
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.graphql/plugin.so }
    granted_capabilities: [network_outbound]

# In the global chain above a failure is logged and the last good value carries
# on. Wire it as a pipeline step when an invalid payload must stop the call:
mcp:
  capabilities:
    tools:
      - name: orders.enriched
        description: Fetch orders and refuse to continue unless the shape matches.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: pipeline
          steps:
            - kind: graphql
              id: fetch
              url: https://orders.example.com/graphql
              operation: "query { orders { id } }"
            - kind: plugin_transform
              id: check
              plugin: dev.mcpg.transform.json-schema
              config:
                pointer: /steps/fetch/output
                schema: { type: object }
dev.mcpg.transform.jsonataJSONata Transform
Transform
alpha
v0.1.0-alpha.17

Applies an operator-supplied JSONata expression to tool arguments or results, so one expression projects fields, filters and aggregates arrays, and builds an entirely new object shape. Used as a pipeline plugin_transform step it reads steps.<id>.output, which is how one backend call’s result gets adapted into the next call’s input shape.

Use it to Reshape one API’s response into the shape the next step expects.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
governance:
  access:
    oidc_oauth:
      providers:
        - issuer: "https://idp.example.com"
          audiences: ["mcpg-gateway"]
          verification: { kind: oidc_jwks, allowed_algs: ["RS256"] }

plugins:
  - id: dev.mcpg.transform.jsonata
    class: transform
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/transform-jsonata:protocol-1" }
    config:
      phase: arguments                # arguments | result | both
      expression: '{ "names": items.name, "total": $sum(items.qty) }'
      max_output_bytes: 1048576

  # A pipeline's first step must be a REGISTRY-DISPATCHED backend kind.
  # `http` and `pipeline` are gateway-native routes with no register-profile
  # spec mapping, and naming one as a step fails boot.
  - id: dev.mcpg.backend.graphql
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.graphql/plugin.so }
    granted_capabilities: [network_outbound]

# The same registered plugin, invoked from one binding's pipeline:
mcp:
  capabilities:
    tools:
      - name: orders.flow
        description: Fetch orders, then reshape them for the enrichment step.
        governance:
          minimum_trust: verified
        backend:
          kind: pipeline
          steps:
            - kind: graphql
              id: fetch
              url: https://orders.example.com/graphql
              operation: "query { orders { id } }"
            - kind: plugin_transform
              id: reshape
              plugin: dev.mcpg.transform.jsonata
              config:
                expression: '{ "ids": steps.fetch.output.orders.id }'
dev.mcpg.transform.maskingField Masking Transform
Transform
alpha
v0.1.0-alpha.17

Redacts named fields — personal data, card numbers, credentials — out of tool arguments before dispatch and out of tool results before they reach the client, matching field names case-insensitively with an optional trailing wildcard so one entry covers a family of keys. It ships as a WASI component rather than a native library, so it runs inside the gateway’s Wasmtime sandbox under operator-set memory, fuel and wall-clock limits.

Use it to Stop a backend’s PII fields reaching the MCP client.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
# Requires a gateway built with --features wasm-plugins, and the descriptor
# copied beside the artifact as mcpg_plugin_transform_masking.wasm.plugin.yaml
plugins:
  - id: dev.mcpg.transform.masking
    class: transform
    kind: wasm
    source: { path: ./plugins/mcpg_plugin_transform_masking.wasm }
    limits: { memory_mb: 16, fuel: 5000000, timeout_ms: 50 }
    config:
      policy: strict                   # strict | input_only | output_only
      redact_fields: [ssn, credit_card, password, "card_*"]
      mask_char: "*"
      mask_length: 8
      preserve_type: false             # false also redacts numeric/boolean values
      nested: true
dev.mcpg.transform.templateTemplate Transform
Transform
alpha
v0.1.0-alpha.17

Renders an operator-supplied MiniJinja (Jinja2-syntax) template with the tool payload as its context: output: string turns a machine-shaped result into prose a model or a human can read, output: json parses the rendered text back into a structured value for JSON-to-JSON reshaping. The template comes from the operator’s config and request data supplies only the render context, so a caller cannot inject template syntax the engine will execute.

Use it to Turn a raw API result into a readable summary for the model.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.transform.template
    class: transform
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/transform-template:protocol-1" }
    config:
      phase: result
      pointer: /structuredContent      # narrow to the payload, keep the envelope
      output: json                     # string (default) | json
      template: '{"summary": "Order {{ id }}: {{ items|length }} item(s), total {{ total }}"}'

  - id: dev.mcpg.backend.graphql
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.graphql/plugin.so }
    granted_capabilities: [network_outbound]

# Or as a pipeline step, rendering a prior step's output:
mcp:
  capabilities:
    tools:
      - name: orders.summary
        description: Fetch an order and return a human-readable summary.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: pipeline
          steps:
            - kind: graphql
              id: fetch
              url: https://orders.example.com/graphql
              operation: "query { order { id customer status } }"
            - kind: plugin_transform
              id: summarise
              plugin: dev.mcpg.transform.template
              config:
                pointer: /steps/fetch/output
                template: "Order {{ id }} for {{ customer }} — {{ status }}"
dev.mcpg.transform.xmlXML Transform
Transform
alpha
v0.1.0-alpha.17

Converts XML and JSON in either direction so a tool can speak JSON to its callers while its backend speaks XML — SOAP envelopes, legacy enterprise APIs, feed documents, vendor exports — using a round-trippable mapping (attributes as @name, mixed text as #text, repeated tags as arrays). Only the five predefined entities and numeric character references are resolved and DTD declarations are skipped, so no externally-defined entity is ever expanded.

Use it to Expose a SOAP or legacy XML service as a JSON MCP tool.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.transform.xml
    class: transform
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/transform-xml:protocol-1" }
    config:
      direction: xml_to_json           # xml_to_json | json_to_xml
      pointer: /body                   # the XML string carried on the arguments
      phase: arguments
      max_output_bytes: 1048576

  - id: dev.mcpg.backend.soap
    class: backend
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/backend-soap:protocol-1" }
    granted_capabilities: [network_outbound]

# Decoding a SOAP response inside one binding's pipeline:
mcp:
  capabilities:
    tools:
      - name: order.lookup
        description: Fetch an order from a SOAP service and return JSON.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: pipeline
          steps:
            - kind: soap
              id: fetch
              endpoint: https://orders.example.com/soap/order
              soap_version: "1.1"
              soap_action: "http://orders.example.com/GetOrder"
              body_template: "<GetOrder xmlns=\"http://orders.example.com/\"/>"
            - kind: plugin_transform
              id: decode
              plugin: dev.mcpg.transform.xml
              config:
                direction: xml_to_json
                pointer: /steps/fetch/output/body
dev.mcpg.transform.xsltXSLT Transform
Transform
alpha
v0.1.0-alpha.17

Applies an operator-supplied XSLT stylesheet to an XML string selected from the payload and returns the serialised result, using the pure-Rust xrust engine (XSLT 1.0 semantics on the XPath 3.1 data model, no system library or FFI). External include/import and document() fetches are denied because the plugin performs no I/O, so an unresolved external reference surfaces as a transform error rather than a network call.

Use it to Normalise a vendor’s XML dialect with stylesheets you already own.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.transform.xslt
    class: transform
    source: { oci: "ghcr.io/mcpg-dev/source-code/plugins/transform-xslt:protocol-1" }
    config:
      phase: result
      input: response.xml              # JSON Pointer or dotted path to the XML string
      output: string                   # string | xml_to_json
      output_method: xml               # xml | text | html (html serialises as XML)
      max_output_bytes: 1048576
      stylesheet: |
        <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
          <xsl:template match='/a'><out><xsl:value-of select='b'/></out></xsl:template>
        </xsl:stylesheet>

  - id: dev.mcpg.backend.graphql
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.graphql/plugin.so }
    granted_capabilities: [network_outbound]

# Or as a pipeline step over the previous step's XML output. The stylesheet is
# inlined: config-load interpolation expands `${env.NAME}` only, so a
# `${file://…}` wrapper would arrive as a literal string, not as XML.
mcp:
  capabilities:
    tools:
      - name: catalogue.normalise
        description: Fetch the vendor feed and normalise it with our stylesheet.
        governance:
          minimum_trust: header_asserted
        backend:
          kind: pipeline
          steps:
            - kind: graphql
              id: call
              url: https://vendor.example.com/graphql
              operation: "query { feed { xml } }"
            - kind: plugin_transform
              id: normalise
              plugin: dev.mcpg.transform.xslt
              config:
                input: steps.call.output.feed.xml
                stylesheet: |
                  <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
                    <xsl:template match='/feed'><items><xsl:value-of select='item'/></items></xsl:template>
                  </xsl:stylesheet>

Watchers

2 plugins
dev.mcpg.watch.cronCron Watch Strategy
Watch strategy
alpha
v0.1.0-alpha.17

Ticks a watched MCP resource on an operator schedule — a seconds-first cron expression, or a fixed second or millisecond interval, with an optional `max_fires` cap — so the gateway re-notifies subscribers of a resource whose upstream has no change feed at all. Each watch is one background thread that recomputes its delay against the wall clock so firing does not drift and joins on cancel so no tick arrives afterwards: pure timekeeping, with no network or filesystem access.

Use it to Re-notify a nightly report resource every five minutes.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.watch.cron
    class: watch_strategy
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/watch-cron:protocol-1"

  - id: dev.mcpg.backend.http
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.http/plugin.so }
    granted_capabilities: [network_outbound]

mcp:
  capabilities:
    resources:
      - name: daily-report
        description: Daily report, re-notified on a fixed cadence.
        uri: "report://daily"
        mime_type: application/json
        governance:
          minimum_trust: header_asserted
        backend:
          kind: http
          url: https://reports.example.com/daily.json
          method: get
        watch:
          strategy:
            type: plugin
            kind: cron
            cron: "0 */5 * * * *"     # every five minutes, UTC
dev.mcpg.watch.fileFilesystem Watch Strategy
Watch strategy
alpha
v0.1.0-alpha.17

Ticks a watched MCP resource the moment a local path changes, backed by the operating system’s native notifier (inotify, kqueue, ReadDirectoryChanges) rather than a poll loop — so a mounted config document, a generated artifact or a drop directory re-notifies subscribers on create, modify or remove, with optional recursion into subdirectories. The path comes from gateway config and never from a request, and a path that cannot be watched fails the subscription instead of starting a watcher that never fires.

Use it to Re-notify subscribers when a mounted config file changes.

Licence
Apache-2.0
Capabilities
none required
Configuration sample
yaml
gateway:
  server:
    trust_subject_header: true

plugins:
  - id: dev.mcpg.watch.file
    class: watch_strategy
    kind: native
    source:
      oci: "ghcr.io/mcpg-dev/source-code/plugins/watch-file:protocol-1"

  # Baked into the published image. The resource below names `kind: command`,
  # and a binding whose backend kind has no registered plugin fails boot.
  - id: dev.mcpg.backend.command
    class: backend
    source: { path: /usr/local/lib/mcpg/plugins/dev.mcpg.backend.command/plugin.so }

mcp:
  capabilities:
    resources:
      - name: app-settings
        description: Application settings, re-notified whenever the file changes.
        uri: "config://app/settings"
        mime_type: application/json
        governance:
          minimum_trust: header_asserted
        backend:
          kind: command
          command: /bin/cat
          args: ["/etc/myapp/settings.json"]
        watch:
          strategy:
            type: plugin
            kind: file
            path: /etc/myapp/settings.json
            event_kinds: [create, modify, remove]

Build your own.

The plugin protocol is documented, versioned, and stable. Native Rust uses the mcpg-plugin-sdk crate; WASM uses the Component Model with WIT bindings. Sign your artifact with mcpg-plugin sign and publish to any OCI registry.