lity, priority, and capability.
Architecture Decisions
- Capability Discovery: The router must query available interfaces for a target service. Not all services support all interface types.
- Priority Resolution: Interfaces are ranked. APIs and MCP servers take precedence over CLIs, which take precedence over delegated browser sessions.
- Fallback Logic: If the preferred interface is unavailable or lacks the specific capability, the router falls back to the next tier.
- Scoping Enforcement: For delegated browser sessions, the router must inject scoping policies (e.g., allowed domains, read-only vs. write access) before execution.
Implementation
The following TypeScript implementation demonstrates a robust InterfaceRouter with capability resolution and fallback mechanisms.
// Core types defining interface capabilities
export enum InterfaceType {
API = 'API',
CLI = 'CLI',
MCP = 'MCP',
DELEGATED_BROWSER = 'DELEGATED_BROWSER'
}
export interface InterfaceCapability {
type: InterfaceType;
priority: number; // Lower number = higher priority
isAvailable: boolean;
supportsWrite: boolean;
requiresAuth: boolean;
metadata: Record<string, any>;
}
export interface ActionRequest {
service: string;
action: string;
payload: any;
requiredCapabilities: string[];
}
// Router configuration
export interface RouterConfig {
services: Record<string, InterfaceCapability[]>;
fallbackPolicy: 'STRICT' | 'PERMISSIVE';
}
export class InterfaceRouter {
private config: RouterConfig;
constructor(config: RouterConfig) {
this.config = config;
}
/**
* Resolves the best interface for a given action.
* Returns the selected capability or throws if no valid interface exists.
*/
resolve(request: ActionRequest): InterfaceCapability {
const serviceCapabilities = this.config.services[request.service];
if (!serviceCapabilities) {
throw new Error(`No capabilities configured for service: ${request.service}`);
}
// Filter capabilities that meet basic requirements
const viableOptions = serviceCapabilities.filter(cap => {
if (!cap.isAvailable) return false;
if (request.payload && !cap.supportsWrite) return false;
return true;
});
if (viableOptions.length === 0) {
if (this.config.fallbackPolicy === 'STRICT') {
throw new Error(`No viable interface for ${request.service}.${request.action}`);
}
// In permissive mode, we might allow a degraded path, but strictly speaking,
// we should fail safe.
throw new Error(`No viable interface and strict policy active.`);
}
// Sort by priority
viableOptions.sort((a, b) => a.priority - b.priority);
const selected = viableOptions[0];
// Audit log for transparency
console.log(`[Router] Selected ${selected.type} for ${request.service}.${request.action} (Priority: ${selected.priority})`);
return selected;
}
/**
* Validates scoping policies for delegated browser sessions.
*/
validateDelegationScope(capability: InterfaceCapability, request: ActionRequest): boolean {
if (capability.type !== InterfaceType.DELEGATED_BROWSER) return true;
const scope = capability.metadata.scope;
// Check domain restrictions
if (scope.allowedDomains && !scope.allowedDomains.includes(request.service)) {
return false;
}
// Check action permissions
if (scope.allowedActions && !scope.allowedActions.includes(request.action)) {
return false;
}
return true;
}
}
Usage Example
const routerConfig: RouterConfig = {
services: {
'crm-system': [
{
type: InterfaceType.API,
priority: 1,
isAvailable: true,
supportsWrite: true,
requiresAuth: true,
metadata: { endpoint: 'https://api.crm.example.com/v2' }
},
{
type: InterfaceType.DELEGATED_BROWSER,
priority: 2,
isAvailable: true,
supportsWrite: true,
requiresAuth: false, // Uses user's existing session
metadata: {
scope: {
allowedDomains: ['app.crm.example.com'],
allowedActions: ['update_contact', 'view_lead']
}
}
}
]
},
fallbackPolicy: 'STRICT'
};
const router = new InterfaceRouter(routerConfig);
// Agent requests an update
const request: ActionRequest = {
service: 'crm-system',
action: 'update_contact',
payload: { id: '123', name: 'New Name' },
requiredCapabilities: ['write']
};
try {
const capability = router.resolve(request);
if (capability.type === InterfaceType.DELEGATED_BROWSER) {
if (!router.validateDelegationScope(capability, request)) {
throw new Error('Delegation scope violation');
}
// Execute via delegated session
} else {
// Execute via API
}
} catch (error) {
// Handle resolution failure
}
Pitfall Guide
-
The Pixel Trap
- Explanation: Relying on CSS selectors or XPath for browser automation. UI elements change frequently, causing silent failures or incorrect interactions.
- Fix: Use APIs or MCP servers whenever available. If browser interaction is unavoidable, use semantic anchors (e.g.,
data-testid attributes) and implement visual regression checks, but treat this as a temporary bridge.
-
Credential Leakage
- Explanation: Passing session cookies or passwords to cloud-based agents. This violates security boundaries and exposes user sessions to unauthorized access.
- Fix: Implement delegated browser sessions where the agent runs locally or in a trusted environment with scoped access. Never transmit raw credentials; use short-lived tokens or local proxy mechanisms that preserve session authority with the user.
-
API Parity Assumption
- Explanation: Assuming the API covers all UI workflows. Many SaaS products have "API gaps" where critical actions (e.g., approving a specific workflow step) are only available in the UI.
- Fix: Conduct an interface audit. Map every agent workflow to available interfaces. Explicitly document gaps and implement fallback strategies for workflows that require browser delegation.
-
Unscoped Browser Access
- Explanation: Granting agents full control over a browser session. This allows the agent to navigate to unintended pages, access unrelated data, or perform actions outside the scope of the task.
- Fix: Enforce strict scoping policies. Limit delegated sessions to specific domains, paths, and actions. Implement a "draft and approve" workflow for high-risk actions, requiring user confirmation before submission.
-
Rate Limit Ignorance
- Explanation: Agents making rapid, concurrent requests to APIs without respecting rate limits, leading to throttling or account suspension.
- Fix: Implement rate limiting and backoff strategies in the execution layer. Cache responses where appropriate and batch requests to minimize API calls.
-
State Drift
- Explanation: Browser sessions can become stale or inconsistent due to background updates, leading to errors when the agent attempts to interact with outdated elements.
- Fix: Use idempotent API calls where possible. For browser interactions, implement state verification steps before critical actions. Refresh sessions periodically and handle session expiration gracefully.
-
Ignoring MCP Semantics
- Explanation: Overlooking Model Context Protocol (MCP) servers as a viable interface. MCP provides a standardized way for products to expose tools and resources to agents with built-in security and validation.
- Fix: Prioritize MCP servers in the interface hierarchy. They offer the semantic alignment of APIs with the flexibility of tool use, making them ideal for agent interactions.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| High-volume data sync | API | Low latency, high reliability, structured data. | Low |
| One-off admin task in legacy portal | Delegated Browser | No API exists; browser is the only interface. | High (Risk/Maintenance) |
| Agent tool use with validation | MCP Server | Standardized protocol, semantic alignment, security. | Medium |
| Local script execution | CLI | Fast, secure, local execution. | Low |
| Workflow requiring user approval | Delegated Browser (Draft Mode) | Allows agent to prepare action, user reviews and submits. | Medium |
Configuration Template
{
"services": {
"support-desk": {
"capabilities": [
{
"type": "API",
"priority": 1,
"isAvailable": true,
"supportsWrite": true,
"metadata": {
"endpoint": "https://api.support.example.com/v1"
}
},
{
"type": "DELEGATED_BROWSER",
"priority": 2,
"isAvailable": true,
"supportsWrite": true,
"metadata": {
"scope": {
"allowedDomains": ["app.support.example.com"],
"allowedActions": ["reply_ticket", "escalate_ticket"]
}
}
}
]
},
"vendor-portal": {
"capabilities": [
{
"type": "DELEGATED_BROWSER",
"priority": 1,
"isAvailable": true,
"supportsWrite": true,
"metadata": {
"scope": {
"allowedDomains": ["portal.vendor.example.com"],
"allowedActions": ["submit_order", "check_status"]
}
}
}
]
}
},
"fallbackPolicy": "STRICT",
"auditLogging": true
}
Quick Start Guide
- Define Capabilities: Create a configuration file mapping services to their available interfaces and priorities.
- Initialize Router: Instantiate the
InterfaceRouter with your configuration.
- Resolve Actions: Call
router.resolve() with each agent action request to determine the optimal interface.
- Execute with Scoping: For delegated browser sessions, validate scoping policies before execution.
- Monitor and Iterate: Review audit logs to identify fallback usage and prioritize API/MCP integration for high-frequency workflows.