tap_mcp_bridge/lib.rs
1//! TAP-MCP Bridge: Secure AI Agent Authentication for E-Commerce
2//!
3//! A Rust library that bridges Visa's Trusted Agent Protocol (TAP) with
4//! Anthropic's Model Context Protocol (MCP), enabling AI agents like Claude
5//! to securely authenticate with merchants and execute payment transactions.
6//!
7//! # What is TAP-MCP Bridge?
8//!
9//! This library solves a critical problem: how can AI agents autonomously transact
10//! with merchants while maintaining security and trust? TAP-MCP Bridge provides:
11//!
12//! - **Cryptographic Authentication**: RFC 9421 HTTP Message Signatures with Ed25519
13//! - **MCP Integration**: Expose TAP operations as MCP tools for AI agents
14//! - **Security by Default**: HTTPS-only, input validation, timeout protection
15//! - **RFC Compliance**: Implements RFC 9421 (HTTP Signatures) and RFC 7638 (JWK Thumbprints)
16//!
17//! # Architecture
18//!
19//! ```text
20//! ┌─────────────────┐
21//! │ AI Agent │ Claude or other MCP-compatible agent
22//! │ (Claude) │
23//! └────────┬────────┘
24//! │ MCP Protocol (JSON-RPC 2.0)
25//! │
26//! ┌────────▼────────────────────────────────────────┐
27//! │ TAP-MCP Bridge (this crate) │
28//! │ ┌──────────────┐ ┌──────────────────┐ │
29//! │ │ MCP Tools │──────│ TAP Signatures │ │
30//! │ │ (checkout, │ │ (RFC 9421 + │ │
31//! │ │ browse) │ │ Ed25519) │ │
32//! │ └──────────────┘ └──────────────────┘ │
33//! └────────┬───────────────────────────────────────┘
34//! │ HTTPS + TAP Signatures
35//! │
36//! ┌────────▼────────┐
37//! │ TAP Merchant │ Visa-protected merchant
38//! │ (e.g., Store) │
39//! └─────────────────┘
40//! ```
41//!
42//! # Quick Start
43//!
44//! ## 1. Execute a Checkout
45//!
46//! ```rust,no_run
47//! use ed25519_dalek::SigningKey;
48//! use tap_mcp_bridge::{
49//! mcp::{CheckoutParams, checkout_with_tap},
50//! tap::TapSigner,
51//! };
52//!
53//! # async fn example() -> tap_mcp_bridge::error::Result<()> {
54//! // Create agent signing key (in production, load from secure storage)
55//! let signing_key = SigningKey::from_bytes(&[0u8; 32]);
56//! let signer = TapSigner::new(signing_key, "agent-123", "https://agent.example.com");
57//!
58//! // Define checkout parameters
59//! let params = CheckoutParams {
60//! merchant_url: "https://merchant.example.com/checkout".to_string(),
61//! consumer_id: "user-456".to_string(),
62//! intent: "payment".to_string(),
63//! country_code: "US".to_string(),
64//! zip: "94025".to_string(),
65//! ip_address: "192.168.1.100".to_string(),
66//! user_agent: "Mozilla/5.0".to_string(),
67//! platform: "macOS".to_string(),
68//! };
69//!
70//! // Execute TAP-authenticated checkout
71//! let result = checkout_with_tap(&signer, params).await?;
72//!
73//! println!("Status: {}", result.status);
74//! println!("Message: {}", result.message);
75//! # Ok(())
76//! # }
77//! ```
78//!
79//! ## 2. Browse Merchant Catalog
80//!
81//! ```rust,no_run
82//! use ed25519_dalek::SigningKey;
83//! use tap_mcp_bridge::{
84//! mcp::{BrowseParams, browse_merchant},
85//! tap::TapSigner,
86//! };
87//!
88//! # async fn example() -> tap_mcp_bridge::error::Result<()> {
89//! let signing_key = SigningKey::from_bytes(&[0u8; 32]);
90//! let signer = TapSigner::new(signing_key, "agent-123", "https://agent.example.com");
91//!
92//! let params = BrowseParams {
93//! merchant_url: "https://merchant.example.com".to_string(),
94//! consumer_id: "user-456".to_string(),
95//! country_code: "US".to_string(),
96//! zip: "94025".to_string(),
97//! ip_address: "192.168.1.100".to_string(),
98//! user_agent: "Mozilla/5.0".to_string(),
99//! platform: "macOS".to_string(),
100//! };
101//!
102//! let result = browse_merchant(&signer, params).await?;
103//! println!("Status: {}", result.status);
104//! println!("Data: {}", result.data);
105//! # Ok(())
106//! # }
107//! ```
108//!
109//! ## 3. Generate TAP Signatures Directly
110//!
111//! ```rust
112//! use ed25519_dalek::SigningKey;
113//! use tap_mcp_bridge::tap::{InteractionType, TapSigner};
114//!
115//! # fn example() -> tap_mcp_bridge::error::Result<()> {
116//! let signing_key = SigningKey::from_bytes(&[0u8; 32]);
117//! let signer = TapSigner::new(signing_key, "agent-123", "https://agent-directory.example.com");
118//!
119//! // Sign an HTTP request per RFC 9421 with TAP parameters
120//! let signature = signer.sign_request(
121//! "POST",
122//! "merchant.example.com",
123//! "/api/checkout",
124//! b"{\"amount\":99.99}",
125//! InteractionType::Checkout,
126//! )?;
127//!
128//! // Use signature headers in HTTP request
129//! println!("Signature: {}", signature.signature);
130//! println!("Signature-Input: {}", signature.signature_input);
131//! println!("Signature-Agent: {}", signature.agent_directory);
132//! println!("Nonce: {}", signature.nonce);
133//! # Ok(())
134//! # }
135//! ```
136//!
137//! ## 4. Generate JWKS for Agent Directory
138//!
139//! ```rust
140//! use ed25519_dalek::SigningKey;
141//! use tap_mcp_bridge::tap::TapSigner;
142//!
143//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
144//! let signing_key = SigningKey::from_bytes(&[0u8; 32]);
145//! let signer = TapSigner::new(signing_key, "agent-123", "https://agent.example.com");
146//!
147//! // Generate JWKS for public key distribution
148//! let jwks = signer.generate_jwks();
149//! let json = jwks.to_json()?;
150//!
151//! // Serve this at /.well-known/http-message-signatures-directory
152//! println!("{}", json);
153//! # Ok(())
154//! # }
155//! ```
156//!
157//! # Module Organization
158//!
159//! - [`tap`]: TAP protocol implementation (RFC 9421 signatures, Ed25519 signing)
160//! - [`mcp`]: MCP tools for AI agent integration (checkout, browse)
161//! - [`error`]: Error types with recovery guidance
162//! - [`reliability`]: Production reliability patterns (retry, circuit breaker)
163//! - [`security`]: Security hardening (rate limiting, audit logging)
164//!
165//! # Security Considerations
166//!
167//! ## Key Management
168//!
169//! - **Never hardcode keys**: Load from environment variables or secure key stores
170//! - **Use HSM in production**: Hardware Security Modules for key protection
171//! - **Unique keys per merchant**: Recommended for key rotation and isolation
172//!
173//! ## Input Validation
174//!
175//! The library automatically validates:
176//! - **URLs**: Must be HTTPS, no localhost/loopback addresses
177//! - **Consumer IDs**: Alphanumeric + hyphens/underscores, 1-64 characters
178//! - **Request bodies**: Content-Digest prevents tampering
179//!
180//! ## Network Security
181//!
182//! - **HTTPS only**: All TAP requests require TLS encryption
183//! - **30-second timeout**: Prevents hanging connections
184//! - **Signature expiration**: Requests expire after 8 minutes (TAP requirement)
185//! - **Replay attack prevention**: Unique nonce (UUID v4) per request
186//! - **Nonce tracking**: Merchants must reject duplicate nonces within 8-minute window
187//!
188//! # Standards Compliance
189//!
190//! This library implements:
191//! - [RFC 9421: HTTP Message Signatures](https://www.rfc-editor.org/rfc/rfc9421.html)
192//! - [RFC 7638: JWK Thumbprint](https://www.rfc-editor.org/rfc/rfc7638.html)
193//! - [RFC 3986: URI Syntax](https://www.rfc-editor.org/rfc/rfc3986.html)
194//!
195//! # Features
196//!
197//! This implementation provides complete TAP protocol compliance:
198//!
199//! **Core Capabilities**:
200//! - ✅ Two MCP tools: `checkout_with_tap`, `browse_merchant`
201//! - ✅ RFC 9421 signature generation with Ed25519
202//! - ✅ TAP required parameters: `tag`, `nonce`, `expires`, `created`, `keyid`, `alg`
203//! - ✅ Replay attack prevention (unique nonce per request)
204//! - ✅ Signature expiration (8-minute maximum window)
205//! - ✅ Interaction type tags (browser-auth, payer-auth)
206//! - ✅ Network error handling with 30-second timeout
207//! - ✅ Input validation (URL sanitization, consumer ID format)
208//!
209//! **TAP Components**:
210//! - ✅ RFC 9421 HTTP Message Signatures with Ed25519
211//! - ✅ Public Key Directory (JWKS at `/.well-known/http-message-signatures-directory`)
212//! - ✅ ID Token (JWT) generation for consumer authentication
213//! - ✅ Agentic Consumer Recognition Object (ACRO)
214//! - ✅ Agentic Payment Container (APC)
215//!
216//! **Production Features**:
217//! - ✅ Prometheus-format metrics (`observability` module in tap-mcp-server)
218//! - ✅ Retry with exponential backoff (`reliability::retry`)
219//! - ✅ Circuit breaker pattern (`reliability::circuit_breaker`)
220//! - ✅ Token bucket rate limiting (`security::rate_limit`)
221//! - ✅ Structured audit logging (`security::audit`)
222//!
223//! **TAP Compliance**: 100% (18/18 requirements)
224//!
225//! **Test Coverage**: 200+ tests (unit, integration, property-based, documentation)
226//!
227//! # Examples
228//!
229//! See the `examples/` directory for complete usage examples:
230//! - `basic_checkout.rs`: Simple checkout flow
231//! - `browse_catalog.rs`: Browsing merchant catalogs
232//! - `error_handling.rs`: Handling common errors
233//! - `signature_generation.rs`: RFC 9421 signature generation
234//! - `jwks_generation.rs`: Generating JWKS for agent directory
235//! - `id_token_generation.rs`: JWT token creation
236//! - `acro_generation.rs`: ACRO object creation
237//! - `apc_generation.rs`: APC encryption/decryption
238//!
239//! # Error Handling
240//!
241//! All operations return [`Result<T, BridgeError>`](error::Result). Errors include
242//! recovery guidance:
243//!
244//! ```rust
245//! use ed25519_dalek::SigningKey;
246//! use tap_mcp_bridge::{
247//! BridgeError,
248//! mcp::{CheckoutParams, checkout_with_tap},
249//! tap::TapSigner,
250//! };
251//!
252//! # async fn example() {
253//! let signing_key = SigningKey::from_bytes(&[0u8; 32]);
254//! let signer = TapSigner::new(signing_key, "agent-123", "https://agent.example.com");
255//!
256//! let params = CheckoutParams {
257//! merchant_url: "https://merchant.example.com/checkout".to_string(),
258//! consumer_id: "user-123".to_string(),
259//! intent: "payment".to_string(),
260//! country_code: "US".to_string(),
261//! zip: "94025".to_string(),
262//! ip_address: "192.168.1.100".to_string(),
263//! user_agent: "Mozilla/5.0".to_string(),
264//! platform: "macOS".to_string(),
265//! };
266//!
267//! match checkout_with_tap(&signer, params).await {
268//! Ok(result) => println!("Success: {}", result.status),
269//! Err(BridgeError::InvalidMerchantUrl(msg)) => {
270//! eprintln!("Invalid URL: {}", msg);
271//! // Fix URL and retry
272//! }
273//! Err(BridgeError::HttpError(e)) => {
274//! eprintln!("Network error: {}", e);
275//! // Retry with exponential backoff using reliability::retry_with_backoff
276//! }
277//! Err(BridgeError::RateLimitExceeded) => {
278//! eprintln!("Rate limit exceeded");
279//! // Wait and retry after backoff
280//! }
281//! Err(BridgeError::CircuitOpen) => {
282//! eprintln!("Circuit breaker is open");
283//! // Wait for circuit recovery
284//! }
285//! Err(e) => eprintln!("Other error: {}", e),
286//! }
287//! # }
288//! ```
289
290#![warn(missing_docs)]
291#![warn(missing_debug_implementations)]
292#![allow(
293 clippy::multiple_crate_versions,
294 reason = "transitive dependencies from rmcp and reqwest"
295)]
296
297pub mod error;
298pub mod mcp;
299pub mod reliability;
300pub mod security;
301pub mod tap;
302
303pub use error::{BridgeError, Result};
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308
309 #[test]
310 fn test_library_exports() {
311 // Verify public API is accessible
312 let _ = std::marker::PhantomData::<BridgeError>;
313 }
314}