Separate error states per tab

Resolves #40.
This commit is contained in:
Justin Spahr-Summers
2024-11-12 13:32:12 +00:00
parent ab9c130610
commit 733d2a6e6e

View File

@@ -79,7 +79,11 @@ const App = () => {
const [tools, setTools] = useState<Tool[]>([]); const [tools, setTools] = useState<Tool[]>([]);
const [toolResult, setToolResult] = const [toolResult, setToolResult] =
useState<CompatibilityCallToolResult | null>(null); useState<CompatibilityCallToolResult | null>(null);
const [error, setError] = useState<string | null>(null); const [errors, setErrors] = useState<Record<string, string | null>>({
resources: null,
prompts: null,
tools: null,
});
const [command, setCommand] = useState<string>(() => { const [command, setCommand] = useState<string>(() => {
return localStorage.getItem("lastCommand") || "mcp-server-everything"; return localStorage.getItem("lastCommand") || "mcp-server-everything";
}); });
@@ -175,17 +179,19 @@ const App = () => {
const makeRequest = async <T extends ZodType<object>>( const makeRequest = async <T extends ZodType<object>>(
request: ClientRequest, request: ClientRequest,
schema: T, schema: T,
tabKey: keyof typeof errors
) => { ) => {
if (!mcpClient) { if (!mcpClient) {
throw new Error("MCP client not connected"); throw new Error("MCP client not connected");
} }
try { try {
const response = await mcpClient.request(request, schema); const response = await mcpClient.request(request, schema);
pushHistory(request, response); pushHistory(request, response);
setErrors(prev => ({ ...prev, [tabKey]: null }));
return response; return response;
} catch (e: unknown) { } catch (e: unknown) {
setError((e as Error).message); setErrors(prev => ({ ...prev, [tabKey]: (e as Error).message }));
throw e; throw e;
} }
}; };
@@ -211,11 +217,12 @@ const App = () => {
params: nextResourceCursor ? { cursor: nextResourceCursor } : {}, params: nextResourceCursor ? { cursor: nextResourceCursor } : {},
}, },
ListResourcesResultSchema, ListResourcesResultSchema,
'resources'
); );
setResources(resources.concat(response.resources ?? [])); setResources(resources.concat(response.resources ?? []));
setNextResourceCursor(response.nextCursor); setNextResourceCursor(response.nextCursor);
}; };
const listResourceTemplates = async () => { const listResourceTemplates = async () => {
const response = await makeRequest( const response = await makeRequest(
{ {
@@ -225,13 +232,14 @@ const App = () => {
: {}, : {},
}, },
ListResourceTemplatesResultSchema, ListResourceTemplatesResultSchema,
'resources'
); );
setResourceTemplates( setResourceTemplates(
resourceTemplates.concat(response.resourceTemplates ?? []), resourceTemplates.concat(response.resourceTemplates ?? []),
); );
setNextResourceTemplateCursor(response.nextCursor); setNextResourceTemplateCursor(response.nextCursor);
}; };
const readResource = async (uri: string) => { const readResource = async (uri: string) => {
const response = await makeRequest( const response = await makeRequest(
{ {
@@ -239,6 +247,7 @@ const App = () => {
params: { uri }, params: { uri },
}, },
ReadResourceResultSchema, ReadResourceResultSchema,
'resources'
); );
setResourceContent(JSON.stringify(response, null, 2)); setResourceContent(JSON.stringify(response, null, 2));
}; };
@@ -250,11 +259,12 @@ const App = () => {
params: nextPromptCursor ? { cursor: nextPromptCursor } : {}, params: nextPromptCursor ? { cursor: nextPromptCursor } : {},
}, },
ListPromptsResultSchema, ListPromptsResultSchema,
'prompts'
); );
setPrompts(response.prompts); setPrompts(response.prompts);
setNextPromptCursor(response.nextCursor); setNextPromptCursor(response.nextCursor);
}; };
const getPrompt = async (name: string, args: Record<string, string> = {}) => { const getPrompt = async (name: string, args: Record<string, string> = {}) => {
const response = await makeRequest( const response = await makeRequest(
{ {
@@ -262,6 +272,7 @@ const App = () => {
params: { name, arguments: args }, params: { name, arguments: args },
}, },
GetPromptResultSchema, GetPromptResultSchema,
'prompts'
); );
setPromptContent(JSON.stringify(response, null, 2)); setPromptContent(JSON.stringify(response, null, 2));
}; };
@@ -273,11 +284,12 @@ const App = () => {
params: nextToolCursor ? { cursor: nextToolCursor } : {}, params: nextToolCursor ? { cursor: nextToolCursor } : {},
}, },
ListToolsResultSchema, ListToolsResultSchema,
'tools'
); );
setTools(response.tools); setTools(response.tools);
setNextToolCursor(response.nextCursor); setNextToolCursor(response.nextCursor);
}; };
const callTool = async (name: string, params: Record<string, unknown>) => { const callTool = async (name: string, params: Record<string, unknown>) => {
const response = await makeRequest( const response = await makeRequest(
{ {
@@ -291,6 +303,7 @@ const App = () => {
}, },
}, },
CompatibilityCallToolResultSchema, CompatibilityCallToolResultSchema,
'tools'
); );
setToolResult(response); setToolResult(response);
}; };
@@ -515,7 +528,7 @@ const App = () => {
resourceContent={resourceContent} resourceContent={resourceContent}
nextCursor={nextResourceCursor} nextCursor={nextResourceCursor}
nextTemplateCursor={nextResourceTemplateCursor} nextTemplateCursor={nextResourceTemplateCursor}
error={error} error={errors.resources}
/> />
<PromptsTab <PromptsTab
prompts={prompts} prompts={prompts}
@@ -525,9 +538,8 @@ const App = () => {
setSelectedPrompt={setSelectedPrompt} setSelectedPrompt={setSelectedPrompt}
promptContent={promptContent} promptContent={promptContent}
nextCursor={nextPromptCursor} nextCursor={nextPromptCursor}
error={error} error={errors.prompts}
/> />
<RequestsTab />
<ToolsTab <ToolsTab
tools={tools} tools={tools}
listTools={listTools} listTools={listTools}
@@ -539,7 +551,7 @@ const App = () => {
}} }}
toolResult={toolResult} toolResult={toolResult}
nextCursor={nextToolCursor} nextCursor={nextToolCursor}
error={error} error={errors.tools}
/> />
<ConsoleTab /> <ConsoleTab />
<PingTab <PingTab