Community-maintained LoopBack 4 server adapter for
Mastra. It mounts Mastra's server routes directly on a
RestApplication while preserving LoopBack request context and dependency
injection.
npm install @sourceloop/mastra-loopback @mastra/core @loopback/core @loopback/restNode.js 22.13 or newer is required. This release targets Mastra 1.72 and newer 1.x releases, LoopBack Core 7, and LoopBack REST 15.
import { RestApplication } from '@loopback/rest';
import { Mastra } from '@mastra/core';
import { LoopbackMastraServer } from '@sourceloop/mastra-loopback';
const app = new RestApplication({
rest: { host: '0.0.0.0', port: 3000 },
});
const mastra = new Mastra();
const adapter = new LoopbackMastraServer({
app,
mastra,
config: { prefix: '/api/mastra' },
});
await adapter.init();
await app.start();The package publishes both ESM and CommonJS entry points with TypeScript declarations.
Mastra handlers receive a real Mastra RequestContext. The adapter injects a
LoopBack bridge under the loopback key:
const loopback = requestContext.get('loopback');
const customerRepository = await loopback.resolve(
'repositories.CustomerRepository',
);
const customer = await customerRepository.findById(customerId);This keeps request-scoped bindings, services, repositories, and other DI-managed artifacts available to Mastra routes, tools, and agents. The adapter also exposes the current Mastra state to LoopBack through these bindings:
providers.mastra.loopback.requestContextproviders.mastra.loopback.authContextproviders.mastra.loopback.abortSignalproviders.mastra.loopback.bridge
Mastra apiRoutes are registered as native LoopBack route entries while
preserving request context and DI:
import { registerApiRoute } from '@mastra/core/server';
mastra.setServer({
apiRoutes: [
registerApiRoute('/customer/:id', {
method: 'GET',
handler: async c => {
const requestContext = c.get('requestContext');
const loopback = requestContext.get('loopback');
const service = await loopback.resolve('services.CustomerService');
return c.json(await service.findById(c.req.param('id')));
},
openapi: { summary: 'Get customer by id' },
}),
],
});Mastra's server auth configuration works normally. Adapter-specific hooks can compose with it before, after, or in place of the default behavior:
const adapter = new LoopbackMastraServer({
app,
mastra,
config: {
prefix: '/api/mastra',
auth: {
authorizeMode: 'after',
authorize: async input =>
input.getHeader('x-tenant-id')
? null
: { status: 403, error: 'Tenant header required' },
resolveContextMode: 'replace',
resolveContext: async input => ({
userId: input.headers['x-user-id'] as string | undefined,
}),
},
},
});See HOW-TO-USE.md for full integration patterns and examples/basic-loopback-app for runnable examples.
- Mastra JSON, streamed, data-stream, MCP HTTP, and MCP SSE responses
- Mastra custom API routes
- Mastra auth, RBAC permissions, and FGA checks, plus optional LoopBack-aware auth composition
multipart/form-datauploads (files arrive asBuffers, JSON fields decoded)- Body-size limits via
bodyLimitOptionsor a route'smaxBodySize(413) - Request cancellation and stream redaction
- Mastra
apiReqLogsrequest logging through the Mastra logger - Custom route prefixes
- LoopBack request-scoped dependency injection
Request logging is registered as LoopBack middleware, so it covers every
request on the application (as app.use does for the Express adapter) and
needs LoopBack's default MiddlewareSequence.
The adapter runs all six of Mastra's published server-adapter conformance
suites from
@mastra/server-adapters-test-suite:
route parity against the live SERVER_ROUTES table, MCP routes, MCP
transports, multipart, body limits, and HTTP logging. Against Mastra 1.72.0 and
suite 0.1.1 every check passes, and CI runs them on every change and before
every release.
npm install --ignore-scripts
npm run verifynpm run verify type-checks, runs the unit, integration, and conformance
suites, and builds both package formats with publint and
are-the-types-wrong. npm run test:conformance runs only the conformance
suites.
Releases are manual and publish from main only.
- In a PR, bump
versioninpackage.jsonand add aCHANGELOG.mdentry. - Merge it to
main. - Run the Release workflow on
mainfrom the Actions tab, or withgh workflow run release.yml --ref main, and approve thenpmdeployment.
The workflow fails if the version is already on npm. Otherwise it reruns the
full CI (conformance included), builds and packs the tarball in an unprivileged
job, publishes that exact tarball with npm trusted publishing (OIDC, with
provenance), and then creates the v<version> tag and GitHub release.
One-time setup, which is what makes "main only" enforced by GitHub and npm rather than by the workflow alone:
- Create an
npmenvironment in the repository settings and limit its deployment branches tomain. - Register this repository,
release.yml, and thenpmenvironment as the trusted publisher for the package on npmjs.com.