()
| 69 | } |
| 70 | |
| 71 | export function createCreativeAgentRouter(): Router { |
| 72 | const router = Router(); |
| 73 | |
| 74 | // Clean expired previews every 5 minutes |
| 75 | const cleanupInterval = setInterval(() => cleanExpiredPreviews(), 5 * 60 * 1000); |
| 76 | cleanupInterval.unref(); |
| 77 | |
| 78 | // Health check |
| 79 | router.get('/health', (_req: Request, res: Response) => { |
| 80 | res.json({ status: 'healthy', service: 'creative-agent' }); |
| 81 | }); |
| 82 | |
| 83 | // adagents.json discovery |
| 84 | router.get('/.well-known/adagents.json', (req: Request, res: Response) => { |
| 85 | const agentBaseUrl = getAgentBaseUrl(req); |
| 86 | |
| 87 | res.json({ |
| 88 | $schema: '/schemas/adagents.json', |
| 89 | contact: { |
| 90 | name: 'AdCP Reference Creative Agent', |
| 91 | url: 'https://adcontextprotocol.org', |
| 92 | }, |
| 93 | agents: [{ |
| 94 | url: `${agentBaseUrl}/mcp`, |
| 95 | type: 'creative', |
| 96 | capabilities: ['list_creative_formats', 'preview_creative'], |
| 97 | }], |
| 98 | last_updated: STARTUP_TIME, |
| 99 | }); |
| 100 | }); |
| 101 | |
| 102 | // CORS preflight |
| 103 | router.options('/mcp', (_req: Request, res: Response) => { |
| 104 | setCORSHeaders(res); |
| 105 | res.status(204).end(); |
| 106 | }); |
| 107 | |
| 108 | // Rate limiting |
| 109 | const mcpRateLimiter = rateLimit({ |
| 110 | windowMs: 60 * 1000, |
| 111 | max: 60, |
| 112 | standardHeaders: true, |
| 113 | legacyHeaders: false, |
| 114 | validate: { xForwardedForHeader: false, ip: false }, |
| 115 | handler: (_req: Request, res: Response) => { |
| 116 | res.status(429).json({ |
| 117 | jsonrpc: '2.0', |
| 118 | id: null, |
| 119 | error: { code: -32000, message: 'Rate limit exceeded. Please try again later.' }, |
| 120 | }); |
| 121 | }, |
| 122 | }); |
| 123 | |
| 124 | // MCP endpoint |
| 125 | router.post('/mcp', mcpRateLimiter, requireToken, async (req: Request, res: Response) => { |
| 126 | setCORSHeaders(res); |
| 127 | |
| 128 | let server: ReturnType<typeof createCreativeAgentServer> | null = null; |
no test coverage detected