Skip to main content
Glama
nh4ttruong

secobserve-mcp

Import File Into SecObserve

secobserve_upload_file

Import local scanner reports, SBOMs, or VEX documents into SecObserve to deduplicate findings, apply rules, and resolve disappeared issues.

Instructions

Import a local scanner report, SBOM or VEX document into SecObserve.

This is the correct way to get findings in: the import deduplicates against existing observations, applies rules, resolves findings that disappeared from the report, and records a vulnerability check. Creating observations by hand with secobserve_create does none of that.

The file must live under the server's import directory (SECOBSERVE_IMPORT_DIR, the working directory by default) and be at most 64 MiB.

Args: kind (str): "observations", "sbom" or "vex". file_path (str): Path to the report, absolute or relative to the import directory. product_id (Optional[int]) / product_name (Optional[str]): exactly one, ignored for kind="vex" which matches on the document's own product data. branch_id (Optional[int]) with product_id, or branch_name (Optional[str]) with product_name; a named branch is created if missing. service (Optional[str]): Service to attach findings to. suppress_licenses (Optional[bool]): kind="observations" only. docker_image_name_tag / endpoint_url / kubernetes_cluster / kubernetes_namespace (Optional[str]): origin metadata recorded on each finding.

Returns: str: The import counts as reported by the API, one per line -- for "observations": observations_new, observations_updated, observations_resolved plus license_components_new/updated/deleted; for "sbom": the license_components_* counts; for "vex": the API's summary.

Examples: - Use when: "import trivy-results.json into product 12, branch main" -> kind="observations", file_path="trivy-results.json", product_id=12, branch_id=3 - Use when: "load this SBOM for the release branch" -> kind="sbom", file_path="sbom.cdx.json", product_name="Portal", branch_name="release-2.1" - Use when: "apply the vendor's VEX" -> kind="vex", file_path="vendor.openvex.json" - Don't use when: the data is behind an API you have configured in SecObserve (use secobserve_api_import).

Error Handling: A path outside the import directory, a missing, empty or oversized file is refused before any request is made. 400 usually means the parser could not read the format -- check the product's expected parser with secobserve_list(resource="parsers"). Read-only mode blocks the call.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
kindYes'observations' = a scanner report (Trivy, Grype, Semgrep, ZAP, ...); 'sbom' = a CycloneDX or SPDX SBOM, which creates license components; 'vex' = a third-party VEX document whose statements assess existing observations.
serviceNoService name to attach the findings to.
branch_idNoTarget branch by id, with product_id.
file_pathYesPath to the file, absolute or relative to the server's import directory.
product_idNoTarget product by id. Give this or product_name.
branch_nameNoTarget branch by name; created if missing. Use with product_name.
endpoint_urlNoOrigin metadata: the scanned URL, for DAST reports.
product_nameNoTarget product by exact name. The by-name endpoints can create the branch on the fly.
suppress_licensesNoFor kind='observations': skip license component extraction from the report.
kubernetes_clusterNoOrigin metadata: cluster.
kubernetes_namespaceNoOrigin metadata: namespace.
docker_image_name_tagNoOrigin metadata: the scanned image, e.g. 'registry/app:1.2.3'.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed16 schema fields changedv0.3.0
    • removedInput schema / $defs
      Removed value: -{
      -  "UploadInput": {
      -    "additionalProperties": false,
      -    "description": "Input model for importing a local scan report, SBOM or VEX document.",
      -    "properties": {
      -      "branch_id": {
      -        "anyOf": [
      -          {
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Target branch by id, with product_id.",
      -        "title": "Branch Id"
      -      },
      -      "branch_name": {
      -        "anyOf": [
      -          {
      -            "maxLength": 255,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Target branch by name; created if missing. Use with product_name.",
      -        "title": "Branch Name"
      -      },
      -      "docker_image_name_tag": {
      -        "anyOf": [
      -          {
      -            "maxLength": 513,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Origin metadata: the scanned image, e.g. 'registry/app:1.2.3'.",
      -        "title": "Docker Image Name Tag"
      -      },
      -      "endpoint_url": {
      -        "anyOf": [
      -          {
      -            "maxLength": 2048,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Origin metadata: the scanned URL, for DAST reports.",
      -        "title": "Endpoint Url"
      -      },
      -      "file_path": {
      -        "description": "Path to the file, absolute or relative to the server's import directory.",
      -        "minLength": 1,
      -        "title": "File Path",
      -        "type": "string"
      -      },
      -      "kind": {
      -        "description": "'observations' = a scanner report (Trivy, Grype, Semgrep, ZAP, ...); 'sbom' = a CycloneDX or SPDX SBOM, which creates license components; 'vex' = a third-party VEX document whose statements assess existing observations.",
      -        "enum": [
      -          "observations",
      -          "sbom",
      -          "vex"
      -        ],
      -        "title": "Kind",
      -        "type": "string"
      -      },
      -      "kubernetes_cluster": {
      -        "anyOf": [
      -          {
      -            "maxLength": 255,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Origin metadata: cluster.",
      -        "title": "Kubernetes Cluster"
      -      },
      -      "kubernetes_namespace": {
      -        "anyOf": [
      -          {
      -            "maxLength": 255,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Origin metadata: namespace.",
      -        "title": "Kubernetes Namespace"
      -      },
      -      "product_id": {
      -        "anyOf": [
      -          {
      -            "minimum": 1,
      -            "type": "integer"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Target product by id. Give this or product_name.",
      -        "title": "Product Id"
      -      },
      -      "product_name": {
      -        "anyOf": [
      -          {
      -            "maxLength": 255,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Target product by exact name. The by-name endpoints can create the branch on the fly.",
      -        "title": "Product Name"
      -      },
      -      "service": {
      -        "anyOf": [
      -          {
      -            "maxLength": 255,
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "Service name to attach the findings to.",
      -        "title": "Service"
      -      },
      -      "suppress_licenses": {
      -        "anyOf": [
      -          {
      -            "type": "boolean"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "default": null,
      -        "description": "For kind='observations': skip license component extraction from the report.",
      -        "title": "Suppress Licenses"
      -      }
      -    },
      -    "required": [
      -      "kind",
      -      "file_path"
      -    ],
      -    "title": "UploadInput",
      -    "type": "object"
      -  }
      -}
    • addedInput schema / additionalProperties
      Added value: +false
    • addedInput schema / properties / branch_id
      Added value: +{
      +  "anyOf": [
      +    {
      +      "minimum": 1,
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Target branch by id, with product_id.",
      +  "title": "Branch Id"
      +}
    • addedInput schema / properties / branch_name
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 255,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Target branch by name; created if missing. Use with product_name.",
      +  "title": "Branch Name"
      +}
    • addedInput schema / properties / docker_image_name_tag
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 513,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Origin metadata: the scanned image, e.g. 'registry/app:1.2.3'.",
      +  "title": "Docker Image Name Tag"
      +}
    • addedInput schema / properties / endpoint_url
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 2048,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Origin metadata: the scanned URL, for DAST reports.",
      +  "title": "Endpoint Url"
      +}
    • addedInput schema / properties / file_path
      Added value: +{
      +  "description": "Path to the file, absolute or relative to the server's import directory.",
      +  "minLength": 1,
      +  "title": "File Path",
      +  "type": "string"
      +}
    • addedInput schema / properties / kind
      Added value: +{
      +  "description": "'observations' = a scanner report (Trivy, Grype, Semgrep, ZAP, ...); 'sbom' = a CycloneDX or SPDX SBOM, which creates license components; 'vex' = a third-party VEX document whose statements assess existing observations.",
      +  "enum": [
      +    "observations",
      +    "sbom",
      +    "vex"
      +  ],
      +  "title": "Kind",
      +  "type": "string"
      +}
    • addedInput schema / properties / kubernetes_cluster
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 255,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Origin metadata: cluster.",
      +  "title": "Kubernetes Cluster"
      +}
    • addedInput schema / properties / kubernetes_namespace
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 255,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Origin metadata: namespace.",
      +  "title": "Kubernetes Namespace"
      +}
    • removedInput schema / properties / params
      Removed value: -{
      -  "$ref": "#/$defs/UploadInput"
      -}
    • addedInput schema / properties / product_id
      Added value: +{
      +  "anyOf": [
      +    {
      +      "minimum": 1,
      +      "type": "integer"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Target product by id. Give this or product_name.",
      +  "title": "Product Id"
      +}
    • addedInput schema / properties / product_name
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 255,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Target product by exact name. The by-name endpoints can create the branch on the fly.",
      +  "title": "Product Name"
      +}
    • addedInput schema / properties / service
      Added value: +{
      +  "anyOf": [
      +    {
      +      "maxLength": 255,
      +      "type": "string"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "Service name to attach the findings to.",
      +  "title": "Service"
      +}
    • addedInput schema / properties / suppress_licenses
      Added value: +{
      +  "anyOf": [
      +    {
      +      "type": "boolean"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ],
      +  "default": null,
      +  "description": "For kind='observations': skip license component extraction from the report.",
      +  "title": "Suppress Licenses"
      +}
    • changedInput schema / required
      Previous value: -[
      -  "params"
      -]New value: +[
      +  "kind",
      +  "file_path"
      +]
  2. First observedv0.1.2

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations, which only provide hints about read-only, open-world, idempotency, and destructiveness. It discloses important behaviors: import deduplicates, applies rules, resolves disappeared findings, records vulnerability checks, creates branches if missing, ignores product selectors for VEX, and is blocked by read-only mode. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but well-structured with clear sections: opening summary, behavioral rationale, Args, Returns, Examples, and Error Handling. Every part adds value, and the most important guidance is front-loaded in the first few sentences. This level of detail is appropriate for a 12-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description fully equips an agent to invoke the tool correctly: it covers parameter relationships, file size and path constraints, return values for each kind, common error causes, and how to recover from a 400. Given the complexity of the tool and the rich schema, nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Even though the input schema has 100% parameter coverage, the description adds critical relational semantics: exactly one of product_id/product_name must be provided, branch_id pairs with product_id, branch_name pairs with product_name, branches are created if missing, suppress_licenses applies only to kind=observations, and origin metadata fields are described. This resolves ambiguity that the schema alone cannot.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Import a local scanner report, SBOM or VEX document into SecObserve.' It clearly differentiates from secobserve_api_import and secobserve_create by explaining why this import path is the correct one for local files.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states when to use this tool, including concrete examples ('Use when: import trivy-results.json...'), and when not to use it: 'Don't use when: the data is behind an API... (use secobserve_api_import).' It also contrasts with secobserve_create, which does not deduplicate or apply rules.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.