| name | telescope-access-mcp |
| description | Dashboard access control and the MCP server in nestjs-telescope. Gate reads with authorizer(ctx) (default-deny in production) and queue mutations separately with authorizeAction(ctx, action) (default-deny ALWAYS). Add a cookie-session login wall with dashboardAuth.{secret,ttl,session,login} (two modes; missing secret or hook is a boot error). Expose a stateless MCP endpoint for coding agents with mcp:true (dev-only) or mcp:{ token } (Bearer-gated, required in production). Use for "lock down the dashboard", "login wall", "retry/remove queue jobs are 403", "connect Claude Code / Cursor to Telescope". |
| license | MIT |
| metadata | {"type":"core","library":"@dudousxd/nestjs-telescope","library_version":"1.12.0","framework":"nestjs"} |
Dashboard access control & MCP
Telescope has two independent gates — one for reads (authorizer) and one for
mutations (authorizeAction) — plus an optional cookie-session login wall
(dashboardAuth) and a header-gated MCP endpoint for coding agents (mcp).
Setup
The simplest production-safe gate authorizes reads off the platform request:
import { TelescopeModule } from '@dudousxd/nestjs-telescope';
TelescopeModule.forRoot({
enabled: true,
authorizer: (ctx) => isAdmin(ctx.request),
authorizeAction: (ctx, action) => isAdmin(ctx.request),
});
Source: packages/core/src/nest/telescope.options.ts
(authorizer, authorizeAction, AuthorizerContext).
Core patterns
Pattern 1 — read gate vs action gate
authorizer defaults to "allow in dev, deny in prod"; authorizeAction defaults
to deny always. A throw in either is treated as a denial (fail closed).
TelescopeModule.forRoot({
enabled: true,
authorizer: (ctx) => Boolean((ctx.request as any).user),
authorizeAction: (ctx, action) => (ctx.request as any).user?.role === 'admin',
});
Source: packages/core/src/nest/telescope.options.ts.
Pattern 2 — a login wall with dashboardAuth
When set, every guarded /api/* route requires a valid signed session cookie AND
the authorizer still runs (AND semantics). Provide a secret plus at least one
mode: session (bridge your host auth) or login (built-in username/password).
TelescopeModule.forRoot({
enabled: true,
dashboardAuth: {
secret: process.env.TELESCOPE_SECRET!,
ttl: '8h',
login: (username, password) =>
username === 'admin' && password === process.env.TELESCOPE_PASS
? { id: 'admin' }
: null,
},
});
Source: packages/core/src/auth/dashboard-auth-config.ts (DashboardAuthOptions,
resolveDashboardAuth), website/content/docs/recipes/dashboard-auth.mdx.
Pattern 3 — the MCP server for coding agents
mcp: true exposes a stateless JSON-RPC endpoint at <path>/api/mcp (open only
when NODE_ENV !== 'production'). Pass { token } to require a Bearer token —
the only way to expose it in production.
TelescopeModule.forRoot({
mcp: { token: process.env.TELESCOPE_MCP_TOKEN },
});
Register it with an agent:
claude mcp add --transport http telescope http://localhost:3000/telescope/api/mcp
Source: packages/core/src/nest/telescope.options.ts (mcp),
packages/core/src/nest/telescope-mcp.controller.ts,
website/content/docs/concepts/mcp.mdx.
Common mistakes
Mistake 1 — expecting authorizer to also gate mutations
TelescopeModule.forRoot({ enabled: true, authorizer: () => true });
TelescopeModule.forRoot({
enabled: true,
authorizer: () => true,
authorizeAction: (ctx, action) => isAdmin(ctx.request),
});
Mechanism: mutations are a separate, default-deny gate so a read-open dashboard can
never retry/remove/redrive jobs without an explicit decision. Source:
packages/core/src/nest/telescope.options.ts (authorizeAction).
Mistake 2 — dashboardAuth without a secret or any mode
TelescopeModule.forRoot({ dashboardAuth: { secret: '' } });
TelescopeModule.forRoot({ dashboardAuth: { secret: 'k'.repeat(32) } });
TelescopeModule.forRoot({
dashboardAuth: { secret: process.env.TELESCOPE_SECRET!, login: verifyCreds },
});
Mechanism: the cookie can never be minted without a signing secret and a mode, so
Telescope throws at boot rather than shipping an open or un-loginable dashboard.
Source: packages/core/src/auth/dashboard-auth-config.ts (resolveDashboardAuth).
Mistake 3 — a tokenless MCP config in production
TelescopeModule.forRoot({ mcp: true });
TelescopeModule.forRoot({ mcp: { token: process.env.TELESCOPE_MCP_TOKEN } });
Mechanism: without a token the MCP endpoint is allowed only when
NODE_ENV !== 'production' (mirroring the default-open-in-dev authorizer); a token
is the only production-safe exposure. Source:
packages/core/src/nest/telescope.options.ts (mcp).