Skip to content

Settings Reference

Every setting a gateway pool holds, in the order the tenant portal presents it. Treat this as a catalogue rather than a checklist: only the values you change are stored on the pool, and every default here is a value chosen to be left alone.

Each setting is shown by its API name (publicBaseUrl) and, in the same row, the label the portal gives it. The Gateway’s own admin console shows the same settings in snake_case (public_base_url); they are the same setting under two spellings.

Nothing on this page requires a restart. A change made in the portal reaches every gateway in the pool within backendSyncIntervalSeconds (five minutes by default).

Settings the container reads from its environment instead - TENANT, GATEWAY_POOL_TOKEN, DATABASE_URL, PORT, LOG_LEVEL - are covered in Configuration.

General

SettingPortal labelDefaultAccepts
publicBaseUrlPublic base URL(none)An absolute http(s):// URL
logLevelLog levelinfodebug, info, warning, error
toolDiscoveryModeTool discoveryfullfull, search
toolDiscoveryMaxResultsSearch results8Integer, 1-100

publicBaseUrl is the address MCP clients actually use. The OAuth issuer, the redirect URI, and the protected-resource URLs are all built from it, so it must match how clients connect - the load balancer’s address where TLS terminates there, not the container’s port.

Left unset, each gateway falls back to http://localhost:<port> and logs a warning. Startup succeeds, which is the trap: the deployment advertises OAuth URLs that only resolve on the container itself, and the symptom appears later as clients unable to finish signing in. Set this anywhere but local development.

toolDiscoveryMode decides the shape of the catalogue served to clients. full offers every tool the caller’s policy allows. search offers two meta-tools instead, so the model describes the capability it needs in natural language and only matching tools enter its context - worth reaching for when a large catalogue would otherwise consume the model’s context window. Policy, inspection, and credential handling are identical in both: a tool invoked through search re-enters the same per-call path.

toolDiscoveryMaxResults caps how many tools one search returns. Ignored in full mode.

Client Access

SettingPortal labelDefaultAccepts
browserCorsAllowedOriginsBrowser origins[]List of origins
oauthRegistrationAllowedRedirectHostsExtra redirect hosts[]List of hostnames
oauthRegistrationMaxClientsMaximum registered clients5000Integer, 0 disables
allowAgentTokensAccept agent tokensfalsetrue, false
allowOnBehalfOfAllow delegationfalsetrue, false
trustRequestIdTrust inbound request IDsfalsetrue, false

Browser origins

Required only by browser-based MCP clients calling the Gateway cross-origin, such as MCP Inspector. An empty list disables CORS entirely - there is no separate on/off switch, because two fields that can disagree about whether CORS is running is one field too many.

The permitted headers and methods are fixed at what the MCP specification requires and are not settable. Leave the list empty in production unless a browser-based client genuinely needs it.

Extra redirect hosts

MCP clients register themselves, which is what lets someone connect a client you did not provision. Loopback (127.0.0.1, ::1, localhost) is always accepted and is what every real client uses - the desktop relay listens on 127.0.0.1, Inspector on localhost.

Registration is anonymous and the redirect URI is where an authorization code is delivered. Keeping it on loopback means a code obtained by phishing someone lands on that person’s own machine rather than a host an attacker controls. Add an entry only for a client that genuinely cannot use loopback, and name the exact host.

Maximum registered clients

A ceiling on live registrations for the tenant, and the backstop against a distributed caller that never trips a per-caller rate limit. Registrations expire with the refresh token lifetime, so this bounds concurrent clients rather than registrations ever made. Beyond it the endpoint returns 503. 0 removes the limit.

Agent tokens and delegation

allowAgentTokens accepts a Britive-issued credential presented directly as Authorization: <scheme> <token> with no OAuth flow - an AI identity token, workload token, or API token. People continue to use the OAuth flow; this is for agents that cannot perform one. Off by default because it widens what the MCP endpoint accepts; with it off, an opaque token is refused with “gateway session required”.

