fix(mcp): harden tool schemas and dispatch (#6815)

This commit is contained in:
Thomas authored and GitHub committed 2026-09-10 19:19:47 +02:00
1 parent f994d665d2
commit ea3dac752f
12 files changed
+531 -157

No files matched your search

+4 -21
View File
@@ -1,5 +1,6 @@
import { createMcpHandler, McpServer } from "@modelcontextprotocol/server";
import { createMcpHandler, fromJsonSchema, McpServer } from "@modelcontextprotocol/server";
import { callMcpTool } from "@homarr/api/mcp";
import type { McpTool } from "@homarr/api/mcp";
import { toAssistantToolOutput } from "../assistant/chat/assistant-tool-output";
@@ -15,15 +16,6 @@ interface CreateMcpProtocolHandlerOptions {
onProtocolError?: (error: Error) => void;
}
const resolveProcedure = (caller: unknown, path: string[]) =>
path.reduce<unknown>(
(current, segment) =>
(typeof current === "object" || typeof current === "function") && current !== null
? (current as Record<string, unknown>)[segment]
: undefined,
caller,
);
export const createMcpProtocolHandler = ({
caller,
tools,
@@ -52,20 +44,11 @@ export const createMcpProtocolHandler = ({
tool.name,
{
description: tool.description,
inputSchema: tool.inputValidator,
inputSchema: fromJsonSchema(tool.inputSchema as Parameters<typeof fromJsonSchema>[0]),
},
async (args) => {
try {
const procedure = resolveProcedure(caller, tool.pathInRouter);
if (typeof procedure !== "function") {
return {
content: [{ type: "text" as const, text: `Tool "${tool.name}" is not callable` }],
isError: true,
};
}
const input = Object.keys(args).length > 0 ? args : undefined;
const result = await (procedure as (value: unknown) => Promise<unknown>)(input);
const result = await callMcpTool(caller, tool, args);
return {
content: [
{