feat(mcp): paginate record lists and describe document inputs

This commit is contained in:
2026-09-14 13:17:37 +02:00
parent 58fc252110
commit 342ad9764e
8 changed files with 302 additions and 123 deletions

View File

@@ -1,3 +1,4 @@
import { limitFromArgs, offsetFromArgs, paginatedResult, paginationProperties } from "../pagination"
import { and, desc, eq, ilike, or } from "drizzle-orm"
import {
branches,
@@ -14,11 +15,6 @@ import {
} from "../../../db/schema"
import { McpTool } from "../types"
const limitFromArgs = (args: Record<string, unknown>, fallback = 25) => {
const raw = Number(args.limit ?? fallback)
if (!Number.isFinite(raw)) return fallback
return Math.min(Math.max(Math.trunc(raw), 1), 100)
}
const stringArg = (args: Record<string, unknown>, key: string) => {
const value = args[key]
@@ -71,7 +67,7 @@ export const masterdataTools: McpTool[] = [
type: "object",
properties: {
query: { type: "string", description: "Suchtext für Name, Lieferantennummer oder Notizen." },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -91,10 +87,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(vendors)
.where(and(...conditions))
.orderBy(vendors.name)
.limit(limitFromArgs(args))
.orderBy(vendors.name, vendors.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -132,7 +129,7 @@ export const masterdataTools: McpTool[] = [
query: { type: "string", description: "Suchtext für Name, E-Mail, Telefon, Rolle oder Notizen." },
customer: { type: "number" },
vendor: { type: "number" },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -161,10 +158,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(contacts)
.where(and(...conditions))
.orderBy(contacts.fullName)
.limit(limitFromArgs(args))
.orderBy(contacts.fullName, contacts.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -176,7 +174,7 @@ export const masterdataTools: McpTool[] = [
type: "object",
properties: {
query: { type: "string", description: "Suchtext für Name, Artikelnummer, Hersteller, EAN, Barcode oder Beschreibung." },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -200,10 +198,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(products)
.where(and(...conditions))
.orderBy(products.name)
.limit(limitFromArgs(args))
.orderBy(products.name, products.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -239,7 +238,7 @@ export const masterdataTools: McpTool[] = [
type: "object",
properties: {
query: { type: "string", description: "Suchtext für Name, Leistungsnummer oder Beschreibung." },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -258,10 +257,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(services)
.where(and(...conditions))
.orderBy(services.name)
.limit(limitFromArgs(args))
.orderBy(services.name, services.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -299,7 +299,7 @@ export const masterdataTools: McpTool[] = [
query: { type: "string", description: "Suchtext für Nummer, Name oder Beschreibung." },
branch: { type: "number" },
project: { type: "number" },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -323,10 +323,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(costcentres)
.where(and(...conditions))
.orderBy(costcentres.number)
.limit(limitFromArgs(args))
.orderBy(costcentres.number, costcentres.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -362,7 +363,7 @@ export const masterdataTools: McpTool[] = [
type: "object",
properties: {
query: { type: "string", description: "Suchtext für Nummer, Name oder Beschreibung." },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -382,10 +383,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(branches)
.where(and(...conditions))
.orderBy(branches.name)
.limit(limitFromArgs(args))
.orderBy(branches.name, branches.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -398,7 +400,7 @@ export const masterdataTools: McpTool[] = [
properties: {
query: { type: "string", description: "Suchtext für Name oder Beschreibung." },
branch: { type: "number" },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -419,10 +421,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(teams)
.where(and(...conditions))
.orderBy(teams.name)
.limit(limitFromArgs(args))
.orderBy(teams.name, teams.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -434,7 +437,7 @@ export const masterdataTools: McpTool[] = [
type: "object",
properties: {
query: { type: "string", description: "Suchtext für Name, Kennzeichen, FIN oder Farbe." },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -455,10 +458,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(vehicles)
.where(and(...conditions))
.orderBy(vehicles.name)
.limit(limitFromArgs(args))
.orderBy(vehicles.name, vehicles.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -471,7 +475,7 @@ export const masterdataTools: McpTool[] = [
properties: {
query: { type: "string", description: "Suchtext für Name, Artikelnummer, Seriennummer, Hersteller oder Beschreibung." },
vendor: { type: "number" },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -496,10 +500,11 @@ export const masterdataTools: McpTool[] = [
.select()
.from(inventoryitems)
.where(and(...conditions))
.orderBy(inventoryitems.name)
.limit(limitFromArgs(args))
.orderBy(inventoryitems.name, inventoryitems.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
{
@@ -535,7 +540,7 @@ export const masterdataTools: McpTool[] = [
type: "object",
properties: {
query: { type: "string", description: "Suchtext für Name, Singular, Plural oder Kürzel." },
limit: { type: "number", minimum: 1, maximum: 100 },
...paginationProperties,
},
},
async handler(context, args) {
@@ -552,10 +557,11 @@ export const masterdataTools: McpTool[] = [
ilike(units.short, `%${query}%`)
)
: undefined)
.orderBy(units.name)
.limit(limitFromArgs(args))
.orderBy(units.name, units.id)
.limit(limitFromArgs(args) + 1)
.offset(offsetFromArgs(args))
return { rows }
return paginatedResult(rows, args)
},
},
]