The Gateway does not validate these credentials itself. It forwards them, and the platform is the authority: an invalid token fails the first per-user call with 401 or 403 and no tool is served.

allowOnBehalfOf honours an inbound X-On-Behalf-Of: <username> header so an agent identity can act for a named person. Britive authorises the delegation - the agent must hold a Delegate relationship to that user, directly or through one of the user’s tags - and audit events record the person as the actor while additionally carrying the agent identity and a delegated flag.

allowOnBehalfOf requires allowAgentTokens. Enabling it alone is rejected: the platform’s delegate check keys off the agent identity, so without an agent credential the header would be an unauthenticated claim about who the caller is.

Trust inbound request IDs

Use an inbound X-Request-Id for audit correlation instead of generating one. Enable only behind a proxy you trust to set it - any caller can otherwise choose its own correlation id.

Sessions & Tokens

SettingPortal labelDefaultAccepts
gatewayAccessTokenTtlSecondsAccess token lifetime28800 (8h)Integer seconds, min 60
gatewayRefreshTokenTtlSecondsRefresh token lifetime604800 (7d)Integer seconds, min 60
sessionAuthorizationTtlSecondsSession re-check interval28800 (8h)Integer seconds, min 60

An access token is additionally capped at the expiry of the underlying Britive session when it is minted, then extended on refresh. The refresh lifetime is how long a client can renew without a fresh browser sign-in.

sessionAuthorizationTtlSeconds is how long a validated session is reused before being re-checked against the platform. Shorter means more platform calls; longer widens the window in which a session revoked in Britive still works at the Gateway.

Backend Policy

Where the Gateway is willing to send a user’s credentials. A backend’s URL arrives from the platform, and every tool call forwards the caller’s checked-out credential or downstream OAuth bearer to it - so the URL is a destination for other people’s secrets, not just a server address. These settings are applied when a backend is mounted, covering both synced and admin-created backends. A refused backend is never contacted, appears as Refused with a reason, and is recorded in the audit trail.

SettingPortal labelDefaultAccepts
backendRequireHttpsRequire HTTPStruetrue, false
backendAllowPrivateNetworksAllow private networkstruetrue, false
backendAllowedHostsAllowed backend hosts[]List of hostnames

backendRequireHttps refuses a backend reachable only over http://, because the credential crosses that connection in a header. Turn it off for a development stack of plain-HTTP containers, not for a deployment.

backendAllowPrivateNetworks is on by default, deliberately: reaching backends inside a network the platform cannot see is a primary purpose of the Gateway, and a self-hosted database MCP server on an internal address is the normal case. Set it to false in a deployment whose backends are all public SaaS, where nothing should ever be pointed at an internal address.

backendAllowedHosts, when non-empty, is an allowlist: any host not named is refused. Matching is exact or by suffix on a label boundary, so example.com permits mcp.example.com and never notexample.com. Naming a host also settles the address-range question for it.

Regardless of these settings, and not configurable: loopback, link-local (including cloud instance metadata addresses such as 169.254.169.254), multicast, and reserved ranges are always refused. Allowlisting such a host does not override this, nor does allowlisting a name that resolves into one of those ranges.

Hostnames are resolved and checked when a backend is mounted and re-verified. A name that resolves to a permitted address now and an internal one later is not caught here

  • use outbound network policy for that.

Inspection

Detectors, modes, and rollout are covered in Payload Inspection.

SettingPortal labelDefaultAccepts
inspection.modeModeauditoff, audit, enforce
inspection.detectorsDetectorsall threepromptInjection, secretScanner, obfuscation
inspection.urlBlocklistDomainsBlocked domains[]List of domains
inspection.urlBlocklistFeedUrlBlocklist feed""A URL
inspection.silentRedactRedact silentlyfalsetrue, false
inspection.debugCaptureResponsesCapture blocked responsesfalsetrue, false
inspection.debugResponseMaxChars(API only)10000Integer, min 1

mode - audit records a verdict and lets the call proceed unchanged; enforce blocks or redacts matching content; off disables inspection entirely. There is no separate enabled flag: off is what that flag used to mean.

