> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt # 自訂 Adapter 當預先建置的 Server Adapter(Hono、Express、Fastify、Koa)不支援你的框架,或你有特定的請求/回應處理需求時,請建立自訂 Adapter。 自訂 Adapter 會在 Mastra 的路由定義與框架的路由系統之間進行轉換。你需要使用框架的 API 實作註冊 Middleware、處理請求及傳送回應的方法。 > **資訊:** 你可以使用下列任一預先建置的 Server Adapter: > > - [@mastra/hono](https://mastra.zisheng.pro/zh-TW/reference/server/hono-adapter) > - [@mastra/express](https://mastra.zisheng.pro/zh-TW/reference/server/express-adapter) > - [@mastra/fastify](https://mastra.zisheng.pro/zh-TW/reference/server/fastify-adapter) > - [@mastra/koa](https://mastra.zisheng.pro/zh-TW/reference/server/koa-adapter) ## 抽象類別 `@mastra/server/server-adapter` 的 `MastraServer` 抽象類別是所有 Adapter 的基礎。它會處理路由註冊邏輯、參數驗證及其他共用功能。你的自訂 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 } ``` 這些型別參數可確保整個 Adapter 實作的型別安全,並在存取框架專用 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: | 索引鍵 | 型別 | 說明 | | ---------------- | ---------------------- | ----------------- | | `mastra` | `Mastra` | Mastra 執行個體 | | `requestContext` | `RequestContext` | 請求範圍的 context map | | `tools` | `Record` | 可用的 Tool | | `abortSignal` | `AbortSignal` | 請求取消訊號 | | `taskStore` | `InMemoryTaskStore` | A2A 任務儲存空間(若已設定) | ### `registerAuthMiddleware()` 註冊驗證與授權 Middleware。此方法應檢查 Mastra 執行個體是否已設定驗證;若未設定,則完全略過註冊。設定驗證後,通常會註冊兩個 Middleware 函式:一個用於驗證(驗證 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 驗證輸入,並傳回具型別的結果。若驗證失敗,這些方法會擲回包含失敗詳細資訊的錯誤。 ## 建構函式 Adapter 的建構函式應接受與基底類別相同的選項,並將其傳給 `super()`。如有需要,你也可以加入其他框架專用選項: ```typescript constructor(options: { app: MyApp; mastra: Mastra; prefix?: string; openapiPath?: string; bodyLimitOptions?: BodyLimitOptions; streamOptions?: StreamOptions; customRouteAuthConfig?: Map; }) { super(options); } ``` 如需各選項的完整文件,請參閱 [Server Adapter](https://mastra.zisheng.pro/zh-TW/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 } } ``` ## 使用方式 完成 Adapter 實作後,請以與現有 Adapter 相同的方式使用: ```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) ``` > **提示:** 建立自訂 Adapter 時,現有的 [@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 儲存、Middleware 註冊及回應處理等框架專用模式。 > > 如果想搭配 Server Adapter 使用 [Studio](https://mastra.zisheng.pro/zh-TW/docs/studio/overview),請使用 [`mastra studio`](https://mastra.zisheng.pro/zh-TW/reference/cli/mastra),只啟動 Studio UI。 ## 相關資源 - [Server Adapter](https://mastra.zisheng.pro/zh-TW/docs/server/server-adapters):概觀與共用概念 - [Hono Adapter](https://mastra.zisheng.pro/zh-TW/reference/server/hono-adapter):參考實作 - [Express Adapter](https://mastra.zisheng.pro/zh-TW/reference/server/express-adapter):參考實作 - [MastraServer 參考文件](https://mastra.zisheng.pro/zh-TW/reference/server/mastra-server):完整 API 參考文件 - [createRoute() 參考文件](https://mastra.zisheng.pro/zh-TW/reference/server/create-route):建立型別安全的自訂路由