@general-analysis/mcp-guard
Version:
An MCP guardrail with built-in AI-powered moderation that aggregates multiple MCP servers into one secure interface
107 lines • 3.74 kB
JavaScript
import { z } from "zod";
import { moderateToolOutput } from "./moderation.js";
/**
* Creates a tool handler that wraps the original tool with moderation
*/
export async function createToolHandler(client, originalToolName, apiKey, enableGuardApi = false) {
return async (args) => {
try {
const result = await client.callTool({
name: originalToolName,
arguments: args,
});
return await moderateToolOutput(result, apiKey, enableGuardApi);
}
catch (error) {
const errorResponse = {
content: [
{
type: "text",
text: `Error executing tool: ${error instanceof Error ? error.message : String(error)}`,
},
],
isError: true,
};
return await moderateToolOutput(errorResponse, apiKey, enableGuardApi);
}
};
}
/**
* Creates a prompt handler (no moderation for prompts)
*/
export async function createPromptHandler(client, originalPromptName, serverName) {
return async (args) => {
try {
const result = await client.getPrompt({
name: originalPromptName,
arguments: args,
});
// No moderation for prompts - pass through directly
return result;
}
catch (error) {
throw new Error(`Error executing prompt: ${error instanceof Error ? error.message : String(error)}`);
}
};
}
/**
* Creates a resource handler (no moderation for resources)
*/
export async function createResourceHandler(client, originalResourceUri, serverName) {
return async (uri) => {
try {
const result = await client.readResource({
uri: originalResourceUri,
});
// No moderation for resources - pass through directly
return result;
}
catch (error) {
throw new Error(`Error reading resource: ${error instanceof Error ? error.message : String(error)}`);
}
};
}
/**
* Converts JSON Schema to Zod schema for MCP tool validation
*/
export function convertJsonSchemaToZod(jsonSchema) {
if (!jsonSchema || typeof jsonSchema !== "object") {
return {};
}
const zodShape = {};
// Handle object type with properties
if (jsonSchema.type === "object" && jsonSchema.properties) {
for (const [key, propSchema] of Object.entries(jsonSchema.properties)) {
const prop = propSchema;
// Convert property based on its type
if (prop.type === "string") {
zodShape[key] = z.string();
}
else if (prop.type === "number") {
zodShape[key] = z.number();
}
else if (prop.type === "integer") {
zodShape[key] = z.number().int();
}
else if (prop.type === "boolean") {
zodShape[key] = z.boolean();
}
else if (prop.type === "array") {
zodShape[key] = z.array(z.any());
}
else if (prop.type === "object") {
zodShape[key] = z.object(convertJsonSchemaToZod(prop));
}
else {
zodShape[key] = z.any();
}
// Handle optional properties
if (!jsonSchema.required || !jsonSchema.required.includes(key)) {
zodShape[key] = zodShape[key].optional();
}
}
}
// If no properties or not an object, return empty shape (accepts any input)
return zodShape;
}
//# sourceMappingURL=handlers.js.map