Explore ready-to-run examples. Switch tabs to see setup and details for each.
Full-Stack Docker Compose Deployment
This is the example from example/token-exchange-m365. It brings up authentication (Keycloak + OAuth2-Proxy), the Enterprise MCP Bridge, and observability (Jaeger, Prometheus, Grafana).
All the things you need in an Enterprise
- Federated SSO via Keycloak with token exchange to Microsoft Entra; OAuth2-Proxy protects the app edge.
- Least-privilege token handling: user tokens never reach the browser tools; the server exchanges and injects provider tokens per request.
- Operational visibility: OTLP traces to Jaeger; metrics for Prometheus; default Grafana Dashboard and connection set up.
- Safety rails: route scoping with
MCP_BASE_PATH
, tool allow/deny lists, and containerized runtime.
- Enterprise identity mapping: realms and provider aliases for multi-tenant setups.
This is not a fully production-ready example, but a starting point for your own deployment. It is designed to be easily extensible and customizable to fit your specific needs.
Prerequisites
- Docker & Docker Compose
- Azure CLI (
az
)
- A free Microsoft Entra (Azure AD) developer account
- An OpenAI-compatible API key (for the MCP server)
Start the full stack
From the example folder, start everything with one script:
cd example/token-exchange-m365
./start.sh
Then open https://inxm.local. Youโll be redirected to Keycloak at https://auth.inxm.local
to log in. On first run, the script also automates the Entra app registration.
Stop and clean up
./stop.sh
Stops the containers and removes local resources created by the demo.
Service configuration (app-mcp-rest)
Key settings for the Enterprise MCP Bridge container:
services:
app-mcp-rest:
container_name: app.mcp-m365-rest-server
image: ghcr.io/inxm-ai/enterprise-mcp-bridge:latest
environment:
# A human-readable name for the service, useful for logging and observability.
SERVICE_NAME: mcp-m365-rest-server
# The command to launch the specific MCP server that this REST wrapper will connect to.
MCP_SERVER_COMMAND: npx -y @softeria/ms-365-mcp-server --org-mode
# The name of the environment variable that the MCP server will use to receive the OAuth token.
OAUTH_ENV: MS365_MCP_OAUTH_TOKEN
# Specifies the authentication provider to use for token exchange.
AUTH_PROVIDER: keycloak
# Allows the REST server to trust self-signed certificates from the auth provider, useful for local development.
AUTH_ALLOW_UNSAFE_CERT: true
# The base URL of the Keycloak instance.
AUTH_BASE_URL: https://auth.inxm.local
# The Keycloak realm where the authentication is configured.
KEYCLOAK_REALM: inxm
# The alias for the external identity provider (in this case, Microsoft 365) within Keycloak.
KEYCLOAK_PROVIDER_ALIAS: ms365
# Sets a URL prefix for all the REST endpoints to prevent conflicts with other services.
MCP_BASE_PATH: /api/mcp/m365
# A comma-separated list of tool names to exclude from the REST endpoints.
EXCLUDE_TOOLS: login,logout,verify-login
# A comma-separated list of tool name patterns to include.
INCLUDE_TOOLS: "*mail*"
# The endpoint for OpenTelemetry Protocol (OTLP) to send trace data to Jaeger for monitoring.
OTLP_ENDPOINT: http://jaeger:4317
depends_on:
keycloak:
condition: service_healthy
jaeger:
condition: service_started
ports:
- "8000:8000"
labels:
- "oauth2-proxy.enable=true"
networks:
- private
OAuth Token Integration
The server can retrieve, refresh, and inject OAuth tokens for downstream services, simplifying security for your tools.
Flow Diagram: Login
sequenceDiagram
participant User
participant AppIngress as App-Ingress (NGINX)
participant OAuth2Proxy as OAuth2-Proxy
participant Keycloak as Keycloak (auth.inxm.local)
participant AppFrontend as App-Frontend (UI)
User ->> AppIngress: Access https://inxm.local
AppIngress ->> OAuth2Proxy: Route Request
OAuth2Proxy ->> Keycloak: Authenticate (redirect)
Keycloak -->> User: Redirect for Login
User ->> Keycloak: Log in
Keycloak -->> OAuth2Proxy: Redirect with Code/Token
OAuth2Proxy ->> AppIngress: Set Cookie/Header
AppIngress ->> AppFrontend: Serve Frontend
Flow Diagram: Tool Request with Token Exchange
sequenceDiagram
participant AppFrontend as App-Frontend
participant AppIngress as App-Ingress (NGINX)
participant OAuth2Proxy as OAuth2-Proxy
participant AppMCPRest as App-MCP-Rest
participant Keycloak as Keycloak
participant DownstreamAPI as Downstream-API
AppFrontend ->> AppIngress: Request Tool Execution
AppIngress ->> OAuth2Proxy: Route Request
OAuth2Proxy ->> AppMCPRest: Forward with Auth Token
AppMCPRest ->> Keycloak: Request Downstream Token (Token Exchange)
Keycloak -->> AppMCPRest: Return Downstream Token
AppMCPRest ->> DownstreamAPI: Access API with Downstream Token
Minimal Example
This is the example from example/minimal-example. It uses the default MCP server and calls the add
tool with a simple payload as a simple curl
request.
cd example/minimal-example
./start.sh
Expected output includes a result of 3
indicating the add tool is working:
Default mcp example
Starting docker container
Calling the add tool with {"a": 2, "b": 1}
{"isError":false,"content":[{"text":"3","structuredContent":null}],"structuredContent":{"result":3}}
Memory Group Access
This is the example from example/memory-group-access. It demonstrates how to limit access to the memory of the Memory MCP Server (and thus the memory available to the LLMs) using your IAM Groups.
cd example/memory-group-access
./start.sh
Then open https://inxm.local and log in using one of the pre-configured users:
Username |
Password |
Groups |
Access |
admin |
admin123 |
administrators |
All group memories + personal |
john.engineer |
engineer123 |
engineering |
Engineering memories + personal |
jane.marketing |
marketing123 |
marketing |
Marketing memories + personal |
bob.sales |
sales123 |
sales |
Sales memories + personal |
Use the small forms that give you access to the @modelcontextprotocol/server-memory
tools and try to access data you're not supposed to.