Skip to main content

Configuration

Configuration surface for the MCP (Model Context Protocol) Services. Most settings are static for hosted clusters (set via Helm values at deploy time); this page documents what each one does so you can override sensibly during local development or when reviewing a Helm change.

appsettings.json

A minimal configuration:

{
"DynamicTools": {
"EnableDynamicToolGeneration": true,
"MaxQueryResultLimit": 1000,
"DefaultQueryLimit": 100,
"AnalyticsTimeoutSeconds": 300,
"EnableToolStatistics": true,
"CkTypeGraphCacheDurationMinutes": 30,
"PreloadModels": ["System-1.0.0", "Basic-1.0.0"]
},
"Runtime": {
"MongoDB": {
"ConnectionString": "mongodb://localhost:27017",
"DatabaseNamePrefix": "octo_"
}
},
"OctoServiceUrls": {
"AssetServiceUrl": "https://localhost:5001/",
"IdentityServiceUrl": "https://localhost:5003/",
"CommunicationServiceUrl": "https://localhost:5005/",
"BotServiceUrl": "https://localhost:5007/",
"ReportingServiceUrl": "https://localhost:5009/"
}
}

DynamicTools

SettingDefaultDescription
EnableDynamicToolGenerationtrueAllow runtime entity CRUD tools to operate against discovered CK types
MaxQueryResultLimit1000Hard cap on a single query_entities / query_entities_simple response
DefaultQueryLimit100Default limit when the caller does not supply one
AnalyticsTimeoutSeconds300Timeout for long-running aggregation/stream-data calls
EnableToolStatisticstrueCollect usage statistics surfaced by get_tool_statistics
CkTypeGraphCacheDurationMinutes30Per-tenant CK type-graph cache TTL
PreloadModels[]CK models to hydrate at startup so the first call doesn't pay the cold-cache cost

OctoServiceUrls — backend endpoints

Each URL points at one of the OctoMesh backend services. The factory throws ServiceConfigurationMissingException on the first call into an unconfigured client, so you only have to set the ones you actually use.

SettingUsed by
AssetServiceUrlTenant lifecycle, Blueprints, CK Model Libraries, Models, Stream Data tools
IdentityServiceUrlAll Identity tools (Users, Roles, Groups, Clients, Providers, API resources/scopes/secrets)
CommunicationServiceUrlCommunication Controller tools (adapters, pipelines, workloads, data flows, triggers, pools)
BotServiceUrlFile-IO downloads, fixup scripts, tenant dump/restore, log-level dispatch
ReportingServiceUrlReporting service tools

Environment variables

appsettings.json values can be overridden with environment variables using the standard .NET __ separator and an OCTO_ prefix. Examples:

export OCTO_OCTOSERVICEURLS__ASSETSERVICEURL=https://asset.example.com/
export OCTO_OCTOSERVICEURLS__IDENTITYSERVICEURL=https://identity.example.com/
export OCTO_RUNTIME__MONGODB__CONNECTIONSTRING="mongodb://mongo.cluster.local:27017"

Hosted clusters wire these through Helm (values-mcp.yaml) into pod environment variables at deployment time.

Tenant resolution

The server is stateless with respect to tenants. Tenants are resolved per request in this priority order:

  1. Tool parameter tenantId — explicit, accepted by every tenant-scoped tool
  2. Route parameter {tenantId} — from the legacy /{tenantId}/mcp endpoint
  3. ErrorIsSuccess: false, ErrorMessage: "..." if neither is present

Endpoints exposed by the server:

EndpointDescription
/mcpTenantless MCP endpoint — tenant via tool parameter
/{tenantId}/mcpTenant-scoped MCP endpoint — backwards compatible

Best practice: register the tenantless /mcp endpoint once and pass tenantId per call. A single MCP session can then move between tenants in one conversation, which is what AI assistants are designed to do.

Authentication & session tokens

The server supports two authentication paths (end-user flow in the Tech Guide: Getting started → Authenticate):

  • Interactive OAuth (default for Claude Code / Claude Desktop): the transport is gated with .RequireAuthorization(); a 401 carries WWW-Authenticate: Bearer resource_metadata=… pointing at the server's RFC 9728 Protected Resource Metadata (/.well-known/oauth-protected-resource), which advertises the Identity Service as authorization server. The MCP client self-registers there via RFC 7591 Dynamic Client Registration (octo-dcr-* clients) and runs Authorization Code + PKCE in the browser.
  • Device flow: the in-band authenticate tool drives OAuth2 Device Authorization using the octo-mcpServices-device client.

Implementation details:

  • Tokens are stored per MCP session (keyed by the Mcp-Session-Id HTTP header) in IMcpSessionTokenStore; since cross-tenant support the store is keyed by (sessionId, tenantId) — the login token is the home entry, exchanged target-tenant tokens are cached alongside it
  • The OAuth access token is propagated to the backend services on every call — authorisation is enforced there, not in the MCP Services
  • A SessionTokenRefresher background service refreshes access tokens before expiry as long as a refresh token is still valid
  • Cross-tenant calls: one token is bound to one operating tenant (tenant_id claim, strictly enforced by TenantAuthorizationMiddleware in the backends). When a tool call targets another tenant, McpSessionContext.TryGetAccessTokenAsync(server, tenantId) transparently performs an RFC 8693 token exchange via ITenantTokenExchanger (client octo-mcpServices-device, acr_values=tenant:{target}) and caches the result; the switch_tenant tool does the same explicitly. Roles are re-resolved in the target tenant by the Identity Service — see the Tech Guide's Cross-Tenant Authentication
  • The Bot service is not tenant-routed and always receives the home/session token

File transfers

Binary payloads do not flow through JSON-RPC. They use an out-of-band HTTP channel:

  • PUT /file-transfer/upload/{transferId} — body is the file bytes; supports chunked streaming
  • GET /file-transfer/download/{transferId} — streams the file with Content-Disposition and range support

Hard limits:

LimitValue
Maximum file size5 GiB
Reservation / download TTL30 minutes
Storage locationPath.GetTempPath()/octo-mcp-file-transfer/<random>/

A FileTransferSweeper background service purges expired entries and their on-disk files every 5 minutes. Transfer IDs are random 128-bit GUIDs in URL paths; there is no extra auth check on the file-transfer endpoints. For stricter setups, put the server behind your own auth gateway.

Never use base64-in-JSON for file content

The file-transfer endpoints are the only sanctioned mechanism for binary payloads. Embedding base64 in a tool parameter blows up the AI client's token budget and the server's memory, and has no fallback path.

Caching

CacheTTLNotes
CK type graphs30 min (configurable)Per-tenant, hydrated lazily; PreloadModels warms it at startup
Available types per tenantCoupled to the type-graph cacheStale right after an import — verify via get_ck_library_status instead of get_available_models
Tool statisticsIn-memory aggregationSurfaced via get_tool_statistics

Health & monitoring

EndpointPurpose
/healthOverall service health
/health/readyReadiness probe
/health/liveLiveness probe

For runtime usage statistics, call get_tool_statistics:

{ "tool": "get_tool_statistics", "parameters": { "timeRange": "day" } }