Skip to content

MCP Ingresses ​

An MCP ingress is an ingress with type: mcp. It exposes one compiled Reactor component as a typed tool on Hantera's shared MCP server at /mcp.

An MCP ingress is a logical endpoint rather than a separate URL:

text
MCP client
  → POST /mcp (tools/call)
  → MCP ingress selected by generated tool name
  → Reactor component invoked with typed arguments
  → component result returned as MCP tool content

Use MCP ingresses to make deliberate business capabilities available to an agent. The component remains reusable by jobs, rules, HTTP ingresses, and other app logic; only the MCP ingress exposes it as a tool.

Define an MCP ingress ​

An MCP ingress can be declared by an app or managed directly as a tenant resource.

Declare the ingress in h_app.yaml:

yaml
id: reports
name: Reports
components:
  - id: reports/revenue-summary.hrc
ingresses:
  - id: revenue-summary
    componentId: reports/revenue-summary.hrc
    type: mcp
    properties:
      title: Revenue summary
      description: Summarize revenue for a date range and optional sales channel.
    execution:
      authority: acl
      acl:
        - graph/order:query
        - graph/order:field:createdAt
        - graph/order:field:status
        - graph/order:field:orderTotal
        - graph/order:field:currencyCode

After installing or activating the app in development mode, this ingress is available to authorized MCP clients as apps_reports_revenue_summary.

All ingress reads return the canonical execution object. For compatibility, a direct ingress API write may use the legacy root-level acl field instead; do not send both acl and execution in the same request.

Tool name and presentation ​

Tool names are deterministic and cannot be configured. Every character outside a-z, A-Z, 0-9, and _ becomes _.

Ingress originIngress IDGenerated MCP tool name
Appapps/reports/revenue-summaryapps_reports_revenue_summary
Tenant resourcereports/revenue-summarytool_reports_revenue_summary

Tool names are limited to 64 characters. The system_ prefix is reserved for Hantera's built-in tools and cannot be used by an ingress.

properties.title and properties.description control how the tool is presented to MCP clients:

FieldLimitFallback
title64 charactersComponent display name, then component ID
description4096 charactersComponent description, then Invokes the '<ingress id>' ingress.

Configured blank or overlong values are rejected; omit a field to use its fallback.

Authorization and execution authority ​

Two independent decisions protect an MCP ingress:

  1. Can the MCP caller invoke this ingress? The session needs mcp/tools/ingress/{ingressId}:call. mcp/tools/ingress:call grants access to all ingress tools; mcp/tools:call covers both ingress and built-in tools.
  2. Which permissions does the component receive while it runs? execution selects the component's effective authority.
yaml
execution:
  authority: acl | caller | restricted-caller
  acl: []
AuthorityComponent authorityACL requirement
aclExactly the ingress ACLOptional; an omitted ACL is empty. This is the default.
callerExactly the caller's effective authorityMust be absent.
restricted-callerCaller authority intersected with the ingress ACLRequired and non-empty.

acl is the safest default: a caller can invoke the tool but does not automatically pass all its authority into the component. Use caller only for a deliberately user-scoped tool. Use restricted-caller when the component must remain inside both the caller's authority and a defined data-access ceiling.

See Execution Authority for the shared ingress model, legacy ACL compatibility, and transport restrictions.

yaml
execution:
  authority: restricted-caller
  acl:
    - graph/order:query
    - graph/order:field:createdAt
    - graph/order:field:orderTotal

This ingress runs with caller authority ∩ ingress ACL.

Component contract ​

The MCP server derives an input schema from the Reactor component's param declarations and an output schema from its result. Required parameters are parameters without defaults.

Supported input and result shapes include text, number, boolean, UUID, instant, date, lists, records, maps, and compatible unions. A nothing union branch maps to JSON null.

MCP tool arguments are JSON objects, so tuple parameters are not supported. Durations, functions, inferred/intersection types, and component contracts deeper than 32 schema levels are also rejected. Streaming results are unsupported in the current version.

Tool structured output is always an object:

  • Record and map results are returned directly.
  • Other scalar or list results are wrapped as { "result": ... }.
  • Multiple from values are returned as an array under result.

An ingress with an invalid component target or non-representable contract is hidden from MCP discovery until it is corrected.

Open a Portal view from an MCP tool ​

Set properties.portal: true to attach Hantera's reusable Portal MCP App to an ingress tool. The attachment lets MCP hosts that support Apps render a Portal view after a successful tool call.

yaml
properties:
  title: Search orders
  description: Search orders and open the matching list in Portal.
  portal: true

portal is presentation metadata only. It does not change the ingress's generated name, call authorization, execution authority, input schema, or result schema. The tool must still return useful structured content and text fallback for MCP clients that do not support Apps.

Choose the Portal destination in the result ​

Enabling the Portal App does not select a destination by itself. The Reactor component chooses the view for each successful call by returning a portal descriptor:

filtrera
param phrase: text

from {
  phrase = phrase
  portal = {
    viewPath = '/sales/orders'
    query = { phrase = phrase }
  }
}
FieldRequiredDescription
portal.viewPathYesAn internal Portal route, such as /sales/orders, /order, or an installed app view. It must be a single-slash relative path: no URI scheme, ?, #, or //.
portal.queryNoA map whose keys and values become URL query parameters. Values are stringified and URL-encoded.

A missing or invalid descriptor does not make the tool invocation fail; an Apps-capable host shows no actionable Portal destination. A missing view or unavailable app view is handled as ordinary Portal navigation.

Security boundary ​

The Portal App is navigation, not a data channel. The MCP bearer token is never passed to the Portal. The standalone Portal host performs its own sign-in flow, and the view loads data using the signed-in Portal user's normal session permissions. Setting portal: true never grants the MCP caller or Portal user additional access.

Collisions and visibility ​

Two MCP ingresses must not expose the same generated name.

  • Two colliding MCP ingresses in one app manifest block app installation and development activation.
  • A collision across active resources — for example, across apps or tenant-managed ingresses — does not block configuration.
  • In an active-set collision, Hantera hides every conflicting tool. It never picks a winner.
  • Each conflicting ingress emits a warning signal at ingresses/{id}/tool.

Unauthorized, inactive, invalid, and colliding tools are all absent from tools/list. An attempt to call one is intentionally indistinguishable from calling an unknown tool.

Verify an ingress ​

  1. Install the app or create the tenant ingress.
  2. Authorize an MCP client with mcp/tools/ingress:call or mcp/tools:call, or grant the exact mcp/tools/ingress/{ingressId}:call permission.
  3. Reconnect the client after role or scope changes.
  4. Run tools/list and find the generated name.
  5. Invoke it with tools/call and an arguments object matching the component parameters.

© 2026 Hantera AB. Org. no.: 559242-9582