Skip to content

feat: Add Agent Discovery Protocol (ADP) support#3192

Open
walkojas-boop wants to merge 2 commits intoComposioHQ:nextfrom
walkojas-boop:add-agent-discovery-protocol
Open

feat: Add Agent Discovery Protocol (ADP) support#3192
walkojas-boop wants to merge 2 commits intoComposioHQ:nextfrom
walkojas-boop:add-agent-discovery-protocol

Conversation

@walkojas-boop
Copy link
Copy Markdown

Summary

Adds a lightweight utility for Composio agents to discover available services at any domain via /.well-known/agent-discovery.json.

ADP lets domains publish what agent services they offer. One fetch, all services discovered.

🤖 Generated with Claude Code

Adds utility for agents to discover services at any domain via
/.well-known/agent-discovery.json. Zero new deps, stdlib only.

Spec: https://github.com/walkojas-boop/agent-discovery-protocol

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@walkojas-boop walkojas-boop requested a review from haxzie as a code owner April 12, 2026 23:40
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 12, 2026

@walkojas-boop is attempting to deploy a commit to the Composio Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 697428e. Configure here.

if use_cache and domain in _cache:
cached_at, cached_result = _cache[domain]
if time.time() - cached_at < _CACHE_TTL:
return DiscoveryResult(cached_result) if cached_result else None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Truthiness check causes inconsistent cached vs uncached results

Medium Severity

The cache-hit path uses if cached_result (truthiness) instead of if cached_result is not None. An empty dict {} is falsy in Python, so if a server returns an empty JSON object, the first call returns a DiscoveryResult({}) via line 105, but subsequent cached calls return None because {} evaluates to False. This creates inconsistent behavior between cached and uncached code paths.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 697428e. Configure here.

url = f"https://{domain}/.well-known/agent-discovery.json"
try:
req = urllib.request.Request(url, headers={"User-Agent": "agent-discovery/0.1"})
with urllib.request.urlopen(req, timeout=timeout) as resp:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No domain validation enables SSRF via arbitrary hosts

Medium Severity

The domain parameter is interpolated directly into a URL and passed to urllib.request.urlopen with no validation. Values like 169.254.169.254, 127.0.0.1, or strings containing @ or # allow server-side request forgery (SSRF) or URL manipulation. Since urlopen follows redirects by default, even an attacker-controlled domain could redirect to internal services.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 697428e. Configure here.


if use_cache:
_cache[domain] = (time.time(), None)
return None
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entire module is dead code with no consumers

Low Severity

discover_services and DiscoveryResult are not imported or used anywhere in the codebase. The module isn't exported from utils/__init__.py, has no tests, and references a spec (walkojas-boop/agent-discovery-protocol) that doesn't appear to be an established or recognized standard. This adds an unintegrated, untested module as dead code.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 697428e. Configure here.

@walkojas-boop walkojas-boop requested a review from jkomyno as a code owner April 14, 2026 10:34
@walkojas-boop
Copy link
Copy Markdown
Author

Updated agent_discovery.py with security hardening from the AutoGPT PR review:

  • SSRF protection: FQDN validation, IP literal rejection, private range blocking
  • DNS rebinding (TOCTOU): pinned IP via custom HTTPSConnection with SNI
  • SSL: explicit TLS 1.2 minimum, domain used for cert verification
  • Redirect blocking: 3xx responses return None (SSRF bypass prevention)
  • Cache validation: DiscoveryResult constructed before caching, catches KeyError/TypeError
  • Negative cache: only 404/410 cached, transient errors retry
  • Cache mutation: deepcopy on init and accessors
  • Exception narrowing: URLError, HTTPError, TimeoutError, SSLError, JSONDecodeError only

Same review feedback from majdyz, Sentry, CodeRabbit, and CodeQL was applied.

@0xbrainkid
Copy link
Copy Markdown

ADP support is the right call for making Composio tools discoverable to the broader agent ecosystem — a standard discovery endpoint means any A2A or ACP-compatible agent can find and evaluate Composio tools without custom integration.

One extension worth including from the start: trust metadata in the discovery document. The /.well-known/agent-discovery.json tells a calling agent what tools exist. A trust field tells it whether those tools have been reliable in practice before it delegates anything consequential.

Composio is actually well-positioned for this because it already has rich usage telemetry — tool call success rates, error patterns, latency distributions. That data is the raw material for behavioral trust attestations. Surfacing a summary in the ADP document (even as a read-only field initially) gives calling agents a signal they currently have no standard way to get:

{
  "name": "composio-tools",
  "endpoints": { ... },
  "trust": {
    "attestation_provider": "AgentFolio",
    "attestation_url": "https://agentfolio.bot/verify/composio",
    "trust_score": 0.94,
    "sample_size": 12400,
    "last_verified": "2026-04-14T00:00:00Z"
  }
}

Composio's existing telemetry could back this directly — the attestation provider just needs to be pointed at the right API endpoint. Happy to discuss integration specifics if useful.

@walkojas-boop
Copy link
Copy Markdown
Author

Appreciate the thinking — and the Composio-specific angle is genuinely the most interesting framing of this I've seen so far. You're right that Composio is sitting on exactly the kind of behavioral data (call success rates, error patterns, latency distributions) that makes attestations meaningful instead of theatrical. That data being available is the precondition for any of this being useful.