detectors is the list of built-in detectors that run. Naming a detector turns it on; an unrecognised name is rejected rather than silently disabling inspection. All run locally, with no model call and no outbound request.

The URL blocklist detector runs whenever urlBlocklistDomains or urlBlocklistFeedUrl is non-empty - there is nothing else to enable. The feed is either a JSON array of strings or one domain per line where # starts a comment. Each gateway fetches it at startup and again whenever the address changes, not on every save, so editing other settings does not call out to the feed’s host. A failed fetch keeps the domains last retrieved and logs a warning, so an outage there cannot quietly shrink the blocklist.

debugResponseMaxChars caps the captured body when debugCaptureResponses is on. It is accepted by the settings API but is not shown in the portal form; the default is suitable for diagnosis.

Audit

What is recorded, retention, and the two optional sinks are covered in Audit & SIEM.

SettingPortal labelDefaultAccepts
audit.categoriesRecorded categoriesaccess, auth, admin, catalogAny of access, auth, admin, catalog, system
injectUserPromptRecord the user’s prompttruetrue, false
injectLlmIntentRecord the model’s reasoningtruetrue, false
injectLlmSessionIdRecord the model’s session idtruetrue, false
audit.stdoutFullFull events to standard outputfalsetrue, false
audit.retentionDaysRetention90Integer days, 0 disables the sweep
audit.platform.enabledSend events to Britivetruetrue, false
audit.platform.eventsEvents to forwardsee Audit & SIEMAction names the Gateway emits
audit.platform.includeContentInclude call contentfalsetrue, false

The three capture settings

Each of injectUserPrompt, injectLlmIntent, and injectLlmSessionId adds a required parameter to the tool schema the model sees, so the model supplies the value on every call. The value is stripped before the call reaches the backend and recorded in the audit trail. None of them appear in the admin console’s tool list.

SettingParameterWhat it captures
injectUserPrompt_user_promptWhat the person actually asked.
injectLlmIntent_llm_intentWhy the model chose this tool and these arguments.
injectLlmSessionId_llm_session_idAn identifier the model holds constant for one chat or coding session.

_llm_session_id is what turns a flat stream of tool calls into chains: every call an agent made while working on one thing carries the same id, so an investigation can pull the whole episode rather than one row at a time. The Gateway cannot derive it - the transport is stateless and one conversation spans many requests. Being a correlation handle rather than content, it reaches your tenant whether or not content forwarding is on.

These three are grouped with Audit in the portal but stored at the top level of the settings object, which is where the Gateway reads them. Which group a field is displayed in and which path it is stored at are separate concerns.

Integrations

SettingPortal labelDefaultAccepts
audit.webhook.urlSIEM webhook""A URL. Empty disables the sink
audit.webhook.headersSIEM webhook headers{}Map of header name to value. Stored encrypted
audit.webhook.transformSIEM payload transform""A JMESPath expression
audit.webhook.verifyTlsVerify the SIEM’s certificatetruetrue, false
metricsEnabledServe Prometheus metricsfalsetrue, false
metricsTokenMetrics token""A bearer token. Stored encrypted

audit.webhook.headers and metricsToken are sensitive: they are stored encrypted and never returned to an administrative reader. The portal shows whether a value is set, and submitting the masked placeholder leaves the stored value alone - so reading the settings and writing them back cannot overwrite a secret you were never shown. The Gateway itself does receive them, because it is the one reader that has to.

metricsEnabled serves Prometheus metrics at GET /metrics. When off, the route returns 404 rather than 403, so a disabled endpoint does not advertise itself. Labels are low-cardinality and non-identifying - backend, decision, outcome - never user ids or tool arguments, which stay in the access-controlled audit log. With metricsToken set, the endpoint requires it as a bearer token, compared in constant time; leave it empty only where the port is reachable solely by your collector.

Rate Limits

Two limiters, keyed differently because the abuse shapes differ.

