Stainless SDK provenance classifier (v0.8.3+)¶
agent_airlock.sdk_provenance.classify_sdk_lineage is a pure-function
classifier that scans an MCP server's User-Agent header and
response-body head for markers indicating the server was generated by
a specific SDK toolchain.
What this is NOT¶
This is not a runtime probe, proxy, or sidecar. agent-airlock's
@Airlock decorator wraps a Python tool function the agent calls;
it does NOT intercept outbound HTTP, so the decorator never sees a
server's response headers on its own. The decorator-in-process model
is a deliberate anti-pivot choice (in-process decorator, not a proxy/sidecar).
This module is a building block. A tool function that itself calls out to an MCP server can pass the response's UA / first bytes through this classifier and tag the result onto the trajectory event.
Anchor¶
Anthropic announced the acquisition of Stainless on 2026-05-13 and the wind-down of hosted Stainless products, including the SDK generator. Operators wanting visibility into which MCP servers in their inventory were generated by the deprecated Stainless toolchain can call this classifier from their own audit hooks.
Quickstart¶
from agent_airlock import (
SDKLineage,
classify_sdk_lineage,
)
# Inside YOUR tool function (agent-airlock does not auto-probe):
response = http_client.get("https://my-mcp-server.example/info")
match = classify_sdk_lineage(
user_agent=response.request.headers.get("User-Agent"),
response_body_head=response.text[:4096],
)
if match.lineage == SDKLineage.STAINLESS:
logger.info(
"mcp_server_lineage_stainless",
match_source=match.match_source,
matched_pattern=match.matched_pattern,
)
# Tag the trajectory event with the lineage label regardless of outcome.
audit_event["sdk_lineage"] = match.lineage.value
Match dataclass¶
@dataclass(frozen=True)
class SDKLineageMatch:
lineage: SDKLineage # STAINLESS | UNKNOWN
match_source: str | None # "user_agent" | "response_body" | None
matched_pattern: str | None # the literal substring that fired
detail: str
A UA match short-circuits — the body is not scanned when the UA already names Stainless. Matching is case-insensitive substring on both surfaces.
Default markers¶
DEFAULT_STAINLESS_UA_PATTERNS = frozenset({
"stainless",
"stainless-sdk",
"stainless-node",
"stainless-python",
})
DEFAULT_STAINLESS_BODY_MARKERS = (
"auto-generated by Stainless",
"Generated by Stainless",
"@stainless-generated",
"stainless-codegen",
)
Only the first 4 KB of the response body is scanned. Operators who want deeper scans should ship the response head through some other tool — keeping the agent-airlock surface lightweight is deliberate.
Operator overrides¶
match = classify_sdk_lineage(
user_agent=ua,
response_body_head=head,
extra_ua_patterns=frozenset({"acme-internal-gen"}),
extra_body_markers=("AcmeCodeGen-v3",),
)
A match on an operator-added pattern still yields SDKLineage.STAINLESS
because there is currently only one lineage label. Future versions
may add additional lineage labels (e.g. OPENAPI_GENERATOR,
STAINLESS_INHERITED) when operator demand justifies the
taxonomy expansion.
Factory¶
from agent_airlock.policy_presets import stainless_provenance_probe_defaults
cfg = stainless_provenance_probe_defaults()
# {
# 'preset_id': 'stainless_provenance_probe_2026_05_19',
# 'severity': 'info',
# 'default_action': 'tag_only',
# 'advisory_url': 'https://www.anthropic.com/news/anthropic-acquires-stainless',
# 'ua_patterns': frozenset({'stainless', 'stainless-sdk', ...}),
# 'body_markers': ('auto-generated by Stainless', ...),
# ...
# }
default_action is "tag_only" — this preset never refuses or
blocks. It is visibility-only.
Honest scope¶
- No automatic probing. agent-airlock does not intercept HTTP on its own. Operators wire this classifier into their own audit hooks.
- One lineage label today. Only Stainless is recognised. The enum can be extended.
- Substring matching, not signature verification. A determined party could spoof the markers. This is a visibility primitive, not a tamper-resistant attestation.
- 4 KB scan window. A banner past byte 4096 of a response is missed by design.
Related¶
OpenAPIDriftGuard(v0.8.1) — runtime payload-shape validation when an OpenAPI spec is available.MetisInspiredCorpusBlockRateGuard(v0.8.2) — release-gate primitive scoring a guard chain against a deterministic exploit-shape corpus.