That said, I want to push back on the same design choice I've pushed back on in the parallel threads on microsoft/autogen#7575 and deepset-ai/haystack#11081, because the answer should be consistent across these specs or none of them are usable together:

trust_score and last_verified should not live in the discovery document itself. The discovery doc is served by the same domain whose trust is being asserted, which means whatever number lives there is self-attestation. A compromised or hostile pipeline can publish 0.99 and last_verified: "right now" into its own agent-discovery.json and there is no cryptographic basis for a calling agent to know it's wrong. The score has to live somewhere a calling agent can fetch and verify against an external party's signing key — otherwise it's just decoration.

The cleaner separation is:

{
  "name": "composio-tools",
  "endpoints": { ... },
  "trust": {
    "attestations": [
      {
        "provider": "AgentFolio",
        "url": "https://agentfolio.bot/verify/composio"
      }
    ]
  }
}

A list (so a single tool platform can surface multiple attestations from different providers — AgentFolio, OxDeAI, future ones), each entry just provider + url. Everything that has to be verified — score, sample size, freshness, signature — lives at the attestation URL, not in the discovery doc. The consuming agent fetches the attestation, verifies the signature against the provider's public key, and then decides whether to trust the score based on whether it trusts the provider.

Where your Composio-telemetry observation actually lands: the bottleneck for this whole pattern isn't the discovery doc shape, it's the attestation API contract on the provider side. If AgentFolio (or any other provider) wants to surface behavioral attestations backed by Composio's real telemetry, what we need to standardize is:

  1. The shape of the data Composio (or any tool platform) hands to the attestation provider — call counts, success/failure breakdowns, time windows, version/build identifiers
  2. The signed response shape the attestation provider returns to a verifier — score, sample size, methodology, expiry, signature, signing kid
  3. The verifier-side pubkey distribution mechanism for the attestation provider (probably JWKS at a .well-known path)

That's the layer where Composio's data actually compounds into value, and it's a much better thing to standardize than the discovery doc field, because it's the contract that determines whether ANY trust provider can plug into ANY tool platform without a custom integration. Get that right and the discovery doc just needs the pointer.

Threading these together: same proposal landed on microsoft/autogen#7575 and deepset-ai/haystack#11081 with the same shape, and there's an adjacent OpenClaw plugin discussion at openclaw/openclaw#66474 (with a draft PR at openclaw/openclaw#66717) that's also wrestling with the same fragmentation. Going to start an RFC on walkojas-boop/agent-discovery-protocol so the trust.attestations shape can be settled in one place rather than re-litigated per repo. If you and AgentFolio want to co-author the attestation API contract piece, I think that's where the real leverage is.

Composio specifically: if you want, I'll open a separate issue on this PR thread once the RFC has a draft, with a concrete proposal for what Composio's telemetry → attestation handoff would look like. That keeps this PR scoped to the discovery doc shape and lets the attestation API conversation happen on its own track.

walkojas-boop added a commit to walkojas-boop/agent-discovery-protocol that referenced this pull request Apr 14, 2026
Formalize a design rule that has been implicit since v0.1: the trust
object in /.well-known/agent-discovery.json contains pointers, not
values. A new trust.attestations array is added as the canonical place
for third-party attestation pointers, each entry just {provider, url}.

Verifiable claims (scores, sample sizes, freshness timestamps,
signatures) are explicitly out of scope for the discovery document
and live at the attestation URL where they can be verified end-to-end
against a trust provider's public key.

Motivation: multiple downstream framework integrations have proposed
embedding fields like trust_score, last_verified, sample_size, and a
flat attestation_provider directly in the trust object. That shape
is unsafe -- the discovery document is served by the same domain
whose trust is being asserted, so anything inside it is
self-attestation. A compromised or hostile publisher can put any
number it wants in its own document and a calling agent has no
cryptographic basis to know it is wrong.

This RFC does not deprecate any existing field. v0.1 documents
remain valid. The attestations array is optional. Rejected fields
encountered by a v0.2 verifier MUST be dropped on read but MUST NOT
cause the document to fail validation -- avoiding a flag-day
migration while making clear those fields are not part of the spec.

The attestation document format is left to ADP-RFC-002 (forthcoming).
This RFC only specifies the minimum properties a verifier should
expect: signed by the provider's key (not the discovered domain's),
identifies a specific subject, carries an explicit expiry, documents
its methodology, and distributes its signing key out-of-band.

Refs the parallel discussions on:
- microsoft/autogen#7575
- deepset-ai/haystack#11081
- ComposioHQ/composio#3192
- AgentOps-AI/agentops#1334
- openclaw/openclaw#66474
- openclaw/openclaw#66717
@walkojas-boop
Copy link
Copy Markdown
Author

Following up: drafted the RFC I mentioned in the parallel threads. ADP-RFC-001: Trust attestations are pointers, not values formalizes the trust.attestations shape as the canonical answer to the trust-metadata question, with the design rule ("trust fields are pointers, not values") and a list of explicitly-rejected in-document fields. Open to comments on the RFC PR if you want to push back on any of it — the goal is to settle the shape in one place rather than re-litigate it per repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants