Working with an agent

The loop an agent runs through the MCP server to change, test, publish, and deploy a collector configuration.

An agent connected to the MCP server changes a configuration in the same steps you would take with the CLI, one tool call per step, and the server describes these steps in the instructions it gives clients. This page walks through the loop so you can steer the agent and read what it reports.

The edit loop

The agent's edit loop: find, read, edit, validate, push, test, publish, deployREAD-ONLY TOOLSa read-only token can call theseWRITE TOOLSthese need write access1Findlist_configurationspick the configuration2Readget_configuration_versionYAML and its collector pin3Validatevalidate_configurationlint_ottl4Pushpush_configurationreturns version_number5Testrun_pipeline_testin the test sandbox6Publishpublish_configuration_versionor push with publish: true7Deploydeploy_configurationthe published versionEdit the YAMLin the agent's contextno tool callvalid: falsestatus: invalidFail or Errornext stepfix the YAML and retry
Steps 1 to 3 need read access, and the later steps need write access. The return arcs carry findings the agent fixes in the YAML before it tries again.
  1. Find. list_configurations returns the configurations you can see (your own and every published one) with id, published state, latest version_number, and collector pin.
  2. Read. get_configuration_version returns the latest version's YAML and its collector pin.
  3. Validate. The agent edits the YAML in its own context and checks it with validate_configuration, passing configuration_id so the check runs on the pinned collector. After editing a transform, filter, routing, or tail_sampling block, it also runs lint_ottl.
  4. Push. push_configuration saves the YAML as a version and returns its version_number.
  5. Test. run_pipeline_test replays a sample through one pipeline of the stored version and checks the agent's assertions.
  6. Publish. publish_configuration_version, or publish: true on the push.
  7. Deploy. deploy_configuration assigns the published version to a fleet's deploy group.

Three results send the agent back to step 3 with findings to fix: valid: false from validation or lint, status: "invalid" from a push, and a test that ends Fail, or Error when stderr shows the collector rejected the configuration. A result with isError set means the call itself failed, for example on a 401, the rate limit, or an unavailable validator; see Results and errors.

Which collector runs it

Every configuration version is pinned to a collector distribution and version, and a result holds only for the collector it ran on. Validation and pipeline tests use the first match in this order.

  1. collector_version and distribution passed on the call.
  2. The stored configuration's pin. It applies automatically when the call targets the stored configuration: push_configuration, and run_pipeline_test with configuration_id and no yaml. For YAML the agent holds, it applies only when the call also passes configuration_id, and comes from the latest version, or from version when a test passes one.
  3. The server default: OpenTelemetry Collector Contrib at the default collector version.
Which collector runs a validation or test: first match winsWHICH COLLECTOR RUNS A VALIDATION OR TESTFirst match wins · checked top to bottom1Explicit on the callcollector_versiondistributionInputs on validate_configuration and run_pipeline_testOnly otelcol-contrib can be named as a distribution.not set2The stored configuration's pine.g. otelcol-contrib 0.159.0The collector version and distribution the configuration is pinned to.Automaticthe call targets the stored configurationpush_configurationrun_pipeline_teststored versionOnly with configuration_idfor YAML you holdvalidate_configurationrun_pipeline_testwith yamlno pin, or no configuration_id3Server defaultotelcol-contrib at the default versionUsed when nothing above is set.Each input falls through on its ownName only collector_version and the distributionstill comes from the pin or the default.YAML YOU HOLDPass configuration_idwithout it3server defaultwith it2the configuration's pinYAML validated on the default can pass thereand still fail on push or in the fleet.
YAML the agent holds runs on the configuration's pin only when the call passes configuration_id. Without it, the check falls through to the server default.

The two inputs fall through separately, so a call that passes only collector_version still takes the distribution from the pin. YAML validated on the server default can pass there and still fail on push or in the fleet.

The API offers only otelcol-contrib as a distribution you can name. Validating or testing YAML with the configuration_id of a configuration locked to another distribution in the app, such as ClickStack, is refused with Unknown collector distribution, as is a push once its latest version is published; a test of its stored version still runs on its pin. The push returns status: "invalid", which no YAML edit clears; a push onto a draft checks the YAML on OpenTelemetry Collector Contrib at the pinned version.

Push and publish

Latest versionWhat push_configuration doesaction
A draftEdits it in place; the server validates the YAML.patched
PublishedValidates the YAML on that version's pin, then appends a new version labeled with description.appended

