diff --git a/cli/package.json b/cli/package.json index beb7d3b14..b3aac604b 100644 --- a/cli/package.json +++ b/cli/package.json @@ -21,7 +21,7 @@ }, "devDependencies": {}, "dependencies": { - "@modelcontextprotocol/sdk": "^1.11.5", + "@modelcontextprotocol/sdk": "^1.13.0", "commander": "^13.1.0", "spawn-rx": "^5.1.2" } diff --git a/client/package.json b/client/package.json index 3f03f0c83..76b613a19 100644 --- a/client/package.json +++ b/client/package.json @@ -23,7 +23,7 @@ "test:watch": "jest --config jest.config.cjs --watch" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.11.5", + "@modelcontextprotocol/sdk": "^1.13.0", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-icons": "^1.3.0", diff --git a/client/src/App.tsx b/client/src/App.tsx index ecd51d2ab..6eeaf29bc 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -51,6 +51,10 @@ import { loadOAuthTokens, handleOAuthDebugConnect } from "./services/oauth"; import { getMCPProxyAddress } from "./utils/configUtils"; import { handleRootsChange, MCPHelperDependencies } from "./utils/mcpHelpers"; +import ElicitationModal, { + ElicitationRequest, +} from "./components/ElicitationModal"; + // Types import { MCPJamServerConfig, @@ -136,6 +140,18 @@ const App = () => { [mcpOperations], ); + const onElicitationRequest = useCallback( + (request: ElicitationRequest, resolve: (result: any) => void) => { + mcpOperations.setPendingElicitationRequest({ + id: nextRequestId.current++, + message: request.params.message, + requestedSchema: request.params.requestedSchema, + resolve, + }); + }, + [mcpOperations], + ); + const getRootsCallback = useCallback(() => rootsRef.current, []); // Connection info @@ -196,6 +212,7 @@ const App = () => { onStdErrNotification, onPendingRequest, getRootsCallback, + onElicitationRequest, ); if (options.autoConnect) { console.log("🔌 Auto-connecting to all servers..."); @@ -236,6 +253,7 @@ const App = () => { configState, onStdErrNotification, onPendingRequest, + onElicitationRequest, getRootsCallback, addClientLog, ], @@ -518,6 +536,7 @@ const App = () => { onStdErrNotification, onPendingRequest, getRootsCallback, + onElicitationRequest ); } catch (error) { addClientLog( @@ -538,6 +557,7 @@ const App = () => { configState.claudeApiKey, onStdErrNotification, onPendingRequest, + onElicitationRequest, getRootsCallback, addClientLog, ]); @@ -1071,6 +1091,10 @@ const App = () => { onClearLogs={mcpOperations.clearClientLogs} /> + {/* GitHub Star Modal */} diff --git a/client/src/components/DynamicJsonForm.tsx b/client/src/components/DynamicJsonForm.tsx index dbbaeac0e..8c3fdfb8d 100644 --- a/client/src/components/DynamicJsonForm.tsx +++ b/client/src/components/DynamicJsonForm.tsx @@ -138,26 +138,136 @@ const DynamicJsonForm = ({ ); } + const isFieldRequired = (fieldPath: string[]): boolean => { + if (typeof schema.required === "boolean") { + return schema.required; + } + if (Array.isArray(schema.required) && fieldPath.length > 0) { + return schema.required.includes(fieldPath[fieldPath.length - 1]); + } + return false; + }; + + if (propSchema.type === "object" && propSchema.properties) { + const objectValue = (currentValue as Record) || {}; + + return ( +
+ {Object.entries(propSchema.properties).map( + ([fieldName, fieldSchema]) => { + const fieldPath = [...path, fieldName]; + const fieldValue = objectValue[fieldName]; + const fieldRequired = isFieldRequired([fieldName]); + + return ( +
+ + {fieldSchema.description && ( +

+ {fieldSchema.description} +

+ )} +
+ {renderFieldInput( + fieldSchema, + fieldValue, + fieldPath, + fieldRequired, + )} +
+
+ ); + }, + )} +
+ ); + } + + const fieldRequired = isFieldRequired(path); + return renderFieldInput(propSchema, currentValue, path, fieldRequired); + }; + + const renderFieldInput = ( + propSchema: JsonSchemaType, + currentValue: JsonValue, + path: string[], + fieldRequired: boolean, + ) => { switch (propSchema.type) { - case "string": + case "string": { + if (propSchema.enum) { + return ( + + ); + } + + let inputType = "text"; + switch (propSchema.format) { + case "email": + inputType = "email"; + break; + case "uri": + inputType = "url"; + break; + case "date": + inputType = "date"; + break; + case "date-time": + inputType = "datetime-local"; + break; + default: + inputType = "text"; + break; + } + return ( { const val = e.target.value; - // Allow clearing non-required fields by setting undefined - // This preserves the distinction between empty string and unset - if (!val && !propSchema.required) { + if (!val && !fieldRequired) { handleFieldChange(path, undefined); } else { handleFieldChange(path, val); } }} placeholder={propSchema.description} - required={propSchema.required} + required={fieldRequired} + minLength={propSchema.minLength} + maxLength={propSchema.maxLength} + pattern={propSchema.pattern} /> ); + } + case "number": return ( { const val = e.target.value; - // Allow clearing non-required number fields - // This preserves the distinction between 0 and unset - if (!val && !propSchema.required) { + if (!val && !fieldRequired) { handleFieldChange(path, undefined); } else { const num = Number(val); @@ -177,9 +285,12 @@ const DynamicJsonForm = ({ } }} placeholder={propSchema.description} - required={propSchema.required} + required={fieldRequired} + min={propSchema.minimum} + max={propSchema.maximum} /> ); + case "integer": return ( { const val = e.target.value; - // Allow clearing non-required integer fields - // This preserves the distinction between 0 and unset - if (!val && !propSchema.required) { + if (!val && !fieldRequired) { handleFieldChange(path, undefined); } else { const num = Number(val); - // Only update if it's a valid integer if (!isNaN(num) && Number.isInteger(num)) { handleFieldChange(path, num); } } }} placeholder={propSchema.description} - required={propSchema.required} + required={fieldRequired} + min={propSchema.minimum} + max={propSchema.maximum} /> ); + case "boolean": return ( - handleFieldChange(path, e.target.checked)} - className="w-4 h-4" - required={propSchema.required} - /> +
+ handleFieldChange(path, e.target.checked)} + className="w-4 h-4" + required={fieldRequired} + /> + + {propSchema.description || "Enable this option"} + +
); + default: return null; } @@ -303,4 +420,4 @@ const DynamicJsonForm = ({ ); }; -export default DynamicJsonForm; +export default DynamicJsonForm; \ No newline at end of file diff --git a/client/src/components/ElicitationModal.tsx b/client/src/components/ElicitationModal.tsx new file mode 100644 index 000000000..458a752e7 --- /dev/null +++ b/client/src/components/ElicitationModal.tsx @@ -0,0 +1,181 @@ +import { useState, useEffect } from "react"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import DynamicJsonForm from "./DynamicJsonForm"; +import { JsonSchemaType, JsonValue } from "@/utils/jsonUtils"; +import { generateDefaultValue } from "@/utils/schemaUtils"; +import Ajv from "ajv"; + +export interface ElicitationRequest { + id: number; + message: string; + requestedSchema: JsonSchemaType; + resolve: (response: ElicitationResponse) => void; +} + +export interface ElicitationResponse { + action: "accept" | "reject" | "cancel"; + content?: Record; +} + +interface ElicitationModalProps { + request: ElicitationRequest | null; + onClose: () => void; +} + +const ElicitationModal = ({ request, onClose }: ElicitationModalProps) => { + const [formData, setFormData] = useState({}); + const [validationError, setValidationError] = useState(null); + + useEffect(() => { + if (request) { + const defaultValue = generateDefaultValue(request.requestedSchema); + setFormData(defaultValue); + setValidationError(null); + } + }, [request]); + + if (!request) return null; + + const validateEmailFormat = (email: string): boolean => { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + }; + + const validateFormData = ( + data: JsonValue, + schema: JsonSchemaType, + ): boolean => { + if ( + schema.type === "object" && + schema.properties && + typeof data === "object" && + data !== null + ) { + const dataObj = data as Record; + + if (Array.isArray(schema.required)) { + for (const field of schema.required) { + const value = dataObj[field]; + if (value === undefined || value === null || value === "") { + setValidationError(`Required field missing: ${field}`); + return false; + } + } + } + + for (const [fieldName, fieldValue] of Object.entries(dataObj)) { + const fieldSchema = schema.properties[fieldName]; + if ( + fieldSchema && + fieldSchema.format === "email" && + typeof fieldValue === "string" + ) { + if (!validateEmailFormat(fieldValue)) { + setValidationError(`Invalid email format: ${fieldName}`); + return false; + } + } + } + } + + return true; + }; + + const handleAccept = () => { + try { + if (!validateFormData(formData, request.requestedSchema)) { + return; + } + + const ajv = new Ajv(); + const validate = ajv.compile(request.requestedSchema); + const isValid = validate(formData); + + if (!isValid) { + const errorMessage = ajv.errorsText(validate.errors); + setValidationError(errorMessage); + return; + } + + request.resolve({ + action: "accept", + content: formData as Record, + }); + onClose(); + } catch (error) { + setValidationError( + error instanceof Error ? error.message : "Validation failed", + ); + } + }; + + const handleReject = () => { + request.resolve({ action: "reject" }); + onClose(); + }; + + const handleCancel = () => { + request.resolve({ action: "cancel" }); + onClose(); + }; + + const schemaTitle = request.requestedSchema.title || "Information Request"; + const schemaDescription = request.requestedSchema.description; + + return ( + + + + {schemaTitle} + + {request.message} + {schemaDescription && ( + + {schemaDescription} + + )} + + + +
+ { + setFormData(newValue); + setValidationError(null); + }} + /> + + {validationError && ( +
+
+ Validation Error: {validationError} +
+
+ )} +
+ + + + + + +
+
+ ); +}; + +export default ElicitationModal; \ No newline at end of file diff --git a/client/src/hooks/useConnectionState.ts b/client/src/hooks/useConnectionState.ts index 11bb927d9..37c8b2ffb 100644 --- a/client/src/hooks/useConnectionState.ts +++ b/client/src/hooks/useConnectionState.ts @@ -6,6 +6,7 @@ import { CreateMessageRequest, CreateMessageResult, Root, + ElicitRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { StdErrNotification } from "@/lib/notificationTypes"; import { ConnectionStatus } from "@/lib/constants"; @@ -35,6 +36,7 @@ export const useConnectionState = ( reject: (error: Error) => void, ) => void, getRoots: () => Root[], + onElicitationRequest?: (request: any, resolve: any) => void, ) => { if (Object.keys(serverConfigs).length === 0) { console.log("No servers configured, skipping connection"); @@ -49,6 +51,7 @@ export const useConnectionState = ( claudeApiKey, onStdErrNotification, onPendingRequest, + onElicitationRequest, getRoots, addRequestHistory: addRequestHistory, addClientLog: addClientLog, @@ -83,6 +86,7 @@ export const useConnectionState = ( reject: (error: Error) => void, ) => void, getRoots: () => Root[], + onElicitationRequest?: (request: any, resolve: any) => void, ) => { const options: MCPClientOptions = { servers: serverConfigs, @@ -92,6 +96,7 @@ export const useConnectionState = ( claudeApiKey, onStdErrNotification, onPendingRequest, + onElicitationRequest, getRoots, addRequestHistory: addRequestHistory, addClientLog: addClientLog, @@ -119,6 +124,7 @@ export const useConnectionState = ( reject: (error: Error) => void, ) => void, getRoots: () => Root[], + onElicitationRequest?: (request: any, resolve: any) => void, ) => { console.log("🔧 addServer called with:", { name, serverConfig }); @@ -132,6 +138,7 @@ export const useConnectionState = ( claudeApiKey, onStdErrNotification, onPendingRequest, + onElicitationRequest, getRoots, addRequestHistory: addRequestHistory, addClientLog: addClientLog, diff --git a/client/src/hooks/useMCPOperations.ts b/client/src/hooks/useMCPOperations.ts index b70c0a05e..9a156c1bc 100644 --- a/client/src/hooks/useMCPOperations.ts +++ b/client/src/hooks/useMCPOperations.ts @@ -21,6 +21,7 @@ import { ClientLogLevels, RequestHistoryInfo, } from "@/hooks/helpers/types"; +import { ElicitationRequest } from "@/components/ElicitationModal"; export interface PendingRequest { id: number; @@ -78,6 +79,8 @@ export const useMCPOperations = () => { const [pendingSampleRequests, setPendingSampleRequests] = useState< PendingRequest[] >([]); + const [pendingElicitationRequest, setPendingElicitationRequest] = + useState(null); const [requestHistory, setRequestHistory] = useState( [], ); @@ -183,6 +186,10 @@ export const useMCPOperations = () => { [addRequestHistory], ); + const handleCloseElicitationModal = () => { + setPendingElicitationRequest(null); + }; + const listResourceTemplates = useCallback( async (mcpAgent: MCPJamAgent | null, selectedServerName: string) => { if (!mcpAgent) return; @@ -722,6 +729,8 @@ export const useMCPOperations = () => { setRoots, pendingSampleRequests, setPendingSampleRequests, + pendingElicitationRequest, + setPendingElicitationRequest, progressTokenRef, // Operations @@ -745,5 +754,6 @@ export const useMCPOperations = () => { addClientLog, clearClientLogs, getClientLogs, + handleCloseElicitationModal, }; }; diff --git a/client/src/mcpjamAgent.ts b/client/src/mcpjamAgent.ts index bcf8fa381..ee00611cd 100644 --- a/client/src/mcpjamAgent.ts +++ b/client/src/mcpjamAgent.ts @@ -30,6 +30,7 @@ export interface MCPClientOptions { resolve: (result: CreateMessageResult) => void, reject: (error: Error) => void, ) => void; + onElicitationRequest?: (request: any, resolve: any) => void; getRoots?: () => unknown[]; addRequestHistory: (request: object, response?: object) => void; addClientLog: (message: string, level: ClientLogLevels) => void; @@ -56,6 +57,7 @@ export class MCPJamAgent { resolve: (result: CreateMessageResult) => void, reject: (error: Error) => void, ) => void; + private onElicitationRequest?: (request: any, resolve: any) => void; private getRoots?: () => unknown[]; private addRequestHistory: (request: object, response?: object) => void; private addClientLog: (message: string, level: ClientLogLevels) => void; @@ -69,6 +71,7 @@ export class MCPJamAgent { this.claudeApiKey = options.claudeApiKey; this.onStdErrNotification = options.onStdErrNotification; this.onPendingRequest = options.onPendingRequest; + this.onElicitationRequest = options.onElicitationRequest; this.getRoots = options.getRoots; this.addRequestHistory = options.addRequestHistory; this.addClientLog = options.addClientLog; @@ -197,6 +200,7 @@ export class MCPJamAgent { this.onStdErrNotification, // onStdErrNotification this.claudeApiKey, // claudeApiKey this.onPendingRequest, // onPendingRequest + this.onElicitationRequest, // onElicitationRequest this.getRoots, // getRoots ); diff --git a/client/src/mcpjamClient.ts b/client/src/mcpjamClient.ts index a5ca6eab9..78e22b8e6 100644 --- a/client/src/mcpjamClient.ts +++ b/client/src/mcpjamClient.ts @@ -15,6 +15,7 @@ import { CreateMessageResult, ListRootsRequestSchema, CreateMessageRequest, + ElicitRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { Anthropic } from "@anthropic-ai/sdk"; import { @@ -89,6 +90,7 @@ export class MCPJamClient extends Client { resolve: (result: CreateMessageResult) => void, reject: (error: Error) => void, ) => void; + onElicitationRequest?: (request: any, resolve: any) => void; getRoots?: () => unknown[]; addRequestHistory: (request: object, response?: object) => void; addClientLog: (message: string, level: ClientLogLevels) => void; @@ -106,6 +108,7 @@ export class MCPJamClient extends Client { resolve: (result: CreateMessageResult) => void, reject: (error: Error) => void, ) => void, + onElicitationRequest?: (request: any, resolve: any) => void, getRoots?: () => unknown[], ) { super( @@ -113,6 +116,7 @@ export class MCPJamClient extends Client { { capabilities: { sampling: {}, + elicitation: {}, roots: { listChanged: true, }, @@ -136,6 +140,7 @@ export class MCPJamClient extends Client { this.inspectorConfig = inspectorConfig; this.onStdErrNotification = onStdErrNotification; this.onPendingRequest = onPendingRequest; + this.onElicitationRequest = onElicitationRequest; this.getRoots = getRoots; this.addRequestHistory = addRequestHistory; this.addClientLog = addClientLog; @@ -510,6 +515,14 @@ export class MCPJamClient extends Client { }); } + if (this.onElicitationRequest) { + this.setRequestHandler(ElicitRequestSchema, (request) => { + return new Promise((resolve) => { + this.onElicitationRequest?.(request, resolve); + }); + }); + } + if (this.getRoots) { this.setRequestHandler(ListRootsRequestSchema, async () => { return { roots: this.getRoots?.() ?? [] }; diff --git a/client/src/utils/jsonUtils.ts b/client/src/utils/jsonUtils.ts index 28cbf3030..6848ff9e6 100644 --- a/client/src/utils/jsonUtils.ts +++ b/client/src/utils/jsonUtils.ts @@ -7,21 +7,30 @@ export type JsonValue = | JsonValue[] | { [key: string]: JsonValue }; -export type JsonSchemaType = { - type: - | "string" - | "number" - | "integer" - | "boolean" - | "array" - | "object" - | "null"; - description?: string; - required?: boolean; - default?: JsonValue; - properties?: Record; - items?: JsonSchemaType; -}; + export type JsonSchemaType = { + type: + | "string" + | "number" + | "integer" + | "boolean" + | "array" + | "object" + | "null"; + title?: string; + description?: string; + required?: boolean | string[]; + default?: JsonValue; + properties?: Record; + items?: JsonSchemaType; + minimum?: number; + maximum?: number; + minLength?: number; + maxLength?: number; + pattern?: string; + format?: string; + enum?: string[]; + enumNames?: string[]; + }; export type JsonObject = { [key: string]: JsonValue }; diff --git a/client/src/utils/mcpHelpers.ts b/client/src/utils/mcpHelpers.ts index 7a15467fa..f7fb290b1 100644 --- a/client/src/utils/mcpHelpers.ts +++ b/client/src/utils/mcpHelpers.ts @@ -19,6 +19,7 @@ import { z } from "zod"; import { Prompt } from "../components/PromptsTab"; import { PendingRequest } from "../components/SamplingTab"; import { StdErrNotification } from "../lib/notificationTypes"; +import { ElicitationRequest } from "@/components/ElicitationModal"; // Types for function dependencies export interface MCPHelperDependencies { @@ -64,6 +65,9 @@ export interface MCPHelperDependencies { > > >; + setPendingElicitationRequest: React.Dispatch< + React.SetStateAction + >; progressTokenRef: React.MutableRefObject; } @@ -408,4 +412,4 @@ export const clearStdErrNotifications = ( >, ) => { setStdErrNotifications([]); -}; +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1d67159ac..94ebc4ab0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mcpjam/inspector", - "version": "0.2.4", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mcpjam/inspector", - "version": "0.2.4", + "version": "0.3.1", "license": "Apache-2.0", "workspaces": [ "client", @@ -18,7 +18,8 @@ "@mcpjam/inspector-cli": "^0.1.6", "@mcpjam/inspector-client": "^0.1.6", "@mcpjam/inspector-server": "^0.1.6", - "@modelcontextprotocol/sdk": "^1.12.0", + "@modelcontextprotocol/sdk": "^1.13.0", + "ajv": "^8.17.1", "concurrently": "^9.0.1", "dotenv": "^16.5.0", "open": "^10.1.0", @@ -42,10 +43,10 @@ }, "cli": { "name": "@mcpjam/inspector-cli", - "version": "0.2.4", + "version": "0.3.1", "license": "Apache-2.0", "dependencies": { - "@modelcontextprotocol/sdk": "^1.11.5", + "@modelcontextprotocol/sdk": "^1.13.0", "commander": "^13.1.0", "spawn-rx": "^5.1.2" }, @@ -63,10 +64,10 @@ }, "client": { "name": "@mcpjam/inspector-client", - "version": "0.2.4", + "version": "0.3.1", "license": "Apache-2.0", "dependencies": { - "@modelcontextprotocol/sdk": "^1.11.5", + "@modelcontextprotocol/sdk": "^1.13.0", "@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-icons": "^1.3.0", @@ -1309,6 +1310,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -1322,6 +1340,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2144,6 +2169,28 @@ "node": ">=18" } }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4182,15 +4229,15 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -5706,6 +5753,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -5719,6 +5783,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6001,6 +6072,22 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastq": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", @@ -7767,9 +7854,9 @@ "license": "MIT" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -9086,6 +9173,15 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -11139,10 +11235,10 @@ }, "server": { "name": "@mcpjam/inspector-server", - "version": "0.2.4", + "version": "0.3.1", "license": "Apache-2.0", "dependencies": { - "@modelcontextprotocol/sdk": "^1.11.5", + "@modelcontextprotocol/sdk": "^1.13.0", "cors": "^2.8.5", "express": "^5.1.0", "ws": "^8.18.0", diff --git a/package.json b/package.json index 332fe7cab..903678abb 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,8 @@ "@mcpjam/inspector-cli": "^0.1.6", "@mcpjam/inspector-client": "^0.1.6", "@mcpjam/inspector-server": "^0.1.6", - "@modelcontextprotocol/sdk": "^1.12.0", + "@modelcontextprotocol/sdk": "^1.13.0", + "ajv": "^8.17.1", "concurrently": "^9.0.1", "dotenv": "^16.5.0", "open": "^10.1.0", diff --git a/server/package.json b/server/package.json index 45e3af72f..3bf44cb78 100644 --- a/server/package.json +++ b/server/package.json @@ -27,7 +27,7 @@ "typescript": "^5.6.2" }, "dependencies": { - "@modelcontextprotocol/sdk": "^1.11.5", + "@modelcontextprotocol/sdk": "^1.13.0", "cors": "^2.8.5", "express": "^5.1.0", "ws": "^8.18.0",