Agent access security

How Scipio 4.0 secures agent access through MCP: the token model, permissions, policy, audit, and expiry.

This page describes how Scipio 4.0 secures agent access through MCP, and what an operator must do before and during production use. Read Agent quickstart for the setup steps.

Principles#

  • A token is a user login. An agent has exactly the permissions of that user. No permission comes from the token itself.
  • Default deny. A call passes only when every gate in the policy engine allows it.
  • One rule for every endpoint. The hub and the application endpoints apply the same policy.
  • Everything is audited. Every tool call, denied or not, writes one McpAuditLog row.
  • Executable code is a separate permission. CMS templates and scripts need MCP_CODE_WRITE.

Permissions and groups#

PermissionGrants
MCP_ACCESSUse any MCP endpoint. Required for every token user.
MCP_GATEWAYCall any service through scipio_service with action call (still subject to the policy engine).
MCP_ENTITY_READRead entities outside a server’s allowlist through scipio_entity with action find.
MANUFACTURING_FLOORDeclare, scan, start and complete production run tasks without MANUFACTURING_UPDATE.
MCP_MAIL_SENDSend a mail from a template through mail_send_template. Granted to FULLADMIN.
MCP_ENTITY_WRITEWrite entities through the entity tools (also needs ENTITY_MAINT).
MCP_ADMINManage tokens of any user, view the audit log, reload the registry, run services of components without a webapp.
MCP_CODE_WRITEWrite CMS FreeMarker templates, Groovy scripts and asset templates. Remote code execution by design.

Seed groups:

  • SCIPIO_AGENT (user scp-agent): MCP_ACCESS, MCP_GATEWAY, OFBTOOLS_VIEW, CMS_VIEW and _VIEW on every main application. Read-only by default.
  • SCIPIO_CUSTOMER_AGENT: MCP_ACCESS only. For shop customers who use an assistant on /shop/mcp.
  • SCIPIO_FLOOR: MCP_ACCESS, OFBTOOLS_VIEW, MANUFACTURING_VIEW and MANUFACTURING_FLOOR. For shop floor device tokens, which declare, scan, start and complete production run tasks and write nothing else.
  • FULLADMIN: every MCP_* permission, including MCP_CODE_WRITE.

Give an agent a dedicated user per purpose. Grant _UPDATE only for the applications the agent must change. Do not reuse a human administrator’s login.

The policy engine#

McpPolicy decides every call in this order. The first failing gate denies the call.

  1. Server access: token allowed for the webapp, user holds MCP_ACCESS, user holds every base permission of the webapp at _VIEW (for example OFBTOOLS_VIEW and ORDERMGR_VIEW). The hub needs MCP_ADMIN or OFBTOOLS_VIEW.
  2. Tool access: a read-only token may call read-only tools only. A tool’s permission attribute is checked when set.
  3. Service deny lists: mcp.service.deny (global), the server’s serviceDeny, and mcp.service.adminOnly (needs MCP_ADMIN).
  4. Gateway permission: a direct service call needs MCP_GATEWAY.
  5. Read-only classification: an entity-auto create, update, delete or expire is a write. A tool’s own readOnly flag never widens a write service into a read.
  6. Service permissions: a service that declares permissions or permissionService enforces them itself.
  7. Component rule: an unguarded service needs the base permission of the component that owns the service: _VIEW for a read, _UPDATE for a write, on every webapp base except the generic OFBTOOLS. A component without a webapp needs MCP_ADMIN, except the components listed in mcp.gateway.openComponents (default common), which use the endpoint’s base permission.

Hand-written tools on a webapp without a base permission (the shop) are allowed only on a server with allowAnonymous=true; every other permission-less webapp fails closed.

Tokens#

  • Format scp_<id>_<secret>_<crc>. Only the SHA-256 hash is stored. The secret is shown once.
  • Expiry: default mcp.token.defaultExpiryDays (90), maximum mcp.token.maxExpiryDays (365). A token without an expiry date is rejected unless mcp.token.allowNoExpiry=true.
  • mcp.token.denyUsers (default system,anonymous) can never own or use a token.
  • webapps limits a token to a list of endpoints. readOnly=Y blocks every write tool.
  • remoteAddrAllow limits a token to addresses or CIDR blocks.
  • maxOrderAmount caps the total of an order placed through shop_cart:checkout or order:create.
  • Revoke a token on Webtools > Agent Access > Tokens. Revocation is immediate.

Transport and input limits#

  • HTTPS is required. X-Forwarded-Proto is honoured only from mcp.trustedProxies.
  • Origin must be in mcp.origin.allow (default: no browser origin passes). Host may be limited with mcp.host.allow.
  • Body at most mcp.request.maxBytes (1 MB), JSON nesting at most 64, batch at most 20 requests, string 64 KB, array 1000 items, list limit 500, result 200 000 characters.
  • Rate limits: mcp.rateLimit.perMinute per token, anonymousPerMinute per address, failedAuthPerMinute per address, maxConcurrent slots per token.

Data protection#

  • mcp.entity.deny: UserLogin*, *Password*, *CreditCard*, *EftAccount*, *PaymentGatewayConfig*, *Secret*, Mcp*, Security*, SystemProperty, Tenant*, *Keystore*, X509*, JobSandbox*. These tables are never readable or writable through the entity tools, for any user.
  • mcp.redact.fields and mcp.redact.patterns mask sensitive values in results, argument echoes and audit rows. A protected field may not be used in a condition, a selection or an ordering of scipio_entity with action find; this closes the value-guessing side channel.
  • Audit rows store redacted arguments, a bounded result (mcp.audit.resultMaxChars) for idempotent replay, and a REPLAY status when a stored result is returned.

Operations checklist#

Before production:

  1. mcp.allowInsecure=false; mcp.trustedProxies set when a proxy terminates TLS.
  2. DevAuthEvent (developer auto-login) removed or gated; see the release checklist.
  3. The smoke token and every test token revoked; scp-agent given only the groups you need.
  4. mcp.gateway.allowUnguarded reviewed. Set it to false to allow only services that declare their own permissions and the tools that profiles declare explicitly.
  5. mcp.tool.disable set for tools you do not want, for example scipio_entity with action store.
  6. Run tools/mcp-test.sh -t <admin> -a <scp-agent> security skills and confirm 0 failures.

During operation:

  • Review Webtools > Agent Access > Audit daily. Filter by DENIED to see blocked attempts.
  • Rotate tokens before they expire: create a new one, update the client, revoke the old one.
  • After a change to a profile, an extension or a skill, click “Reload agent registry”.

Incident response:

  1. Revoke the token (Tokens page). The next request fails with 401.
  2. Disable the user login when the account itself is suspect.
  3. Read the audit rows of the token: tokenId, toolName, argsSummary, remoteAddr.
  4. Undo data changes with the normal application tools; the audit row names the service.

Known limits in 4.0#

  • No OAuth. Bearer tokens only.
  • No server-initiated push (SSE) and no elicitation. Confirmation is a client-side hint (_meta.requiresConfirmation).
  • Rate limits are per JVM, not per cluster.
  • An agent that reads business data can still be misled by adversarial text inside that data. The skills tell the agent to treat returned data as data, not instructions; the client must enforce it.

Ask the people who wrote it.

Support, development and training from the team that builds Scipio ERP.