Fügt einen geschützten MCP-JSON-RPC-Endpunkt mit Buchhaltungs-Tools und Aufgaben-Tools hinzu. Berechtigungen werden rollenbasiert pro Mandant geprüft und die Auth-Logik berücksichtigt nun alle Rollen eines Nutzers.
89 lines
2.4 KiB
TypeScript
89 lines
2.4 KiB
TypeScript
import { FastifyInstance, FastifyRequest } from "fastify"
|
|
import { and, eq, or, isNull, inArray } from "drizzle-orm"
|
|
import {
|
|
authRoles,
|
|
authRolePermissions,
|
|
authUserRoles,
|
|
} from "../../db/schema"
|
|
import { McpContext, McpTool } from "./types"
|
|
|
|
export async function loadTenantPermissions(
|
|
server: FastifyInstance,
|
|
userId: string,
|
|
tenantId: number
|
|
) {
|
|
const roleRows = await server.db
|
|
.select({
|
|
roleId: authUserRoles.role_id,
|
|
})
|
|
.from(authUserRoles)
|
|
.innerJoin(
|
|
authRoles,
|
|
and(
|
|
eq(authRoles.id, authUserRoles.role_id),
|
|
or(isNull(authRoles.tenant_id), eq(authRoles.tenant_id, tenantId))
|
|
)
|
|
)
|
|
.where(
|
|
and(
|
|
eq(authUserRoles.user_id, userId),
|
|
eq(authUserRoles.tenant_id, tenantId)
|
|
)
|
|
)
|
|
|
|
const roleIds = Array.from(new Set(roleRows.map((row) => row.roleId)))
|
|
|
|
if (roleIds.length === 0) return []
|
|
|
|
const permissionRows = await server.db
|
|
.select({
|
|
permission: authRolePermissions.permission,
|
|
})
|
|
.from(authRolePermissions)
|
|
.where(inArray(authRolePermissions.role_id, roleIds))
|
|
|
|
return Array.from(new Set(permissionRows.map((row) => row.permission)))
|
|
}
|
|
|
|
export async function createMcpContext(
|
|
server: FastifyInstance,
|
|
request: FastifyRequest
|
|
): Promise<McpContext> {
|
|
const user = request.user
|
|
|
|
if (!user?.user_id) {
|
|
throw Object.assign(new Error("Authentication required"), { statusCode: 401 })
|
|
}
|
|
|
|
if (!user.tenant_id) {
|
|
throw Object.assign(new Error("MCP benötigt einen aktiven Mandanten"), { statusCode: 403 })
|
|
}
|
|
|
|
const permissions = await loadTenantPermissions(server, user.user_id, user.tenant_id)
|
|
|
|
return {
|
|
server,
|
|
request,
|
|
tenantId: user.tenant_id,
|
|
userId: user.user_id,
|
|
isAdmin: Boolean(user.is_admin),
|
|
permissions,
|
|
}
|
|
}
|
|
|
|
export function assertToolPermission(context: McpContext, tool: McpTool) {
|
|
if (context.isAdmin) return
|
|
|
|
const allowed = tool.requiredPermissions.every((permission) =>
|
|
context.permissions.includes(permission)
|
|
)
|
|
|
|
if (!allowed) {
|
|
throw Object.assign(
|
|
new Error(`Fehlende Berechtigung für ${tool.name}: ${tool.requiredPermissions.join(", ")}`),
|
|
{ statusCode: 403 }
|
|
)
|
|
}
|
|
}
|
|
|