From b279a1a62c0a60842c80e82e3f93ecef3c8f5478 Mon Sep 17 00:00:00 2001 From: samanhappy Date: Thu, 1 Jan 2026 22:41:46 +0800 Subject: [PATCH] chore: update mcp sdk dependencies to latest versions (#546) --- frontend/src/components/GroupCard.tsx | 194 ++++++++-------- frontend/src/components/ServerCard.tsx | 21 +- frontend/src/components/ui/PromptCard.tsx | 4 +- frontend/src/components/ui/ToolCard.tsx | 259 +++++++++++----------- package.json | 2 +- pnpm-lock.yaml | 34 ++- 6 files changed, 281 insertions(+), 233 deletions(-) diff --git a/frontend/src/components/GroupCard.tsx b/frontend/src/components/GroupCard.tsx index 165080c..ea9c8bd 100644 --- a/frontend/src/components/GroupCard.tsx +++ b/frontend/src/components/GroupCard.tsx @@ -1,99 +1,103 @@ -import { useState, useRef, useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import { Group, Server, IGroupServerConfig } from '@/types' -import { Edit, Trash, Copy, Check, Link, FileCode, DropdownIcon, Wrench } from '@/components/icons/LucideIcons' -import DeleteDialog from '@/components/ui/DeleteDialog' -import { useToast } from '@/contexts/ToastContext' -import { useSettingsData } from '@/hooks/useSettingsData' +import { useState, useRef, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Group, Server, IGroupServerConfig } from '@/types'; +import { + Edit, + Trash, + Copy, + Check, + Link, + FileCode, + DropdownIcon, + Wrench, +} from '@/components/icons/LucideIcons'; +import DeleteDialog from '@/components/ui/DeleteDialog'; +import { useToast } from '@/contexts/ToastContext'; +import { useSettingsData } from '@/hooks/useSettingsData'; interface GroupCardProps { - group: Group - servers: Server[] - onEdit: (group: Group) => void - onDelete: (groupId: string) => void + group: Group; + servers: Server[]; + onEdit: (group: Group) => void; + onDelete: (groupId: string) => void; } -const GroupCard = ({ - group, - servers, - onEdit, - onDelete -}: GroupCardProps) => { - const { t } = useTranslation() - const { showToast } = useToast() - const { installConfig } = useSettingsData() - const [showDeleteDialog, setShowDeleteDialog] = useState(false) - const [copied, setCopied] = useState(false) - const [showCopyDropdown, setShowCopyDropdown] = useState(false) - const [expandedServer, setExpandedServer] = useState(null) - const dropdownRef = useRef(null) +const GroupCard = ({ group, servers, onEdit, onDelete }: GroupCardProps) => { + const { t } = useTranslation(); + const { showToast } = useToast(); + const { installConfig } = useSettingsData(); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [copied, setCopied] = useState(false); + const [showCopyDropdown, setShowCopyDropdown] = useState(false); + const [expandedServer, setExpandedServer] = useState(null); + const dropdownRef = useRef(null); // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { - setShowCopyDropdown(false) + setShowCopyDropdown(false); } - } + }; - document.addEventListener('mousedown', handleClickOutside) + document.addEventListener('mousedown', handleClickOutside); return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, []) + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); const handleEdit = () => { - onEdit(group) - } + onEdit(group); + }; const handleDelete = () => { - setShowDeleteDialog(true) - } + setShowDeleteDialog(true); + }; const handleConfirmDelete = () => { - onDelete(group.id) - setShowDeleteDialog(false) - } + onDelete(group.id); + setShowDeleteDialog(false); + }; const copyToClipboard = (text: string) => { if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(text).then(() => { - setCopied(true) - setShowCopyDropdown(false) - showToast(t('common.copySuccess'), 'success') - setTimeout(() => setCopied(false), 2000) - }) + setCopied(true); + setShowCopyDropdown(false); + showToast(t('common.copySuccess'), 'success'); + setTimeout(() => setCopied(false), 2000); + }); } else { // Fallback for HTTP or unsupported clipboard API - const textArea = document.createElement('textarea') - textArea.value = text + const textArea = document.createElement('textarea'); + textArea.value = text; // Avoid scrolling to bottom - textArea.style.position = 'fixed' - textArea.style.left = '-9999px' - document.body.appendChild(textArea) - textArea.focus() - textArea.select() + textArea.style.position = 'fixed'; + textArea.style.left = '-9999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); try { - document.execCommand('copy') - setCopied(true) - setShowCopyDropdown(false) - showToast(t('common.copySuccess'), 'success') - setTimeout(() => setCopied(false), 2000) + document.execCommand('copy'); + setCopied(true); + setShowCopyDropdown(false); + showToast(t('common.copySuccess'), 'success'); + setTimeout(() => setCopied(false), 2000); } catch (err) { - showToast(t('common.copyFailed') || 'Copy failed', 'error') - console.error('Copy to clipboard failed:', err) + showToast(t('common.copyFailed') || 'Copy failed', 'error'); + console.error('Copy to clipboard failed:', err); } - document.body.removeChild(textArea) + document.body.removeChild(textArea); } - } + }; const handleCopyId = () => { - copyToClipboard(group.id) - } + copyToClipboard(group.id); + }; const handleCopyUrl = () => { - copyToClipboard(`${installConfig.baseUrl}/mcp/${group.id}`) - } + copyToClipboard(`${installConfig.baseUrl}/mcp/${group.id}`); + }; const handleCopyJson = () => { const jsonConfig = { @@ -101,23 +105,23 @@ const GroupCard = ({ mcphub: { url: `${installConfig.baseUrl}/mcp/${group.id}`, headers: { - Authorization: "Bearer " - } - } - } - } - copyToClipboard(JSON.stringify(jsonConfig, null, 2)) - } + Authorization: 'Bearer ', + }, + }, + }, + }; + copyToClipboard(JSON.stringify(jsonConfig, null, 2)); + }; // Helper function to normalize group servers to get server names const getServerNames = (servers: string[] | IGroupServerConfig[]): string[] => { - return servers.map(server => typeof server === 'string' ? server : server.name); + return servers.map((server) => (typeof server === 'string' ? server : server.name)); }; // Helper function to get server configuration const getServerConfig = (serverName: string): IGroupServerConfig | undefined => { - const server = group.servers.find(s => - typeof s === 'string' ? s === serverName : s.name === serverName + const server = group.servers.find((s) => + typeof s === 'string' ? s === serverName : s.name === serverName, ); if (typeof server === 'string') { return { name: server, tools: 'all' }; @@ -127,11 +131,11 @@ const GroupCard = ({ // Get servers that belong to this group const serverNames = getServerNames(group.servers); - const groupServers = servers.filter(server => serverNames.includes(server.name)); + const groupServers = servers.filter((server) => serverNames.includes(server.name)); return ( -
-
+
+

{group.name}

@@ -175,9 +179,7 @@ const GroupCard = ({
- {group.description && ( -

{group.description}

- )} + {group.description &&

{group.description}

}
@@ -200,17 +202,19 @@ const GroupCard = ({
-
+
{groupServers.length === 0 ? (

{t('groups.noServers')}

) : (
- {groupServers.map(server => { + {groupServers.map((server) => { const serverConfig = getServerConfig(server.name); - const hasToolRestrictions = serverConfig && serverConfig.tools !== 'all' && Array.isArray(serverConfig.tools); - const toolCount = hasToolRestrictions && Array.isArray(serverConfig?.tools) - ? serverConfig.tools.length - : (server.tools?.length || 0); // Show total tool count when all tools are selected + const hasToolRestrictions = + serverConfig && serverConfig.tools !== 'all' && Array.isArray(serverConfig.tools); + const toolCount = + hasToolRestrictions && Array.isArray(serverConfig?.tools) + ? serverConfig.tools.length + : server.tools?.length || 0; // Show total tool count when all tools are selected const isExpanded = expandedServer === server.name; @@ -219,7 +223,7 @@ const GroupCard = ({ if (hasToolRestrictions && Array.isArray(serverConfig?.tools)) { return serverConfig.tools; } else if (server.tools && server.tools.length > 0) { - return server.tools.map(tool => tool.name); + return server.tools.map((tool) => tool.name); } return []; }; @@ -235,9 +239,15 @@ const GroupCard = ({ onClick={handleServerClick} > {server.name} - + {toolCount > 0 && ( @@ -278,7 +288,7 @@ const GroupCard = ({ isGroup={true} />
- ) -} + ); +}; -export default GroupCard \ No newline at end of file +export default GroupCard; diff --git a/frontend/src/components/ServerCard.tsx b/frontend/src/components/ServerCard.tsx index cbc4e40..40c3b80 100644 --- a/frontend/src/components/ServerCard.tsx +++ b/frontend/src/components/ServerCard.tsx @@ -18,7 +18,14 @@ interface ServerCardProps { onReload?: (server: Server) => Promise; } -const ServerCard = ({ server, onRemove, onEdit, onToggle, onRefresh, onReload }: ServerCardProps) => { +const ServerCard = ({ + server, + onRemove, + onEdit, + onToggle, + onRefresh, + onReload, +}: ServerCardProps) => { const { t } = useTranslation(); const { showToast } = useToast(); const [isExpanded, setIsExpanded] = useState(false); @@ -232,10 +239,10 @@ const ServerCard = ({ server, onRemove, onEdit, onToggle, onRefresh, onReload }: return ( <>
setIsExpanded(!isExpanded)} >
@@ -385,9 +392,9 @@ const ServerCard = ({ server, onRemove, onEdit, onToggle, onRefresh, onReload }: {isExpanded && ( <> {server.tools && ( -
+
{t('server.tools')}
@@ -405,9 +412,9 @@ const ServerCard = ({ server, onRemove, onEdit, onToggle, onRefresh, onReload }: )} {server.prompts && ( -
+
{t('server.prompts')}
diff --git a/frontend/src/components/ui/PromptCard.tsx b/frontend/src/components/ui/PromptCard.tsx index 1b818d1..f791566 100644 --- a/frontend/src/components/ui/PromptCard.tsx +++ b/frontend/src/components/ui/PromptCard.tsx @@ -171,9 +171,9 @@ const PromptCard = ({ prompt, server, onToggle, onDescriptionUpdate }: PromptCar }; return ( -
+
setIsExpanded(!isExpanded)} >
diff --git a/frontend/src/components/ui/ToolCard.tsx b/frontend/src/components/ui/ToolCard.tsx index 31c20fb..f9eea4a 100644 --- a/frontend/src/components/ui/ToolCard.tsx +++ b/frontend/src/components/ui/ToolCard.tsx @@ -1,19 +1,27 @@ -import { useState, useCallback, useRef, useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import { Tool } from '@/types' -import { ChevronDown, ChevronRight, Play, Loader, Edit, Check, Copy } from '@/components/icons/LucideIcons' -import { callTool, ToolCallResult, updateToolDescription } from '@/services/toolService' -import { useSettingsData } from '@/hooks/useSettingsData' -import { useToast } from '@/contexts/ToastContext' -import { Switch } from './ToggleGroup' -import DynamicForm from './DynamicForm' -import ToolResult from './ToolResult' +import { useState, useCallback, useRef, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Tool } from '@/types'; +import { + ChevronDown, + ChevronRight, + Play, + Loader, + Edit, + Check, + Copy, +} from '@/components/icons/LucideIcons'; +import { callTool, ToolCallResult, updateToolDescription } from '@/services/toolService'; +import { useSettingsData } from '@/hooks/useSettingsData'; +import { useToast } from '@/contexts/ToastContext'; +import { Switch } from './ToggleGroup'; +import DynamicForm from './DynamicForm'; +import ToolResult from './ToolResult'; interface ToolCardProps { - server: string - tool: Tool - onToggle?: (toolName: string, enabled: boolean) => void - onDescriptionUpdate?: (toolName: string, description: string) => void + server: string; + tool: Tool; + onToggle?: (toolName: string, enabled: boolean) => void; + onDescriptionUpdate?: (toolName: string, description: string) => void; } // Helper to check for "empty" values @@ -26,165 +34,173 @@ function isEmptyValue(value: any): boolean { } const ToolCard = ({ tool, server, onToggle, onDescriptionUpdate }: ToolCardProps) => { - const { t } = useTranslation() - const { showToast } = useToast() - const { nameSeparator } = useSettingsData() - const [isExpanded, setIsExpanded] = useState(false) - const [showRunForm, setShowRunForm] = useState(false) - const [isRunning, setIsRunning] = useState(false) - const [result, setResult] = useState(null) - const [isEditingDescription, setIsEditingDescription] = useState(false) - const [customDescription, setCustomDescription] = useState(tool.description || '') - const descriptionInputRef = useRef(null) - const descriptionTextRef = useRef(null) - const [textWidth, setTextWidth] = useState(0) - const [copiedToolName, setCopiedToolName] = useState(false) + const { t } = useTranslation(); + const { showToast } = useToast(); + const { nameSeparator } = useSettingsData(); + const [isExpanded, setIsExpanded] = useState(false); + const [showRunForm, setShowRunForm] = useState(false); + const [isRunning, setIsRunning] = useState(false); + const [result, setResult] = useState(null); + const [isEditingDescription, setIsEditingDescription] = useState(false); + const [customDescription, setCustomDescription] = useState(tool.description || ''); + const descriptionInputRef = useRef(null); + const descriptionTextRef = useRef(null); + const [textWidth, setTextWidth] = useState(0); + const [copiedToolName, setCopiedToolName] = useState(false); // Focus the input when editing mode is activated useEffect(() => { if (isEditingDescription && descriptionInputRef.current) { - descriptionInputRef.current.focus() + descriptionInputRef.current.focus(); // Set input width to match text width if (textWidth > 0) { - descriptionInputRef.current.style.width = `${textWidth + 20}px` // Add some padding + descriptionInputRef.current.style.width = `${textWidth + 20}px`; // Add some padding } } - }, [isEditingDescription, textWidth]) + }, [isEditingDescription, textWidth]); // Measure text width when not editing useEffect(() => { if (!isEditingDescription && descriptionTextRef.current) { - setTextWidth(descriptionTextRef.current.offsetWidth) + setTextWidth(descriptionTextRef.current.offsetWidth); } - }, [isEditingDescription, customDescription]) + }, [isEditingDescription, customDescription]); // Generate a unique key for localStorage based on tool name and server const getStorageKey = useCallback(() => { - return `mcphub_tool_form_${server ? `${server}_` : ''}${tool.name}` - }, [tool.name, server]) + return `mcphub_tool_form_${server ? `${server}_` : ''}${tool.name}`; + }, [tool.name, server]); // Clear form data from localStorage const clearStoredFormData = useCallback(() => { - localStorage.removeItem(getStorageKey()) - }, [getStorageKey]) + localStorage.removeItem(getStorageKey()); + }, [getStorageKey]); const handleToggle = (enabled: boolean) => { if (onToggle) { - onToggle(tool.name, enabled) + onToggle(tool.name, enabled); } - } + }; const handleDescriptionEdit = () => { - setIsEditingDescription(true) - } + setIsEditingDescription(true); + }; const handleDescriptionSave = async () => { try { - const result = await updateToolDescription(server, tool.name, customDescription) + const result = await updateToolDescription(server, tool.name, customDescription); if (result.success) { - setIsEditingDescription(false) + setIsEditingDescription(false); if (onDescriptionUpdate) { - onDescriptionUpdate(tool.name, customDescription) + onDescriptionUpdate(tool.name, customDescription); } } else { // Revert on error - setCustomDescription(tool.description || '') - console.error('Failed to update tool description:', result.error) + setCustomDescription(tool.description || ''); + console.error('Failed to update tool description:', result.error); } } catch (error) { - console.error('Error updating tool description:', error) - setCustomDescription(tool.description || '') - setIsEditingDescription(false) + console.error('Error updating tool description:', error); + setCustomDescription(tool.description || ''); + setIsEditingDescription(false); } - } + }; const handleDescriptionChange = (e: React.ChangeEvent) => { - setCustomDescription(e.target.value) - } + setCustomDescription(e.target.value); + }; const handleDescriptionKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { - handleDescriptionSave() + handleDescriptionSave(); } else if (e.key === 'Escape') { - setCustomDescription(tool.description || '') - setIsEditingDescription(false) + setCustomDescription(tool.description || ''); + setIsEditingDescription(false); } - } + }; const handleCopyToolName = async (e: React.MouseEvent) => { - e.stopPropagation() - + e.stopPropagation(); + try { if (navigator.clipboard && window.isSecureContext) { - await navigator.clipboard.writeText(tool.name) - setCopiedToolName(true) - showToast(t('common.copySuccess'), 'success') - setTimeout(() => setCopiedToolName(false), 2000) + await navigator.clipboard.writeText(tool.name); + setCopiedToolName(true); + showToast(t('common.copySuccess'), 'success'); + setTimeout(() => setCopiedToolName(false), 2000); } else { // Fallback for HTTP or unsupported clipboard API - const textArea = document.createElement('textarea') - textArea.value = tool.name - textArea.style.position = 'fixed' - textArea.style.left = '-9999px' - document.body.appendChild(textArea) - textArea.focus() - textArea.select() + const textArea = document.createElement('textarea'); + textArea.value = tool.name; + textArea.style.position = 'fixed'; + textArea.style.left = '-9999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); try { - document.execCommand('copy') - setCopiedToolName(true) - showToast(t('common.copySuccess'), 'success') - setTimeout(() => setCopiedToolName(false), 2000) + document.execCommand('copy'); + setCopiedToolName(true); + showToast(t('common.copySuccess'), 'success'); + setTimeout(() => setCopiedToolName(false), 2000); } catch (err) { - showToast(t('common.copyFailed'), 'error') - console.error('Copy to clipboard failed:', err) + showToast(t('common.copyFailed'), 'error'); + console.error('Copy to clipboard failed:', err); } - document.body.removeChild(textArea) + document.body.removeChild(textArea); } } catch (error) { - showToast(t('common.copyFailed'), 'error') - console.error('Copy to clipboard failed:', error) + showToast(t('common.copyFailed'), 'error'); + console.error('Copy to clipboard failed:', error); } - } + }; const handleRunTool = async (arguments_: Record) => { - setIsRunning(true) + setIsRunning(true); try { // filter empty values - arguments_ = Object.fromEntries(Object.entries(arguments_).filter(([_, v]) => !isEmptyValue(v))) - const result = await callTool({ - toolName: tool.name, - arguments: arguments_, - }, server) + arguments_ = Object.fromEntries( + Object.entries(arguments_).filter(([_, v]) => !isEmptyValue(v)), + ); + const result = await callTool( + { + toolName: tool.name, + arguments: arguments_, + }, + server, + ); - setResult(result) + setResult(result); // Clear form data on successful submission // clearStoredFormData() } catch (error) { setResult({ success: false, error: error instanceof Error ? error.message : 'Unknown error occurred', - }) + }); } finally { - setIsRunning(false) + setIsRunning(false); } - } + }; const handleCancelRun = () => { - setShowRunForm(false) + setShowRunForm(false); // Clear form data when cancelled - clearStoredFormData() - setResult(null) - } + clearStoredFormData(); + setResult(null); + }; const handleCloseResult = () => { - setResult(null) - } + setResult(null); + }; return ( -
+
setIsExpanded(!isExpanded)} + className="flex justify-between items-center cursor-pointer p-2" + onClick={(e) => { + e.stopPropagation(); + setIsExpanded(!isExpanded); + }} >

@@ -194,11 +210,7 @@ const ToolCard = ({ tool, server, onToggle, onDescriptionUpdate }: ToolCardProps onClick={handleCopyToolName} title={t('common.copy')} > - {copiedToolName ? ( - - ) : ( - - )} + {copiedToolName ? : } {isEditingDescription ? ( @@ -213,14 +225,14 @@ const ToolCard = ({ tool, server, onToggle, onDescriptionUpdate }: ToolCardProps onClick={(e) => e.stopPropagation()} style={{ minWidth: '100px', - width: textWidth > 0 ? `${textWidth + 20}px` : 'auto' + width: textWidth > 0 ? `${textWidth + 20}px` : 'auto', }} />

-
e.stopPropagation()} - > +
e.stopPropagation()}>
)} - -
)}
- ) -} + ); +}; -export default ToolCard \ No newline at end of file +export default ToolCard; diff --git a/package.json b/package.json index ee95de4..b34aa66 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "license": "ISC", "dependencies": { "@apidevtools/swagger-parser": "^12.0.0", - "@modelcontextprotocol/sdk": "^1.20.2", + "@modelcontextprotocol/sdk": "^1.25.1", "@node-oauth/oauth2-server": "^5.2.1", "@types/adm-zip": "^0.5.7", "@types/bcrypt": "^6.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f180622..0a93dda 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,8 +19,8 @@ importers: specifier: ^12.0.0 version: 12.0.0(openapi-types@12.1.3) '@modelcontextprotocol/sdk': - specifier: ^1.20.2 - version: 1.24.0(zod@3.25.76) + specifier: ^1.25.1 + version: 1.25.1(hono@4.11.3)(zod@3.25.76) '@node-oauth/oauth2-server': specifier: ^5.2.1 version: 5.2.1 @@ -826,6 +826,12 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@hono/node-server@1.19.7': + resolution: {integrity: sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} @@ -1112,8 +1118,8 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@modelcontextprotocol/sdk@1.24.0': - resolution: {integrity: sha512-D8h5KXY2vHFW8zTuxn2vuZGN0HGrQ5No6LkHwlEA9trVgNdPL3TF1dSqKA7Dny6BbBYKSW/rOBDXdC8KJAjUCg==} + '@modelcontextprotocol/sdk@1.25.1': + resolution: {integrity: sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -2859,6 +2865,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono@4.11.3: + resolution: {integrity: sha512-PmQi306+M/ct/m5s66Hrg+adPnkD5jiO6IjA7WhWw0gSBSo1EcRegwuI1deZ+wd5pzCGynCcn2DprnE4/yEV4w==} + engines: {node: '>=16.9.0'} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3214,6 +3224,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -5097,6 +5110,10 @@ snapshots: '@eslint/js@8.57.1': {} + '@hono/node-server@1.19.7(hono@4.11.3)': + dependencies: + hono: 4.11.3 + '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 @@ -5465,8 +5482,9 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@modelcontextprotocol/sdk@1.24.0(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@3.25.76)': dependencies: + '@hono/node-server': 1.19.7(hono@4.11.3) ajv: 8.17.1 ajv-formats: 3.0.1(ajv@8.17.1) content-type: 1.0.5 @@ -5477,11 +5495,13 @@ snapshots: express: 5.2.1 express-rate-limit: 7.5.1(express@5.2.1) jose: 6.1.3 + json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 zod: 3.25.76 zod-to-json-schema: 3.25.0(zod@3.25.76) transitivePeerDependencies: + - hono - supports-color '@napi-rs/wasm-runtime@0.2.12': @@ -7273,6 +7293,8 @@ snapshots: dependencies: function-bind: 1.1.2 + hono@4.11.3: {} + html-escaper@2.0.2: {} html-parse-stringify@3.0.1: @@ -7812,6 +7834,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {}