Skip to main content
Glama

Devops Check Certs

devops_check_certs
Read-onlyIdempotent

Inspect SSL/TLS certificate health for one or more domains by performing a real TLS handshake. Works for any internet-accessible domain — no vendor registry required. Reports days to expiry (flagged at < 30 days warning and < 7 days critical), certificate subject and SANs, issuer, hostname coverage, chain-trust verification, TLS protocol version negotiated (flags TLS 1.0/1.1 as insecure), cipher suite, and HSTS presence. The handshake completes even for a certificate clients would reject, so a broken certificate is reported rather than hidden behind a connection error: a hostname mismatch surfaces in cert.hostname_verification_error and a chain-trust failure (self-signed, untrusted root) in cert.authorization_error, both status "critical". If a domain fails to connect at all, check devops_check_dns first — the name may not resolve.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
portNoTLS port. Defaults to 443. Use 8443 or custom ports for non-standard HTTPS endpoints.
domainsYesDomains to inspect. Do not include "https://" — pass the bare hostname. Up to 10 per call.
timeout_msNoConnection timeout per domain in milliseconds. Defaults to the DEVOPS_STATUS_CERT_TIMEOUT_MS env var (5000 when unset). Increase for slow or geographically distant endpoints.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
resultsNoPer-domain certificate inspection results.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema fields changed
    • changedOutput schema / properties / results / items / properties / cert / description
      Previous value: -"Certificate details, or null when connection failed (error status)."New value: +"Certificate details, or null when no certificate was retrieved (status \"error\")."
    • changedOutput schema / properties / results / items / properties / error / description
      Previous value: -"Connection error message when status is \"error\"."New value: +"Why status is \"error\". Either no handshake completed — the domain was rejected as a private, loopback, or cloud-metadata target, a connection failure such as \"getaddrinfo ENOTFOUND …\", or \"Timed out after 5000ms\" — with cert and tls null and flags empty; or the handshake completed but the server presented no certificate, with cert null and the TLS session still reported in tls and flags. Null for every other status."
    • changedOutput schema / properties / results / items / properties / flags / description
      Previous value: -"Human-readable warnings and issues found: \"Expires in 12 days (warning)\", \"Certificate expired 40 days ago\", \"Hostname mismatch — the certificate does not cover api.example.com; clients will reject it\", \"Certificate chain not trusted (SELF_SIGNED_CERT_IN_CHAIN); clients will reject it\", \"Self-signed certificate\", \"Insecure TLS version in use: TLSv1.1\", \"HSTS present\" / \"HSTS not configured\"."New value: +"Human-readable findings about the certificate and TLS session that were read: \"Expires in 12 days (warning)\", \"Certificate expired 40 days ago\", \"Hostname mismatch — the certificate does not cover api.example.com; clients will reject it\", \"Certificate chain not trusted (SELF_SIGNED_CERT_IN_CHAIN); clients will reject it\", \"Self-signed certificate\", \"Insecure TLS version in use: TLSv1.1\", \"HSTS present\" / \"HSTS not configured\". Empty when the connection never completed a handshake (rejected target, connection failure, or timeout) — the reason is in \"error\" only. A handshake that completed without a certificate keeps its TLS-session findings here alongside \"error\"."
    • changedOutput schema / properties / results / items / properties / status / description
      Previous value: -"Overall status. \"critical\" — the certificate expires in < 7 days or has already expired, the hostname is not covered by the certificate, chain verification failed (self-signed or untrusted root), or an insecure TLS version was negotiated; every one of these is rejected by ordinary clients. \"warning\" — expires in < 30 days. \"ok\" — none of the above. \"error\" — the connection failed and no certificate was retrieved."New value: +"Overall status. \"critical\" — the certificate expires in < 7 days or has already expired, the hostname is not covered by the certificate, chain verification failed (self-signed or untrusted root), or an insecure TLS version was negotiated; every one of these is rejected by ordinary clients. \"warning\" — expires in < 30 days. \"ok\" — none of the above. \"error\" — no certificate was retrieved: the domain was rejected, the connection failed or timed out, or the server presented no certificate; the reason is in \"error\"."
    • changedOutput schema / properties / results / items / properties / tls / description
      Previous value: -"TLS session details, or null when connection failed."New value: +"TLS session details, or null when no TLS handshake completed."
  2. Changed3 schema fields changed
    • changedOutput schema / properties / results / items / properties / cert / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "authorization_error": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "OpenSSL chain-verification code when the certificate chain does not validate against the system trust store, or null when it validates. Common values: \"DEPTH_ZERO_SELF_SIGNED_CERT\" (self-signed leaf), \"SELF_SIGNED_CERT_IN_CHAIN\" / \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\" (issuing root not trusted), \"CERT_HAS_EXPIRED\" (also reported in \"days_until_expiry\"). This is the authoritative chain-trust signal — the issuer and subject fields alone cannot detect an untrusted root."
      -      },
      -      "chain_depth": {
      -        "anyOf": [
      -          {
      -            "maximum": 9007199254740991,
      -            "minimum": -9007199254740991,
      -            "type": "integer"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Number of certificates the server sent, counting the leaf. Null when the runtime does not expose the issuer chain — read \"chain_depth_unavailable_reason\" in that case. Not a self-signed indicator: use \"authorization_error\" for that."
      -      },
      -      "chain_depth_unavailable_reason": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Why \"chain_depth\" is null, or null when a depth was measured. Absence of a depth is a runtime limitation, not a finding about the certificate."
      -      },
      -      "days_until_expiry": {
      -        "description": "Days remaining until certificate expiry. Negative = already expired.",
      -        "maximum": 9007199254740991,
      -        "minimum": -9007199254740991,
      -        "type": "integer"
      -      },
      -      "hostname_verification_error": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Node's hostname-verification message when the requested domain is not covered by the certificate's CN or SANs (e.g. \"Hostname/IP does not match certificate's altnames: …\"), or null when the hostname is covered. A non-null value means ordinary clients reject this certificate for this hostname; compare against the \"san\" list to see what it does cover."
      -      },
      -      "issuer": {
      -        "description": "Issuer common name.",
      -        "type": "string"
      -      },
      -      "san": {
      -        "description": "Subject Alternative Names covered by this certificate.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "serial": {
      -        "description": "Certificate serial number.",
      -        "type": "string"
      -      },
      -      "subject": {
      -        "description": "Certificate subject CN.",
      -        "type": "string"
      -      },
      -      "valid_from": {
      -        "description": "ISO 8601 UTC timestamp of certificate validity start.",
      -        "type": "string"
      -      },
      -      "valid_until": {
      -        "description": "ISO 8601 UTC timestamp of certificate expiry.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "subject",
      -      "san",
      -      "issuer",
      -      "valid_from",
      -      "valid_until",
      -      "days_until_expiry",
      -      "chain_depth",
      -      "chain_depth_unavailable_reason",
      -      "hostname_verification_error",
      -      "authorization_error",
      -      "serial"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "authorization_error": {
      +        "description": "OpenSSL chain-verification code when the certificate chain does not validate against the system trust store, or null when it validates. Common values: \"DEPTH_ZERO_SELF_SIGNED_CERT\" (self-signed leaf), \"SELF_SIGNED_CERT_IN_CHAIN\" / \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\" (issuing root not trusted), \"CERT_HAS_EXPIRED\" (also reported in \"days_until_expiry\"). This is the authoritative chain-trust signal — the issuer and subject fields alone cannot detect an untrusted root.",
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "chain_depth": {
      +        "anyOf": [
      +          {
      +            "maximum": 9007199254740991,
      +            "minimum": -9007199254740991,
      +            "type": "integer"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Number of certificates the server sent, counting the leaf. Null when the runtime does not expose the issuer chain — read \"chain_depth_unavailable_reason\" in that case. Not a self-signed indicator: use \"authorization_error\" for that."
      +      },
      +      "chain_depth_unavailable_reason": {
      +        "description": "Why \"chain_depth\" is null, or null when a depth was measured. Absence of a depth is a runtime limitation, not a finding about the certificate.",
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "days_until_expiry": {
      +        "description": "Days remaining until certificate expiry. Negative = already expired.",
      +        "maximum": 9007199254740991,
      +        "minimum": -9007199254740991,
      +        "type": "integer"
      +      },
      +      "hostname_verification_error": {
      +        "description": "Node's hostname-verification message when the requested domain is not covered by the certificate's CN or SANs (e.g. \"Hostname/IP does not match certificate's altnames: …\"), or null when the hostname is covered. A non-null value means ordinary clients reject this certificate for this hostname; compare against the \"san\" list to see what it does cover.",
      +        "type": [
      +          "string",
      +          "null"
      +        ]
      +      },
      +      "issuer": {
      +        "description": "Issuer common name.",
      +        "type": "string"
      +      },
      +      "san": {
      +        "description": "Subject Alternative Names covered by this certificate.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "serial": {
      +        "description": "Certificate serial number.",
      +        "type": "string"
      +      },
      +      "subject": {
      +        "description": "Certificate subject CN.",
      +        "type": "string"
      +      },
      +      "valid_from": {
      +        "description": "ISO 8601 UTC timestamp of certificate validity start.",
      +        "type": "string"
      +      },
      +      "valid_until": {
      +        "description": "ISO 8601 UTC timestamp of certificate expiry.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "subject",
      +      "san",
      +      "issuer",
      +      "valid_from",
      +      "valid_until",
      +      "days_until_expiry",
      +      "chain_depth",
      +      "chain_depth_unavailable_reason",
      +      "hostname_verification_error",
      +      "authorization_error",
      +      "serial"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • removedOutput schema / properties / results / items / properties / error / anyOf
      Removed value: -[
      -  {
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]
    • addedOutput schema / properties / results / items / properties / error / type
      Added value: +[
      +  "string",
      +  "null"
      +]
  3. Changed6 schema fields changed
    • changedInput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedInput schema / additionalProperties
      Added value: +false
    • changedOutput schema / $schema
      Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • addedOutput schema / anyOf
      Added value: +[
      +  {
      +    "not": {
      +      "required": [
      +        "error"
      +      ]
      +    },
      +    "required": [
      +      "results"
      +    ]
      +  },
      +  {
      +    "required": [
      +      "error"
      +    ]
      +  }
      +]
    • addedOutput schema / properties / error
      Added value: +{
      +  "additionalProperties": {},
      +  "description": "Present when the call failed. Absent on success.",
      +  "properties": {
      +    "code": {
      +      "description": "JSON-RPC error code for this failure.",
      +      "maximum": 9007199254740991,
      +      "minimum": -9007199254740991,
      +      "type": "integer"
      +    },
      +    "data": {
      +      "additionalProperties": {},
      +      "properties": {
      +        "reason": {
      +          "description": "Machine-readable failure mode. Declared by this tool: `invalid_domain`: A domain string contains a protocol prefix or invalid characters. Other values are possible when a failure originates below the handler.",
      +          "examples": [
      +            "invalid_domain"
      +          ],
      +          "type": "string"
      +        },
      +        "recovery": {
      +          "additionalProperties": {},
      +          "description": "Actionable next step for the caller.",
      +          "properties": {
      +            "hint": {
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "hint"
      +          ],
      +          "type": "object"
      +        },
      +        "retryable": {
      +          "description": "Whether retrying may succeed.",
      +          "type": "boolean"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "message": {
      +      "description": "Human-readable description of what went wrong.",
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "code",
      +    "message"
      +  ],
      +  "type": "object"
      +}
    • removedOutput schema / required
      Removed value: -[
      -  "results"
      -]
  4. Changed3 schema fields changed
    • changedOutput schema / properties / results / items / properties / cert / anyOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "chain_depth": {
      -        "description": "Number of certificates in the chain (1 = self-signed).",
      -        "maximum": 9007199254740991,
      -        "minimum": -9007199254740991,
      -        "type": "integer"
      -      },
      -      "days_until_expiry": {
      -        "description": "Days remaining until certificate expiry. Negative = already expired.",
      -        "maximum": 9007199254740991,
      -        "minimum": -9007199254740991,
      -        "type": "integer"
      -      },
      -      "issuer": {
      -        "description": "Issuer common name.",
      -        "type": "string"
      -      },
      -      "san": {
      -        "description": "Subject Alternative Names covered by this certificate.",
      -        "items": {
      -          "type": "string"
      -        },
      -        "type": "array"
      -      },
      -      "serial": {
      -        "description": "Certificate serial number.",
      -        "type": "string"
      -      },
      -      "subject": {
      -        "description": "Certificate subject CN.",
      -        "type": "string"
      -      },
      -      "valid_from": {
      -        "description": "ISO 8601 UTC timestamp of certificate validity start.",
      -        "type": "string"
      -      },
      -      "valid_until": {
      -        "description": "ISO 8601 UTC timestamp of certificate expiry.",
      -        "type": "string"
      -      }
      -    },
      -    "required": [
      -      "subject",
      -      "san",
      -      "issuer",
      -      "valid_from",
      -      "valid_until",
      -      "days_until_expiry",
      -      "chain_depth",
      -      "serial"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "authorization_error": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "OpenSSL chain-verification code when the certificate chain does not validate against the system trust store, or null when it validates. Common values: \"DEPTH_ZERO_SELF_SIGNED_CERT\" (self-signed leaf), \"SELF_SIGNED_CERT_IN_CHAIN\" / \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\" (issuing root not trusted), \"CERT_HAS_EXPIRED\" (also reported in \"days_until_expiry\"). This is the authoritative chain-trust signal — the issuer and subject fields alone cannot detect an untrusted root."
      +      },
      +      "chain_depth": {
      +        "anyOf": [
      +          {
      +            "maximum": 9007199254740991,
      +            "minimum": -9007199254740991,
      +            "type": "integer"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Number of certificates the server sent, counting the leaf. Null when the runtime does not expose the issuer chain — read \"chain_depth_unavailable_reason\" in that case. Not a self-signed indicator: use \"authorization_error\" for that."
      +      },
      +      "chain_depth_unavailable_reason": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Why \"chain_depth\" is null, or null when a depth was measured. Absence of a depth is a runtime limitation, not a finding about the certificate."
      +      },
      +      "days_until_expiry": {
      +        "description": "Days remaining until certificate expiry. Negative = already expired.",
      +        "maximum": 9007199254740991,
      +        "minimum": -9007199254740991,
      +        "type": "integer"
      +      },
      +      "hostname_verification_error": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Node's hostname-verification message when the requested domain is not covered by the certificate's CN or SANs (e.g. \"Hostname/IP does not match certificate's altnames: …\"), or null when the hostname is covered. A non-null value means ordinary clients reject this certificate for this hostname; compare against the \"san\" list to see what it does cover."
      +      },
      +      "issuer": {
      +        "description": "Issuer common name.",
      +        "type": "string"
      +      },
      +      "san": {
      +        "description": "Subject Alternative Names covered by this certificate.",
      +        "items": {
      +          "type": "string"
      +        },
      +        "type": "array"
      +      },
      +      "serial": {
      +        "description": "Certificate serial number.",
      +        "type": "string"
      +      },
      +      "subject": {
      +        "description": "Certificate subject CN.",
      +        "type": "string"
      +      },
      +      "valid_from": {
      +        "description": "ISO 8601 UTC timestamp of certificate validity start.",
      +        "type": "string"
      +      },
      +      "valid_until": {
      +        "description": "ISO 8601 UTC timestamp of certificate expiry.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "subject",
      +      "san",
      +      "issuer",
      +      "valid_from",
      +      "valid_until",
      +      "days_until_expiry",
      +      "chain_depth",
      +      "chain_depth_unavailable_reason",
      +      "hostname_verification_error",
      +      "authorization_error",
      +      "serial"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedOutput schema / properties / results / items / properties / flags / description
      Previous value: -"Human-readable warnings and issues found: \"expires in 12 days\", \"TLS 1.1 in use\", \"self-signed certificate\", \"HSTS present\", etc."New value: +"Human-readable warnings and issues found: \"Expires in 12 days (warning)\", \"Certificate expired 40 days ago\", \"Hostname mismatch — the certificate does not cover api.example.com; clients will reject it\", \"Certificate chain not trusted (SELF_SIGNED_CERT_IN_CHAIN); clients will reject it\", \"Self-signed certificate\", \"Insecure TLS version in use: TLSv1.1\", \"HSTS present\" / \"HSTS not configured\"."
    • changedOutput schema / properties / results / items / properties / status / description
      Previous value: -"Overall status: ok, warning (< 30 days), critical (< 7 days or insecure TLS), or error (connection failed)."New value: +"Overall status. \"critical\" — the certificate expires in < 7 days or has already expired, the hostname is not covered by the certificate, chain verification failed (self-signed or untrusted root), or an insecure TLS version was negotiated; every one of these is rejected by ordinary clients. \"warning\" — expires in < 30 days. \"ok\" — none of the above. \"error\" — the connection failed and no certificate was retrieved."
  5. Changed2 schema fields changed
    • addedInput schema / properties / domains / items / minLength
      Added value: +1
    • removedInput schema / properties / domains / items / pattern
      Removed value: -"^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
  6. Changed1 schema field changed
    • changedInput schema / properties / timeout_ms / description
      Previous value: -"Connection timeout per domain in milliseconds. Increase for slow or geographically distant endpoints."New value: +"Connection timeout per domain in milliseconds. Defaults to the DEVOPS_STATUS_CERT_TIMEOUT_MS env var (5000 when unset). Increase for slow or geographically distant endpoints."
  7. Added

TDQS

A4.5/5.0
Behavior5/5

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

Annotations already mark readOnly/openWorld/idempotent, but the description adds substantial behavioral detail: handshakes complete even for rejected certificates, TLS 1.0/1.1 are flagged insecure, and error fields hostname_verification_error and authorization_error carry critical status. These non-obvious behaviors directly affect how an agent interprets results, going far beyond the annotation hints.

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?

Three dense sentences cover purpose, scope, output highlights, error behavior, and a sibling fallback. Every clause earns its place and the core purpose is front-loaded with no fluff or repetition.

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 is thorough for a complex check tool: it states what is checked, constraints, edge-case behavior, and when to switch to another tool. With an output schema present, it needn't enumerate return values, and it even names specific error fields, leaving few gaps for an agent to call it correctly.

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

Parameters3/5

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

The input schema covers 100% of parameters with descriptive text, so the description doesn't need to re-explain port, domains, or timeout. It implicitly confirms multi-domain use but adds little over the schema; baseline 3 is appropriate.

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: 'Inspect SSL/TLS certificate health for one or more domains by performing a real TLS handshake.' It also differentiates itself from a sibling by mentioning devops_check_dns for connection failures, so an agent can identify the tool's unique role without opening the schema.

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

Usage Guidelines4/5

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

It gives a clear usage context: works for any internet-accessible domain, no vendor registry needed, and explicitly routes connection failures to devops_check_dns. While it doesn't contrast with every sibling, the DNS fallback and domain scope provide solid directional guidance for when to use this tool.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.