app() you group multiple related operations in a single deployment. Your AI agents discover each tool individually via MCP, and each has its own HTTP route.
Pattern: app() + multiple define() + .describe() on each field + shared config + ctx.env.get() for secrets.
index.ts
Local testing
Start the server withjelou dev and test each tool:
400 with the error details:
Why it works this way
- Automatic routes — the keys
createContact,searchContacts,deleteContactgenerate/create-contact,/search-contacts,/delete-contact. - GET vs POST —
searchContactsusesconfig: { methods: ["GET"] }to receive parameters as query strings. The others use POST by default. descriptionmatters — each tool has a specific description that tells the AI agent exactly what it does and what it returns. “Searches contacts by name or email” is much better than “Searches contacts”.- Shared config —
corsandtimeoutare defined once inapp()and apply to all tools. Each tool can override them if needed. - Centralized secrets — all 3 tools use
ctx.env.get("CRM_API_KEY"). You configure the secret once withjelou secrets set. - Unified MCP —
curl http://localhost:3000/mcpreturns the 3 tools as independent tools the agent can invoke.