A push returns status: "saved", or status: "invalid" with the validator's errors. The agent reads version_number from the result, since a push onto a draft keeps the draft's number. Published versions are immutable, and publishing one again succeeds. A configuration that was never published is visible only to its author, so one the agent creates with a service-account token appears to you and your teammates only once a version is published. See Versions & publishing.

Pipeline tests

run_pipeline_test runs the same pipeline tests as the editor's Testing tab and telflo test: a real collector in a sandbox replays sample_text through one pipeline and evaluates the rules, OTTL assertions over what the pipeline emits. The sandbox strips connectors, removes every pipeline but the target, and does not substitute organization variables, so inline real values.

The sample must match the pipeline's receiver: OTLP JSON for OTLP receivers, raw lines for filelog, and syslog lines for syslog. The call tests a stored version with configuration_id (the latest, or version), or YAML the agent holds with yaml. The whole request must fit the size limit.

Write the rules

Each rule is one OTTL assertion. This example tests a transform processor that replaces user.email with its SHA-256 hash, on ten log records: four with an email address and six without, one of them a health check with the body health check ok.

{
  "configuration_id": "<configuration id>",
  "signal_type": "logs",
  "pipeline": "logs/in",
  "sample_text": "<OTLP JSON with the ten log records>",
  "rules": [
    {
      "name": "total count",
      "context": "log",
      "quantifier": "count",
      "condition": "true",
      "count": { "operator": "eq", "value": 10 }
    },
    {
      "name": "emails hashed",
      "context": "log",
      "quantifier": "count",
      "condition": "IsMatch(attributes[\"user.email\"], \"^[0-9a-f]{64}$\")",
      "count": { "operator": "eq", "value": 4 }
    },
    {
      "name": "health check untouched",
      "context": "log",
      "quantifier": "count",
      "condition": "body == \"health check ok\" and attributes[\"user.email\"] == nil",
      "count": { "operator": "eq", "value": 1 }
    },
    {
      "name": "no raw email left",
      "context": "log",
      "quantifier": "none",
      "condition": "IsMatch(attributes[\"user.email\"], \"@\")"
    }
  ]
}

The first three rules are the controls every test should carry:

  1. Total count. condition: "true" with the count quantifier fixes how many records survive, so a processor that drops records fails the test.
  2. Proof the processor acted. emails hashed asserts the effect, a 64-character hex value, without naming a value from the sample.
  3. Untouched control. A record the processor must not match survives unchanged. Exact values are fine here and for values the configuration hard-codes.

The fourth rule is a leak check. The CLI's authoring rules on quantifiers, tautologies, and regex escaping apply unchanged, and Tools lists every rule field.

Wait for the result

How run_pipeline_test hands off a long runTIME SINCE THE CALL0 s45 s90 sdefault deadlinemaximumAGENT CALLSrun_pipeline_testwait_seconds: 45default 45, at most 90Starts the run in the sandboxand polls it for up to wait_secondsprogress notification, about every 10 s,when the client asks for progressWaits up to 90 sif you raise wait_secondsMany clients time out a call after 60 s.FINISHES INSIDE THE WAITThe same call returns the resultSuccessassertions passedFailassertions failedErrorcollector or sandbox failed: read stderrAll three are results; per-rule detail is in validation_results.STILL RUNNING AT THE DEADLINEThe call returnsRunningwith its id and a next hintget_test_runa few seconds apartuntil status is Success, Fail or Erroronce finishedget_test_run_outputreturns what the target pipeline emittedWhen the rules pass on a stored version, run again with save_rules to save them to that version's Validation tab.
With the default wait, the call returns before the 60-second timeout many clients apply. A longer run keeps going in the sandbox, and the agent picks it up with get_test_run.

run_pipeline_test waits up to wait_seconds (0 to 90, default 45) for the run to finish. A longer run returns status: "Running" with its id, last_status, a next hint, and a poll_error if reading the status failed; the agent passes the id as run_id to get_test_run every few seconds until the status is Success, Fail, or Error. The tool's own polling counts against the rate limit.

Read the results

Fail means the collector ran and an assertion failed; each entry in validation_results reports passed and, on failure, an error_message or a failure_detail with samples and counts. Error means the collector or the sandbox failed, and stderr is the place to look first. A Fail, or an Error whose stderr shows the collector rejected the configuration, sends the agent back to the YAML; stderr that starts with The test was never executed: means the sandbox never ran it, so the agent retries later. get_test_run_output returns what the target pipeline emitted, which shows why a rule did not match; a 404 means the run has not finished or produced no output.

Save rules to the Validation sub-tab

The editor's Testing tab has a Validation sub-tab of saved rules, one set per version and pipeline, which a plain run never changes. Two inputs use it. Both need configuration_id without yaml, and every run's result reports rules_source as saved or inline.

  • save_rules: true saves rules for pipeline, then runs the version's saved set. It replaces only rules saved earlier through the API, keeps rules added by hand in the app, and reports both counts under validation_pipeline. Use it once the assertions pass.
  • use_saved_rules: true runs the rules the version already has. Passing rules as well is refused.

get_validation_rules shows what is saved on a version. A service-account token can save rules onto configurations its service account created or that are published. See Validating output.

Deploy

deploy_configuration assigns a configuration version to a deploy group, which the API and the tools call a deployment (deployment_id, list_deployments). Without version, it deploys the published version and fails when there is none.

SituationWhat happens
deployment_id is givenThat group is updated to this configuration and version.
Exactly one group in the fleet serves the configurationThat group is updated, and name is ignored.
Several serve itAn error lists them; pass deployment_id.
None serves itWith name, a new group is created. Without it, an error asks for name.

name and role apply only when the tool creates a group. To point another existing group at the configuration, pass its deployment_id; to run the configuration in an additional new group alongside the current one, create the group on the fleet's Deploy Groups tab in the app. A new group on a Kubernetes supervisor fleet needs a role of node, cluster, or gateway, which cannot be changed later, and its namespace defaults to telflo-collectors; on a server fleet, leave role out.

Collectors pick up the version on their next check-in, and deploying an earlier published version rolls back. See Update the configuration.

Install collectors

To install into a new fleet, create it with create_fleet as a server fleet (server-supervisor) or a Kubernetes supervisor fleet (kubernetes-supervisor). get_fleet_install_command returns the same command as the app's install dialogs and telflo fleet install.

platformFleet typeReturns
dockerServer fleetA container run command.
linuxServer fleetThe All In One supervisor bundle command, through a Quick Deploy URL valid for 24 hours.
kubernetesKubernetes supervisor fleetA curl for the deploy group's values.yaml, through a URL valid for 24 hours, and the helm command that installs it.

A server fleet installs into its Default deploy group unless deployment_id names another. A Kubernetes supervisor fleet needs a deploy group first, created with deploy_configuration, and needs deployment_id only when it has several.

env sets the variables the configuration reads (names use letters, digits, and _, and do not start with a digit), and env_var_names lists every name the collector expects. A variable left without a value becomes a <value> placeholder in the Docker and Kubernetes commands; the Linux bundle leaves it for you to set on the host. Where the result's notes say --env NAME=value, pass the value in env. The agent should not run the command unless its own machine is the target host. See Install collectors.

The Docker and Linux commands and the result's token field carry the fleet's install token, and the Kubernetes command downloads a values.yaml that holds it, so hand the command to the operator who runs it and see Secrets in transcripts if it leaks.

Start from a flow

  1. list_flows returns the catalog, with the collector each flow was validated on.
  2. get_flow returns one flow's description and yaml.
  3. validate_configuration with that YAML and no configuration_id checks it on the server default, the collector the new configuration will run on.
  4. create_configuration with a name and the YAML creates an unpublished draft, version 1.

create_configuration has no collector pin input, the same gap as telflo config create, so the new configuration runs on OpenTelemetry Collector Contrib at the server's default version, which can differ from the one the flow was validated on. When the flow's version matters, create the configuration with Use this flow in the app, which pins it, and give the agent its name. See Flows.

Example prompts

Each prompt is one line to give the agent, with the tools it typically calls.

PromptTools
Which of our configurations have unpublished drafts, and what collector version is each on?list_configurations
In checkout-gateway, hash user.email in the logs/in pipeline, then validate, push, and test it with a count control, proof it hashed, and an untouched record.list_configurations, get_configuration_version, validate_configuration, lint_ottl, push_configuration, run_pipeline_test
That test passed on version 7, so save its rules to the Validation tab.run_pipeline_test with save_rules
Publish version 7 of checkout-gateway and deploy it to the prod-east fleet.list_configurations, publish_configuration_version, list_fleets, deploy_configuration
Give me the Linux arm64 install command for the edge-hosts fleet, with OTLP_ENDPOINT set to https://otlp.example.com.list_fleets, get_fleet_install_command
Find a flow for tail sampling and start a configuration from it called payments-sampling.list_flows, get_flow, validate_configuration, create_configuration
The test you just ran ended in Error, so read its stderr and output and tell me what broke.get_test_run, get_test_run_output

Last updated on

On this page