맞춤형 어댑터
사전 구축된 서버 어댑터(Hono, Express, Fastify, Koa)가 프레임워크를 지원하지 않거나 특정 요청/응답 처리 요구 사항이 있는 경우 사용자 지정 어댑터를 만듭니다.
사용자 정의 어댑터는 Mastra의 경로 정의와 프레임워크의 라우팅 시스템 간을 변환합니다. 프레임워크의 API를 사용하여 미들웨어를 등록하고, 요청을 처리하고, 응답을 보내는 메서드를 구현하게 됩니다.
다음과 같은 사전 구축된 서버 어댑터를 사용하세요.
추상 수업추상 수업에 대한 직접 링크
@mastra/server/server-adapter의 MastraServer 추상 클래스는 모든 어댑터의 기반을 제공합니다. 경로 등록 로직, 매개변수 검증 및 기타 공통 기능을 처리합니다. 사용자 지정 어댑터는 이 클래스를 확장하고 프레임워크별 부분을 구현합니다.
클래스는 프레임워크의 유형을 나타내는 세 가지 유형 매개변수를 사용합니다.
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에 액세스할 때 적절한 입력을 가능하게 합니다.
필수 방법필수 방법에 대한 직접 링크
이러한 6가지 추상 메서드를 구현해야 합니다. 각각은 컨텍스트 첨부부터 응답 전송까지 요청 수명주기의 특정 부분을 처리합니다.
registerContextMiddleware()registercontextmiddleware에 대한 직접 링크
이 메서드는 가장 먼저 실행되며 들어오는 모든 요청에 Mastra 컨텍스트를 연결합니다. 경로 핸들러가 작동하려면 Mastra 인스턴스, Tool 및 기타 컨텍스트에 접근할 수 있어야 합니다. 이 컨텍스트를 연결하는 방법은 프레임워크마다 다릅니다. Express는 res.locals를 사용하고, Hono는 c.set()을 사용하며, 다른 프레임워크에는 각자의 패턴이 있습니다.
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();
});
}
첨부할 컨텍스트:
| 키 | 유형 | 설명 |
|---|---|---|
mastra | Mastra | Mastra 인스턴스 |
requestContext | RequestContext | 요청 범위 컨텍스트 맵 |
tools | Record<string, Tool> | 사용 가능한 Tool |
abortSignal | AbortSignal | 요청 취소 신호 |
taskStore | InMemoryTaskStore | A2A 작업 저장소(구성된 경우) |
registerAuthMiddleware()registerauthmiddleware에 대한 직접 링크
인증 및 승인 미들웨어를 등록합니다. 이 방법은 Mastra 인스턴스에 인증이 구성되어 있는지 확인하고 그렇지 않은 경우 등록을 완전히 건너뛰어야 합니다. 인증이 구성되면 일반적으로 두 개의 미들웨어 기능, 즉 인증(토큰 유효성 검사 및 사용자 설정)과 권한 부여(사용자가 요청한 리소스에 액세스할 수 있는지 확인) 기능을 등록하게 됩니다.
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()registerroute에 대한 직접 링크
프레임워크에 단일 경로를 등록합니다. 이 메서드는 초기화 중 각 Mastra 경로에 대해 한 번씩 호출됩니다. 경로, HTTP 메서드, 핸들러 함수 및 검증용 Zod 스키마가 포함된 ServerRoute 객체를 받습니다. 구현에서는 이를 프레임워크의 라우팅 시스템에 연결해야 합니다.
async registerRoute(
app: MyApp,
route: ServerRoute,
{ prefix }: { prefix?: string }
): Promise<void> {
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()getparams에 대한 직접 링크
수신 요청에서 URL 매개변수, 쿼리 매개변수 및 요청 본문을 추출합니다. 프레임워크마다 이러한 값을 서로 다른 방식으로 노출합니다. Express는 req.params, req.query, req.body를 사용하지만, 다른 프레임워크는 다른 속성 이름을 사용하거나 메서드 호출이 필요할 수 있습니다. 이 메서드는 프레임워크의 추출 방식을 정규화합니다.
async getParams(
route: ServerRoute,
request: MyRequest
): Promise<{
urlParams: Record<string, string>;
queryParams: Record<string, string>;
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()sendresponse에 대한 직접 링크
경로의 응답 유형에 따라 클라이언트에 응답을 다시 보냅니다. Mastra 경로는 대부분의 API 응답에 대한 JSON, Agent 생성에 대한 스트림, MCP 전송에 대한 특수 유형 등 다양한 응답 유형을 반환할 수 있습니다. 구현에서는 프레임워크에 맞게 각 유형을 적절하게 처리해야 합니다.
async sendResponse(
route: ServerRoute,
response: MyResponse,
result: unknown
): Promise<unknown> {
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()stream에 대한 직접 링크
Agent 생성을 위한 스트리밍 응답을 처리합니다. Agent가 응답을 생성할 때 사용 가능해지면 클라이언트에 전송해야 하는 청크 스트림을 생성합니다. 이 메서드는 스트림에서 읽고, 선택적으로 수정을 적용하여 민감한 데이터를 숨기고, 적절한 형식(SSE 또는 줄 바꿈으로 구분된 JSON)으로 응답에 청크를 씁니다.
async stream(
route: ServerRoute,
response: MyResponse,
result: unknown
): Promise<unknown> {
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 스키마로 경로 매개변수 검증 |
parseQueryParams(route, params) | Zod 스키마로 쿼리 매개변수 검증 |
parseBody(route, body) | Zod 스키마로 본문 검증 |
mergeRequestContext({ paramsRequestContext, bodyRequestContext }) | 여러 소스의 요청 컨텍스트 병합 |
registerRoutes() | 모든 Mastra 경로 등록(각 경로에 대해 registerRoute 호출) |
registerOpenAPIRoute(app, config, { prefix }) | OpenAPI 사양 엔드포인트 등록 |
parse* 메서드는 각 경로에 정의된 Zod 스키마를 사용하여 입력을 검증하고 유형이 지정된 결과를 반환합니다. 검증에 실패하면 무엇이 잘못되었는지에 관한 세부 정보가 포함된 오류를 발생시킵니다. |
건설자건설자에 대한 직접 링크
어댑터의 생성자는 기본 클래스와 동일한 옵션을 받아 super()에 전달해야 합니다. 필요한 경우 프레임워크별 옵션을 추가할 수 있습니다.
constructor(options: {
app: MyApp;
mastra: Mastra;
prefix?: string;
openapiPath?: string;
bodyLimitOptions?: BodyLimitOptions;
streamOptions?: StreamOptions;
customRouteAuthConfig?: Map<string, boolean>;
}) {
super(options);
}
각 옵션의 전체 문서는 서버 어댑터를 참조하세요.
전체 예시전체 예시에 대한 직접 링크
다음은 필요한 모든 메서드를 보여주는 뼈대 구현입니다. 이는 프레임워크별 부분에 의사코드를 사용하고 프레임워크의 실제 API로 바꿉니다.
import { MastraServer, ServerRoute } from '@mastra/server/server-adapter'
import type { Mastra } from '@mastra/core'
export class MyFrameworkServer extends MastraServer<MyApp, MyRequest, MyResponse> {
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<void> {
// ... 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
}
}
용법용법에 대한 직접 링크
어댑터가 구현되면 제공된 어댑터와 동일한 방식으로 사용하십시오.
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 및 @mastra/express 구현을 참고하면 좋습니다. 이러한 구현은 컨텍스트 저장, 미들웨어 등록 및 응답 처리와 관련된 프레임워크별 패턴을 처리하는 방법을 보여 줍니다.
서버 어댑터와 함께 Studio를 사용하려면 mastra studio를 사용하여 Studio UI만 실행하세요.
관련된관련된에 대한 직접 링크
- 서버 어댑터: 개요 및 공유 개념
- 호노 어댑터: 참조 구현
- 익스프레스 어댑터: 참조 구현
- Mastra서버 참조: 전체 API 참조
- createRoute() 참조: 유형이 안전한 사용자 지정 경로 만들기