util.ts•1.94 kB
import { type Tool, tool } from '@supabase/mcp-utils';
import type { z } from 'zod';
type RequireKeys<Injected, Params> = {
[K in keyof Injected]: K extends keyof Params ? Injected[K] : never;
};
export type InjectableTool<
Params extends z.ZodObject<any> = z.ZodObject<any>,
Result = unknown,
Injected extends Partial<z.infer<Params>> = {},
> = Tool<Params, Result> & {
/**
* Optionally injects static parameter values into the tool's
* execute function and removes them from the parameter schema.
*
* Useful to scope tools to a specific project at config time
* without redefining the tool.
*/
inject?: Injected & RequireKeys<Injected, z.infer<Params>>;
};
export function injectableTool<
Params extends z.ZodObject<any>,
Result,
Injected extends Partial<z.infer<Params>>,
>({
description,
annotations,
parameters,
inject,
execute,
}: InjectableTool<Params, Result, Injected>) {
// If all injected parameters are undefined, return the original tool
if (!inject || Object.values(inject).every((value) => value === undefined)) {
return tool({
description,
annotations,
parameters,
execute,
});
}
// Create a mask used to remove injected parameters from the schema
const mask = Object.fromEntries(
Object.entries(inject)
.filter(([_, value]) => value !== undefined)
.map(([key]) => [key, true as const])
);
type NonNullableKeys = {
[K in keyof Injected]: Injected[K] extends undefined ? never : K;
}[keyof Injected];
type CleanParams = z.infer<Params> extends any
? {
[K in keyof z.infer<Params> as K extends NonNullableKeys
? never
: K]: z.infer<Params>[K];
}
: never;
return tool({
description,
annotations,
parameters: parameters.omit(mask),
execute: (args) => execute({ ...args, ...inject }),
}) as Tool<z.ZodObject<any, any, any, CleanParams>, Result>;
}