Adding New Modules & Routers
Relevant source files
The following files were used as context for generating this wiki page:
- .claude/skills/new-module/SKILL.md
- .claude/skills/new-router/SKILL.md
- apps/api/src/infrastructure/http/app-router.ts
- apps/api/test/infrastructure/http/server.integration.test.ts
- apps/api/spec/bio.md
- apps/api/src/infrastructure/http/routes/mcp.router.ts
- apps/api/test/modules/bio/interface/bio.tool.integration.test.ts
New modules and routers extend the thoth API by providing specialized business logic and entry points for HTTP or Model Context Protocol (MCP) requests. Modules act as vertical slices of functionality, while routers expose this functionality to the outside world through the AppRouter configuration.
Module Architecture
The thoth project organizes code into modules within apps/api/src/modules/. Each module typically encapsulates a specific domain area like bio, auth, or agent.
Module Structure
A standard module consists of three primary layers:
- Domain: Defines core entities and business rules.
- Application: Contains services that coordinate domain logic and interface with infrastructure ports.
- Interface: Provides controllers for HTTP routes or
McpToolimplementations for MCP clients.
The diagram above shows the typical dependency flow where external entry points (Routers) interact with the Interface layer of a module.
Sources: apps/api/src/infrastructure/http/app-router.ts:28-40, apps/api/spec/bio.md:1-10
MCP Tool Registration
Modules often expose functionality as MCP tools. An interface class implements the McpTool interface, defining a register method that adds tools to the MCP server.
export interface McpTool {
register: (server: McpServer, context: McpRequestContext) => void;
}
Sources: apps/api/test/infrastructure/http/mcp.router.test.ts:28-34, apps/api/test/infrastructure/http/server.integration.test.ts:11-18
Router Implementation
Routers define the HTTP endpoints and middleware for specific modules. They are implemented as injectable classes and subsequently mounted onto the main application.
Defining a Router
A router class typically uses express.Router to define its endpoints. It receives a controller or service via constructor injection to handle the business logic.
Sources: apps/api/test/infrastructure/http/bio.router.test.ts:31-35
The AppRouter Configuration
The AppRouter class is the central point for mounting all modular routers. It applies global middleware and defines the base paths for each sub-router.
| Component | Path | Description |
|---|---|---|
| WelcomeRouter | / | Base landing and status route. |
| HealthRouter | /health | Liveness and readiness checks. |
| BioRouter | /bio | Public bio retrieval. |
| AgentRouter | /threads | AI agent thread management. |
| AuthRouter | / | OAuth 2.1 authentication endpoints. |
| McpRouter | /mcp | MCP transport (SSE/JSON-RPC). |
Sources: apps/api/src/infrastructure/http/app-router.ts:47-65
Mounting Process Flow
The sequence diagram illustrates how the Dependency Injection (DI) container resolves routers before the AppRouter mounts them to the Express application.
Sources: apps/api/src/infrastructure/http/app-router.ts:26-40, apps/api/test/infrastructure/http/server.integration.test.ts:8-25
Adding a New Module and Router
Follow these steps to integrate a new feature into the API:
- Define Specification: Create a Markdown specification in
apps/api/spec/<module>.mddefining inputs, outputs, and rules.- Example:
apps/api/spec/bio.mddefines rules for handles and bio fields.
- Example:
- Create Module Structure: Create the directory
apps/api/src/modules/<name>/withdomain,application, andinterfacesubdirectories. - Implement Logic:
- Write Domain entities.
- Write an Application Service (e.g.,
BioService). - Write a Controller or Tool (e.g.,
BioTool).
- Create Router: Create a router file in
apps/api/src/infrastructure/http/routes/<name>.router.ts. - Bind in DI: Register the new service, controller, and router in the DI container (managed in
apps/api/src/di/index.ts). - Mount Router:
- Inject the new router into the
AppRouterconstructor. - Call
app.use()in themountmethod ofAppRouter.
- Inject the new router into the
- Register MCP Tool (Optional): If the module includes MCP tools, ensure the interface implements
McpTooland is bound soMcpRoutercan access it.
Sources: apps/api/src/infrastructure/http/app-router.ts:28-40, apps/api/test/infrastructure/http/server.integration.test.ts:11-30, apps/api/test/modules/bio/interface/bio.tool.integration.test.ts:40-45
Security and Middleware
New routers should consider the project's security rules:
- Authentication: Private tools or routes must use
mcpAuthMiddlewareorAuthPort.verifyBearer. - Validation: Use Zod schemas to validate inputs, as seen in
BioToolvalidation rules. - Error Handling: Routers should use the global
errorHandlermounted at the end ofAppRouter.mount.
Sources: apps/api/src/infrastructure/http/app-router.ts:63-78, apps/api/spec/bio.md:25-30, apps/api/test/infrastructure/http/mcp-auth.middleware.test.ts:39-45
The modular architecture ensures that new features remain isolated and testable while maintaining a consistent structure for HTTP and MCP communication.