SettingPortal labelDefaultAccepts
toolCallRateLimitBurstTool call burst30Integer, 0 disables
toolCallRateLimitPerSecondTool calls per second2.0Number
authRateLimitMaxFailuresSign-in failures allowed10Integer, 0 disables
authRateLimitWindowSecondsFailure window60.0Number of seconds
authRateLimitLockoutSecondsLockout300.0Number of seconds
oauthRegistrationRateLimitBurstRegistration burst5Integer, 0 disables
oauthRegistrationRateLimitPerSecondRegistrations per second0.2Number

Tool calls are limited per user, not per address, because many users share an egress address. Burst is the back-to-back allowance from idle; the rate is sustained throughput. A rejected call is audited as decision=deny outcome=rate_limited and returns an error instructing the model to stop retrying.

Sign-in limits count only failures, keyed by client IP, so a caller that is succeeding is never throttled. A successful exchange clears the record.

Client registration is unauthenticated by necessity, and the failure lockout does not bound it - a well-formed registration is a success, and succeeding is exactly what someone filling the table would be doing. These two settings bound it instead, with oauthRegistrationMaxClients as the tenant-wide ceiling.

X-Forwarded-For is not trusted for the sign-in limits, since a caller can set it. Behind a proxy, apply address-based limits at the proxy.

Counters are held per gateway process, so a pool of N gateways has an effective ceiling of N times these rates. They exist to stop runaway repetition, not to meter usage precisely. For an exact global limit, enforce it at your ingress.

Advanced

Cache lifetimes and timeouts. Each has a correct default and rarely a reason to change, which is why the portal collapses this group.

Synchronisation and verification

SettingPortal labelDefaultAccepts
backendSyncIntervalSecondsSync interval300Integer seconds, min 30
backendVerifyTimeoutSecondsBackend probe timeout10.0Number of seconds, min 0.1
backendVerifyRetryIntervalSecondsBackend retry interval900Integer seconds, 0 disables retries

backendSyncIntervalSeconds governs both backends and these settings: it is the upper bound on how long any change made on the tenant takes to reach a running gateway. Sync Now in the admin console does the same pass on demand.

Mounting a backend is an in-memory registration, so a tenant with many MCP servers becomes serviceable immediately and each backend is probed in the background. The probe timeout stops one unroutable host from holding a slot until the OS TCP timeout. A backend left in issue is re-probed after the retry interval, because an issue is a snapshot of one moment and usually gets fixed; Sync Now ignores the spacing.

Caches

Shorter values mean more platform calls; longer values widen the window in which a change upstream has not yet taken effect here. Each pair is a fresh-hit window and a grace period for serving a stale answer when the platform is unreachable.

SettingPortal labelDefaultAccepts
adminCheckCacheTtlSecondsAdministrator check cache300Integer seconds
adminCheckStaleIfErrorSecondsAdministrator check grace600Integer seconds
identityCacheTtlSecondsIdentity cache300Integer seconds
identityCacheStaleIfErrorSecondsIdentity cache grace600Integer seconds
allowedToolsCacheTtlSecondsPermitted tools cache60Integer seconds
allowedToolsCacheStaleIfErrorSecondsPermitted tools grace300Integer seconds
oauthMetadataCacheTtlSecondsSign-in metadata cache3600Integer seconds

Administrator access is decided by your Britive tenant: a caller holding mcp.server.manage is an administrator, and there is no local administrator list and no way to disable the check. Once the grace period lapses on an unreachable platform, administrator access is refused rather than assumed. Use of a stale answer is recorded in the audit trail and shown in the admin console.

Tokens and headers

SettingPortal labelDefaultAccepts
gatewayRefreshReuseGraceSecondsRefresh reuse grace30.0Number of seconds, 0 revokes on any repeat
checkoutHeaderMaxValueLengthMaximum credential length2048Integer characters, min 1
hstsMaxAgeSecondsHSTS max-age0Integer seconds, 0 disables

Refresh tokens are single-use: presenting one returns a replacement and retires it, and presenting a retired one is treated as a compromise, revoking that session and every token issued from it. The grace window covers a client that legitimately presents the same token twice - two refreshes in flight, or a retry after a lost response - by returning the same replacement instead of revoking. 0 revokes on any repeat, at the cost of occasionally signing users out for their own concurrency.

