e3536df3c9
- Replace build_server_card() with the ServerCard.from_server() classmethod, matching the SDK's from_* alternate-constructor idiom; the _ServerIdentity protocol moves to mcp.shared.experimental.server_card alongside it. - Make DiscoveryResult iterable over its listings (__iter__/__len__), so 'for listing in result:' works without the .listings attribute hop. - Remove the client-side server_card_url() helper: card URLs must come from an AI Catalog entry per the discovery spec, never be constructed by the client. fetch_server_card's docstring now says so. - Explain the RFC 6598 shared address space constant in the SSRF guard and rename it _CGNAT_NETWORK -> _SHARED_ADDRESS_SPACE; ipaddress reports these addresses as neither private nor global, so the guard names them explicitly. All symbols are experimental (no deprecation cycle), so the removals are clean.
23 lines
1.2 KiB
Python
23 lines
1.2 KiB
Python
import httpx2
|
|
|
|
from mcp import Client
|
|
from mcp.client.experimental.server_card import discover_server_cards, reconcile_server_card
|
|
from mcp.client.streamable_http import streamable_http_client
|
|
from mcp.shared.experimental.server_card import resolve_remote
|
|
|
|
|
|
async def main() -> None:
|
|
result = await discover_server_cards("https://example.com/docs")
|
|
for listing in result:
|
|
print(listing.entry.identifier, "listed on", listing.listing_domain, "hosted at", listing.hosting_domain)
|
|
|
|
chosen = result.listings[0] # your host app: consent UI, dedup on chosen.card.endpoint_urls()
|
|
assert chosen.card.remotes is not None
|
|
resolved = resolve_remote(chosen.card.remotes[0], {"token": "..."}) # ValueError names missing inputs
|
|
|
|
async with httpx2.AsyncClient(headers=resolved.headers, follow_redirects=True) as http_client:
|
|
transport = streamable_http_client(resolved.url, http_client=http_client)
|
|
async with Client(transport) as client:
|
|
for mismatch in reconcile_server_card(chosen.card, client.server_info): # advisory: runtime wins
|
|
print("card mismatch:", mismatch.field, mismatch.card_value, mismatch.runtime_value)
|