Aller au contenu principal

ADR-041: Plugin Architecture — Community Core vs Enterprise Extensions

Metadata

FieldValue
Status✅ Accepted
Date2026-02-12
Decision MakersChristophe ABOULICAM, Platform Team
LinearCAB-1136
  • ADR-024: Gateway Unified Modes — 4 deployment modes (edge-mcp, sidecar, proxy, shadow)
  • ADR-037: Deployment Modes Sovereign-First — Sovereign, Hybrid, SaaS tiers
  • ADR-039: mTLS Mutual Authentication — Enterprise-grade certificate auth
  • ADR-040: Born GitOps — Multi-environment promotion architecture

Context

The Problem

STOA has 559 gateway tests, mTLS, circuit breakers, multi-tenant RBAC, OIDC federation, and Kafka metering. All of this is invisible to a freelancer who just wants to expose their REST API to AI agents via MCP.

Today, there is no stoa init. No 30-second path from zero to first MCP call. The platform is enterprise-ready but community-hostile.

Meanwhile, the competitive landscape has shifted dramatically:

PlatformMCP SupportOpen SourceCommunity Tier"MCP to Everything"
KongEnterprise MCP Gateway + Context Mesh (Feb 2026)Community Edition (BSL for enterprise features)Limited — no MCP in OSSKong-managed APIs only
Gravitee4.10 MCP Proxy + AI Agent Management (Jan 2026)OSS (enterprise features gated)Limited — MCP is enterpriseGravitee-managed APIs only
STOAMCP Gateway (Rust, production)Apache 2.0 (no BSL, no feature gating)MissingAny API, any protocol

The Insight: MCP to Everything, Not MCP to MCP

Kong transforms APIs already managed by Kong into MCP tools. Gravitee proxies MCP traffic between MCP-aware components. Neither bridges non-MCP backends to MCP.

STOA's differentiator is MCP to Everything:

REST API      ──→ UAC ──→ MCP Tools
SOAP Service ──→ UAC ──→ MCP Tools
GraphQL API ──→ UAC ──→ MCP Tools
gRPC Service ──→ UAC ──→ MCP Tools
Legacy HTTP ──→ UAC ──→ MCP Tools

The UAC (Universal API Contract) is the translation layer. "Define Once, Expose Everywhere" — including to AI agents.

The Strategic Question

How do we make STOA accessible to freelancers in 30 seconds while keeping enterprise features available for large organizations?

Decision

Principle #1: Security Is Not a Tier

Security features are always included, even in the free Community Core. Credential storage uses the OS keychain by default — never plaintext files. This is a fundamental design principle, not a premium feature.

This positions STOA against every competitor:

  • Kong: admin tokens in headers, no native keychain
  • kubectl: tokens in plaintext ~/.kube/config
  • AWS CLI: credentials in plaintext ~/.aws/credentials
  • Docker: tokens in base64 (not encrypted) in ~/.docker/config.json

Principle #2: Community Core = Complete Product

The Community Core is not a crippled trial. It is a fully functional API-to-MCP gateway that a freelancer can use in production, forever, for free.

Principle #3: Enterprise Extensions = Opt-In Activation

Enterprise features are already implemented in the codebase. They are activated via Cargo feature flags, configuration, or Keycloak setup — not via license keys or paywalls.

Two-Tier Architecture

Tier 1 — Community Core (Apache 2.0, free forever)

CategoryFeatureStatus
GatewayProxy + routing✅ Implemented
GatewayRate limiting✅ Implemented
GatewayAPI key authentication✅ Implemented
GatewaySSRF protection✅ Implemented
GatewaySecurity headers✅ Implemented
GatewayPrometheus metrics✅ Implemented
BridgeOpenAPI → MCP auto-bridgeTo build
BridgeSOAP (WSDL) → MCP bridgePlanned (Q3)
BridgeGraphQL → MCP bridgePlanned (Q3)
CLIstoactl init (project scaffold)To build
CLIstoactl bridge (import + expose)To build
CLIstoactl doctor (diagnostic)To build
SecurityOS Keychain credential storageTo build
SecurityKey rotation (stoactl auth rotate-key)To build
SecurityCredential access audit logTo build
PackagingDocker image stoa:communityTo build
Docs"Getting Started in 5 Minutes" guideTo build

Tier 2 — Enterprise Extensions (opt-in, same Apache 2.0 license)

CategoryFeatureActivationStatus
AuthmTLS mutual authenticationConfig + --features mtls✅ Implemented (PR #224)
AuthOIDC federation (multi-realm)Keycloak config✅ Implemented
AuthMulti-tenant RBACKeycloak config✅ Implemented
ResilienceCircuit breakerGateway config✅ Implemented (PR #218)
ObservabilityKafka metering--features kafka✅ Implemented
ObservabilityOpenTelemetry tracing--features otelPlanned
DeploymentSidecar mode (Kong/Envoy/NGINX)STOA_MODE=sidecarStub (Q2)
DeploymentShadow mode (traffic → UAC auto-gen)STOA_MODE=shadowPartial
DeploymentK8s CRD watcher + federation--features k8sPlanned
DeploymentMulti-environment promotionGitOps (ADR-040)✅ Implemented
PackagingDocker image stoa:enterpriseAll features compiledTo build
SupportSLA + consultingCommercial contract

Credential Storage Architecture

API keys and tokens MUST be stored in the OS keychain. Never in plaintext files.

Resolution Hierarchy (priority order)

1. --api-key flag          (one-time use, never persisted)
2. STOA_API_KEY env var (CI/CD and containers only)
3. OS Keychain (macOS Keychain / Linux secret-service / Windows Credential Manager)
4. ❌ NEVER a plaintext file

Implementation

OSBackendLibrary
macOSSecurity.framework (Keychain)Go: go-keyring, Rust: keyring crate
LinuxD-Bus Secret Service (GNOME Keyring / KWallet)Go: go-keyring, Rust: keyring crate
WindowsCredential Manager (WinCred)Go: go-keyring, Rust: keyring crate
CI/headlessEnv var fallback (STOA_API_KEY)Native
ContainerMounted file (/run/secrets/stoa)Native

Security Requirements (Epictetus review)

  • Auto-rotation: stoactl auth rotate-key --auto --interval 90d schedules key rotation
  • Audit log: every keychain read/write logged to ~/.stoa/audit.log (local, not sent anywhere)
  • stoactl auth status: shows "Key stored in: macOS Keychain" (never shows the key itself)
  • No ~/.stoa/credentials: the file must not exist. If detected, stoactl doctor warns and offers migration

The 30-Second Path: stoactl initstoactl bridge

# Freelance: zero to MCP in 30 seconds
$ stoactl init my-project
✓ Created docker-compose.yml (gateway + echo backend)
✓ Created stoa.yaml (minimal config)
✓ Run: cd my-project && docker compose up -d

$ stoactl bridge ./openapi.yaml
✓ Parsed OpenAPI 3.x spec
✓ Generated 8 MCP tools from 8 endpoints
✓ Registered tools on gateway
✓ MCP endpoint: http://localhost:8080/mcp/sse

# Done. Any MCP client (Claude, GPT, etc.) can call your API.

stoactl doctor (Zeno review)

Diagnostic command that verifies the full stack:

$ stoactl doctor
✓ Docker: running (v27.5.1)
✓ Gateway: healthy (http://localhost:8080/health)
✓ Keychain: accessible (macOS Keychain)
✓ API key: valid (expires in 87 days)
✓ Port 8080: available
✓ MCP endpoint: responding (3 tools registered)
✗ OpenAPI spec: 2 warnings (circular ref in #/components/schemas/Node)

Growth Path

The same user, same codebase, scales from freelance to enterprise:

StageWhat They UseCost
Day 1 — Freelancestoactl init + bridge → REST to MCP0€
Day 30 — Growing+ API keys for clients + rate limiting + monitoring0€
Day 90 — Scale-up+ custom domains + multi-API catalog0€
Day 180 — Enterprise+ mTLS + RBAC + federation + sidecar mode + SLASupport contract

Docker Packaging

Two images, same Dockerfile with build args:

ImageFeatures CompiledSize TargetUse Case
ghcr.io/stoa-platform/gateway:communityDefault (no optional features)< 30 MBFreelance, indie, small teams
ghcr.io/stoa-platform/gateway:enterprise--all-features (kafka, k8s, otel, mtls)< 50 MBLarge organizations
ghcr.io/stoa-platform/gateway:latestAlias for community< 30 MBDefault pull

Both images are Apache 2.0. The enterprise image is not "paid" — it just includes heavier dependencies (rdkafka, k8s client, etc.) that most freelancers don't need.

Consequences

Positive

  • Community adoption: 30-second onboarding removes the #1 friction
  • MCP-to-everything positioning: unique vs Kong (MCP-for-Kong) and Gravitee (MCP-to-MCP proxy)
  • Security by default: keychain-first is a genuine differentiator against every competitor
  • No BSL trap: Apache 2.0 for everything, including enterprise features — trust signal for OSS community
  • Enterprise upsell natural: same platform, same code, just activate more features + buy support

Negative

  • OpenAPI bridge complexity: circular refs, allOf/oneOf/anyOf, discriminators, polymorphic schemas require a robust parser — not a simple mapping
  • Cross-OS keychain testing: macOS Keychain, GNOME Keyring, KWallet, Windows Credential Manager all behave differently
  • Two Docker images = two CI pipelines: build matrix, testing matrix, release coordination
  • No revenue gate: enterprise features are free — revenue comes only from support/consulting

Mitigations

  • OpenAPI bridge: use proven parser (utoipa for Rust, libopenapi for Go) — don't hand-roll
  • Keychain: keyring crate/library abstracts all OS backends behind one API
  • Docker: single Dockerfile with ARG FEATURES="", conditional cargo build
  • Revenue: shadow mode is the closer — "we analyze your traffic estate for free, you pay for the migration consulting"

Alternatives Considered

Alternative A: BSL/SSPL License for Enterprise Features

Kong and Elastic use BSL (Business Source License) to gate features. Revenue-protective but community-hostile.

Rejected: STOA's positioning is explicitly anti-BSL. Apache 2.0 is a trust signal. Changing license would destroy credibility before building it.

Alternative B: Feature Flags via License Key

Traditional SaaS model — enterprise features require a license key file.

Rejected: adds complexity, creates support burden, doesn't align with "security is not a tier" principle. Cargo feature flags at compile time are simpler and more transparent.

Alternative C: Separate Enterprise Codebase (Fork)

Maintain a private fork with enterprise-only code.

Rejected: maintenance nightmare, merge conflicts, community contributions can't benefit from enterprise hardening. Single codebase with feature flags is strictly better.

Implementation Plan

Phase 1 — Community CLI (stoactl) — CAB-1136-P1

StepDeliverable
1stoactl init — scaffold project (docker-compose + config)
2stoactl doctor — diagnostic command
3Keychain integration (go-keyring) — store/retrieve/rotate API keys
4stoactl auth — login, status, rotate-key with keychain backend
5Audit log for credential access

Phase 2 — OpenAPI-to-MCP Bridge — CAB-1136-P2

StepDeliverable
1OpenAPI 3.x parser (handle refs, allOf/oneOf/anyOf, circular refs)
2MCP tool generator (endpoint → tool mapping, parameter extraction)
3stoactl bridge command (parse + generate + register on gateway)
4Hot-reload: file watcher on spec file, auto-update tools on change

Phase 3 — Docker Packaging + Documentation — CAB-1136-P3

StepDeliverable
1Dockerfile with ARG FEATURES for community/enterprise builds
2CI pipeline for dual-image build + push
3"Getting Started in 5 Minutes" guide on docs.gostoa.dev
4Feature toggle reference documentation

Phase 4 — Extended Protocol Bridges — CAB-1136-P4

StepDeliverable
1SOAP (WSDL) → UAC → MCP bridge
2GraphQL (introspection) → UAC → MCP bridge
3gRPC (proto) → UAC → MCP bridge

Competitive Positioning Summary

Kong:      "MCP for Kong-managed APIs"     → Vendor lock-in
Gravitee: "MCP proxy for MCP traffic" → MCP-to-MCP only
STOA: "MCP for everything" → Any API, any protocol, free forever

Kong: Enterprise MCP Gateway → $$$$
Gravitee: Enterprise AI Agent Management → $$$
STOA: Community Core + stoactl bridge → 0€, Apache 2.0

Kong: Credentials in headers → Not secure by default
Gravitee: Standard config files → Not secure by default
STOA: OS Keychain by default → Secure by design, even free tier

"Kong fait MCP pour Kong. Gravitee fait MCP pour Gravitee. STOA fait MCP pour tout le monde."

References