> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/llms.txt # 自訂轉接器 當預先建置的伺服器轉接器(Hono、Express、Fastify、Koa)不支援你的框架,或你對請求/回應處理有特定要求時,便可建立自訂轉接器。 自訂轉接器會在 Mastra 的路由定義與你的框架路由系統之間進行轉換。你需要使用框架的 API,實作註冊中介軟件、處理請求和傳送回應的方法。 > **資訊:** 你可以使用以下任何一個預先建置的伺服器轉接器: > > - [@mastra/hono](https://mastra.zisheng.pro/zh-HK/reference/server/hono-adapter) > - [@mastra/express](https://mastra.zisheng.pro/zh-HK/reference/server/express-adapter) > - [@mastra/fastify](https://mastra.zisheng.pro/zh-HK/reference/server/fastify-adapter) > - [@mastra/koa](https://mastra.zisheng.pro/zh-HK/reference/server/koa-adapter) ## 抽象類別 `MastraServer` 抽象類別來自 `@mastra/server/server-adapter`,為所有轉接器提供基礎。它會處理路由註冊邏輯、參數驗證及其他共用功能。你的自訂轉接器會擴充此類別,並實作框架專用的部分。 此類別接受三個代表框架類型的類型參數: ```typescript import { MastraServer } from '@mastra/server/server-adapter' export class MyFrameworkServer extends MastraServer< // Your framework's app type (e.g., FastifyInstance) MyApp, // Your framework's request type (e.g., FastifyRequest) MyRequest, // Your framework's response type (e.g., FastifyReply) MyResponse > { // Implement abstract methods } ``` 這些類型參數可確保整個轉接器實作的類型安全,並讓你在存取框架專用 API 時獲得正確的類型。 ## 必須實作的方法 你必須實作以下六個抽象方法。每個方法會處理請求生命週期中的特定部分,從附加 context 到傳送回應。 ### `registerContextMiddleware()` 此方法會最先執行,並將 Mastra context 附加至每個傳入的請求。路由處理常式需要存取 Mastra 執行個體、Tool 及其他 context 才能運作。附加此 context 的方式取決於你的框架:Express 使用 `res.locals`,Hono 使用 `c.set()`,其他框架則有各自的模式。 ```typescript registerContextMiddleware(): void { this.app.use('*', (req, res, next) => { // Attach context to your framework's request/response res.locals.mastra = this.mastra; res.locals.requestContext = new RequestContext(); res.locals.tools = this.tools; res.locals.abortSignal = createAbortSignal(req); next(); }); } ``` 需要附加的 context: | Key | 類型 | 說明 | | ---------------- | ---------------------- | -------------------- | | `mastra` | `Mastra` | Mastra 執行個體 | | `requestContext` | `RequestContext` | 以請求為作用域的 context map | | `tools` | `Record` | 可用的 Tool | | `abortSignal` | `AbortSignal` | 請求取消訊號 | | `taskStore` | `InMemoryTaskStore` | A2A 任務儲存空間(如已設定) | ### `registerAuthMiddleware()` 註冊身份驗證及授權中介軟件。此方法應檢查 Mastra 執行個體是否已設定身份驗證;如未設定,便應完全略過註冊。設定身份驗證後,你通常需要註冊兩個中介軟件函式:一個用於身份驗證(驗證 token 並設定使用者),另一個用於授權(檢查使用者能否存取所請求的資源)。 ```typescript registerAuthMiddleware(): void { const authConfig = this.mastra.getServer()?.auth; if (!authConfig) return; // Register authentication (validate token, set user) this.app.use('*', async (req, res, next) => { const token = extractToken(req); const user = await authConfig.authenticateToken?.(token, req); if (!user) { return res.status(401).json({ error: 'Unauthorized' }); } res.locals.user = user; next(); }); // Register authorization (check permissions) this.app.use('*', async (req, res, next) => { const allowed = await authConfig.authorize?.( req.path, req.method, res.locals.user, res ); if (!allowed) { return res.status(403).json({ error: 'Forbidden' }); } next(); }); } ``` ### `registerRoute()` 在你的框架中註冊單一路由。初始化期間,每個 Mastra 路由都會呼叫此方法一次。它接收一個 `ServerRoute` 物件,其中包含路徑、HTTP 方法、處理常式函式,以及用於驗證的 Zod schema。你的實作應將這些內容連接至框架的路由系統。 ```typescript async registerRoute( app: MyApp, route: ServerRoute, { prefix }: { prefix?: string } ): Promise { const path = `${prefix || ''}${route.path}`; const method = route.method.toLowerCase(); app[method](path, async (req, res) => { try { // 1. Extract parameters const params = await this.getParams(route, req); // 2. Validate with Zod schemas const queryParams = await this.parseQueryParams(route, params.queryParams); const body = await this.parseBody(route, params.body); // 3. Build handler params const handlerParams = { ...params.urlParams, ...queryParams, ...(typeof body === 'object' ? body : {}), mastra: this.mastra, requestContext: res.locals.requestContext, tools: res.locals.tools, abortSignal: res.locals.abortSignal, taskStore: this.taskStore, }; // 4. Call handler const result = await route.handler(handlerParams); // 5. Send response return this.sendResponse(route, res, result); } catch (error) { const status = error.status ?? error.details?.status ?? 500; return res.status(status).json({ error: error.message }); } }); } ``` ### `getParams()` 從傳入的請求中擷取 URL 參數、查詢參數及請求內文。不同框架會以不同方式公開這些值:Express 使用 `req.params`、`req.query` 和 `req.body`,其他框架則可能使用不同的屬性名稱,或要求呼叫方法。此方法會為你的框架將擷取方式標準化。 ```typescript async getParams( route: ServerRoute, request: MyRequest ): Promise<{ urlParams: Record; queryParams: Record; body: unknown; }> { return { // From route path (e.g., :agentId) urlParams: request.params, // From URL query string queryParams: request.query, // From request body body: request.body, }; } ``` ### `sendResponse()` 根據路由的回應類型,將回應傳送給客戶端。Mastra 路由可傳回不同的回應類型:大部分 API 回應使用 JSON、Agent 生成內容使用串流,而 MCP 傳輸則使用特殊類型。你的實作應按框架需要妥善處理每種類型。 ```typescript async sendResponse( route: ServerRoute, response: MyResponse, result: unknown ): Promise { switch (route.responseType) { case 'json': return response.json(result); case 'stream': return this.stream(route, response, result); case 'datastream-response': // Return AI SDK Response directly return result; case 'mcp-http': // Handle MCP HTTP transport return this.handleMcpHttp(response, result); case 'mcp-sse': // Handle MCP SSE transport return this.handleMcpSse(response, result); default: return response.json(result); } } ``` ### `stream()` 處理 Agent 生成內容的串流回應。Agent 生成回應時,會產生一連串資料區塊,這些區塊應在可用時即時傳送至客戶端。此方法會從串流讀取資料、選擇性套用遮蔽以隱藏敏感資料,並以適當格式(SSE 或以換行分隔的 JSON)將資料區塊寫入回應。 ```typescript async stream( route: ServerRoute, response: MyResponse, result: unknown ): Promise { const isSSE = route.streamFormat === 'sse'; // Set streaming headers based on format response.setHeader('Content-Type', isSSE ? 'text/event-stream' : 'text/plain'); response.setHeader('Transfer-Encoding', 'chunked'); const reader = result.fullStream.getReader(); try { while (true) { const { done, value } = await reader.read(); if (done) break; // Apply redaction if enabled const chunk = this.streamOptions.redact ? redactChunk(value) : value; // Format based on stream format if (isSSE) { response.write(`data: ${JSON.stringify(chunk)}\n\n`); } else { response.write(JSON.stringify(chunk) + '\x1E'); } } // Send completion marker (SSE uses data: [DONE], other formats use record separator) if (isSSE) { response.write('data: [DONE]\n\n'); } response.end(); } catch (error) { reader.cancel(); throw error; } } ``` ## 輔助方法 基礎類別提供你可在實作中使用的輔助方法。這些方法會處理參數驗證和路由註冊等常見工作,因此你毋須重新實作: | 方法 | 說明 | | ------------------------------------------------------------------- | --------------------------------------- | | `parsePathParams(route, params)` | 使用 Zod schema 驗證路徑參數 | | `parseQueryParams(route, params)` | 使用 Zod schema 驗證查詢參數 | | `parseBody(route, body)` | 使用 Zod schema 驗證內文 | | `mergeRequestContext({ paramsRequestContext, bodyRequestContext })` | 合併來自多個來源的請求 context | | `registerRoutes()` | 註冊所有 Mastra 路由(為每個路由呼叫 `registerRoute`) | | `registerOpenAPIRoute(app, config, { prefix })` | 註冊 OpenAPI 規格端點 | `parse*` 方法會使用每個路由定義的 Zod schema 驗證輸入,並傳回具有類型的結果。如果驗證失敗,這些方法會擲回錯誤,並提供出錯詳情。 ## 建構函式 你的轉接器建構函式應接受與基礎類別相同的選項,並將它們傳遞給 `super()`。如有需要,你亦可加入其他框架專用選項: ```typescript constructor(options: { app: MyApp; mastra: Mastra; prefix?: string; openapiPath?: string; bodyLimitOptions?: BodyLimitOptions; streamOptions?: StreamOptions; customRouteAuthConfig?: Map; }) { super(options); } ``` 請參閱[伺服器轉接器](https://mastra.zisheng.pro/zh-HK/docs/server/server-adapters),了解每個選項的完整文件。 ## 完整範例 以下骨架實作展示所有必須實作的方法。框架專用部分使用虛擬程式碼,請替換為框架實際使用的 API: ```typescript import { MastraServer, ServerRoute } from '@mastra/server/server-adapter' import type { Mastra } from '@mastra/core' export class MyFrameworkServer extends MastraServer { constructor(options: { app: MyApp; mastra: Mastra; prefix?: string }) { super(options) } registerContextMiddleware(): void { this.app.use('*', (req, res, next) => { res.locals.mastra = this.mastra res.locals.requestContext = this.mergeRequestContext({ paramsRequestContext: req.query.requestContext, bodyRequestContext: req.body?.requestContext, }) res.locals.tools = this.tools ?? {} res.locals.abortSignal = createAbortSignal(req) next() }) } registerAuthMiddleware(): void { const authConfig = this.mastra.getServer()?.auth if (!authConfig) return // ... implement auth middleware } async registerRoute( app: MyApp, route: ServerRoute, { prefix }: { prefix?: string }, ): Promise { // ... implement route registration } async getParams(route: ServerRoute, request: MyRequest) { return { urlParams: request.params, queryParams: request.query, body: request.body, } } async sendResponse(route: ServerRoute, response: MyResponse, result: unknown) { if (route.responseType === 'stream') { return this.stream(route, response, result) } return response.json(result) } async stream(route: ServerRoute, response: MyResponse, result: unknown) { // ... implement streaming } } ``` ## 使用方式 實作轉接器後,便可按使用內置轉接器的相同方式使用它: ```typescript import { MyFrameworkServer } from './my-framework-adapter' import { mastra } from './mastra' const app = createMyFrameworkApp() const server = new MyFrameworkServer({ app, mastra }) await server.init() app.listen(4111) ``` > **提示:** 建立自訂轉接器時,現有的 [@mastra/hono](https://github.com/mastra-ai/mastra/blob/main/server-adapters/hono/src/index.ts) 和 [@mastra/express](https://github.com/mastra-ai/mastra/blob/main/server-adapters/express/src/index.ts) 實作是很好的參考。它們展示如何處理框架專用的 context 儲存和中介軟件註冊模式,以及回應處理。 > > 如要配合你的伺服器轉接器使用 [Studio](https://mastra.zisheng.pro/zh-HK/docs/studio/overview),請使用 [`mastra studio`](https://mastra.zisheng.pro/zh-HK/reference/cli/mastra),只啟動 Studio UI。 ## 相關內容 - [伺服器轉接器](https://mastra.zisheng.pro/zh-HK/docs/server/server-adapters):概覽及共用概念 - [Hono 轉接器](https://mastra.zisheng.pro/zh-HK/reference/server/hono-adapter):參考實作 - [Express 轉接器](https://mastra.zisheng.pro/zh-HK/reference/server/express-adapter):參考實作 - [MastraServer 參考資料](https://mastra.zisheng.pro/zh-HK/reference/server/mastra-server):完整 API 參考資料 - [createRoute() 參考資料](https://mastra.zisheng.pro/zh-HK/reference/server/create-route):建立類型安全的自訂路由