checkoutHeaderMaxValueLength bounds a single credential value forwarded to a backend. A longer credential is refused rather than truncated, because a truncated secret fails at the backend with a misleading error. Raise it for a backend that legitimately needs larger values, such as a long session token or a PEM-encoded key.

hstsMaxAgeSeconds is sent only on HTTPS responses. It is off by default because the header is durable in a way that is hard to undo: a browser that receives it refuses plain HTTP to that host for the full period, so a development stack that emits it by accident makes its own origin unusable. Set it here or at your TLS edge once the deployment is permanently HTTPS-only. 31536000 is one year.

All other security headers - Content-Security-Policy, frame and MIME-type protections, and no-store on responses carrying credentials - are sent unconditionally and need no configuration.

Audit and inspection timers

SettingPortal labelDefaultAccepts
audit.toolsListHeartbeatSecondsCatalogue heartbeat86400 (24h)Integer seconds
audit.retentionSweepIntervalMinutesRetention sweep1440 (24h)Integer minutes, min 1
audit.webhook.timeoutSecondsSIEM timeout5.0Number of seconds, min 0.1
audit.webhook.maxRetriesSIEM retries3Integer
inspection.requestTimeoutMsInspection request budget250Integer milliseconds, min 1
inspection.responseTimeoutMsInspection response budget500Integer milliseconds, min 1

The catalogue heartbeat is how long an unchanged tool catalogue stays silent before re-affirming itself once, so that no events means nothing changed rather than that recording stopped.

What Is No Longer a Setting

Several values that a configuration file once carried are now fixed. Each either has exactly one correct answer, or bounds an attacker-supplied payload, or sizes an internal batch that no administrator can hold an informed opinion about.

Fixed valueWhy it is not a setting
Master secretReplaced by the pool encryption key (encryptionKey), minted by the platform, delivered only to a gateway, and never shown in any interface. It has no read endpoint: a person who could copy it could forge gateway sessions. Nothing to generate, distribute, or keep in sync across replicas.
Platform API base URLDerived from TENANT, which accepts a full URL. A second way to say where Britive is could only ever contradict the first.
Supported auth strategiesBoth strategies that exist are the only ones there are. Removing one would silently unmount backends configured that way.
CORS allowed headers, methods, and credentialsThe header and method lists are exactly what the MCP specification requires. The Gateway authenticates with bearer tokens and never cookies, so credentialed CORS is never needed.
Client-registration payload boundsBody 16 KB, 8 redirect URIs, 512 characters per URI, 16 items per metadata list, 256 characters per metadata string - all far above what a real client sends. They bound an unauthenticated payload rather than expressing a preference. Exceeding one returns 400 naming the field; values are never silently truncated.
Per-backend inspection trustA “trusted” backend meant enforce mode quietly did not enforce. Inspection either runs or it does not, and inspection.mode says which. Every backend is inspected the same way.
Custom inspection pluginsImport paths set remotely and run with full gateway privileges is remote code execution by configuration. If custom inspectors return, they will arrive as a signed artifact.
Audit JSONL file pathA path inside a container nobody mounts. Postgres, stdout, the webhook, and platform forwarding cover every real destination.
Queue sizes, batch sizes, probe concurrency, blocklist fetch timeoutEach sink buffers 10,000 events; retention deletes 10,000 rows per statement; the platform sink batches 50 events with a 5-second flush and a 10-second timeout; 12 backends are probed at once; the blocklist feed fetch times out at 10 seconds. Internal sizing - and both ends of the platform audit sink are Britive’s, so there is nobody for whom a different flush interval is the right answer.
Entitlement checkout cache lifetimesFixed at 60 seconds for a positive entitlement and 3600 for “no credential providers are bound to this tool”. A positive entitlement is a live decision, so it is re-asked often; the negative one only changes when an administrator binds something, which is a deliberate act rather than something that lapses. Neither is a preference.

Next Steps

Last updated on