Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/insomnia/src/main/mcp/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
...(workspaceCaCert?.path && !workspaceCaCert?.disabled
? { ca: await insecureReadFile(workspaceCaCert.path) }
: {}),
...(mcpRequest.sslValidation === false ? { rejectUnauthorized: false } : {}),
},
});
};
3 changes: 3 additions & 0 deletions packages/insomnia/src/models/mcp-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export interface BaseMcpRequest {
roots: Root[];
subscribeResources: string[];
connected: boolean;
// See: https://nodejs.org/api/tls.html#tlsconnectoptions-callback
sslValidation: boolean;
}
export type McpServerPrimitiveTypes = 'tools' | 'resources' | 'prompts' | 'resourceTemplates';

Expand All @@ -55,6 +57,7 @@ export function init(): BaseMcpRequest {
roots: [],
subscribeResources: [],
connected: false,
sslValidation: true,
};
}

Expand Down
24 changes: 22 additions & 2 deletions packages/insomnia/src/ui/components/mcp/mcp-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const McpPane = () => {
const [requestPaneActiveTab, setRequestPaneActiveTab] = useState<RequestPaneTabs>('params');
const patchRequest = useRequestPatcher();
const requestId = activeRequest._id;
const { activeEnvironment } = useWorkspaceLoaderData()!;
const { activeEnvironment, caCertificate } = useWorkspaceLoaderData()!;
const readyState = useMcpReadyState({ requestId });
const parentRef = useRef<HTMLDivElement>(null);
const [direction, setDirection] = useState<'horizontal' | 'vertical'>(
Expand Down Expand Up @@ -365,6 +365,13 @@ export const McpPane = () => {
}
}, [activeResponse?._id, readyState]);

const caStatus =
activeRequest.sslValidation === false
? 'warning'
: caCertificate?.path && !caCertificate.disabled
? 'success'
: 'default';

return (
<PanelGroup
ref={sidebarPanelRef}
Expand Down Expand Up @@ -408,7 +415,20 @@ export const McpPane = () => {
className="flex max-w-full flex-1 items-center justify-center gap-2 truncate rounded-sm px-4 py-1 text-sm text-[--color-font] ring-1 ring-transparent transition-all hover:bg-[--hl-xs] focus:ring-inset focus:ring-[--hl-md] aria-pressed:bg-[--hl-sm]"
>
<Icon icon="file-contract" className="w-5 flex-shrink-0" />
<span className="truncate">Manage Certificates</span>
<span className="inline-flex items-center gap-2 truncate">
Manage Certificates
{caStatus !== 'default' && (
<Icon
icon="circle"
className={`${
{
success: 'text-[--color-success]',
warning: 'text-[--color-warning]',
}[caStatus]
} h-2 w-2`}
/>
)}
</span>
</Button>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import React from 'react';
import { Button, Dialog, Heading, Modal, ModalOverlay } from 'react-aria-components';
import { Button, Dialog, Heading, Modal, ModalOverlay, ToggleButton } from 'react-aria-components';
import { useParams } from 'react-router';

import {
type McpRequestLoaderData,
useRequestLoaderData,
} from '~/routes/organization.$organizationId.project.$projectId.workspace.$workspaceId.debug.request.$requestId';
import { CACertificate } from '~/ui/components/modals/workspace-certificates-modal';
import { useRequestPatcher } from '~/ui/hooks/use-request';

import { useWorkspaceLoaderData } from '../../../routes/organization.$organizationId.project.$projectId.workspace.$workspaceId';
import { Icon } from '../icon';
Expand All @@ -12,11 +17,12 @@ export const MCPCertificatesModal = ({ onClose }: { onClose: () => void }) => {
workspaceId: string;
};

const { activeRequest } = useRequestLoaderData()! as McpRequestLoaderData;
const routeData = useWorkspaceLoaderData()!;

const patchRequest = useRequestPatcher();
const { caCertificate } = routeData;

if (!workspaceId) {
if (!workspaceId || !activeRequest) {
return null;
}

Expand Down Expand Up @@ -46,6 +52,39 @@ export const MCPCertificatesModal = ({ onClose }: { onClose: () => void }) => {
</div>
<div className="flex w-full flex-1 basis-96 select-none flex-col gap-6 overflow-hidden overflow-y-auto rounded">
<CACertificate caCertificate={caCertificate} />

<div className="flex flex-col gap-4">
<Heading className="text-xl">Extra Options</Heading>
<div className="flex items-center justify-between gap-2">
<span>SSL Certificate Validation</span>
<ToggleButton
data-test-id="mcp-reject-unauthorized-toggle"
onChange={isSelected => {
patchRequest(activeRequest._id, {
sslValidation: isSelected,
});
}}
isSelected={activeRequest.sslValidation}
className="flex h-full w-[12ch] flex-shrink-0 items-center justify-start gap-2 rounded-sm px-2 text-sm text-[--color-font] ring-1 ring-transparent transition-all hover:bg-[--hl-xs] focus:ring-inset focus:ring-[--hl-md]"
>
{({ isSelected }) => (
<>
<Icon
icon={isSelected ? 'toggle-on' : 'toggle-off'}
className={`${isSelected ? 'text-[--color-success]' : ''}`}
/>
<span>{isSelected ? 'Enabled' : 'Disabled'}</span>
</>
)}
</ToggleButton>
</div>

<p className="max-w-[80ch] text-sm text-[--hl]">
When disabled, SSL/TLS certificates will not be validated. Disabling this allows connecting to
servers with self-signed, expired, or invalid certificates. It is recommended that you only disable
this when using trusted local development environments.
</p>
</div>
</div>
<div className="flex items-center justify-end gap-2">
<Button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,10 @@ export const CACertificate = ({ caCertificate, tip }: { caCertificate?: CaCertif
return (
<>
<Heading className="text-xl">CA Certificate</Heading>
<p className="max-w-[80ch] text-sm text-[--hl]">
{tip ||
'One or more PEM format certificates in a single file to pass to curl. Overrides the root CA certificate. On MacOS please upload your local Keychain certificates here.'}
</p>
<div className="flex flex-col gap-2">
{caCertificate ? (
<div className="flex items-center justify-between gap-2 rounded-sm border border-solid border-[--hl-sm] p-4">
Expand Down Expand Up @@ -399,11 +403,6 @@ export const CACertificate = ({ caCertificate, tip }: { caCertificate?: CaCertif
</FileTrigger>
</div>
)}
<p className="max-w-[80ch] text-sm italic text-[--hl]">
<Icon icon="info-circle" className="pr-2" />
{tip ||
'One or more PEM format certificates in a single file to pass to curl. Overrides the root CA certificate. On MacOS please upload your local Keychain certificates here.'}
</p>
</div>
</>
);
Expand Down
Loading