Skip to content
ConduitConduit

Log shipping to your SIEM

Conduit keeps an org-scoped audit trail — every tool call and every admin action — for 90 days. Log shipping forwards that trail, as it happens, to the SIEM your security team already watches. Configure it at /org/log-shipping (admin or owner role; requires an active subscription).

Two event sources, each shipped independently with its own cursor so a stalled destination never loses events:

Source One event per Fields
request_log MCP tool call user_id, org_id, vendor_slug, tool_name, status_code, response_time_ms, tool_arguments, response_summary
admin_audit_log Admin action org_id, actor_id, target_id, event_type, metadata

tool_arguments and response_summary are redacted before they are written — see Prompt Capture & Privacy for the exact boundary. Log shipping never widens it.

Events are batched (up to 500 per source) and flushed every 30 seconds. Each send attempt — success or failure — is itself recorded in the admin audit log as log_shipping_send_attempted. Conduit also keeps a per-destination error log (the last 50, pruned on write); fetch the 10 most recent via GET /api/orgs/:orgId/log-shipping/:id (the recentErrors field) — the destination’s card in the dashboard doesn’t display them.

  1. Open /org/log-shipping → Add Destination.
  2. Pick the platform, paste the credentials it asks for (below), and Add.
  3. Click Test on the new card. Conduit sends one synthetic request_log event with message: "MCP Gateway log shipping test". Search for it in your SIEM.

Endpoint URLs must be public HTTPS hosts — Conduit refuses private and link-local addresses and will not follow redirects.

Huntress’s intake is a Splunk-compatible HTTP Event Collector, so nothing to install.

  1. In Huntress: SIEM → Sources → HEC Sources → Add a Generic HEC source. Copy the token.
  2. In Conduit: platform Huntress Managed SIEM, paste the token. The endpoint (https://hec.huntress.io) is prefilled and fixed — Huntress has one HEC host, so Conduit rejects any other endpoint for this platform.

Events arrive with sourcetype conduit:request_log / conduit:admin_audit_log and source conduit.

  1. Settings → Data Inputs → HTTP Event Collector → New Token. Note the token and, if you want one, the target index.
  2. In Conduit: platform Splunk, endpoint is your HEC base URL (e.g. https://http-inputs-<stack>.splunkcloud.com or https://splunk.example.com:8088), paste the token, optionally set Index.

Conduit posts to <endpoint>/services/collector/event with Authorization: Splunk <token>.

  1. Create an API key in Kibana → Stack Management → API keys (or use a username/password). The key needs create_doc and auto_configure on the target data stream.
  2. In Conduit: platform Elasticsearch, endpoint is the Elasticsearch URL (Elastic Cloud: the Elasticsearch endpoint, not Kibana), paste the encoded API key.
  3. Optional Data stream — defaults to logs-conduit-default, which matches Elastic’s built-in logs-*-* index template, so nothing needs setting up to start receiving events (see the note below on when a custom template is worth adding).

Each document carries @timestamp, event.dataset (conduit.request_log / conduit.admin_audit_log), event.id, org_id, and the source fields above.

tool_arguments is arbitrary per-tool JSON, so its shape varies from one tool call to the next. Elastic’s dynamic mapping infers a field’s type from the first document it sees, so if one tool sends tool_arguments.ticketId as a number and another sends it as a string, the second write is rejected as a mapping conflict. Conduit drops a permanently-rejected document — a mapping conflict or a malformed document is rejected identically however many times it is resent — and records the count against the destination, so one bad document cannot stall the rest of the stream. Rejections that resending can fix (Elastic’s per-item 429 back-pressure when the write queue is full, or a 503 while a shard is unavailable) are not dropped: the batch is held and retried on the next flush. If mapping conflicts matter to you, map tool_arguments as a flattened field in a custom index template scoped to your data stream.

Conduit uses the Azure Monitor Logs Ingestion API (the DCR-based API; the legacy HTTP Data Collector API is out of support as of 14 September 2026). One-time Azure setup:

  1. Custom table. In your Log Analytics workspace → Tables → Create → New custom log (DCR-based), name it Conduit (Azure appends _CL). Use this schema:

    Column Type
    TimeGenerated datetime
    source string
    org_id string
    event_id string
    user_id string
    vendor_slug string
    tool_name string
    status_code int
    response_time_ms int
    tool_arguments dynamic
    response_summary string
    actor_id string
    target_id string
    event_type string
    metadata dynamic

    The wizard creates a Data Collection Rule (DCR) and a Data Collection Endpoint (DCE) with a stream named Custom-Conduit_CL. Accept the default source transform.

  2. Entra app. Register an application, create a client secret, and assign the app the Monitoring Metrics Publisher role on the DCR (DCR → Access control (IAM)).

  3. Collect the ingestion endpoint. If your DCR has a DCE — the portal wizard above always creates one — use the DCE’s Logs ingestion URI (https://<dce>.<region>-1.ingest.monitor.azure.com). If instead your DCR was created directly ("kind": "Direct", via CLI/PowerShell/REST/Bicep) on or after 31 March 2024, it has no DCE and needs none: open the DCR in JSON view and use properties.endpoints.logsIngestion.endpoint — same host shape, generated for the DCR itself. Either way, also grab the DCR’s Immutable Id (JSON view), the tenant ID, and the app’s client ID and secret.

  4. In Conduit: platform Microsoft Sentinel, endpoint = whichever logs-ingestion URI you collected above, fill in the four IDs/secret. Leave Stream name blank unless you renamed it. The endpoint must be an *.ingest.monitor.azure.com host — DCE and DCR-native endpoints both match; the Azure sovereign clouds are not supported.

Data appears in Conduit_CL within a few minutes of the first flush. Sentinel analytics rules can then query it like any custom table.

Endpoint is the Loki base URL (Grafana Cloud: https://logs-prod-<region>.grafana.net). Grafana Cloud needs the numeric Username (instance ID) plus an API key as Token; self-hosted Loki with no auth needs neither. Streams are labelled org_id, source, platform=mcp-gateway.

Endpoint is a GELF HTTP input (https://graylog.example.com:12201). Token is optional. One GELF message per event; payload fields are flattened as _-prefixed additional fields.

Endpoint is the LogScale base URL; Ingest Token is required; Repository is optional (omit for the token’s default). Events are tagged host=mcp-gateway, source=<source>.

For any intake that accepts a JSON array over HTTPS — Datadog (https://http-intake.logs.datadoghq.com/api/v2/logs, header DD-API-KEY), Sumo Logic HTTP sources (the source URL, no header), Logstash http input, Cribl, or your own collector.

Set the endpoint verbatim and, if the intake needs one, an Auth header name and value (e.g. Authorization / Bearer …). Conduit POSTs [{ id, timestamp, source, org_id, ...fields }] with Content-Type: application/json — that media type is fixed, so Content-Type is not usable as the auth header name.