From 5f869fa904eaa8643fe2a359c096deea1b8cd3f5 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Tue, 4 Nov 2025 13:59:30 -0800 Subject: [PATCH 01/27] feat: initial draft of core unified AI card schema definition --- type/.gitignore | 2 + type/ai-card-example.md | 84 +++++++++++++ type/src/ai-card.ts | 259 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 type/.gitignore create mode 100644 type/ai-card-example.md create mode 100644 type/src/ai-card.ts diff --git a/type/.gitignore b/type/.gitignore new file mode 100644 index 0000000..58b805f --- /dev/null +++ b/type/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +node_modules/ \ No newline at end of file diff --git a/type/ai-card-example.md b/type/ai-card-example.md new file mode 100644 index 0000000..42c2292 --- /dev/null +++ b/type/ai-card-example.md @@ -0,0 +1,84 @@ +Here is an example `ai-card.json` file that defines a single **"Stock Trading Agent"** which provides its functions over both A2A and MCP. + +Notice here the top-level `name` is for the agent, and the `name` field *inside* each service is just a label for that specific protocol interface. + +```json +{ + "$schema": "https://a2a-protocol.org/ai-card/v1/schema.json", + "specVersion": "1.0.0", + "id": "did:example:agent-stock-trader-9a", + "name": "Stock Trading Agent", + "description": "Helps with stock trading to find best stocks. This agent is available over A2A and MCP.", + "logoUrl": "https://www.acme-finance.com/images/stock-agent.png", + "tags": ["finance", "stocks", "trading", "a2a", "mcp"], + + "publisher": { + "id": "did:example:org-acme-finance", + "name": "Acme Financial Corp" + }, + + "trust": { + "attestations": [ + { + "type": "SOC2-Type2", + "description": "Annual SOC 2 Type II Report", + "credentialUrl": "https://trust.acme-finance.com/reports/soc2-latest.pdf" + } + ] + }, + + "services": [ + { + "name": "Stock Trading Agent (A2A Interface)", + "endpoint": "https://api.acme-finance.com/a2a/v1", + "type": "a2a", + "authentication": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "tokenUrl": "https://auth.acme-finance.com/token", + "scopes": { + "stocks:read": "Allows getting stock quotes", + "stocks:write": "Allows executing trades" + } + } + } + }, + "protocolSpecific": { + "protocolVersion": "0.3.0", + "skills": [ + { "name": "getStockQuote" }, + { "name": "executeTrade" } + ] + } + }, + { + "name": "Stock Trading Agent (MCP Interface)", + "endpoint": "https://api.acme-finance.com/mcp/v1", + "type": "mcp", + "authentication": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "tokenUrl": "https://auth.acme-finance.com/token", + "scopes": { "tools:call": "Allows calling MCP tools" } + } + } + }, + "protocolSpecific": { + "protocolVersion": "2025-06-18", + "capabilities": { + "serverFeatures": ["tools"], + "tools": [ + { "name": "getStockQuote" }, + { "name": "executeTrade" } + ] + } + } + } + ], + + "createdAt": "2025-01-20T10:00:00Z", + "updatedAt": "2025-11-01T15:00:00Z" +} +``` \ No newline at end of file diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts new file mode 100644 index 0000000..d35102b --- /dev/null +++ b/type/src/ai-card.ts @@ -0,0 +1,259 @@ +// --8<-- [start:AICard] +/** + * The unified AI Card object for a single agent. + */ +export interface AICard { + /** + * Declares the schema this card adheres to. + * e.g., "https://ai-agent-protocol.org/ai-card/v1/schema.json" + */ + $schema: string; + + /** + * The version of the AI Card specification itself. + */ + specVersion: string; + + /** + * The primary verifiable ID for the agent (e.g., DID). + */ + id: string; + + /** + * A human-readable name for the agent. + */ + name: string; + + /** + * A short, human-readable description of the agent's purpose. + */ + description: string; + + /** + * A direct URL to the agent's logo image. + */ + logoUrl?: string; + + /** + * A list of keywords to aid in discovery. + */ + tags?: string[]; + + /** + * Information about the entity (company or individual) that published this agent. + */ + publisher: Publisher; + + /** + * Holds all trust, compliance, and identity information. + */ + trust: Trust; + + /** + * An array of all interaction protocols this agent supports. + * This is the core of the extensibility model. + */ + services: ( + | A2AService // For A2A + | MCPService // For MCP + | CustomService // For "Custom/Foo" protocol + )[]; + + /** + * An ISO 8601 timestamp of when the agent was first published. + */ + createdAt: string; + + /** + * An ISO 8601 timestamp of when this card was last updated. + */ + updatedAt: string; + + /** + * An open "black box" for any other non-standard metadata. + */ + metadata?: Record; +} +// --8<-- [end:AICard] + +// --- CORE COMPONENTS --- + +// --8<-- [start:Publisher] +/** + * Defines the entity (company, individual) that published the agent. + */ +export interface Publisher { + /** + * A verifiable ID for the publisher, e.g., a DID or organization ID. + */ + id: string; + + /** + * The human-readable name of the publisher. + */ + name: string; + + /** + * A URL to a verifiable credential (e.g., JWT) proving the publisher's identity. + */ + attestation?: string; +} +// --8<-- [end:Publisher] + +// --8<-- [start:Trust] +/** + * Defines the security, identity, and compliance posture of the agent. + */ +export interface Trust { + // NOTE: 'identity' and other fields can be added here later. + + /** + * A list of compliance or other attestations. + */ + attestations?: Attestation[]; +} +// --8<-- [end:Trust] + +// --8<-- [start:Attestation] +/** + * A single compliance, security, or custom attestation. + */ +export interface Attestation { + /** + * The type of attestation (e.Go., "SOC2", "HIPAA", "CustomBadge"). + */ + type: string; + + /** + * (Low-Trust) A URL to a simple JSON "badge" file. + */ + badgeUrl?: string; + + /** + * (High-Trust) A URL to a verifiable credential (e.g., a JWT or PDF report). + * Use this when the credential is large or hosted remotely. + */ + credentialUrl?: string; + + /** + * (High-Trust) The embedded, base64-encoded credential itself (e.g., a JWT). + * Use this for self-contained attestations (no extra network call). + */ + credentialValue?: string; +} +// --8<-- [end:Attestation] + +// --- DEFINITION TO INTERACTION SERVICES --- +// We don't need to change core ai-card schema for adding or editing or removing the specific interaction service protocols. +// Instead, we define each interaction protocol as a separate "service" type that extends a common base. +// This allows us to add new protocols in the future without changing the core schema. + +// --8<-- [start:BaseService] +/** + * A generic representation of an interaction service. + * All specific service types extend this. + */ +export interface BaseService { + /** + * A human-readable name for this specific service endpoint. + */ + name: string; + + /** + * The full URL to the service endpoint. + */ + endpoint: string; + + /** + * The authentication mechanism for this endpoint. + * (Using 'any' for simplicity, can be typed to OpenAPI SecurityScheme later). + */ + authentication: any; +} +// --8<-- [end:BaseService] + +// --8<-- [start:A2AService] +/** + * Defines the service entry for an A2A-compliant agent. + */ +export interface A2AService extends BaseService { + /** + * The protocol type identifier. Must be "a2a". + */ + type: "a2a"; + + /** + * A "black box" object containing all A2A-specific data. + */ + protocolSpecific: A2AProtocolSpecific; +} +// --8<-- [end:A2AService] + +// --8<-- [start:MCPService] +/** + * Defines the service entry for an MCP-compliant agent. + */ +export interface MCPService extends BaseService { + /** + * The protocol type identifier. Must be "mcp". + */ + type: "mcp"; + + /** + * A "black box" object containing all MCP-specific data. + */ + protocolSpecific: MCPProtocolSpecific; +} +// --8<-- [end:MCPService] + +// --8<-- [start:CustomService] +/** + * Defines the service entry for any custom "Foo" protocol. + * The 'type' string is custom. + */ +export interface CustomService extends BaseService { + /** + * A custom protocol identifier string (e.g., "foo", "my-protocol"). + */ + type: string; + + /** + * An arbitrary JSON object for any custom data. + */ + protocolSpecific: Record; +} +// --8<-- [end:CustomService] + +// --- PROTOCOL-SPECIFIC PAYLOADS --- + +// --8<-- [start:A2AProtocolSpecific] +/** + * Protocol-specific payload for an A2A service. + * The AI Card spec does not validate the contents of this. + */ +export interface A2AProtocolSpecific { + /** + * The version of the A2A protocol this endpoint supports. + */ + protocolVersion: string; + + // More A2A specific fields to be defined later + // (e.g., skills, capabilities, preferredTransport) +} +// --8<-- [end:A2AProtocolSpecific] + +// --8<-- [start:MCPProtocolSpecific] +/** + * Protocol-specific payload for an MCP service. + * The AI Card spec does not validate the contents of this. + */ +export interface MCPProtocolSpecific { + /** + * The version of the MCP protocol this endpoint supports. + */ + protocolVersion: string; + + // More MCP specific fields to be defined later + // (e.g., capabilities, supportedModels) +} +// --8<-- [end:MCPProtocolSpecific] \ No newline at end of file From 774c17e5b0ced7e9342bcbf402d85f86e6fd1c10 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Tue, 4 Nov 2025 15:43:07 -0800 Subject: [PATCH 02/27] feat: updated the initial ai card schema to include only the core fields, service specific metadata are defined as extensions --- type/ai-card-example.md | 67 +++++++++++------- type/src/a2a-proto-specific.ts | 74 +++++++++++++++++++ type/src/ai-card.ts | 126 ++++++++------------------------- 3 files changed, 146 insertions(+), 121 deletions(-) create mode 100644 type/src/a2a-proto-specific.ts diff --git a/type/ai-card-example.md b/type/ai-card-example.md index 42c2292..7118a08 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -6,34 +6,45 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* { "$schema": "https://a2a-protocol.org/ai-card/v1/schema.json", "specVersion": "1.0.0", - "id": "did:example:agent-stock-trader-9a", - "name": "Stock Trading Agent", - "description": "Helps with stock trading to find best stocks. This agent is available over A2A and MCP.", - "logoUrl": "https://www.acme-finance.com/images/stock-agent.png", + "id": "did:example:agent-finance-001", + "name": "Acme Finance Agent", + "description": "An agent for executing stock trades and getting market analysis. Available via A2A and MCP.", + "logoUrl": "https://www.acme-finance.com/images/agent-logo.png", "tags": ["finance", "stocks", "trading", "a2a", "mcp"], "publisher": { "id": "did:example:org-acme-finance", - "name": "Acme Financial Corp" + "name": "Acme Financial Corp", + "attestation": "https://trust.acme-finance.com/publisher.jwt" }, "trust": { + "identity": { + "type": "did", + "id": "did:example:agent-finance-001" + }, "attestations": [ { "type": "SOC2-Type2", - "description": "Annual SOC 2 Type II Report", + "description": "Annual SOC 2 Type II Report (Confidential)", "credentialUrl": "https://trust.acme-finance.com/reports/soc2-latest.pdf" + }, + { + "type": "FINRA-Audit", + "description": "FINRA Compliance Attestation (Embedded JWT)", + "credentialValue": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1ZGl0LmZpbnJhLm9yZyIsInN1YiI6ImRpZDpleGFtcGxlOmFnZW50LWZpbmFuY2UtMDAxIiwiZXhwIjoxNzYyMjM2MDAwLCJhdHRlc3RhdGlvbiI6eyJ0eXBlIjoiRklOUkEtQXVkaXQiLCJzdGF0dXMiOiJhY3RpdmUifX0.VGhpcy1pcy1hLXZlcnktc2FtcGxlLXNpZ25hdHVyZQ" } ] }, "services": [ { - "name": "Stock Trading Agent (A2A Interface)", + "name": "Finance Agent (A2A Interface)", "endpoint": "https://api.acme-finance.com/a2a/v1", "type": "a2a", "authentication": { "type": "oauth2", + "description": "OAuth 2.0 Client Credentials Flow", "flows": { "clientCredentials": { "tokenUrl": "https://auth.acme-finance.com/token", @@ -46,39 +57,43 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* }, "protocolSpecific": { "protocolVersion": "0.3.0", + "preferredTransport": "JSONRPC", + "capabilities": { + "supportsStreaming": true, + "supportsPushNotifications": false + }, "skills": [ - { "name": "getStockQuote" }, - { "name": "executeTrade" } + { + "name": "getStockQuote", + "description": "Get the latest stock quote for a symbol." + }, + { + "name": "executeTrade", + "description": "Execute a stock trade (buy/sell)." + } ] } }, { - "name": "Stock Trading Agent (MCP Interface)", + "name": "Finance Agent (MCP Interface)", "endpoint": "https://api.acme-finance.com/mcp/v1", "type": "mcp", "authentication": { - "type": "oauth2", - "flows": { - "clientCredentials": { - "tokenUrl": "https://auth.acme-finance.com/token", - "scopes": { "tools:call": "Allows calling MCP tools" } - } - } + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" }, "protocolSpecific": { - "protocolVersion": "2025-06-18", - "capabilities": { - "serverFeatures": ["tools"], - "tools": [ - { "name": "getStockQuote" }, - { "name": "executeTrade" } - ] - } + "protocolVersion": "2025-06-18" } } ], "createdAt": "2025-01-20T10:00:00Z", - "updatedAt": "2025-11-01T15:00:00Z" + "updatedAt": "2025-11-01T15:00:00Z", + + "metadata": { + "region": "us-east-1" + } } ``` \ No newline at end of file diff --git a/type/src/a2a-proto-specific.ts b/type/src/a2a-proto-specific.ts new file mode 100644 index 0000000..b5b1f80 --- /dev/null +++ b/type/src/a2a-proto-specific.ts @@ -0,0 +1,74 @@ +/** + * For illustration purposes only. Not part of the AI Card spec. + * Defines the protocol-specific payload for an A2A service. + * This is referenced in the A2AService interface's 'protocolSpecific' field. + * We keep this separate to avoid bloating the core AI Card schema with protocol-specific details. + * Here we only copied some fields from the A2A Agent Spec as example. + * The A2AProtocolSpecific is a self-describing manifest for an agent. It provides essential + * metadata including the agent's identity, capabilities, supported + * communication methods, and security requirements. + */ +export interface A2AProtocolSpecific { + /** + * The version of the A2A protocol this agent supports. + * @default "0.3.0" + */ + protocolVersion: string; + /** + * A human-readable name for the agent. + * + * @TJS-examples ["Recipe Agent"] + */ + name: string; + /** + * A human-readable description of the agent, assisting users and other agents + * in understanding its purpose. + * + * @TJS-examples ["Agent that helps users with recipes and cooking."] + */ + description: string; + /** + * The preferred endpoint URL for interacting with the agent. + * This URL MUST support the transport specified by 'preferredTransport'. + * + * @TJS-examples ["https://api.example.com/a2a/v1"] + */ + url: string; + + + /** An optional URL to an icon for the agent. */ + iconUrl?: string; + /** + * The agent's own version number. The format is defined by the provider. + * + * @TJS-examples ["1.0.0"] + */ + version: string; + /** An optional URL to the agent's documentation. */ + documentationUrl?: string; + /** + * A list of security requirement objects that apply to all agent interactions. Each object + * lists security schemes that can be used. Follows the OpenAPI 3.0 Security Requirement Object. + * This list can be seen as an OR of ANDs. Each object in the list describes one possible + * set of security requirements that must be present on a request. This allows specifying, + * for example, "callers must either use OAuth OR an API Key AND mTLS." + * + * @TJS-examples [[{"oauth": ["read"]}, {"api-key": [], "mtls": []}]] + */ + security?: { [scheme: string]: string[] }[]; + /** + * Default set of supported input MIME types for all skills, which can be + * overridden on a per-skill basis. + */ + defaultInputModes: string[]; + /** + * Default set of supported output MIME types for all skills, which can be + * overridden on a per-skill basis. + */ + defaultOutputModes: string[]; + /** + * If true, the agent can provide an extended agent card with additional details + * to authenticated users. Defaults to false. + */ + supportsAuthenticatedExtendedCard?: boolean; +} \ No newline at end of file diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index d35102b..1bc51c8 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -53,11 +53,7 @@ export interface AICard { * An array of all interaction protocols this agent supports. * This is the core of the extensibility model. */ - services: ( - | A2AService // For A2A - | MCPService // For MCP - | CustomService // For "Custom/Foo" protocol - )[]; + services: BaseService[]; /** * An ISO 8601 timestamp of when the agent was first published. @@ -100,6 +96,23 @@ export interface Publisher { } // --8<-- [end:Publisher] +// --8<-- [start:Identity] +/** + * A verifiable identity for the agent or publisher. + */ +export interface Identity { + /** + * The type of identity (e.g., "did", "spiffe"). + */ + type: string; + + /** + * The identity string itself. + */ + id: string; +} +// --8<-- [end:Identity] + // --8<-- [start:Trust] /** * Defines the security, identity, and compliance posture of the agent. @@ -143,17 +156,17 @@ export interface Attestation { } // --8<-- [end:Attestation] -// --- DEFINITION TO INTERACTION SERVICES --- -// We don't need to change core ai-card schema for adding or editing or removing the specific interaction service protocols. -// Instead, we define each interaction protocol as a separate "service" type that extends a common base. -// This allows us to add new protocols in the future without changing the core schema. - // --8<-- [start:BaseService] /** * A generic representation of an interaction service. * All specific service types extend this. */ export interface BaseService { + /** + * A custom protocol identifier string (e.g., "a2a", "mcp", "foo"). + */ + type: string; + /** * A human-readable name for this specific service endpoint. */ @@ -166,94 +179,17 @@ export interface BaseService { /** * The authentication mechanism for this endpoint. - * (Using 'any' for simplicity, can be typed to OpenAPI SecurityScheme later). + * (Using 'any' for simplicity, can be similar to A2A SecurityScheme). + * Add here if we want to standardize authentication across all services. + * Otherwise, each protocol would define its own. */ authentication: any; -} -// --8<-- [end:BaseService] - -// --8<-- [start:A2AService] -/** - * Defines the service entry for an A2A-compliant agent. - */ -export interface A2AService extends BaseService { - /** - * The protocol type identifier. Must be "a2a". - */ - type: "a2a"; /** - * A "black box" object containing all A2A-specific data. + * An arbitrary JSON object for protocol-specific data. + * The AI Card spec does not validate the contents of this, so we keep core schema clean. + * Each specific service type will define its own structure for this field. */ - protocolSpecific: A2AProtocolSpecific; + protocolSpecific: Record; // The "black box" for protocol-specific data } -// --8<-- [end:A2AService] - -// --8<-- [start:MCPService] -/** - * Defines the service entry for an MCP-compliant agent. - */ -export interface MCPService extends BaseService { - /** - * The protocol type identifier. Must be "mcp". - */ - type: "mcp"; - - /** - * A "black box" object containing all MCP-specific data. - */ - protocolSpecific: MCPProtocolSpecific; -} -// --8<-- [end:MCPService] - -// --8<-- [start:CustomService] -/** - * Defines the service entry for any custom "Foo" protocol. - * The 'type' string is custom. - */ -export interface CustomService extends BaseService { - /** - * A custom protocol identifier string (e.g., "foo", "my-protocol"). - */ - type: string; - - /** - * An arbitrary JSON object for any custom data. - */ - protocolSpecific: Record; -} -// --8<-- [end:CustomService] - -// --- PROTOCOL-SPECIFIC PAYLOADS --- - -// --8<-- [start:A2AProtocolSpecific] -/** - * Protocol-specific payload for an A2A service. - * The AI Card spec does not validate the contents of this. - */ -export interface A2AProtocolSpecific { - /** - * The version of the A2A protocol this endpoint supports. - */ - protocolVersion: string; - - // More A2A specific fields to be defined later - // (e.g., skills, capabilities, preferredTransport) -} -// --8<-- [end:A2AProtocolSpecific] - -// --8<-- [start:MCPProtocolSpecific] -/** - * Protocol-specific payload for an MCP service. - * The AI Card spec does not validate the contents of this. - */ -export interface MCPProtocolSpecific { - /** - * The version of the MCP protocol this endpoint supports. - */ - protocolVersion: string; - - // More MCP specific fields to be defined later - // (e.g., capabilities, supportedModels) -} -// --8<-- [end:MCPProtocolSpecific] \ No newline at end of file +// --8<-- [end:BaseService] From 5f7a39929887247f62915462ccd08d567e3ee0c7 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Wed, 5 Nov 2025 07:25:55 -0800 Subject: [PATCH 03/27] feat: initial ai card - updated comments --- type/src/a2a-proto-specific.ts | 11 ++++------- type/src/ai-card.ts | 6 ++++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/type/src/a2a-proto-specific.ts b/type/src/a2a-proto-specific.ts index b5b1f80..26800e8 100644 --- a/type/src/a2a-proto-specific.ts +++ b/type/src/a2a-proto-specific.ts @@ -1,12 +1,9 @@ /** - * For illustration purposes only. Not part of the AI Card spec. - * Defines the protocol-specific payload for an A2A service. + * We copied here for illustration purposes only + * == It's the same AgentCard in A2A Spec (or we can remove some fields since it's covered in AI card) == + * Defines the protocol-specific metadata payload for an A2A service. * This is referenced in the A2AService interface's 'protocolSpecific' field. - * We keep this separate to avoid bloating the core AI Card schema with protocol-specific details. - * Here we only copied some fields from the A2A Agent Spec as example. - * The A2AProtocolSpecific is a self-describing manifest for an agent. It provides essential - * metadata including the agent's identity, capabilities, supported - * communication methods, and security requirements. + * Here we only copied some fields from the A2A Agent Spec as example. */ export interface A2AProtocolSpecific { /** diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 1bc51c8..133e6e5 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -169,6 +169,7 @@ export interface BaseService { /** * A human-readable name for this specific service endpoint. + * For example, "Travel Agent A2A Endpoint". */ name: string; @@ -186,10 +187,11 @@ export interface BaseService { authentication: any; /** - * An arbitrary JSON object for protocol-specific data. + * An arbitrary JSON object for protocol-specific metadata. * The AI Card spec does not validate the contents of this, so we keep core schema clean. * Each specific service type will define its own structure for this field. + * For A2A services, this would be the A2AProtocolSpecific type (== current AgentCard). */ - protocolSpecific: Record; // The "black box" for protocol-specific data + protocolSpecific: Record; // The protocol-specific metadata } // --8<-- [end:BaseService] From 9d975873075e9f38d62caa102506843c7fd44097 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Wed, 5 Nov 2025 09:38:53 -0800 Subject: [PATCH 04/27] feat: updated the ai-card-example --- type/ai-card-example.md | 51 ++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/type/ai-card-example.md b/type/ai-card-example.md index 7118a08..ac1ee6f 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -39,9 +39,9 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "services": [ { + "type": "a2a", "name": "Finance Agent (A2A Interface)", "endpoint": "https://api.acme-finance.com/a2a/v1", - "type": "a2a", "authentication": { "type": "oauth2", "description": "OAuth 2.0 Client Credentials Flow", @@ -64,31 +64,50 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* }, "skills": [ { - "name": "getStockQuote", - "description": "Get the latest stock quote for a symbol." + "id": "get-stock-analysis-prediction", + "name": "run stock anaylysis and prediction", + "description": "Use the latest LLM based technology to run stock analysis and precdictions", + "tags": ["stock", "analysis", "prediction"], + "examples": [ + "Run stock prediction for GOOG" + ], + "inputModes": ["application/json", "text/plain"], + "outputModes": [ + "application/json", + "text/html" + ] }, - { - "name": "executeTrade", - "description": "Execute a stock trade (buy/sell)." - } ] } }, + { - "name": "Finance Agent (MCP Interface)", - "endpoint": "https://api.acme-finance.com/mcp/v1", "type": "mcp", + "name": "MCP Interface", + "endpoint": "https://api.example.com/mcp/v1", "authentication": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" + "type": "bearer", + "scheme": "MCP-Custom-Auth" }, "protocolSpecific": { - "protocolVersion": "2025-06-18" + "protocolVersion": "2025-06-18", + "transport": "jsonrpc-http", + "capabilities": { + "serverFeatures": [ + "prompts", + "resources", + "tools" + ], + "clientFeatures": [ + "sampling" + ], + "supportedModels": [ + "acme-finance-model-v3" + ] + } } - } - ], - + }, + ], "createdAt": "2025-01-20T10:00:00Z", "updatedAt": "2025-11-01T15:00:00Z", From a334ccf7d8700f7e97bd82622b86ffe66a07fc6a Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Wed, 5 Nov 2025 14:22:42 -0800 Subject: [PATCH 05/27] feat: updated ai card based on latest MCP specific proposal, added ai-catalog draft definition, updated examples --- type/ai-catalog-example.md | 36 ++++++++++++ type/comparison.md | 17 ++++++ type/src/a2a-proto-specific.ts | 71 ----------------------- type/src/ai-catalog.ts | 94 ++++++++++++++++++++++++++++++ type/src/protocol-extension.ts | 103 +++++++++++++++++++++++++++++++++ 5 files changed, 250 insertions(+), 71 deletions(-) create mode 100644 type/ai-catalog-example.md create mode 100644 type/comparison.md delete mode 100644 type/src/a2a-proto-specific.ts create mode 100644 type/src/ai-catalog.ts create mode 100644 type/src/protocol-extension.ts diff --git a/type/ai-catalog-example.md b/type/ai-catalog-example.md new file mode 100644 index 0000000..efd9872 --- /dev/null +++ b/type/ai-catalog-example.md @@ -0,0 +1,36 @@ +The lightweighted AI Catalog for: /.well-known/ai-catalog.json + +The Client's Workflow + - Client: "What agents does api.acme-corp.com have?" + - GET /.well-known/ai-catalog.json + - Client: "Got the list. I see two agents. I want to use the 'Acme Finance Agent'." + - (Parses the cardUrl from the catalog): https://api.acme-corp.com/agents/finance-agent/ai-card.json + - GET /agents/finance-agent/ai-card.json + - Client: "Got the full AI Card. Now I can see its A2A/MCP endpoints and its trust information." + +```json +{ + "$schema": "https://a2a-protocol.org/ai-catalog/v1/schema.json", + "specVersion": "1.0.0", + "host": { + "name": "Acme Services Inc.", + "id": "did:example:org-acme-corp" + }, + "agents": [ + { + "id": "did:example:agent-finance-001", + "name": "Acme Finance Agent", + "description": "An agent for executing stock trades.", + "tags": ["finance", "stocks"], + "cardUrl": "https://api.acme-corp.com/agents/finance-agent/ai-card.json" + }, + { + "id": "did:example:agent-weather-002", + "name": "Acme Weather Agent", + "description": "Provides real-time weather forecasts.", + "tags": ["weather", "forecast"], + "cardUrl": "https://api.acme-corp.com/agents/weather-agent/ai-card.json" + } + ] +} +``` \ No newline at end of file diff --git a/type/comparison.md b/type/comparison.md new file mode 100644 index 0000000..704d0e4 --- /dev/null +++ b/type/comparison.md @@ -0,0 +1,17 @@ +## Comparison of Card Structures + +The unified AI Card defines core AI Card Features that's common in both (or more) protocols. It works by: +- "Lifting" all common fields (id, name, description, publisher, authentication, trust, etc) to the top level. +- "Plugging in" all protocol-specific fields (skills for A2A, capabilities for MCP) into the protocolSpecific payload. + +This table shows how the fields from A2A and MCP map to the unified AI Card structure. +| Concept | A2A AgentCard (Spec) | MCP Server Card (Proposal) | Unified AI Card (Our Definition) | +| :--- | :--- | :--- | :--- | +| **Identity** | Implied by host | `serverInfo.name` (ID) | `id` (Top-level, verifiable DID) | +| **Name** | `name` | `serverInfo.title` | `name` (Top-level, human-readable) | +| **Description** | `description` | `description` | `description` (Top-level) | +| **Publisher** | `AgentProvider` (object) | `serverInfo` | `publisher` (Top-level Publisher object) | +| **Trust/ID** | Not explicitly defined | Not explicitly defined | `trust` (Top-level Trust object) | +| **Endpoint** | `url` | `transport.endpoint` | `services` array > `endpoint` | +| **Authentication** | `securitySchemes` (in card) | `authentication` (in card) | `services` array > `authentication` (Common, OpenAPI-based) | +| **Protocol Details** | `skills`, `preferredTransport`, `capabilities` | `capabilities`, `tools`, `prompts`, `resources` | `services` array > `protocolSpecific` | \ No newline at end of file diff --git a/type/src/a2a-proto-specific.ts b/type/src/a2a-proto-specific.ts deleted file mode 100644 index 26800e8..0000000 --- a/type/src/a2a-proto-specific.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * We copied here for illustration purposes only - * == It's the same AgentCard in A2A Spec (or we can remove some fields since it's covered in AI card) == - * Defines the protocol-specific metadata payload for an A2A service. - * This is referenced in the A2AService interface's 'protocolSpecific' field. - * Here we only copied some fields from the A2A Agent Spec as example. - */ -export interface A2AProtocolSpecific { - /** - * The version of the A2A protocol this agent supports. - * @default "0.3.0" - */ - protocolVersion: string; - /** - * A human-readable name for the agent. - * - * @TJS-examples ["Recipe Agent"] - */ - name: string; - /** - * A human-readable description of the agent, assisting users and other agents - * in understanding its purpose. - * - * @TJS-examples ["Agent that helps users with recipes and cooking."] - */ - description: string; - /** - * The preferred endpoint URL for interacting with the agent. - * This URL MUST support the transport specified by 'preferredTransport'. - * - * @TJS-examples ["https://api.example.com/a2a/v1"] - */ - url: string; - - - /** An optional URL to an icon for the agent. */ - iconUrl?: string; - /** - * The agent's own version number. The format is defined by the provider. - * - * @TJS-examples ["1.0.0"] - */ - version: string; - /** An optional URL to the agent's documentation. */ - documentationUrl?: string; - /** - * A list of security requirement objects that apply to all agent interactions. Each object - * lists security schemes that can be used. Follows the OpenAPI 3.0 Security Requirement Object. - * This list can be seen as an OR of ANDs. Each object in the list describes one possible - * set of security requirements that must be present on a request. This allows specifying, - * for example, "callers must either use OAuth OR an API Key AND mTLS." - * - * @TJS-examples [[{"oauth": ["read"]}, {"api-key": [], "mtls": []}]] - */ - security?: { [scheme: string]: string[] }[]; - /** - * Default set of supported input MIME types for all skills, which can be - * overridden on a per-skill basis. - */ - defaultInputModes: string[]; - /** - * Default set of supported output MIME types for all skills, which can be - * overridden on a per-skill basis. - */ - defaultOutputModes: string[]; - /** - * If true, the agent can provide an extended agent card with additional details - * to authenticated users. Defaults to false. - */ - supportsAuthenticatedExtendedCard?: boolean; -} \ No newline at end of file diff --git a/type/src/ai-catalog.ts b/type/src/ai-catalog.ts new file mode 100644 index 0000000..d79e9f4 --- /dev/null +++ b/type/src/ai-catalog.ts @@ -0,0 +1,94 @@ + +/** + * This file acts as the lightweight "index" (catalog) file served from a host's well-known URL, + * which is /.well-known/ai-catalog.json + */ + +// --8<-- [start:HostInfo] +/** + * Basic information about the host of the catalog. + */ +export interface HostInfo { + /** + * The human-readable name of the host (e.g., the company name). + */ + name: string; + + /** + * A verifiable ID for the host (e.g., a DID). + */ + id?: string; + + /** + * A URL to the host's main documentation. + */ + documentationUrl?: string; + + /** + * A URL to the host's logo. + */ + logoUrl?: string; +} +// --8<-- [end:HostInfo] + +// --8<-- [start:AgentEntry] +/** + * A lightweight entry in the catalog, providing basic discovery + * information and a link to the full AI Card. + */ +export interface AgentEntry { + /** + * The primary verifiable ID for the agent (e.g., DID). + * This MUST match the 'id' in the full AICard. + */ + id: string; + + /** + * A human-readable name for the agent. + */ + name: string; + + /** + * A short description of the agent. + */ + description: string; + + /** + * A list of tags for filtering and discovery. + */ + tags?: string[]; + + /** + * The full, absolute URL to this agent's complete ai-card.json file. + */ + cardUrl: string; +} +// --8<-- [end:AgentEntry] + +// --8<-- [start:AICatalog] +/** + * Defines the structure for a host's master agent catalog. + * This file is expected to be at "/.well-known/ai-catalog.json". + */ +export interface AICatalog { + /** + * Declares the schema this catalog adheres to. + */ + $schema: string; + + /** + * The version of the AI Catalog specification itself. + */ + specVersion: string; + + /** + * Information about the host/publisher of the entire catalog. + */ + host: HostInfo; + + /** + * An array of lightweight entries for all agents on this host. + */ + agents: AgentEntry[]; +} +// --8<-- [end:AICatalog] \ No newline at end of file diff --git a/type/src/protocol-extension.ts b/type/src/protocol-extension.ts new file mode 100644 index 0000000..5f0d2de --- /dev/null +++ b/type/src/protocol-extension.ts @@ -0,0 +1,103 @@ +/** + * This file is not part of the core spec. It's maintained by the protocol + * teams (A2A, MCP) to define what goes inside their protocolSpecific. + * Slightly simplified version from the current A2A AgentCard and MCP Proposal types. + */ + +// --8<-- [start:A2AProtocolSpecific] +/** + * The payload for the 'protocolSpecific' field when type == "a2a". + * This is defined and maintained by the A2A project. + */ +export interface A2AProtocolSpecific { + /** + * From A2A Spec: The version of the A2A protocol. + */ + protocolVersion: string; + + /** + * From A2A Spec: The preferred transport (e.g., "JSONRPC"). + */ + preferredTransport?: string; + + /** + * From A2A Spec: List of alternative transports/URLs. + */ + additionalInterfaces?: { + transport: string; + url: string; + }[]; + + /** + * From A2A Spec: A2A-specific capabilities. + */ + capabilities?: { + supportsStreaming?: boolean; + supportsPushNotifications?: boolean; + }; + + /** + * From A2A Spec: The list of skills this agent provides. + */ + skills: { + name: string; + description: string; + inputSchema?: Record; + }[]; +} +// --8<-- [end:A2AProtocolSpecific] + +// --8<-- [start:MCPProtocolSpecific] +/** + * The payload for the 'protocolSpecific' field when type == "mcp". + * This is defined and maintained by the MCP project. + */ +export interface MCPProtocolSpecific { + /** + * From MCP Proposal: The version of the MCP protocol. + */ + protocolVersion: string; + + /** + * From MCP Proposal: The type of transport (e.g., "streamable-http"). + * The 'endpoint' is already in the BaseService. + */ + transportType?: string; + + /** + * From MCP Proposal: MCP-specific server capabilities. + */ + capabilities: { + tools?: { listChanged?: boolean }; + prompts?: { listChanged?: boolean }; + resources?: { subscribe?: boolean; listChanged?: boolean }; + }; + + /** + * From MCP Proposal: Required client capabilities. + */ + requires?: { + sampling?: object; + roots?: object; + }; + + /** + * From MCP Proposal: Static list of tools, or "dynamic". + */ + tools: "dynamic" | { + name: string; + description: string; + inputSchema?: Record; + }[]; + + /** + * From MCP Proposal: Static list of prompts, or "dynamic". + */ + prompts: "dynamic" | { name: string; description: string }[]; + + /** + * From MCP Proposal: Static list of resources, or "dynamic". + */ + resources: "dynamic" | { name: string; uri: string }[]; +} +// --8<-- [end:MCPProtocolSpecific] \ No newline at end of file From 999a93ca31039feab11303fd9aca939c9b3baff2 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Wed, 5 Nov 2025 14:23:35 -0800 Subject: [PATCH 06/27] feat: updated ai-card-example.md --- type/ai-card-example.md | 63 ++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/type/ai-card-example.md b/type/ai-card-example.md index ac1ee6f..8a4d3c1 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -26,12 +26,10 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "attestations": [ { "type": "SOC2-Type2", - "description": "Annual SOC 2 Type II Report (Confidential)", "credentialUrl": "https://trust.acme-finance.com/reports/soc2-latest.pdf" }, { "type": "FINRA-Audit", - "description": "FINRA Compliance Attestation (Embedded JWT)", "credentialValue": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1ZGl0LmZpbnJhLm9yZyIsInN1YiI6ImRpZDpleGFtcGxlOmFnZW50LWZpbmFuY2UtMDAxIiwiZXhwIjoxNzYyMjM2MDAwLCJhdHRlc3RhdGlvbiI6eyJ0eXBlIjoiRklOUkEtQXVkaXQiLCJzdGF0dXMiOiJhY3RpdmUifX0.VGhpcy1pcy1hLXZlcnktc2FtcGxlLXNpZ25hdHVyZQ" } ] @@ -64,50 +62,45 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* }, "skills": [ { - "id": "get-stock-analysis-prediction", - "name": "run stock anaylysis and prediction", - "description": "Use the latest LLM based technology to run stock analysis and precdictions", - "tags": ["stock", "analysis", "prediction"], - "examples": [ - "Run stock prediction for GOOG" - ], - "inputModes": ["application/json", "text/plain"], - "outputModes": [ - "application/json", - "text/html" - ] - }, + "name": "runStockAnalysisAndPrediction", + "description": "Use the latest LLM based technology to run stock analysis and predictions", + "inputSchema": { + "type": "object", + "properties": { + "symbol": { "type": "string" } + } + } + } ] } }, - { "type": "mcp", - "name": "MCP Interface", - "endpoint": "https://api.example.com/mcp/v1", + "name": "Finance Agent (MCP Interface)", + "endpoint": "https://api.acme-finance.com/mcp/v1", "authentication": { - "type": "bearer", - "scheme": "MCP-Custom-Auth" + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" }, "protocolSpecific": { "protocolVersion": "2025-06-18", - "transport": "jsonrpc-http", + "transportType": "streamable-http", "capabilities": { - "serverFeatures": [ - "prompts", - "resources", - "tools" - ], - "clientFeatures": [ - "sampling" - ], - "supportedModels": [ - "acme-finance-model-v3" - ] - } + "tools": { "listChanged": true }, + "prompts": { "listChanged": true }, + "resources": { "subscribe": true } + }, + "requires": { + "sampling": {} + }, + "tools": "dynamic", + "prompts": "dynamic", + "resources": "dynamic" } - }, - ], + } + ], + "createdAt": "2025-01-20T10:00:00Z", "updatedAt": "2025-11-01T15:00:00Z", From 473da2628fe24569fe3b6f4b8e04e530be8fcb86 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 13:30:45 -0800 Subject: [PATCH 07/27] feat: updated ai-card and ai-catalog spec based on feedbacks --- type/ai-card-example.md | 7 +++++-- type/src/ai-card.ts | 44 ++++++++++++++++++++++++++--------------- type/src/ai-catalog.ts | 7 +++++++ 3 files changed, 40 insertions(+), 18 deletions(-) diff --git a/type/ai-card-example.md b/type/ai-card-example.md index 8a4d3c1..6352a74 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -15,7 +15,10 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "publisher": { "id": "did:example:org-acme-finance", "name": "Acme Financial Corp", - "attestation": "https://trust.acme-finance.com/publisher.jwt" + "attestation": { + "type": "IdentityProof", + "credentialUrl": "https://trust.acme.com/identity.jwt" + } }, "trust": { @@ -84,7 +87,7 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "bearerFormat": "JWT" }, "protocolSpecific": { - "protocolVersion": "2025-06-18", + "protocolVersions": ["2025-06-18", "2025-09-19"], "transportType": "streamable-http", "capabilities": { "tools": { "listChanged": true }, diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 133e6e5..5bce14f 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -15,7 +15,13 @@ export interface AICard { specVersion: string; /** - * The primary verifiable ID for the agent (e.g., DID). + * A globally unique identifier for the agent. + * * **Recommendation:** We strongly recommend using a **Verifiable URI**, + * like a DID (`did:method:...`). + * Using a verifiable format allows clients to cryptographically prove + * agent identity and ownership. + * * Simple UUIDs or names are allowed but offer no trust guarantees. + * **Constraint:** This MUST match the `trust.identity.id` field. */ id: string; @@ -30,7 +36,13 @@ export interface AICard { description: string; /** - * A direct URL to the agent's logo image. + * A URL to the agent's logo. + * * **Security Note:** We strongly recommend using **Data URLs** (RFC 2397) + * (e.g., "data:image/png;base64,...") to embed the image binary directly. + * * While standard HTTP URLs ("https://...") are allowed, they are discouraged + * for enterprise/high-security environments because "dereferencing" (fetching) + * the URL can leak user IP addresses (tracking) and creates a dependency on + * external hosting uptime. */ logoUrl?: string; @@ -61,7 +73,8 @@ export interface AICard { createdAt: string; /** - * An ISO 8601 timestamp of when this card was last updated. + * An ISO 8601 timestamp of when this **entire AI Card** was last modified. + * This includes changes to common metadata OR any of the service definitions. */ updatedAt: string; @@ -82,7 +95,7 @@ export interface Publisher { /** * A verifiable ID for the publisher, e.g., a DID or organization ID. */ - id: string; + identity: Identity; /** * The human-readable name of the publisher. @@ -90,9 +103,10 @@ export interface Publisher { name: string; /** - * A URL to a verifiable credential (e.g., JWT) proving the publisher's identity. + * A verifiable credential proving the publisher's identity. + * Reuses the Attestation type to support both URLs and embedded tokens. */ - attestation?: string; + attestation?: Attestation; } // --8<-- [end:Publisher] @@ -118,8 +132,11 @@ export interface Identity { * Defines the security, identity, and compliance posture of the agent. */ export interface Trust { - // NOTE: 'identity' and other fields can be added here later. - + /** + * A verifiable ID for the Agent. + */ + identity: Identity; + /** * A list of compliance or other attestations. */ @@ -138,19 +155,14 @@ export interface Attestation { type: string; /** - * (Low-Trust) A URL to a simple JSON "badge" file. - */ - badgeUrl?: string; - - /** - * (High-Trust) A URL to a verifiable credential (e.g., a JWT or PDF report). + * A URL to a verifiable credential (e.g., a JWT or PDF report). * Use this when the credential is large or hosted remotely. */ credentialUrl?: string; /** - * (High-Trust) The embedded, base64-encoded credential itself (e.g., a JWT). - * Use this for self-contained attestations (no extra network call). + * The embedded, base64-encoded credential itself (e.g., a JWT). + * Use this for self-contained attestations. */ credentialValue?: string; } diff --git a/type/src/ai-catalog.ts b/type/src/ai-catalog.ts index d79e9f4..e1f8410 100644 --- a/type/src/ai-catalog.ts +++ b/type/src/ai-catalog.ts @@ -62,6 +62,13 @@ export interface AgentEntry { * The full, absolute URL to this agent's complete ai-card.json file. */ cardUrl: string; + + /** + * An ISO 8601 timestamp of when the referenced `ai-card.json` file + * was last modified. + * Used by crawlers to determine if they need to re-fetch the full card. + */ + updatedAt: string; } // --8<-- [end:AgentEntry] From 772816b4faeef6bebf8e42f1d5747b700d3db0c4 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 14:45:14 -0800 Subject: [PATCH 08/27] feat: Updated spec: support multiple endpont, add notes for .well-known patterns --- type/src/ai-card.ts | 34 +++++++++++++++++++++++++++------- type/src/ai-catalog.ts | 4 +++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 5bce14f..52fa40b 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -134,6 +134,7 @@ export interface Identity { export interface Trust { /** * A verifiable ID for the Agent. + * This MUST match the root `id` of the card. */ identity: Identity; @@ -150,7 +151,7 @@ export interface Trust { */ export interface Attestation { /** - * The type of attestation (e.Go., "SOC2", "HIPAA", "CustomBadge"). + * The type of attestation (e.g., "SOC2", "HIPAA", "CustomBadge"). */ type: string; @@ -168,6 +169,23 @@ export interface Attestation { } // --8<-- [end:Attestation] +// --8<-- [start:AgentEndpoint] +/** + * Defines a physical access point for a service. + */ +export interface AgentEndpoint { + /** + * The full URL to the endpoint. + */ + url: string; + + /** + * Optional transport type identifier (e.g., "http", "grpc", "ws"). + * Helps clients choose the best endpoint without trying them all. + */ + transport?: string; +} + // --8<-- [start:BaseService] /** * A generic representation of an interaction service. @@ -186,13 +204,15 @@ export interface BaseService { name: string; /** - * The full URL to the service endpoint. + * A list of endpoints where this service can be accessed. + * This allows a single service definition (with one set of skills) + * to be available over multiple transports (e.g., HTTP and WebSocket). */ - endpoint: string; + endpoints: AgentEndpoint[]; /** * The authentication mechanism for this endpoint. - * (Using 'any' for simplicity, can be similar to A2A SecurityScheme). + * (Using 'any' for simplicity, can be similar to A2A SecurityScheme or OpenAPI). * Add here if we want to standardize authentication across all services. * Otherwise, each protocol would define its own. */ @@ -200,10 +220,10 @@ export interface BaseService { /** * An arbitrary JSON object for protocol-specific metadata. - * The AI Card spec does not validate the contents of this, so we keep core schema clean. + * The AI Card spec does not validate the contents of this, keeping the core schema clean. * Each specific service type will define its own structure for this field. - * For A2A services, this would be the A2AProtocolSpecific type (== current AgentCard). + * For A2A services, this would be the A2AProtocolSpecific type (replacing current AgentCard). */ protocolSpecific: Record; // The protocol-specific metadata } -// --8<-- [end:BaseService] +// --8<-- [end:BaseService] \ No newline at end of file diff --git a/type/src/ai-catalog.ts b/type/src/ai-catalog.ts index e1f8410..39f586f 100644 --- a/type/src/ai-catalog.ts +++ b/type/src/ai-catalog.ts @@ -1,7 +1,9 @@ /** * This file acts as the lightweight "index" (catalog) file served from a host's well-known URL, - * which is /.well-known/ai-catalog.json + * which is /.well-known/ai-catalog.json. + * Note this is the recommended binding for ** domain-based discovery **, but the AI Card format is + * transport-agnostic and intended to be served by SaaS Registry APIs as well. */ // --8<-- [start:HostInfo] From 16112e29f9458db2a1fbcf578bcaac74d97aab1f Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 15:12:59 -0800 Subject: [PATCH 09/27] feat: add policy and TOS url field --- type/src/ai-card.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 52fa40b..e7b5cad 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -142,6 +142,18 @@ export interface Trust { * A list of compliance or other attestations. */ attestations?: Attestation[]; + + /** + * A URL to the agent's Privacy Policy. + * Critical for registries to display data handling practices. + */ + privacyPolicyUrl?: string; + + /** + * A URL to the agent's Terms of Service. + * Critical for establishing legal usage rights. + */ + termsOfServiceUrl?: string; } // --8<-- [end:Trust] From 7d55a04e03ad37ddd6f9f313de8ade3befe60b66 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 15:36:47 -0800 Subject: [PATCH 10/27] feat: added maturity, signature to ai card spec and also use map for services --- type/src/ai-card.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index e7b5cad..60464a4 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -62,10 +62,23 @@ export interface AICard { trust: Trust; /** - * An array of all interaction protocols this agent supports. - * This is the core of the extensibility model. + * The agent's lifecycle stage. + * Useful for registries to filter out experimental or deprecated agents. */ - services: BaseService[]; + maturity?: "preview" | "stable" | "deprecated"; + + /** + * A detached JWS compact serialization (
..) + * signing the canonical content of this card. + * Used to cryptographically bind the card content to the `id` (DID). + */ + signature?: string; + + /** + * A map of interaction protocols this agent supports, keyed by protocol type. + * e.g., { "a2a": { ... }, "mcp": { ... } } + */ + services: Record; /** * An ISO 8601 timestamp of when the agent was first published. From 123070fa9c512119ce36999afa330217d57c1aee Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 15:40:09 -0800 Subject: [PATCH 11/27] feat: updated ai-card-example.md --- type/ai-card-example.md | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/type/ai-card-example.md b/type/ai-card-example.md index 6352a74..a9c08c6 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -11,10 +11,15 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "description": "An agent for executing stock trades and getting market analysis. Available via A2A and MCP.", "logoUrl": "https://www.acme-finance.com/images/agent-logo.png", "tags": ["finance", "stocks", "trading", "a2a", "mcp"], + "maturity": "stable", + "signature": "eyJhbGciOiJFUzI1NiJ9..[detached-jws-signature]..", "publisher": { - "id": "did:example:org-acme-finance", "name": "Acme Financial Corp", + "identity": { + "type": "did", + "id": "did:example:org-acme-finance" + }, "attestation": { "type": "IdentityProof", "credentialUrl": "https://trust.acme.com/identity.jwt" @@ -35,14 +40,21 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "type": "FINRA-Audit", "credentialValue": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1ZGl0LmZpbnJhLm9yZyIsInN1YiI6ImRpZDpleGFtcGxlOmFnZW50LWZpbmFuY2UtMDAxIiwiZXhwIjoxNzYyMjM2MDAwLCJhdHRlc3RhdGlvbiI6eyJ0eXBlIjoiRklOUkEtQXVkaXQiLCJzdGF0dXMiOiJhY3RpdmUifX0.VGhpcy1pcy1hLXZlcnktc2FtcGxlLXNpZ25hdHVyZQ" } - ] + ], + "privacyPolicyUrl": "https://acme-finance.com/legal/privacy", + "termsOfServiceUrl": "https://acme-finance.com/legal/terms" }, - "services": [ - { + "services": { + "a2a": { "type": "a2a", "name": "Finance Agent (A2A Interface)", - "endpoint": "https://api.acme-finance.com/a2a/v1", + "endpoints": [ + { + "url": "https://api.acme-finance.com/a2a/v1", + "transport": "http" + } + ], "authentication": { "type": "oauth2", "description": "OAuth 2.0 Client Credentials Flow", @@ -77,10 +89,15 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* ] } }, - { + "mcp": { "type": "mcp", "name": "Finance Agent (MCP Interface)", - "endpoint": "https://api.acme-finance.com/mcp/v1", + "endpoints": [ + { + "url": "https://api.acme-finance.com/mcp/v1", + "transport": "http" + } + ], "authentication": { "type": "http", "scheme": "bearer", @@ -102,7 +119,7 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "resources": "dynamic" } } - ], + }, "createdAt": "2025-01-20T10:00:00Z", "updatedAt": "2025-11-01T15:00:00Z", From 879fcf8860d7c7c5100d8db1133c95f0584da81e Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 16:14:36 -0800 Subject: [PATCH 12/27] feat: use service-type for services as key, also add CDDL spec format --- type/ai-card.md | 79 +++++++++++++++++++++++++++++++++++++++++++++ type/ai-catalog.md | 30 +++++++++++++++++ type/src/ai-card.ts | 12 ++++++- 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 type/ai-card.md create mode 100644 type/ai-catalog.md diff --git a/type/ai-card.md b/type/ai-card.md new file mode 100644 index 0000000..7c4725c --- /dev/null +++ b/type/ai-card.md @@ -0,0 +1,79 @@ +### AI Card Specification in CDDL format +```ini +; ============================================================================ +; AI Card Specification (v1) +; A unified metadata format for AI Agents +; ============================================================================ + +AICard = { + $schema: text, ; URI to the JSON schema + specVersion: text, ; e.g. "1.0.0" + id: text, ; Globally unique ID (DID or stable URL). MUST match trust.identity.id + name: text, ; Human-readable name + description: text, ; Short description + ? logoUrl: text, ; URL to logo (Data URI recommended) + ? tags: [* text], ; Discovery keywords + ? maturity: MaturityLevel, ; Lifecycle stage + ? signature: text, ; Detached JWS signing the card content + publisher: Publisher, ; Who owns this agent + trust: Trust, ; Security and Identity proofs + + ; Map of supported protocols (e.g. "a2a" => Service, "mcp" => Service) + services: { * ServiceType => BaseService }, + + createdAt: tdate, ; ISO 8601 Date + updatedAt: tdate, ; ISO 8601 Date + ? metadata: { * text => any } ; Extensible metadata bucket +} + +; Enum for maturity +MaturityLevel = "preview" / "stable" / "deprecated" + +; Service type choices (Standard + Custom) +ServiceType = "mcp" / "a2a" / text + +; --- Core Components --- + +Publisher = { + identity: Identity, + name: text, + ? attestation: Attestation ; Identity proof (e.g. verifying the DID) +} + +Trust = { + identity: Identity, ; The Agent's Identity. MUST match root ID. + ? attestations: [* Attestation], ; Compliance proofs (SOC2, HIPAA) + ? privacyPolicyUrl: text, + ? termsOfServiceUrl: text +} + +Identity = { + type: text, ; e.g. "did", "spiffe" + id: text ; The identifier string +} + +Attestation = { + type: text, ; e.g. "SOC2-Type2", "HIPAA-Audit" + ; Verifiable credentials + ? credentialUrl: text, ; Remote JWT/Report + ? credentialValue: text ; Embedded JWT/Proof +} + +; --- Interaction Services --- + +BaseService = { + type: text, ; Protocol ID (e.g. "a2a", "mcp") + name: text, ; Human-readable label for this interface + endpoints: [* AgentEndpoint], + ? authentication: any, ; Recommended: OpenAPI Security Scheme Object + + ; The "Black Box" for protocol-specific data + ; Validated by the protocol's own schema (e.g. A2A or MCP schema) + protocolSpecific: { * text => any } +} + +AgentEndpoint = { + url: text, ; Full URL + ? transport: text ; e.g. "http", "ws", "grpc" +} +``` \ No newline at end of file diff --git a/type/ai-catalog.md b/type/ai-catalog.md new file mode 100644 index 0000000..8275401 --- /dev/null +++ b/type/ai-catalog.md @@ -0,0 +1,30 @@ +### AI Catalog Specification in CDDL format +```ini +; ============================================================================ +; AI Catalog Specification (v1) +; The "Index" file served at /.well-known/ai-catalog.json +; ============================================================================ + +AICatalog = { + $schema: text, ; URI to the JSON schema + specVersion: text, ; Version of the Catalog spec (e.g. "1.0.0") + host: HostInfo, ; Who runs this server/registry + agents: [* AgentCatalogEntry] ; The list of available agents +} + +HostInfo = { + name: text, ; The human-readable name of the host (e.g., the company name) + ? id: text, ; Host Identity (DID) + ? documentationUrl: text, ; A URL to the host's main documentation + ? logoUrl: text ; A URL to the host's logo +} + +AgentCatalogEntry = { + id: text, ; Must match the id in the linked AI Card + name: text, ; Human-readable name for the AI Card + description: text, ; Short description + ? tags: [* text], ; A list of tags for filtering and discovery + cardUrl: text, ; URL to the full ai-card.json + updatedAt: tdate ; Last modified time of the AI Card (for crawler optimization) +} +``` \ No newline at end of file diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 60464a4..80fb09a 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -78,7 +78,7 @@ export interface AICard { * A map of interaction protocols this agent supports, keyed by protocol type. * e.g., { "a2a": { ... }, "mcp": { ... } } */ - services: Record; + services: Record; /** * An ISO 8601 timestamp of when the agent was first published. @@ -100,6 +100,16 @@ export interface AICard { // --- CORE COMPONENTS --- +// --8<-- [start:ServiceType] +/** + * The protocol identifier for a service. + * Supports standard protocols ("a2a", "mcp") and custom strings. + * The `(string & {})` syntax preserves autocomplete for the known values + * while allowing any other string. + */ +export type ServiceType = "a2a" | "mcp" | (string & {}); +// --8<-- [end:ServiceType] + // --8<-- [start:Publisher] /** * Defines the entity (company, individual) that published the agent. From 3b7547676756871ca51b7d8a556cd331ff248913 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 16:16:52 -0800 Subject: [PATCH 13/27] feat: updated ai-card.md descriptions --- type/ai-card.md | 66 +++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/type/ai-card.md b/type/ai-card.md index 7c4725c..4b11d2c 100644 --- a/type/ai-card.md +++ b/type/ai-card.md @@ -7,23 +7,28 @@ AICard = { $schema: text, ; URI to the JSON schema - specVersion: text, ; e.g. "1.0.0" + specVersion: text, ; Version of the AI Card spec (e.g. "1.0.0") + id: text, ; Globally unique ID (DID or stable URL). MUST match trust.identity.id - name: text, ; Human-readable name - description: text, ; Short description - ? logoUrl: text, ; URL to logo (Data URI recommended) - ? tags: [* text], ; Discovery keywords - ? maturity: MaturityLevel, ; Lifecycle stage + name: text, ; Human-readable name for the agent + description: text, ; Short description of the agent's purpose + + ? logoUrl: text, ; URL to logo. Data URLs (RFC 2397) are recommended for privacy + ? tags: [* text], ; List of keywords to aid in discovery + + ? maturity: MaturityLevel, ; Lifecycle stage of the agent ? signature: text, ; Detached JWS signing the card content - publisher: Publisher, ; Who owns this agent - trust: Trust, ; Security and Identity proofs + + publisher: Publisher, ; Information about the entity that owns this agent + trust: Trust, ; Security, identity, and compliance proofs ; Map of supported protocols (e.g. "a2a" => Service, "mcp" => Service) services: { * ServiceType => BaseService }, - createdAt: tdate, ; ISO 8601 Date - updatedAt: tdate, ; ISO 8601 Date - ? metadata: { * text => any } ; Extensible metadata bucket + createdAt: tdate, ; ISO 8601 Date when the agent was published + updatedAt: tdate, ; ISO 8601 Date when this card was last modified + + ? metadata: { * text => any } ; Open slot for custom/non-standard metadata } ; Enum for maturity @@ -35,36 +40,39 @@ ServiceType = "mcp" / "a2a" / text ; --- Core Components --- Publisher = { - identity: Identity, - name: text, - ? attestation: Attestation ; Identity proof (e.g. verifying the DID) + identity: Identity, ; Verifiable ID of the publisher organization + name: text, ; Human-readable name of the publisher + ? attestation: Attestation ; Proof of the publisher's identity } Trust = { - identity: Identity, ; The Agent's Identity. MUST match root ID. - ? attestations: [* Attestation], ; Compliance proofs (SOC2, HIPAA) - ? privacyPolicyUrl: text, - ? termsOfServiceUrl: text + identity: Identity, ; The Agent's Identity. MUST match the root 'id' + ? attestations: [* Attestation], ; List of compliance credentials (SOC2, HIPAA, etc.) + ? privacyPolicyUrl: text, ; URL to the privacy policy + ? termsOfServiceUrl: text ; URL to the terms of service } Identity = { - type: text, ; e.g. "did", "spiffe" - id: text ; The identifier string + type: text, ; Identity type (e.g. "did", "spiffe") + id: text ; The identifier string itself } Attestation = { - type: text, ; e.g. "SOC2-Type2", "HIPAA-Audit" - ; Verifiable credentials - ? credentialUrl: text, ; Remote JWT/Report - ? credentialValue: text ; Embedded JWT/Proof + type: text, ; Type of proof (e.g. "SOC2-Type2", "HIPAA-Audit") + + ; Verifiable credentials (High-Trust) + ? credentialUrl: text, ; Remote URL to a signed credential (e.g. JWT/PDF) + ? credentialValue: text ; Embedded base64-encoded credential (e.g. JWT) } ; --- Interaction Services --- BaseService = { - type: text, ; Protocol ID (e.g. "a2a", "mcp") - name: text, ; Human-readable label for this interface - endpoints: [* AgentEndpoint], + type: ServiceType, ; Protocol ID (e.g. "a2a", "mcp"). Matches map key. + name: text, ; Human-readable name for this specific interface + + endpoints: [* AgentEndpoint], ; List of physical access points + ? authentication: any, ; Recommended: OpenAPI Security Scheme Object ; The "Black Box" for protocol-specific data @@ -73,7 +81,7 @@ BaseService = { } AgentEndpoint = { - url: text, ; Full URL - ? transport: text ; e.g. "http", "ws", "grpc" + url: text, ; The full URL to the endpoint + ? transport: text ; Transport hint (e.g. "http", "ws", "grpc") } ``` \ No newline at end of file From d19b2ea454dd4a91591e211a30ffbf63ec034bc0 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 24 Nov 2025 16:20:56 -0800 Subject: [PATCH 14/27] feat: renamed ai-card.md to ai-card-cddl.md, same for ai-catalog.md --- type/{ai-card.md => ai-card-cddl.md} | 2 +- type/{ai-catalog.md => ai-catalog-cddl.md} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename type/{ai-card.md => ai-card-cddl.md} (99%) rename type/{ai-catalog.md => ai-catalog-cddl.md} (100%) diff --git a/type/ai-card.md b/type/ai-card-cddl.md similarity index 99% rename from type/ai-card.md rename to type/ai-card-cddl.md index 4b11d2c..cbb29c8 100644 --- a/type/ai-card.md +++ b/type/ai-card-cddl.md @@ -25,7 +25,7 @@ AICard = { ; Map of supported protocols (e.g. "a2a" => Service, "mcp" => Service) services: { * ServiceType => BaseService }, - createdAt: tdate, ; ISO 8601 Date when the agent was published + createdAt: tdate, ; ISO 8601 Date when the agent was created updatedAt: tdate, ; ISO 8601 Date when this card was last modified ? metadata: { * text => any } ; Open slot for custom/non-standard metadata diff --git a/type/ai-catalog.md b/type/ai-catalog-cddl.md similarity index 100% rename from type/ai-catalog.md rename to type/ai-catalog-cddl.md From 7b69e6c24a7f6ea214014f2ad786775ad1ee5e38 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 1 Dec 2025 14:49:20 -0800 Subject: [PATCH 15/27] feat: updated ai card spec based on feedbacks --- type/ai-card-cddl.md | 48 +++++-------- type/ai-card-example.md | 124 ++++++++++++++------------------- type/ai-catalog-cddl.md | 4 +- type/src/ai-card.ts | 149 +++++++++++----------------------------- 4 files changed, 114 insertions(+), 211 deletions(-) diff --git a/type/ai-card-cddl.md b/type/ai-card-cddl.md index cbb29c8..0b5a96f 100644 --- a/type/ai-card-cddl.md +++ b/type/ai-card-cddl.md @@ -6,28 +6,31 @@ ; ============================================================================ AICard = { - $schema: text, ; URI to the JSON schema - specVersion: text, ; Version of the AI Card spec (e.g. "1.0.0") + $schema: text, ; URI to the JSON schema (e.g. "https://...") + specVersion: text, ; Major.Minor version (e.g. "1.0") - id: text, ; Globally unique ID (DID or stable URL). MUST match trust.identity.id + ; --- Identity (Subject) --- + id: text, ; The Primary Key / Subject of this card (DID, SPIFFE, or URL) + ? identityType: text, ; Type hint (e.g. "did", "spiffe"). Optional if clear from ID. + + ; --- Metadata --- name: text, ; Human-readable name for the agent description: text, ; Short description of the agent's purpose - - ? logoUrl: text, ; URL to logo. Data URLs (RFC 2397) are recommended for privacy + ? logoUrl: text, ; URL to logo. Data URL (RFC 2397) recommended for privacy ? tags: [* text], ; List of keywords to aid in discovery - ? maturity: MaturityLevel, ; Lifecycle stage of the agent - ? signature: text, ; Detached JWS signing the card content - + ; --- Ownership & Trust --- publisher: Publisher, ; Information about the entity that owns this agent - trust: Trust, ; Security, identity, and compliance proofs + trust: Trust, ; Security and compliance proofs + ? signature: text, ; Detached JWS signing the card content + ; --- Protocols --- ; Map of supported protocols (e.g. "a2a" => Service, "mcp" => Service) services: { * ServiceType => BaseService }, + ; --- Housekeeping --- createdAt: tdate, ; ISO 8601 Date when the agent was created updatedAt: tdate, ; ISO 8601 Date when this card was last modified - ? metadata: { * text => any } ; Open slot for custom/non-standard metadata } @@ -40,23 +43,19 @@ ServiceType = "mcp" / "a2a" / text ; --- Core Components --- Publisher = { - identity: Identity, ; Verifiable ID of the publisher organization + id: text, ; Verifiable ID of the publisher organization + ? identityType: text, ; Type hint (e.g. "did", "dns") name: text, ; Human-readable name of the publisher ? attestation: Attestation ; Proof of the publisher's identity } Trust = { - identity: Identity, ; The Agent's Identity. MUST match the root 'id' + ; Identity is now implicit (matches Root id) ? attestations: [* Attestation], ; List of compliance credentials (SOC2, HIPAA, etc.) ? privacyPolicyUrl: text, ; URL to the privacy policy ? termsOfServiceUrl: text ; URL to the terms of service } -Identity = { - type: text, ; Identity type (e.g. "did", "spiffe") - id: text ; The identifier string itself -} - Attestation = { type: text, ; Type of proof (e.g. "SOC2-Type2", "HIPAA-Audit") @@ -68,20 +67,11 @@ Attestation = { ; --- Interaction Services --- BaseService = { - type: ServiceType, ; Protocol ID (e.g. "a2a", "mcp"). Matches map key. - name: text, ; Human-readable name for this specific interface - - endpoints: [* AgentEndpoint], ; List of physical access points - - ? authentication: any, ; Recommended: OpenAPI Security Scheme Object + type: ServiceType, ; Protocol ID (matches key in services map) + ? name: text, ; Human-readable label (e.g. "Primary Interface") ; The "Black Box" for protocol-specific data - ; Validated by the protocol's own schema (e.g. A2A or MCP schema) + ; Endpoints, Auth, and Skills are defined INSIDE here by the protocol spec. protocolSpecific: { * text => any } } - -AgentEndpoint = { - url: text, ; The full URL to the endpoint - ? transport: text ; Transport hint (e.g. "http", "ws", "grpc") -} ``` \ No newline at end of file diff --git a/type/ai-card-example.md b/type/ai-card-example.md index a9c08c6..8f06727 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -5,40 +5,35 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* ```json { "$schema": "https://a2a-protocol.org/ai-card/v1/schema.json", - "specVersion": "1.0.0", + "specVersion": "1.0", + "id": "did:example:agent-finance-001", + "identityType": "did", "name": "Acme Finance Agent", - "description": "An agent for executing stock trades and getting market analysis. Available via A2A and MCP.", - "logoUrl": "https://www.acme-finance.com/images/agent-logo.png", - "tags": ["finance", "stocks", "trading", "a2a", "mcp"], + "description": "An agent for executing stock trades and getting market analysis via A2A and MCP.", + "logoUrl": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgZmlsbD0iIzRjNTFnZiIgLz48L3N2Zz4=", "maturity": "stable", "signature": "eyJhbGciOiJFUzI1NiJ9..[detached-jws-signature]..", "publisher": { + "id": "did:example:org-acme", + "identityType": "did", "name": "Acme Financial Corp", - "identity": { - "type": "did", - "id": "did:example:org-acme-finance" - }, - "attestation": { - "type": "IdentityProof", - "credentialUrl": "https://trust.acme.com/identity.jwt" - } + "attestation": { + "type": "IdentityProof", + "credentialUrl": "https://trust.acme.com/identity.jwt" + } }, "trust": { - "identity": { - "type": "did", - "id": "did:example:agent-finance-001" - }, "attestations": [ - { - "type": "SOC2-Type2", - "credentialUrl": "https://trust.acme-finance.com/reports/soc2-latest.pdf" + { + "type": "SOC2-Type2", + "credentialUrl": "https://trust.acme-finance.com/reports/soc2-latest.pdf" }, - { - "type": "FINRA-Audit", - "credentialValue": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1ZGl0LmZpbnJhLm9yZyIsInN1YiI6ImRpZDpleGFtcGxlOmFnZW50LWZpbmFuY2UtMDAxIiwiZXhwIjoxNzYyMjM2MDAwLCJhdHRlc3RhdGlvbiI6eyJ0eXBlIjoiRklOUkEtQXVkaXQiLCJzdGF0dXMiOiJhY3RpdmUifX0.VGhpcy1pcy1hLXZlcnktc2FtcGxlLXNpZ25hdHVyZQ" + { + "type": "FINRA-Audit", + "credentialValue": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1ZGl0LmZpbnJhLm9yZyIsInN1YiI6ImRpZDpleGFtcGxlOmFnZW50LWZpbmFuY2UtMDAxIiwiZXhwIjoxNzYyMjM2MDAwLCJhdHRlc3RhdGlvbiI6eyJ0eXBlIjoiRklOUkEtQXVkaXQiLCJzdGF0dXMiOiJhY3RpdmUifX0.VGhpcy1pcy1hLXZlcnktc2FtcGxlLXNpZ25hdHVyZQ" } ], "privacyPolicyUrl": "https://acme-finance.com/legal/privacy", @@ -48,72 +43,59 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "services": { "a2a": { "type": "a2a", - "name": "Finance Agent (A2A Interface)", - "endpoints": [ - { - "url": "https://api.acme-finance.com/a2a/v1", - "transport": "http" - } - ], - "authentication": { - "type": "oauth2", - "description": "OAuth 2.0 Client Credentials Flow", - "flows": { - "clientCredentials": { - "tokenUrl": "https://auth.acme-finance.com/token", - "scopes": { - "stocks:read": "Allows getting stock quotes", - "stocks:write": "Allows executing trades" - } - } - } - }, + "name": "Finance A2A Interface", "protocolSpecific": { "protocolVersion": "0.3.0", - "preferredTransport": "JSONRPC", - "capabilities": { - "supportsStreaming": true, - "supportsPushNotifications": false - }, - "skills": [ + "supportedInterfaces": [ { - "name": "runStockAnalysisAndPrediction", - "description": "Use the latest LLM based technology to run stock analysis and predictions", - "inputSchema": { - "type": "object", - "properties": { - "symbol": { "type": "string" } + "transport": "JSONRPC", + "url": "https://api.acme-finance.com/a2a/v1" + } + ], + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "clientCredentials": { + "tokenUrl": "https://auth.acme-finance.com/token", + "scopes": { + "stocks:read": "Allows getting stock quotes", + "stocks:write": "Allows executing trades" + } } } } + }, + "skills": [ + { + "id": "skill-stock-analysis", + "name": "Run Stock Analysis", + "description": "Use the latest LLM based technology to run stock analysis and predictions.", + "inputModes": ["application/json"], + "outputModes": ["application/json", "text/markdown"], + "tags": ["finance", "analysis", "prediction"] + } ] } }, "mcp": { "type": "mcp", - "name": "Finance Agent (MCP Interface)", - "endpoints": [ - { - "url": "https://api.acme-finance.com/mcp/v1", - "transport": "http" - } - ], - "authentication": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - }, + "name": "Finance MCP Interface", "protocolSpecific": { - "protocolVersions": ["2025-06-18", "2025-09-19"], - "transportType": "streamable-http", + "protocolVersion": "2025-06-18", + "transport": { + "type": "streamable-http", + "endpoint": "https://api.acme-finance.com/mcp/v1" + }, + "authentication": { + "type": "oauth2", + "required": true + }, "capabilities": { "tools": { "listChanged": true }, "prompts": { "listChanged": true }, "resources": { "subscribe": true } }, - "requires": { - "sampling": {} - }, "tools": "dynamic", "prompts": "dynamic", "resources": "dynamic" diff --git a/type/ai-catalog-cddl.md b/type/ai-catalog-cddl.md index 8275401..b732af2 100644 --- a/type/ai-catalog-cddl.md +++ b/type/ai-catalog-cddl.md @@ -9,7 +9,7 @@ AICatalog = { $schema: text, ; URI to the JSON schema specVersion: text, ; Version of the Catalog spec (e.g. "1.0.0") host: HostInfo, ; Who runs this server/registry - agents: [* AgentCatalogEntry] ; The list of available agents + agents: [* AICardEntry] ; The list of available agents } HostInfo = { @@ -19,7 +19,7 @@ HostInfo = { ? logoUrl: text ; A URL to the host's logo } -AgentCatalogEntry = { +AICardEntry = { id: text, ; Must match the id in the linked AI Card name: text, ; Human-readable name for the AI Card description: text, ; Short description diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 80fb09a..5d5f20b 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -5,25 +5,26 @@ export interface AICard { /** * Declares the schema this card adheres to. - * e.g., "https://ai-agent-protocol.org/ai-card/v1/schema.json" + * e.g., "https://a2a-protocol.org/ai-card/v1/schema.json" */ $schema: string; /** - * The version of the AI Card specification itself. + * The version of the AI Card specification itself (e.g., "1.0"). + * Major.Minor version only. */ specVersion: string; /** - * A globally unique identifier for the agent. - * * **Recommendation:** We strongly recommend using a **Verifiable URI**, - * like a DID (`did:method:...`). - * Using a verifiable format allows clients to cryptographically prove - * agent identity and ownership. - * * Simple UUIDs or names are allowed but offer no trust guarantees. - * **Constraint:** This MUST match the `trust.identity.id` field. + * The primary verifiable ID for the agent (e.g., DID, SPIFFE, or stable URL). + * This acts as the Subject of the card. */ id: string; + + /** + * Optional hint for the identity type (e.g., "did", "spiffe"). + */ + identityType?: string; /** * A human-readable name for the agent. @@ -36,13 +37,7 @@ export interface AICard { description: string; /** - * A URL to the agent's logo. - * * **Security Note:** We strongly recommend using **Data URLs** (RFC 2397) - * (e.g., "data:image/png;base64,...") to embed the image binary directly. - * * While standard HTTP URLs ("https://...") are allowed, they are discouraged - * for enterprise/high-security environments because "dereferencing" (fetching) - * the URL can leak user IP addresses (tracking) and creates a dependency on - * external hosting uptime. + * A URL to the agent's logo image. Data URLs (RFC 2397) are recommended. */ logoUrl?: string; @@ -52,31 +47,27 @@ export interface AICard { tags?: string[]; /** - * Information about the entity (company or individual) that published this agent. + * The lifecycle stage of the agent. + */ + maturity?: "preview" | "stable" | "deprecated"; + + /** + * Information about the entity (company or individual) that owns this agent. */ publisher: Publisher; /** - * Holds all trust, compliance, and identity information. + * Holds security, compliance, and legal information. */ trust: Trust; /** - * The agent's lifecycle stage. - * Useful for registries to filter out experimental or deprecated agents. - */ - maturity?: "preview" | "stable" | "deprecated"; - - /** - * A detached JWS compact serialization (
..) - * signing the canonical content of this card. - * Used to cryptographically bind the card content to the `id` (DID). + * A detached JWS compact serialization signing the canonical content of this card. */ signature?: string; /** - * A map of interaction protocols this agent supports, keyed by protocol type. - * e.g., { "a2a": { ... }, "mcp": { ... } } + * A map of all interaction protocols this agent supports, keyed by protocol type (e.g. 'a2a', 'mcp'). */ services: Record; @@ -86,13 +77,12 @@ export interface AICard { createdAt: string; /** - * An ISO 8601 timestamp of when this **entire AI Card** was last modified. - * This includes changes to common metadata OR any of the service definitions. + * An ISO 8601 timestamp of when this entire AI Card document was last modified. */ updatedAt: string; /** - * An open "black box" for any other non-standard metadata. + * An open 'black box' for any other non-standard metadata. */ metadata?: Record; } @@ -116,9 +106,14 @@ export type ServiceType = "a2a" | "mcp" | (string & {}); */ export interface Publisher { /** - * A verifiable ID for the publisher, e.g., a DID or organization ID. + * A verifiable ID for the publisher (e.g., DID). */ - identity: Identity; + id: string; + + /** + * Optional hint for the publisher identity type. + */ + identityType?: string; /** * The human-readable name of the publisher. @@ -126,41 +121,17 @@ export interface Publisher { name: string; /** - * A verifiable credential proving the publisher's identity. - * Reuses the Attestation type to support both URLs and embedded tokens. + * Proof of the publisher's identity. */ attestation?: Attestation; } // --8<-- [end:Publisher] -// --8<-- [start:Identity] -/** - * A verifiable identity for the agent or publisher. - */ -export interface Identity { - /** - * The type of identity (e.g., "did", "spiffe"). - */ - type: string; - - /** - * The identity string itself. - */ - id: string; -} -// --8<-- [end:Identity] - // --8<-- [start:Trust] /** * Defines the security, identity, and compliance posture of the agent. */ export interface Trust { - /** - * A verifiable ID for the Agent. - * This MUST match the root `id` of the card. - */ - identity: Identity; - /** * A list of compliance or other attestations. */ @@ -168,13 +139,11 @@ export interface Trust { /** * A URL to the agent's Privacy Policy. - * Critical for registries to display data handling practices. */ privacyPolicyUrl?: string; /** * A URL to the agent's Terms of Service. - * Critical for establishing legal usage rights. */ termsOfServiceUrl?: string; } @@ -186,79 +155,41 @@ export interface Trust { */ export interface Attestation { /** - * The type of attestation (e.g., "SOC2", "HIPAA", "CustomBadge"). + * The type of attestation (e.g., "SOC2-Type2", "HIPAA-Audit"). */ type: string; /** - * A URL to a verifiable credential (e.g., a JWT or PDF report). - * Use this when the credential is large or hosted remotely. + * (High-Trust) A URL to a verifiable credential (e.g., a JWT or PDF report). */ credentialUrl?: string; /** - * The embedded, base64-encoded credential itself (e.g., a JWT). - * Use this for self-contained attestations. + * (High-Trust) The embedded, base64-encoded credential itself (e.g., a JWT). */ credentialValue?: string; } // --8<-- [end:Attestation] -// --8<-- [start:AgentEndpoint] -/** - * Defines a physical access point for a service. - */ -export interface AgentEndpoint { - /** - * The full URL to the endpoint. - */ - url: string; - - /** - * Optional transport type identifier (e.g., "http", "grpc", "ws"). - * Helps clients choose the best endpoint without trying them all. - */ - transport?: string; -} - // --8<-- [start:BaseService] /** - * A generic representation of an interaction service. - * All specific service types extend this. + * A generic wrapper for a specific protocol interface. */ export interface BaseService { /** - * A custom protocol identifier string (e.g., "a2a", "mcp", "foo"). + * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the services map. */ type: string; /** - * A human-readable name for this specific service endpoint. - * For example, "Travel Agent A2A Endpoint". - */ - name: string; - - /** - * A list of endpoints where this service can be accessed. - * This allows a single service definition (with one set of skills) - * to be available over multiple transports (e.g., HTTP and WebSocket). - */ - endpoints: AgentEndpoint[]; - - /** - * The authentication mechanism for this endpoint. - * (Using 'any' for simplicity, can be similar to A2A SecurityScheme or OpenAPI). - * Add here if we want to standardize authentication across all services. - * Otherwise, each protocol would define its own. + * A human-readable label for this interface. */ - authentication: any; + name?: string; /** - * An arbitrary JSON object for protocol-specific metadata. - * The AI Card spec does not validate the contents of this, keeping the core schema clean. - * Each specific service type will define its own structure for this field. - * For A2A services, this would be the A2AProtocolSpecific type (replacing current AgentCard). + * The 'Black Box' for protocol-specific data (Endpoints, Auth, Skills). + * Validated by the protocol's own schema. */ - protocolSpecific: Record; // The protocol-specific metadata + protocolSpecific: Record; } // --8<-- [end:BaseService] \ No newline at end of file From 8ea75bd5181a2ef0bc3020914df86098ee640792 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 1 Dec 2025 19:07:41 -0800 Subject: [PATCH 16/27] feat: make trust field optional so dev/internal agents can choose to not provide the complex id verification and compliance trust field --- type/ai-card-cddl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/type/ai-card-cddl.md b/type/ai-card-cddl.md index 0b5a96f..4448555 100644 --- a/type/ai-card-cddl.md +++ b/type/ai-card-cddl.md @@ -21,7 +21,7 @@ AICard = { ? maturity: MaturityLevel, ; Lifecycle stage of the agent ; --- Ownership & Trust --- publisher: Publisher, ; Information about the entity that owns this agent - trust: Trust, ; Security and compliance proofs + ? trust: Trust, ; Security and compliance proofs ? signature: text, ; Detached JWS signing the card content ; --- Protocols --- From c0dcf3e21dd93c6a1acaca61611cb64e0a5a138c Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 1 Dec 2025 19:08:20 -0800 Subject: [PATCH 17/27] feat: clarify that the id field can be any globally unique URI --- type/ai-card-cddl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/type/ai-card-cddl.md b/type/ai-card-cddl.md index 4448555..86b95a8 100644 --- a/type/ai-card-cddl.md +++ b/type/ai-card-cddl.md @@ -10,7 +10,7 @@ AICard = { specVersion: text, ; Major.Minor version (e.g. "1.0") ; --- Identity (Subject) --- - id: text, ; The Primary Key / Subject of this card (DID, SPIFFE, or URL) + id: text, ; The Primary Key / Subject of this card, Globally Unique URI (per RFC 3986), (DID, SPIFFE, or URL) ? identityType: text, ; Type hint (e.g. "did", "spiffe"). Optional if clear from ID. ; --- Metadata --- From ba9e1044c4d1e1c23c6995eff5a93cfbf1544b43 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Mon, 1 Dec 2025 19:20:56 -0800 Subject: [PATCH 18/27] updated comparison table --- type/comparison.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/type/comparison.md b/type/comparison.md index 704d0e4..76154e6 100644 --- a/type/comparison.md +++ b/type/comparison.md @@ -5,13 +5,16 @@ The unified AI Card defines core AI Card Features that's common in both (or more - "Plugging in" all protocol-specific fields (skills for A2A, capabilities for MCP) into the protocolSpecific payload. This table shows how the fields from A2A and MCP map to the unified AI Card structure. -| Concept | A2A AgentCard (Spec) | MCP Server Card (Proposal) | Unified AI Card (Our Definition) | +| Concept | A2A `AgentCard` (Spec) | MCP `Server Card` (Proposal) | **Unified `AI Card` (V1)** | | :--- | :--- | :--- | :--- | -| **Identity** | Implied by host | `serverInfo.name` (ID) | `id` (Top-level, verifiable DID) | -| **Name** | `name` | `serverInfo.title` | `name` (Top-level, human-readable) | -| **Description** | `description` | `description` | `description` (Top-level) | -| **Publisher** | `AgentProvider` (object) | `serverInfo` | `publisher` (Top-level Publisher object) | -| **Trust/ID** | Not explicitly defined | Not explicitly defined | `trust` (Top-level Trust object) | -| **Endpoint** | `url` | `transport.endpoint` | `services` array > `endpoint` | -| **Authentication** | `securitySchemes` (in card) | `authentication` (in card) | `services` array > `authentication` (Common, OpenAPI-based) | -| **Protocol Details** | `skills`, `preferredTransport`, `capabilities` | `capabilities`, `tools`, `prompts`, `resources` | `services` array > `protocolSpecific` | \ No newline at end of file +| **Identity (Subject)** | Implied by Host | `serverInfo.name` | **`id`** (Root URI) + `identityType` | +| **Name** | `name` | `serverInfo.title` | **`name`** | +| **Description** | `description` | `description` | **`description`** | +| **Logo** | `icon_url` | `iconUrl` | **`logoUrl`** (Rec: Data URI) | +| **Publisher** | `provider` (Object) | `serverInfo` | **`publisher`** (Object with `id`, `name`) | +| **Trust / Security** | `signatures` (Optional) | Not Defined | **`trust`** (Optional Object: Proofs, Policies) | +| **Protocol Support** | Implied (A2A Only) | Implied (MCP Only) | **`services`** (Map: `"a2a": {...}`, `"mcp": {...}`) | +| **Endpoint URL** | `url` | `transport.endpoint` | `services[x].protocolSpecific` (**Delegated**) | +| **Authentication** | `securitySchemes` | `authentication` | `services[x].protocolSpecific` (**Delegated**) | +| **Capabilities** | `skills` | `tools`, `resources` | `services[x].protocolSpecific` (**Delegated**) | +| **Versioning** | `version` | `serverInfo.version` | **`specVersion`** (Card Ver) + `updatedAt` | \ No newline at end of file From c8c2bef76845e9dab6d1891bfd1622b3c76f617d Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Thu, 4 Dec 2025 17:04:31 -0800 Subject: [PATCH 19/27] spec: Rename 'services' to 'interfaces', adopt 'AI Service' terminology, and simplify 'Attestation' to use Reference Pattern instead of specific credential fields --- type/ai-card-cddl.md | 41 ++++++++++++++++++++------------------ type/ai-card-example.md | 21 ++++++++++--------- type/ai-catalog-cddl.md | 6 +++--- type/ai-catalog-example.md | 2 +- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/type/ai-card-cddl.md b/type/ai-card-cddl.md index 86b95a8..cfc6b0a 100644 --- a/type/ai-card-cddl.md +++ b/type/ai-card-cddl.md @@ -2,7 +2,7 @@ ```ini ; ============================================================================ ; AI Card Specification (v1) -; A unified metadata format for AI Agents +; A unified metadata format for AI Services (Agents/Tools) ; ============================================================================ AICard = { @@ -14,30 +14,28 @@ AICard = { ? identityType: text, ; Type hint (e.g. "did", "spiffe"). Optional if clear from ID. ; --- Metadata --- - name: text, ; Human-readable name for the agent - description: text, ; Short description of the agent's purpose + name: text, ; Human-readable name for the AI service + description: text, ; Short description of the AI service's purpose ? logoUrl: text, ; URL to logo. Data URL (RFC 2397) recommended for privacy ? tags: [* text], ; List of keywords to aid in discovery - ? maturity: MaturityLevel, ; Lifecycle stage of the agent + ? maturity: MaturityLevel, ; Lifecycle stage of the AI service + ; --- Ownership & Trust --- - publisher: Publisher, ; Information about the entity that owns this agent - ? trust: Trust, ; Security and compliance proofs - ? signature: text, ; Detached JWS signing the card content + publisher: Publisher, ; Information about the entity that owns this AI service + ? trust: Trust, ; Security and compliance proofs (Optional) + ? signature: text, ; Detached JWS signing the card content (Integrity) ; --- Protocols --- - ; Map of supported protocols (e.g. "a2a" => Service, "mcp" => Service) - services: { * ServiceType => BaseService }, + ; Map of supported protocol interfaces (e.g. "a2a" => Interface, "mcp" => Interface) + interfaces: { * ServiceType => ProtocolInterface }, ; --- Housekeeping --- - createdAt: tdate, ; ISO 8601 Date when the agent was created + createdAt: tdate, ; ISO 8601 Date when the AI service was first created updatedAt: tdate, ; ISO 8601 Date when this card was last modified ? metadata: { * text => any } ; Open slot for custom/non-standard metadata } -; Enum for maturity MaturityLevel = "preview" / "stable" / "deprecated" - -; Service type choices (Standard + Custom) ServiceType = "mcp" / "a2a" / text ; --- Core Components --- @@ -59,19 +57,24 @@ Trust = { Attestation = { type: text, ; Type of proof (e.g. "SOC2-Type2", "HIPAA-Audit") - ; Verifiable credentials (High-Trust) - ? credentialUrl: text, ; Remote URL to a signed credential (e.g. JWT/PDF) - ? credentialValue: text ; Embedded base64-encoded credential (e.g. JWT) + ; Reference Pattern (Generic for Remote or Inline) + uri: text, ; remote location: "https://..." or inline "data:..." + mediaType: text, ; Format: "application/pdf", "application/jwt" + + ? digest: text, ; Hash for integrity (e.g. "sha256:...") + ? size: uint, ; Size in bytes + ? description: text ; Human-readable label } -; --- Interaction Services --- +; --- Interaction Interfaces --- -BaseService = { - type: ServiceType, ; Protocol ID (matches key in services map) +ProtocolInterface = { + type: ServiceType, ; Protocol ID (matches key in interfaces map) ? name: text, ; Human-readable label (e.g. "Primary Interface") ; The "Black Box" for protocol-specific data ; Endpoints, Auth, and Skills are defined INSIDE here by the protocol spec. protocolSpecific: { * text => any } } + ``` \ No newline at end of file diff --git a/type/ai-card-example.md b/type/ai-card-example.md index 8f06727..459cdf9 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -21,7 +21,8 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "name": "Acme Financial Corp", "attestation": { "type": "IdentityProof", - "credentialUrl": "https://trust.acme.com/identity.jwt" + "uri": "https://trust.acme.com/identity.jwt", + "mediaType": "application/jwt" } }, @@ -29,18 +30,23 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "attestations": [ { "type": "SOC2-Type2", - "credentialUrl": "https://trust.acme-finance.com/reports/soc2-latest.pdf" + "description": "2025 SOC2 Type II Report", + "uri": "https://trust.acme-finance.com/reports/soc2-latest.pdf", + "mediaType": "application/pdf", + "digest": "sha256:a1b2c3d4..." }, { "type": "FINRA-Audit", - "credentialValue": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0.eyJpc3MiOiJodHRwczovL2F1ZGl0LmZpbnJhLm9yZyIsInN1YiI6ImRpZDpleGFtcGxlOmFnZW50LWZpbmFuY2UtMDAxIiwiZXhwIjoxNzYyMjM2MDAwLCJhdHRlc3RhdGlvbiI6eyJ0eXBlIjoiRklOUkEtQXVkaXQiLCJzdGF0dXMiOiJhY3RpdmUifX0.VGhpcy1pcy1hLXZlcnktc2FtcGxlLXNpZ25hdHVyZQ" + "description": "Embedded Audit Token", + "uri": "data:application/jwt;base64,eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0...", + "mediaType": "application/jwt" } ], "privacyPolicyUrl": "https://acme-finance.com/legal/privacy", "termsOfServiceUrl": "https://acme-finance.com/legal/terms" }, - "services": { + "interfaces": { "a2a": { "type": "a2a", "name": "Finance A2A Interface", @@ -59,8 +65,7 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "clientCredentials": { "tokenUrl": "https://auth.acme-finance.com/token", "scopes": { - "stocks:read": "Allows getting stock quotes", - "stocks:write": "Allows executing trades" + "stocks:read": "Allows getting stock quotes" } } } @@ -92,9 +97,7 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "required": true }, "capabilities": { - "tools": { "listChanged": true }, - "prompts": { "listChanged": true }, - "resources": { "subscribe": true } + "tools": { "listChanged": true } }, "tools": "dynamic", "prompts": "dynamic", diff --git a/type/ai-catalog-cddl.md b/type/ai-catalog-cddl.md index b732af2..64d63e8 100644 --- a/type/ai-catalog-cddl.md +++ b/type/ai-catalog-cddl.md @@ -9,7 +9,7 @@ AICatalog = { $schema: text, ; URI to the JSON schema specVersion: text, ; Version of the Catalog spec (e.g. "1.0.0") host: HostInfo, ; Who runs this server/registry - agents: [* AICardEntry] ; The list of available agents + services: [* AIServiceEntry] ; The list of available AI services } HostInfo = { @@ -19,9 +19,9 @@ HostInfo = { ? logoUrl: text ; A URL to the host's logo } -AICardEntry = { +AIServiceEntry = { id: text, ; Must match the id in the linked AI Card - name: text, ; Human-readable name for the AI Card + name: text, ; Human-readable name for the AI Service description: text, ; Short description ? tags: [* text], ; A list of tags for filtering and discovery cardUrl: text, ; URL to the full ai-card.json diff --git a/type/ai-catalog-example.md b/type/ai-catalog-example.md index efd9872..8ce5d86 100644 --- a/type/ai-catalog-example.md +++ b/type/ai-catalog-example.md @@ -16,7 +16,7 @@ The Client's Workflow "name": "Acme Services Inc.", "id": "did:example:org-acme-corp" }, - "agents": [ + "services": [ { "id": "did:example:agent-finance-001", "name": "Acme Finance Agent", From ed1c4aac12eecf2f56da58a93334549e77187670 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Thu, 4 Dec 2025 17:16:47 -0800 Subject: [PATCH 20/27] spec: updated spec's type script format based on latest discussion --- type/ai-catalog-cddl.md | 2 +- type/src/ai-card.ts | 78 ++++++++++++++++--------- type/src/ai-catalog.ts | 40 ++++++------- type/src/protocol-extension.ts | 103 --------------------------------- 4 files changed, 71 insertions(+), 152 deletions(-) delete mode 100644 type/src/protocol-extension.ts diff --git a/type/ai-catalog-cddl.md b/type/ai-catalog-cddl.md index 64d63e8..68a434f 100644 --- a/type/ai-catalog-cddl.md +++ b/type/ai-catalog-cddl.md @@ -20,7 +20,7 @@ HostInfo = { } AIServiceEntry = { - id: text, ; Must match the id in the linked AI Card + id: text, ; Must match the id in the linked AI Service Card name: text, ; Human-readable name for the AI Service description: text, ; Short description ? tags: [* text], ; A list of tags for filtering and discovery diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 5d5f20b..2bdb745 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -1,11 +1,11 @@ // --8<-- [start:AICard] /** - * The unified AI Card object for a single agent. + * The unified AI Card object for a single AI Service (Agent or Tool). */ export interface AICard { /** * Declares the schema this card adheres to. - * e.g., "https://a2a-protocol.org/ai-card/v1/schema.json" + * e.g., "https://ai-service-protocol.org/ai-card/v1/schema.json" */ $schema: string; @@ -16,7 +16,7 @@ export interface AICard { specVersion: string; /** - * The primary verifiable ID for the agent (e.g., DID, SPIFFE, or stable URL). + * The primary verifiable ID for the AI service (e.g., DID, SPIFFE, or stable URL). * This acts as the Subject of the card. */ id: string; @@ -27,17 +27,17 @@ export interface AICard { identityType?: string; /** - * A human-readable name for the agent. + * A human-readable name for the AI service. */ name: string; /** - * A short, human-readable description of the agent's purpose. + * A short, human-readable description of the AI service's purpose. */ description: string; /** - * A URL to the agent's logo image. Data URLs (RFC 2397) are recommended. + * A URL to the AI service's logo image. Data URLs (RFC 2397) are recommended. */ logoUrl?: string; @@ -47,19 +47,19 @@ export interface AICard { tags?: string[]; /** - * The lifecycle stage of the agent. + * The lifecycle stage of the AI service. */ maturity?: "preview" | "stable" | "deprecated"; /** - * Information about the entity (company or individual) that owns this agent. + * Information about the entity (company or individual) that owns this AI service. */ publisher: Publisher; /** * Holds security, compliance, and legal information. */ - trust: Trust; + trust?: Trust; /** * A detached JWS compact serialization signing the canonical content of this card. @@ -67,12 +67,12 @@ export interface AICard { signature?: string; /** - * A map of all interaction protocols this agent supports, keyed by protocol type (e.g. 'a2a', 'mcp'). + * A map of all interaction protocols this AI service supports, keyed by protocol type (e.g. 'a2a', 'mcp'). */ - services: Record; + interfaces: Record; /** - * An ISO 8601 timestamp of when the agent was first published. + * An ISO 8601 timestamp of when the AI service was first published. */ createdAt: string; @@ -92,17 +92,17 @@ export interface AICard { // --8<-- [start:ServiceType] /** - * The protocol identifier for a service. + * The protocol identifier for an AI service interface. * Supports standard protocols ("a2a", "mcp") and custom strings. * The `(string & {})` syntax preserves autocomplete for the known values * while allowing any other string. */ -export type ServiceType = "a2a" | "mcp" | (string & {}); +export type InterfaceType = "a2a" | "mcp" | (string & {}); // --8<-- [end:ServiceType] // --8<-- [start:Publisher] /** - * Defines the entity (company, individual) that published the agent. + * Defines the entity (company, individual) that published the AI service. */ export interface Publisher { /** @@ -129,7 +129,7 @@ export interface Publisher { // --8<-- [start:Trust] /** - * Defines the security, identity, and compliance posture of the agent. + * Defines the security, identity, and compliance posture of the AI service. */ export interface Trust { /** @@ -138,12 +138,12 @@ export interface Trust { attestations?: Attestation[]; /** - * A URL to the agent's Privacy Policy. + * A URL to the AI service's Privacy Policy. */ privacyPolicyUrl?: string; /** - * A URL to the agent's Terms of Service. + * A URL to the AI service's Terms of Service. */ termsOfServiceUrl?: string; } @@ -151,33 +151,55 @@ export interface Trust { // --8<-- [start:Attestation] /** - * A single compliance, security, or custom attestation. + * A reference to a compliance or security proof. + * Uses the "Reference Pattern" (URI + MediaType + Digest) to be format-agnostic. */ export interface Attestation { /** - * The type of attestation (e.g., "SOC2-Type2", "HIPAA-Audit"). + * The semantic type of the attestation (e.g., "SOC2-Type2", "HIPAA-Audit"). */ type: string; /** - * (High-Trust) A URL to a verifiable credential (e.g., a JWT or PDF report). + * The location of the credential. + * Supports both remote locations (https://) and inline data (data://). */ - credentialUrl?: string; + uri: string; /** - * (High-Trust) The embedded, base64-encoded credential itself (e.g., a JWT). + * The format of the credential file (e.g., "application/jwt", "application/pdf"). + * Allows the verifier to select the correct parser. */ - credentialValue?: string; + mediaType: string; + + /** + * (Optional but Recommended) Cryptographic hash of the credential content. + * e.g., "sha256:..." + * Critical for remote URLs to ensure the file hasn't been swapped. + */ + digest?: string; + + /** + * (Optional) The size of the credential in bytes. + * Useful for clients to decide whether to download large reports. + */ + size?: number; + + /** + * (Optional) A human-readable description of this attestation. + * e.g., "2025 Annual Security Audit" + */ + description?: string; } // --8<-- [end:Attestation] -// --8<-- [start:BaseService] +// --8<-- [start:ProtocolInterface] /** * A generic wrapper for a specific protocol interface. */ -export interface BaseService { +export interface ProtocolInterface { /** - * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the services map. + * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the interfaces map. */ type: string; @@ -192,4 +214,4 @@ export interface BaseService { */ protocolSpecific: Record; } -// --8<-- [end:BaseService] \ No newline at end of file +// --8<-- [end:ProtocolInterface] \ No newline at end of file diff --git a/type/src/ai-catalog.ts b/type/src/ai-catalog.ts index 39f586f..5abbc32 100644 --- a/type/src/ai-catalog.ts +++ b/type/src/ai-catalog.ts @@ -1,4 +1,3 @@ - /** * This file acts as the lightweight "index" (catalog) file served from a host's well-known URL, * which is /.well-known/ai-catalog.json. @@ -8,50 +7,50 @@ // --8<-- [start:HostInfo] /** - * Basic information about the host of the catalog. + * Basic information about the host/registry publishing this catalog. */ export interface HostInfo { /** - * The human-readable name of the host (e.g., the company name). + * The human-readable name of the host (e.g., "Acme Enterprise Registry"). */ name: string; /** - * A verifiable ID for the host (e.g., a DID). + * A verifiable ID for the host (e.g., a DID or domain). */ id?: string; /** - * A URL to the host's main documentation. + * A URL to the host's main documentation or landing page. */ documentationUrl?: string; /** - * A URL to the host's logo. + * A URL to the host's logo image. */ logoUrl?: string; } // --8<-- [end:HostInfo] -// --8<-- [start:AgentEntry] +// --8<-- [start:AIServiceEntry] /** * A lightweight entry in the catalog, providing basic discovery - * information and a link to the full AI Card. + * information and a link to the full AICard. */ -export interface AgentEntry { +export interface AIServiceEntry { /** - * The primary verifiable ID for the agent (e.g., DID). - * This MUST match the 'id' in the full AICard. + * The primary verifiable ID for the AI Service. + * This MUST match the `id` field in the linked `ai-card.json`. */ id: string; /** - * A human-readable name for the agent. + * A human-readable name for the AI service. */ name: string; /** - * A short description of the agent. + * A short description of the AI service. */ description: string; @@ -61,7 +60,7 @@ export interface AgentEntry { tags?: string[]; /** - * The full, absolute URL to this agent's complete ai-card.json file. + * The full, absolute URL to this AI service's complete `ai-card.json` file. */ cardUrl: string; @@ -70,23 +69,24 @@ export interface AgentEntry { * was last modified. * Used by crawlers to determine if they need to re-fetch the full card. */ - updatedAt: string; + updatedAt: string; } -// --8<-- [end:AgentEntry] +// --8<-- [end:ServiceEntry] // --8<-- [start:AICatalog] /** - * Defines the structure for a host's master agent catalog. + * Defines the structure for a host's master AI service catalog. * This file is expected to be at "/.well-known/ai-catalog.json". */ export interface AICatalog { /** * Declares the schema this catalog adheres to. + * e.g., "https://ai-service-protocol.org/ai-catalog/v1/schema.json" */ $schema: string; /** - * The version of the AI Catalog specification itself. + * The version of the AI Catalog specification itself (e.g., "1.0"). */ specVersion: string; @@ -96,8 +96,8 @@ export interface AICatalog { host: HostInfo; /** - * An array of lightweight entries for all agents on this host. + * An array of lightweight entries for all AI Services available on this host. */ - agents: AgentEntry[]; + services: AIServiceEntry[]; } // --8<-- [end:AICatalog] \ No newline at end of file diff --git a/type/src/protocol-extension.ts b/type/src/protocol-extension.ts deleted file mode 100644 index 5f0d2de..0000000 --- a/type/src/protocol-extension.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * This file is not part of the core spec. It's maintained by the protocol - * teams (A2A, MCP) to define what goes inside their protocolSpecific. - * Slightly simplified version from the current A2A AgentCard and MCP Proposal types. - */ - -// --8<-- [start:A2AProtocolSpecific] -/** - * The payload for the 'protocolSpecific' field when type == "a2a". - * This is defined and maintained by the A2A project. - */ -export interface A2AProtocolSpecific { - /** - * From A2A Spec: The version of the A2A protocol. - */ - protocolVersion: string; - - /** - * From A2A Spec: The preferred transport (e.g., "JSONRPC"). - */ - preferredTransport?: string; - - /** - * From A2A Spec: List of alternative transports/URLs. - */ - additionalInterfaces?: { - transport: string; - url: string; - }[]; - - /** - * From A2A Spec: A2A-specific capabilities. - */ - capabilities?: { - supportsStreaming?: boolean; - supportsPushNotifications?: boolean; - }; - - /** - * From A2A Spec: The list of skills this agent provides. - */ - skills: { - name: string; - description: string; - inputSchema?: Record; - }[]; -} -// --8<-- [end:A2AProtocolSpecific] - -// --8<-- [start:MCPProtocolSpecific] -/** - * The payload for the 'protocolSpecific' field when type == "mcp". - * This is defined and maintained by the MCP project. - */ -export interface MCPProtocolSpecific { - /** - * From MCP Proposal: The version of the MCP protocol. - */ - protocolVersion: string; - - /** - * From MCP Proposal: The type of transport (e.g., "streamable-http"). - * The 'endpoint' is already in the BaseService. - */ - transportType?: string; - - /** - * From MCP Proposal: MCP-specific server capabilities. - */ - capabilities: { - tools?: { listChanged?: boolean }; - prompts?: { listChanged?: boolean }; - resources?: { subscribe?: boolean; listChanged?: boolean }; - }; - - /** - * From MCP Proposal: Required client capabilities. - */ - requires?: { - sampling?: object; - roots?: object; - }; - - /** - * From MCP Proposal: Static list of tools, or "dynamic". - */ - tools: "dynamic" | { - name: string; - description: string; - inputSchema?: Record; - }[]; - - /** - * From MCP Proposal: Static list of prompts, or "dynamic". - */ - prompts: "dynamic" | { name: string; description: string }[]; - - /** - * From MCP Proposal: Static list of resources, or "dynamic". - */ - resources: "dynamic" | { name: string; uri: string }[]; -} -// --8<-- [end:MCPProtocolSpecific] \ No newline at end of file From f84259ae5cc48d334db1d305927de2a4557acaa4 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Thu, 11 Dec 2025 17:07:06 -0800 Subject: [PATCH 21/27] updated .gitignore --- .gitignore | 5 +++++ type/.gitignore | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 .gitignore delete mode 100644 type/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5500a9a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +node_modules/ +tsconfig.json +type/*.md +specification/json/ \ No newline at end of file diff --git a/type/.gitignore b/type/.gitignore deleted file mode 100644 index 58b805f..0000000 --- a/type/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.DS_Store -node_modules/ \ No newline at end of file From 49c50f3b6d22e7dcfbe3bfa56d69880db3c8e1fa Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Thu, 11 Dec 2025 17:09:25 -0800 Subject: [PATCH 22/27] updated the field name from interfaces to protocols for supported protocol interfaces in AI card --- .gitignore | 4 +++- type/ai-card-cddl.md | 8 +++---- type/ai-card-example.md | 2 +- type/src/ai-card.ts | 46 ++++++++++++++++++++--------------------- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 5500a9a..c28a1d7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ node_modules/ tsconfig.json type/*.md -specification/json/ \ No newline at end of file +specification/json/ +package-lock.json +package.json \ No newline at end of file diff --git a/type/ai-card-cddl.md b/type/ai-card-cddl.md index cfc6b0a..690c06a 100644 --- a/type/ai-card-cddl.md +++ b/type/ai-card-cddl.md @@ -27,7 +27,7 @@ AICard = { ; --- Protocols --- ; Map of supported protocol interfaces (e.g. "a2a" => Interface, "mcp" => Interface) - interfaces: { * ServiceType => ProtocolInterface }, + protocols: { * ProtocolType => Protocol }, ; --- Housekeeping --- createdAt: tdate, ; ISO 8601 Date when the AI service was first created @@ -36,7 +36,7 @@ AICard = { } MaturityLevel = "preview" / "stable" / "deprecated" -ServiceType = "mcp" / "a2a" / text +ProtocolType = "mcp" / "a2a" / text ; --- Core Components --- @@ -66,9 +66,9 @@ Attestation = { ? description: text ; Human-readable label } -; --- Interaction Interfaces --- +; --- Interaction Protocol --- -ProtocolInterface = { +Protocol = { type: ServiceType, ; Protocol ID (matches key in interfaces map) ? name: text, ; Human-readable label (e.g. "Primary Interface") diff --git a/type/ai-card-example.md b/type/ai-card-example.md index 459cdf9..934ee3d 100644 --- a/type/ai-card-example.md +++ b/type/ai-card-example.md @@ -46,7 +46,7 @@ Notice here the top-level `name` is for the agent, and the `name` field *inside* "termsOfServiceUrl": "https://acme-finance.com/legal/terms" }, - "interfaces": { + "protocols": { "a2a": { "type": "a2a", "name": "Finance A2A Interface", diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index 2bdb745..b19f0fc 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -5,7 +5,7 @@ export interface AICard { /** * Declares the schema this card adheres to. - * e.g., "https://ai-service-protocol.org/ai-card/v1/schema.json" + * e.g., "https://a2a-protocol.org/ai-card/v1/schema.json" */ $schema: string; @@ -16,7 +16,7 @@ export interface AICard { specVersion: string; /** - * The primary verifiable ID for the AI service (e.g., DID, SPIFFE, or stable URL). + * The primary verifiable ID for the service (e.g., DID, SPIFFE, or stable URL). * This acts as the Subject of the card. */ id: string; @@ -27,17 +27,17 @@ export interface AICard { identityType?: string; /** - * A human-readable name for the AI service. + * A human-readable name for the service. */ name: string; /** - * A short, human-readable description of the AI service's purpose. + * A short, human-readable description of the service's purpose. */ description: string; /** - * A URL to the AI service's logo image. Data URLs (RFC 2397) are recommended. + * A URL to the service's logo image. Data URLs (RFC 2397) are recommended. */ logoUrl?: string; @@ -47,12 +47,12 @@ export interface AICard { tags?: string[]; /** - * The lifecycle stage of the AI service. + * The lifecycle stage of the service. */ maturity?: "preview" | "stable" | "deprecated"; /** - * Information about the entity (company or individual) that owns this AI service. + * Information about the entity (company or individual) that owns this service. */ publisher: Publisher; @@ -67,12 +67,12 @@ export interface AICard { signature?: string; /** - * A map of all interaction protocols this AI service supports, keyed by protocol type (e.g. 'a2a', 'mcp'). + * A map of all interaction protocols this service supports, keyed by protocol type (e.g. 'a2a', 'mcp'). */ - interfaces: Record; + protocols: Record; /** - * An ISO 8601 timestamp of when the AI service was first published. + * An ISO 8601 timestamp of when the service was first published. */ createdAt: string; @@ -90,19 +90,19 @@ export interface AICard { // --- CORE COMPONENTS --- -// --8<-- [start:ServiceType] +// --8<-- [start:ProtocolType] /** - * The protocol identifier for an AI service interface. + * The identifier for a supported protocol. * Supports standard protocols ("a2a", "mcp") and custom strings. * The `(string & {})` syntax preserves autocomplete for the known values * while allowing any other string. */ -export type InterfaceType = "a2a" | "mcp" | (string & {}); -// --8<-- [end:ServiceType] +export type ProtocolType = "a2a" | "mcp" | (string & {}); +// --8<-- [end:ProtocolType] // --8<-- [start:Publisher] /** - * Defines the entity (company, individual) that published the AI service. + * Defines the entity (company, individual) that published the service. */ export interface Publisher { /** @@ -129,7 +129,7 @@ export interface Publisher { // --8<-- [start:Trust] /** - * Defines the security, identity, and compliance posture of the AI service. + * Defines the security, identity, and compliance posture of the service. */ export interface Trust { /** @@ -138,12 +138,12 @@ export interface Trust { attestations?: Attestation[]; /** - * A URL to the AI service's Privacy Policy. + * A URL to the service's Privacy Policy. */ privacyPolicyUrl?: string; /** - * A URL to the AI service's Terms of Service. + * A URL to the service's Terms of Service. */ termsOfServiceUrl?: string; } @@ -193,13 +193,13 @@ export interface Attestation { } // --8<-- [end:Attestation] -// --8<-- [start:ProtocolInterface] +// --8<-- [start:Protocol] /** - * A generic wrapper for a specific protocol interface. + * The data structure containing specific configuration for a protocol (e.g., endpoints, auth schemes). */ -export interface ProtocolInterface { +export interface Protocol { /** - * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the interfaces map. + * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the protocols map. */ type: string; @@ -214,4 +214,4 @@ export interface ProtocolInterface { */ protocolSpecific: Record; } -// --8<-- [end:ProtocolInterface] \ No newline at end of file +// --8<-- [end:Protocol] \ No newline at end of file From a47e2d2b44cb5664af4fdaa01b73371d2d655183 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Fri, 26 Dec 2025 11:40:34 -0800 Subject: [PATCH 23/27] refactor: rename Protocol to ProtocolDetail and update related types in AI Card specification, updated comparison.md --- type/ai-card-cddl.md | 8 ++++---- type/comparison.md | 8 ++++---- type/src/ai-card.ts | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/type/ai-card-cddl.md b/type/ai-card-cddl.md index 690c06a..8ebc881 100644 --- a/type/ai-card-cddl.md +++ b/type/ai-card-cddl.md @@ -27,7 +27,7 @@ AICard = { ; --- Protocols --- ; Map of supported protocol interfaces (e.g. "a2a" => Interface, "mcp" => Interface) - protocols: { * ProtocolType => Protocol }, + protocols: { * ProtocolType => ProtocolDetail }, ; --- Housekeeping --- createdAt: tdate, ; ISO 8601 Date when the AI service was first created @@ -68,9 +68,9 @@ Attestation = { ; --- Interaction Protocol --- -Protocol = { - type: ServiceType, ; Protocol ID (matches key in interfaces map) - ? name: text, ; Human-readable label (e.g. "Primary Interface") +ProtocolDetail = { + type: ProtocolType, ; Protocol ID (matches key in protocols map) + ? name: text, ; Human-readable label (e.g. "Fiance Agent A2A") ; The "Black Box" for protocol-specific data ; Endpoints, Auth, and Skills are defined INSIDE here by the protocol spec. diff --git a/type/comparison.md b/type/comparison.md index 76154e6..ad8314b 100644 --- a/type/comparison.md +++ b/type/comparison.md @@ -13,8 +13,8 @@ This table shows how the fields from A2A and MCP map to the unified AI Card stru | **Logo** | `icon_url` | `iconUrl` | **`logoUrl`** (Rec: Data URI) | | **Publisher** | `provider` (Object) | `serverInfo` | **`publisher`** (Object with `id`, `name`) | | **Trust / Security** | `signatures` (Optional) | Not Defined | **`trust`** (Optional Object: Proofs, Policies) | -| **Protocol Support** | Implied (A2A Only) | Implied (MCP Only) | **`services`** (Map: `"a2a": {...}`, `"mcp": {...}`) | -| **Endpoint URL** | `url` | `transport.endpoint` | `services[x].protocolSpecific` (**Delegated**) | -| **Authentication** | `securitySchemes` | `authentication` | `services[x].protocolSpecific` (**Delegated**) | -| **Capabilities** | `skills` | `tools`, `resources` | `services[x].protocolSpecific` (**Delegated**) | +| **Protocol Support** | Implied (A2A Only) | Implied (MCP Only) | **`protocols`** (Map: `"a2a": {...}`, `"mcp": {...}`) | +| **Endpoint URL** | `url` | `transport.endpoint` | `protocols[x].protocolSpecific` (**Delegated**) | +| **Authentication** | `securitySchemes` | `authentication` | `protocols[x].protocolSpecific` (**Delegated**) | +| **Capabilities** | `skills` | `tools`, `resources` | `protocols[x].protocolSpecific` (**Delegated**) | | **Versioning** | `version` | `serverInfo.version` | **`specVersion`** (Card Ver) + `updatedAt` | \ No newline at end of file diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts index b19f0fc..23700be 100644 --- a/type/src/ai-card.ts +++ b/type/src/ai-card.ts @@ -69,7 +69,7 @@ export interface AICard { /** * A map of all interaction protocols this service supports, keyed by protocol type (e.g. 'a2a', 'mcp'). */ - protocols: Record; + protocols: Record; /** * An ISO 8601 timestamp of when the service was first published. @@ -193,11 +193,11 @@ export interface Attestation { } // --8<-- [end:Attestation] -// --8<-- [start:Protocol] +// --8<-- [start:ProtocolDetail] /** * The data structure containing specific configuration for a protocol (e.g., endpoints, auth schemes). */ -export interface Protocol { +export interface ProtocolDetail { /** * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the protocols map. */ @@ -214,4 +214,4 @@ export interface Protocol { */ protocolSpecific: Record; } -// --8<-- [end:Protocol] \ No newline at end of file +// --8<-- [end:ProtocolDetail] \ No newline at end of file From b30935360c8df3e73ca648aaa77e4f750acf50e5 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Thu, 5 Mar 2026 15:18:27 -0800 Subject: [PATCH 24/27] Merge converged changes from PR #17, added artifacts, also update naming from PR #18 Co-authored-by: Luca Muscariello --- .../cddl/ai-card.md | 32 ++- .../cddl/ai-cddl.md | 6 +- {type => specification/cddl}/comparison.md | 0 specification/examples/ai-catalog.json | 33 +++ specification/examples/data-asset-card.json | 55 +++++ specification/examples/live-service-card.json | 100 ++++++++ type/ai-card-example.md | 116 ---------- type/ai-catalog-example.md | 36 --- type/src/ai-card.ts | 217 ------------------ type/src/ai-catalog.ts | 103 --------- 10 files changed, 216 insertions(+), 482 deletions(-) rename type/ai-card-cddl.md => specification/cddl/ai-card.md (79%) rename type/ai-catalog-cddl.md => specification/cddl/ai-cddl.md (88%) rename {type => specification/cddl}/comparison.md (100%) create mode 100644 specification/examples/ai-catalog.json create mode 100644 specification/examples/data-asset-card.json create mode 100644 specification/examples/live-service-card.json delete mode 100644 type/ai-card-example.md delete mode 100644 type/ai-catalog-example.md delete mode 100644 type/src/ai-card.ts delete mode 100644 type/src/ai-catalog.ts diff --git a/type/ai-card-cddl.md b/specification/cddl/ai-card.md similarity index 79% rename from type/ai-card-cddl.md rename to specification/cddl/ai-card.md index 8ebc881..0f990dc 100644 --- a/type/ai-card-cddl.md +++ b/specification/cddl/ai-card.md @@ -9,12 +9,9 @@ AICard = { $schema: text, ; URI to the JSON schema (e.g. "https://...") specVersion: text, ; Major.Minor version (e.g. "1.0") - ; --- Identity (Subject) --- - id: text, ; The Primary Key / Subject of this card, Globally Unique URI (per RFC 3986), (DID, SPIFFE, or URL) - ? identityType: text, ; Type hint (e.g. "did", "spiffe"). Optional if clear from ID. - + identifier: text, ; agent global unqiue identifier in URN format (see: https://github.com/Agent-Card/ai-card/pull/18) ; --- Metadata --- - name: text, ; Human-readable name for the AI service + displayName: text, ; Human-readable name for the AI service description: text, ; Short description of the AI service's purpose ? logoUrl: text, ; URL to logo. Data URL (RFC 2397) recommended for privacy ? tags: [* text], ; List of keywords to aid in discovery @@ -42,18 +39,39 @@ ProtocolType = "mcp" / "a2a" / text Publisher = { id: text, ; Verifiable ID of the publisher organization - ? identityType: text, ; Type hint (e.g. "did", "dns") name: text, ; Human-readable name of the publisher + ? identityType: text, ; Type hint (e.g. "did", "dns") ? attestation: Attestation ; Proof of the publisher's identity } Trust = { - ; Identity is now implicit (matches Root id) + ; --- Identity (Subject) --- + identity: text, ; The Primary Key / Subject of this card, Globally Unique URI (per RFC 3986), (DID, SPIFFE, or URL) + ? identityType: text, ; Type hint (e.g. "did", "spiffe"). Optional if clear from ID. + + ? trustSchema: TrustSchema, ? attestations: [* Attestation], ; List of compliance credentials (SOC2, HIPAA, etc.) + ? provenance: [* ProvenanceLink], ? privacyPolicyUrl: text, ; URL to the privacy policy ? termsOfServiceUrl: text ; URL to the terms of service } +TrustSchema = { + id: text, + version: text, + ? governanceUri: text, + ? verificationMethods: [* text] +} + +ProvenanceLink = { + relation: text, + sourceId: text, + ? sourceDigest: text, + ? registryUri: text, + ? statementUri: text, + ? signatureRef: text +} + Attestation = { type: text, ; Type of proof (e.g. "SOC2-Type2", "HIPAA-Audit") diff --git a/type/ai-catalog-cddl.md b/specification/cddl/ai-cddl.md similarity index 88% rename from type/ai-catalog-cddl.md rename to specification/cddl/ai-cddl.md index 68a434f..55a867f 100644 --- a/type/ai-catalog-cddl.md +++ b/specification/cddl/ai-cddl.md @@ -8,8 +8,8 @@ AICatalog = { $schema: text, ; URI to the JSON schema specVersion: text, ; Version of the Catalog spec (e.g. "1.0.0") - host: HostInfo, ; Who runs this server/registry - services: [* AIServiceEntry] ; The list of available AI services + ? host: HostInfo, ; Who runs this server/registry + entry: [* CatalogEntry] ; The list of available AI services } HostInfo = { @@ -19,7 +19,7 @@ HostInfo = { ? logoUrl: text ; A URL to the host's logo } -AIServiceEntry = { +CatalogEntry = { id: text, ; Must match the id in the linked AI Service Card name: text, ; Human-readable name for the AI Service description: text, ; Short description diff --git a/type/comparison.md b/specification/cddl/comparison.md similarity index 100% rename from type/comparison.md rename to specification/cddl/comparison.md diff --git a/specification/examples/ai-catalog.json b/specification/examples/ai-catalog.json new file mode 100644 index 0000000..efd1783 --- /dev/null +++ b/specification/examples/ai-catalog.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://agent-card.github.io/spec/sep-0015/catalog-schema.json", + "specVersion": "1.0", + "host": { + "name": "Acme Services Inc.", + "id": "did:example:org-acme-corp", + "documentationUrl": "https://docs.acme-corp.com/agents" + }, + "records": [ + { + "id": "did:example:agent-finance-001", + "name": "Acme Finance Agent", + "description": "Multi-protocol finance agent.", + "tags": [ + "finance", + "trading" + ], + "cardUrl": "https://api.acme-corp.com/cards/acme-finance-agent.json", + "updatedAt": "2026-02-22T16:30:00Z" + }, + { + "id": "urn:example:data:market-dataset-2026q1", + "name": "Market Dataset Q1 2026", + "description": "Artifact-focused card for training and evaluation.", + "tags": [ + "dataset", + "finance" + ], + "cardUrl": "https://api.acme-corp.com/cards/market-dataset-2026q1.json", + "updatedAt": "2026-02-22T16:00:00Z" + } + ] +} \ No newline at end of file diff --git a/specification/examples/data-asset-card.json b/specification/examples/data-asset-card.json new file mode 100644 index 0000000..b5042de --- /dev/null +++ b/specification/examples/data-asset-card.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://agent-card.github.io/spec/sep-0015/schema.json", + "specVersion": "1.0", + "cardVersion": "2026.02.22", + "identifier": "urn:example:data:market-dataset-2026q1", + "displayName": "Market Dataset Q1 2026", + "description": "Historical market data prepared for model training and evaluation.", + "publisher": { + "id": "did:example:org-acme", + "identityType": "did", + "name": "Acme Financial Corp" + }, + "artifacts": { + "dataset": { + "id": "artifact/dataset", + "version": "1.0.0", + "data": { + "format": "parquet", + "artifacts": [ + { + "uri": "oci://registry.example.com/ai-data/market-dataset:2026q1", + "mediaType": "application/parquet", + "digest": "sha256:9999888877776666555544443333222211110000aaaabbbbccccddddeeeeffff", + "size": 24599124, + "description": "Primary dataset artifact" + } + ] + } + } + }, + "trust": { + "identity": "did:example:data:market-dataset-2026q1", + "identityType": "did", + "trustSchema": { + "id": "https://trust.acme-finance.com/schemas/ai-card-trust-profile", + "version": "1.0", + "governanceUri": "https://trust.acme-finance.com/policies/ai-card-trust", + "verificationMethods": [ + "did", + "x509" + ] + }, + "provenance": [ + { + "relation": "publishedFrom", + "sourceId": "oci://registry.example.com/ai-data/market-dataset:2026q1", + "sourceDigest": "sha256:9999888877776666555544443333222211110000aaaabbbbccccddddeeeeffff", + "registryUri": "oci://registry.example.com/ai-data/market-dataset@sha256:9999888877776666555544443333222211110000aaaabbbbccccddddeeeeffff", + "statementUri": "https://trust.acme-finance.com/provenance/market-dataset-2026q1.dsse.json" + } + ] + }, + "createdAt": "2026-02-22T16:00:00Z", + "updatedAt": "2026-02-22T16:00:00Z" +} \ No newline at end of file diff --git a/specification/examples/live-service-card.json b/specification/examples/live-service-card.json new file mode 100644 index 0000000..c77471a --- /dev/null +++ b/specification/examples/live-service-card.json @@ -0,0 +1,100 @@ +{ + "$schema": "https://agent-card.github.io/spec/sep-0015/schema.json", + "specVersion": "1.0", + "cardVersion": "2026.02.22", + "identifier": "urn:example:agent-finance-001", + "displayName": "Acme Finance Agent", + "description": "Executes finance workflows through multiple protocol adapters.", + "publisher": { + "id": "did:example:org-acme", + "name": "Acme Financial Corp", + "identityType": "did" + }, + "protocols": { + "a2a": { + "id": "protocol/a2a", + "version": "0.1.0", + "required": true, + "data": { + "protocolVersion": "0.3.0", + "locators": [ + { + "type": "https", + "role": "api", + "uri": "https://api.acme-finance.com/a2a/v1" + } + ], + "skills": [ + { + "id": "skill-stock-analysis", + "name": "Run Stock Analysis" + } + ] + } + }, + "mcp": { + "id": "protocol/mcp", + "version": "0.1.0", + "required": true, + "data": { + "protocolVersion": "2025-06-18", + "locators": [ + { + "type": "https", + "role": "api", + "uri": "https://api.acme-finance.com/mcp/v1" + } + ], + "capabilities": { + "tools": { + "listChanged": true + } + } + } + } + }, + "trust": { + "id": "did:example:agent-finance-001", + "identityType": "did", + "trustSchema": { + "id": "https://trust.acme-finance.com/schemas/ai-card-trust-profile", + "version": "1.0", + "governanceUri": "https://trust.acme-finance.com/policies/ai-card-trust", + "verificationMethods": [ + "did", + "x509", + "dns-01" + ] + }, + "privacyPolicyUrl": "https://acme-finance.com/legal/privacy", + "termsOfServiceUrl": "https://acme-finance.com/legal/terms", + "provenance": [ + { + "relation": "materializedFrom", + "sourceId": "urn:example:data:market-dataset-2026q1", + "sourceDigest": "sha256:9999888877776666555544443333222211110000aaaabbbbccccddddeeeeffff", + "registryUri": "oci://registry.example.com/ai-data/market-dataset@sha256:9999888877776666555544443333222211110000aaaabbbbccccddddeeeeffff", + "statementUri": "https://trust.acme-finance.com/provenance/finance-agent-runtime-20260222.dsse.json", + "signatureRef": "did:example:org-acme#keys-1" + } + ], + "attestations": [ + { + "type": "SOC2-Type2", + "uri": "https://trust.acme-finance.com/reports/soc2-latest.pdf", + "mediaType": "application/pdf", + "digest": "sha256:a1b2c3d4" + } + ] + }, + "signatures": [ + { + "format": "jws-compact", + "keyId": "did:example:org-acme#keys-1", + "createdAt": "2026-02-22T16:30:00Z", + "value": "eyJhbGciOiJFUzI1NiJ9..detached-signature" + } + ], + "createdAt": "2026-02-22T16:00:00Z", + "updatedAt": "2026-02-22T16:30:00Z" +} \ No newline at end of file diff --git a/type/ai-card-example.md b/type/ai-card-example.md deleted file mode 100644 index 934ee3d..0000000 --- a/type/ai-card-example.md +++ /dev/null @@ -1,116 +0,0 @@ -Here is an example `ai-card.json` file that defines a single **"Stock Trading Agent"** which provides its functions over both A2A and MCP. - -Notice here the top-level `name` is for the agent, and the `name` field *inside* each service is just a label for that specific protocol interface. - -```json -{ - "$schema": "https://a2a-protocol.org/ai-card/v1/schema.json", - "specVersion": "1.0", - - "id": "did:example:agent-finance-001", - "identityType": "did", - "name": "Acme Finance Agent", - "description": "An agent for executing stock trades and getting market analysis via A2A and MCP.", - "logoUrl": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48Y2lyY2xlIGN4PSI1MCIgY3k9IjUwIiByPSI0MCIgZmlsbD0iIzRjNTFnZiIgLz48L3N2Zz4=", - "maturity": "stable", - "signature": "eyJhbGciOiJFUzI1NiJ9..[detached-jws-signature]..", - - "publisher": { - "id": "did:example:org-acme", - "identityType": "did", - "name": "Acme Financial Corp", - "attestation": { - "type": "IdentityProof", - "uri": "https://trust.acme.com/identity.jwt", - "mediaType": "application/jwt" - } - }, - - "trust": { - "attestations": [ - { - "type": "SOC2-Type2", - "description": "2025 SOC2 Type II Report", - "uri": "https://trust.acme-finance.com/reports/soc2-latest.pdf", - "mediaType": "application/pdf", - "digest": "sha256:a1b2c3d4..." - }, - { - "type": "FINRA-Audit", - "description": "Embedded Audit Token", - "uri": "data:application/jwt;base64,eyJhbGciOiJSUzI1NiIsImtpZCI6ImZpbnJhLWtleS0xIn0...", - "mediaType": "application/jwt" - } - ], - "privacyPolicyUrl": "https://acme-finance.com/legal/privacy", - "termsOfServiceUrl": "https://acme-finance.com/legal/terms" - }, - - "protocols": { - "a2a": { - "type": "a2a", - "name": "Finance A2A Interface", - "protocolSpecific": { - "protocolVersion": "0.3.0", - "supportedInterfaces": [ - { - "transport": "JSONRPC", - "url": "https://api.acme-finance.com/a2a/v1" - } - ], - "securitySchemes": { - "oauth2": { - "type": "oauth2", - "flows": { - "clientCredentials": { - "tokenUrl": "https://auth.acme-finance.com/token", - "scopes": { - "stocks:read": "Allows getting stock quotes" - } - } - } - } - }, - "skills": [ - { - "id": "skill-stock-analysis", - "name": "Run Stock Analysis", - "description": "Use the latest LLM based technology to run stock analysis and predictions.", - "inputModes": ["application/json"], - "outputModes": ["application/json", "text/markdown"], - "tags": ["finance", "analysis", "prediction"] - } - ] - } - }, - "mcp": { - "type": "mcp", - "name": "Finance MCP Interface", - "protocolSpecific": { - "protocolVersion": "2025-06-18", - "transport": { - "type": "streamable-http", - "endpoint": "https://api.acme-finance.com/mcp/v1" - }, - "authentication": { - "type": "oauth2", - "required": true - }, - "capabilities": { - "tools": { "listChanged": true } - }, - "tools": "dynamic", - "prompts": "dynamic", - "resources": "dynamic" - } - } - }, - - "createdAt": "2025-01-20T10:00:00Z", - "updatedAt": "2025-11-01T15:00:00Z", - - "metadata": { - "region": "us-east-1" - } -} -``` \ No newline at end of file diff --git a/type/ai-catalog-example.md b/type/ai-catalog-example.md deleted file mode 100644 index 8ce5d86..0000000 --- a/type/ai-catalog-example.md +++ /dev/null @@ -1,36 +0,0 @@ -The lightweighted AI Catalog for: /.well-known/ai-catalog.json - -The Client's Workflow - - Client: "What agents does api.acme-corp.com have?" - - GET /.well-known/ai-catalog.json - - Client: "Got the list. I see two agents. I want to use the 'Acme Finance Agent'." - - (Parses the cardUrl from the catalog): https://api.acme-corp.com/agents/finance-agent/ai-card.json - - GET /agents/finance-agent/ai-card.json - - Client: "Got the full AI Card. Now I can see its A2A/MCP endpoints and its trust information." - -```json -{ - "$schema": "https://a2a-protocol.org/ai-catalog/v1/schema.json", - "specVersion": "1.0.0", - "host": { - "name": "Acme Services Inc.", - "id": "did:example:org-acme-corp" - }, - "services": [ - { - "id": "did:example:agent-finance-001", - "name": "Acme Finance Agent", - "description": "An agent for executing stock trades.", - "tags": ["finance", "stocks"], - "cardUrl": "https://api.acme-corp.com/agents/finance-agent/ai-card.json" - }, - { - "id": "did:example:agent-weather-002", - "name": "Acme Weather Agent", - "description": "Provides real-time weather forecasts.", - "tags": ["weather", "forecast"], - "cardUrl": "https://api.acme-corp.com/agents/weather-agent/ai-card.json" - } - ] -} -``` \ No newline at end of file diff --git a/type/src/ai-card.ts b/type/src/ai-card.ts deleted file mode 100644 index 23700be..0000000 --- a/type/src/ai-card.ts +++ /dev/null @@ -1,217 +0,0 @@ -// --8<-- [start:AICard] -/** - * The unified AI Card object for a single AI Service (Agent or Tool). - */ -export interface AICard { - /** - * Declares the schema this card adheres to. - * e.g., "https://a2a-protocol.org/ai-card/v1/schema.json" - */ - $schema: string; - - /** - * The version of the AI Card specification itself (e.g., "1.0"). - * Major.Minor version only. - */ - specVersion: string; - - /** - * The primary verifiable ID for the service (e.g., DID, SPIFFE, or stable URL). - * This acts as the Subject of the card. - */ - id: string; - - /** - * Optional hint for the identity type (e.g., "did", "spiffe"). - */ - identityType?: string; - - /** - * A human-readable name for the service. - */ - name: string; - - /** - * A short, human-readable description of the service's purpose. - */ - description: string; - - /** - * A URL to the service's logo image. Data URLs (RFC 2397) are recommended. - */ - logoUrl?: string; - - /** - * A list of keywords to aid in discovery. - */ - tags?: string[]; - - /** - * The lifecycle stage of the service. - */ - maturity?: "preview" | "stable" | "deprecated"; - - /** - * Information about the entity (company or individual) that owns this service. - */ - publisher: Publisher; - - /** - * Holds security, compliance, and legal information. - */ - trust?: Trust; - - /** - * A detached JWS compact serialization signing the canonical content of this card. - */ - signature?: string; - - /** - * A map of all interaction protocols this service supports, keyed by protocol type (e.g. 'a2a', 'mcp'). - */ - protocols: Record; - - /** - * An ISO 8601 timestamp of when the service was first published. - */ - createdAt: string; - - /** - * An ISO 8601 timestamp of when this entire AI Card document was last modified. - */ - updatedAt: string; - - /** - * An open 'black box' for any other non-standard metadata. - */ - metadata?: Record; -} -// --8<-- [end:AICard] - -// --- CORE COMPONENTS --- - -// --8<-- [start:ProtocolType] -/** - * The identifier for a supported protocol. - * Supports standard protocols ("a2a", "mcp") and custom strings. - * The `(string & {})` syntax preserves autocomplete for the known values - * while allowing any other string. - */ -export type ProtocolType = "a2a" | "mcp" | (string & {}); -// --8<-- [end:ProtocolType] - -// --8<-- [start:Publisher] -/** - * Defines the entity (company, individual) that published the service. - */ -export interface Publisher { - /** - * A verifiable ID for the publisher (e.g., DID). - */ - id: string; - - /** - * Optional hint for the publisher identity type. - */ - identityType?: string; - - /** - * The human-readable name of the publisher. - */ - name: string; - - /** - * Proof of the publisher's identity. - */ - attestation?: Attestation; -} -// --8<-- [end:Publisher] - -// --8<-- [start:Trust] -/** - * Defines the security, identity, and compliance posture of the service. - */ -export interface Trust { - /** - * A list of compliance or other attestations. - */ - attestations?: Attestation[]; - - /** - * A URL to the service's Privacy Policy. - */ - privacyPolicyUrl?: string; - - /** - * A URL to the service's Terms of Service. - */ - termsOfServiceUrl?: string; -} -// --8<-- [end:Trust] - -// --8<-- [start:Attestation] -/** - * A reference to a compliance or security proof. - * Uses the "Reference Pattern" (URI + MediaType + Digest) to be format-agnostic. - */ -export interface Attestation { - /** - * The semantic type of the attestation (e.g., "SOC2-Type2", "HIPAA-Audit"). - */ - type: string; - - /** - * The location of the credential. - * Supports both remote locations (https://) and inline data (data://). - */ - uri: string; - - /** - * The format of the credential file (e.g., "application/jwt", "application/pdf"). - * Allows the verifier to select the correct parser. - */ - mediaType: string; - - /** - * (Optional but Recommended) Cryptographic hash of the credential content. - * e.g., "sha256:..." - * Critical for remote URLs to ensure the file hasn't been swapped. - */ - digest?: string; - - /** - * (Optional) The size of the credential in bytes. - * Useful for clients to decide whether to download large reports. - */ - size?: number; - - /** - * (Optional) A human-readable description of this attestation. - * e.g., "2025 Annual Security Audit" - */ - description?: string; -} -// --8<-- [end:Attestation] - -// --8<-- [start:ProtocolDetail] -/** - * The data structure containing specific configuration for a protocol (e.g., endpoints, auth schemes). - */ -export interface ProtocolDetail { - /** - * The protocol identifier (e.g., "a2a", "mcp"). Must match the key in the protocols map. - */ - type: string; - - /** - * A human-readable label for this interface. - */ - name?: string; - - /** - * The 'Black Box' for protocol-specific data (Endpoints, Auth, Skills). - * Validated by the protocol's own schema. - */ - protocolSpecific: Record; -} -// --8<-- [end:ProtocolDetail] \ No newline at end of file diff --git a/type/src/ai-catalog.ts b/type/src/ai-catalog.ts deleted file mode 100644 index 5abbc32..0000000 --- a/type/src/ai-catalog.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * This file acts as the lightweight "index" (catalog) file served from a host's well-known URL, - * which is /.well-known/ai-catalog.json. - * Note this is the recommended binding for ** domain-based discovery **, but the AI Card format is - * transport-agnostic and intended to be served by SaaS Registry APIs as well. - */ - -// --8<-- [start:HostInfo] -/** - * Basic information about the host/registry publishing this catalog. - */ -export interface HostInfo { - /** - * The human-readable name of the host (e.g., "Acme Enterprise Registry"). - */ - name: string; - - /** - * A verifiable ID for the host (e.g., a DID or domain). - */ - id?: string; - - /** - * A URL to the host's main documentation or landing page. - */ - documentationUrl?: string; - - /** - * A URL to the host's logo image. - */ - logoUrl?: string; -} -// --8<-- [end:HostInfo] - -// --8<-- [start:AIServiceEntry] -/** - * A lightweight entry in the catalog, providing basic discovery - * information and a link to the full AICard. - */ -export interface AIServiceEntry { - /** - * The primary verifiable ID for the AI Service. - * This MUST match the `id` field in the linked `ai-card.json`. - */ - id: string; - - /** - * A human-readable name for the AI service. - */ - name: string; - - /** - * A short description of the AI service. - */ - description: string; - - /** - * A list of tags for filtering and discovery. - */ - tags?: string[]; - - /** - * The full, absolute URL to this AI service's complete `ai-card.json` file. - */ - cardUrl: string; - - /** - * An ISO 8601 timestamp of when the referenced `ai-card.json` file - * was last modified. - * Used by crawlers to determine if they need to re-fetch the full card. - */ - updatedAt: string; -} -// --8<-- [end:ServiceEntry] - -// --8<-- [start:AICatalog] -/** - * Defines the structure for a host's master AI service catalog. - * This file is expected to be at "/.well-known/ai-catalog.json". - */ -export interface AICatalog { - /** - * Declares the schema this catalog adheres to. - * e.g., "https://ai-service-protocol.org/ai-catalog/v1/schema.json" - */ - $schema: string; - - /** - * The version of the AI Catalog specification itself (e.g., "1.0"). - */ - specVersion: string; - - /** - * Information about the host/publisher of the entire catalog. - */ - host: HostInfo; - - /** - * An array of lightweight entries for all AI Services available on this host. - */ - services: AIServiceEntry[]; -} -// --8<-- [end:AICatalog] \ No newline at end of file From 2b0192db69e4d83cf7d673924f1771aeccb6a9fd Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Tue, 10 Mar 2026 21:22:19 -0700 Subject: [PATCH 25/27] updated cardUrl description for ai-catalog --- specification/cddl/ai-cddl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specification/cddl/ai-cddl.md b/specification/cddl/ai-cddl.md index 55a867f..4dd1287 100644 --- a/specification/cddl/ai-cddl.md +++ b/specification/cddl/ai-cddl.md @@ -24,7 +24,7 @@ CatalogEntry = { name: text, ; Human-readable name for the AI Service description: text, ; Short description ? tags: [* text], ; A list of tags for filtering and discovery - cardUrl: text, ; URL to the full ai-card.json - updatedAt: tdate ; Last modified time of the AI Card (for crawler optimization) + cardUrl: text, ; URL to the full card (agent.json, mcp.json, ai-card.json, etc) + updatedAt: tdate ; Last modified time of the card (for crawler optimization) } ``` \ No newline at end of file From e94c58e3121d2ab6f2bc9ffb72e6fd1bc5815ed1 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Tue, 10 Mar 2026 21:26:30 -0700 Subject: [PATCH 26/27] fix the name for ai-catalog.md, also changed the fields of each entry from `entry` to `records` --- specification/cddl/{ai-cddl.md => ai-catalog.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename specification/cddl/{ai-cddl.md => ai-catalog.md} (90%) diff --git a/specification/cddl/ai-cddl.md b/specification/cddl/ai-catalog.md similarity index 90% rename from specification/cddl/ai-cddl.md rename to specification/cddl/ai-catalog.md index 4dd1287..1e515e6 100644 --- a/specification/cddl/ai-cddl.md +++ b/specification/cddl/ai-catalog.md @@ -8,8 +8,8 @@ AICatalog = { $schema: text, ; URI to the JSON schema specVersion: text, ; Version of the Catalog spec (e.g. "1.0.0") - ? host: HostInfo, ; Who runs this server/registry - entry: [* CatalogEntry] ; The list of available AI services + ? host: HostInfo, ; Who runs this server/registry + records: [* CatalogEntry] ; The list of available AI services } HostInfo = { From f8b7ba2e9a528bf0749fed5f506c1bad75dd4802 Mon Sep 17 00:00:00 2001 From: Junjie Bu Date: Tue, 10 Mar 2026 21:40:53 -0700 Subject: [PATCH 27/27] updated field description for records in ai-catalog --- specification/cddl/ai-catalog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specification/cddl/ai-catalog.md b/specification/cddl/ai-catalog.md index 1e515e6..d575eec 100644 --- a/specification/cddl/ai-catalog.md +++ b/specification/cddl/ai-catalog.md @@ -9,7 +9,7 @@ AICatalog = { $schema: text, ; URI to the JSON schema specVersion: text, ; Version of the Catalog spec (e.g. "1.0.0") ? host: HostInfo, ; Who runs this server/registry - records: [* CatalogEntry] ; The list of available AI services + records: [* CatalogEntry] ; The list of available AI Catalog entries } HostInfo = {