Skip to content

Conversation

@Larry-Osakwe
Copy link
Contributor

Summary

This PR introduces the keycardai-agents package, a production-ready SDK for building agent services with secure service-to-service (A2A) delegation using Keycard authentication. The package enables CrewAI workflows to be deployed as HTTP services and supports A2A communication for other frameworks.

What's New

Core Features

  • Agent Card Server - FastAPI-based HTTP server for deploying CrewAI crews as authenticated services
  • A2A Service Client - Client for discovering and invoking other agent services with OAuth token exchange
  • Service Discovery - Agent card discovery with intelligent caching (15-minute TTL)
  • CrewAI Integration - Automatic A2A tool generation via get_a2a_tools() for seamless crew-to-crew delegation
  • Delegation Chain Tracking - Full audit trail of service-to-service calls

Security & Production Readiness

  • JWT Signature Verification - Secure token validation using JWKS from Keycard (agent_card_server.py:195-226)
  • Token Expiration & Issuer Validation - Validates exp, iss, and aud claims
  • RFC 8693 Token Exchange - Standards-compliant OAuth 2.0 token exchange for service delegation
  • Comprehensive Test Coverage - 54 tests covering all core functionality (80%+ coverage)

Framework Support
CrewAI (Full Support):

  • Deploy crews as HTTP services with OAuth authentication
  • Automatic A2A tool generation
  • Service discovery and delegation chain tracking

Other Frameworks (A2A Client Only):

  • LangChain, LangGraph, AutoGen, and custom agents can use the A2A client to call CrewAI services
  • No server deployment for non-CrewAI frameworks yet (requires adapter wrapper)

Key Implementation Details

Service Discovery with Caching (discovery.py:83-133):

  • 15-minute default TTL for agent cards
  • Automatic refetch on expiration
  • Force refresh option for cache bypass
  • URL normalization to prevent duplicate entries

CrewAI A2A Tools (integrations/crewai_a2a.py):

  • Automatic tool generation from agent cards
  • Pass-through of delegation context
  • Optional service list or automatic discovery

@kamil-keycard
Copy link
Collaborator

kamil-keycard commented Dec 16, 2025

Couple of things I would like to see before we merge this:

  • put some structure into client/server split. Will be easier to understand how to consume these
  • abstract the crewai specific exec from the core server implementation. This way we can integrate with various frameworks, and re-use the same sever boilerplate
  • add the oauth protected metadata to the server agent. This way we can configure them as protected resource and enable standard oauth login flow
  • re-use the verification methods from other packages. If it makes sense to migrate some of them to the oauth package, than lets do this so it can be easily shared between these concrete implementations.

Creates an HTTP server with three endpoints:
- GET /.well-known/agent-card.json (public): Service discovery
- POST /invoke (protected): Execute crew
- GET /status (public): Health check
Copy link
Collaborator

Choose a reason for hiding this comment

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

We call this "agent_card_server" but this very crew_ai specific.

Can we split this into

  • generic a2a server
  • mounting crew ai adapter on top of it

If we want to quickly ship something crew ai specific, lets make these function names less generic

delegation_chain: list[str]


class AgentCardResponse(BaseModel):
Copy link
Collaborator

Choose a reason for hiding this comment

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


try:
# Construct JWKS URI from zone
jwks_uri = f"https://{config.zone_id}.keycard.cloud/.well-known/jwks.json"
Copy link
Collaborator

Choose a reason for hiding this comment

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

This cannot be hardcoded. This is already wrong URL for keycard.

You need to do https://uvzk3wjne6267192mbu1f0b73n.keycard.cloud/.well-known/openid-configuration lookup to read the jwks endpoint address.

This should really already be present in the oauth package. Have a look at

class JWTAccessToken(BaseModel):

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants