Skip to main content
Glama

Convex MCP server

Official
by get-convex
PanelCard.tsx6.65 kB
import classNames from "classnames"; import { ExportIntegrationType } from "system-udfs/convex/_system/frontend/common"; import { ExternalLinkIcon } from "@radix-ui/react-icons"; import { Button } from "@ui/Button"; import { Modal } from "@ui/Modal"; import { IntegrationUnavailableReason, LogIntegration, ExceptionReportingIntegration, integrationToLogo, STREAMING_EXPORT_DESCRIPTION, LOG_STREAMS_DESCRIPTION, } from "@common/lib/integrationHelpers"; import { useState, ReactNode, useCallback } from "react"; import { IntegrationTitle } from "./IntegrationTitle"; import { IntegrationOverflowMenu } from "./IntegrationOverflowMenu"; import { IntegrationStatus } from "./IntegrationStatus"; import { AxiomConfigurationForm } from "./AxiomConfigurationForm"; import { DatadogConfigurationForm } from "./DatadogConfigurationForm"; import { SentryConfigurationForm } from "./SentryConfigurationForm"; import { WebhookConfigurationForm } from "./WebhookConfigurationForm"; export type PanelCardProps = { className?: string; integration: | LogIntegration | ExceptionReportingIntegration | { kind: ExportIntegrationType }; unavailableReason: IntegrationUnavailableReason | null; }; export function PanelCard({ className, integration, unavailableReason, }: PanelCardProps) { const classes = classNames( "py-3 px-4", "items-center gap-2.5 transition-colors rounded-sm text-sm font-medium", "border", className, ); const { logo } = integrationToLogo(integration.kind); const [modalState, setModalState] = useState<{ showing: boolean; content?: ReactNode; }>({ showing: false, content: undefined, }); const closeModal = useCallback(() => { setModalState({ showing: false, content: undefined, }); }, [setModalState]); () => {}; return ( <div className={classes}> {(integration.kind === "airbyte" || integration.kind === "fivetran") && ( <div className="flex flex-wrap items-center justify-between gap-2"> <IntegrationTitle logo={logo} integrationKind={integration.kind} description={STREAMING_EXPORT_DESCRIPTION} /> <div className="ml-auto"> {unavailableReason === null && ( <Button href={exportSetupLink(integration.kind)} target="_blank" className="flex items-center gap-2" inline variant="neutral" > <div>Get Started</div> <ExternalLinkIcon /> </Button> )} </div> </div> )} {(integration.kind === "sentry" || integration.kind === "axiom" || integration.kind === "datadog" || integration.kind === "webhook") && ( <div className="flex flex-wrap items-center justify-between gap-2"> {modalState.content} <IntegrationTitle logo={logo} integrationKind={integration.kind} description={LOG_STREAMS_DESCRIPTION} /> <div className="flex items-center gap-4"> <IntegrationStatus integration={integration} /> {unavailableReason === null && ( <IntegrationOverflowMenu integration={integration} onConfigure={() => setModalState({ showing: true, content: renderModal && renderModal(integration, closeModal), }) } /> )} </div> </div> )} </div> ); } function exportSetupLink(kind: ExportIntegrationType): string { switch (kind) { case "airbyte": return "https://docs.airbyte.com/integrations/sources/convex"; case "fivetran": return "https://fivetran.com/integrations/convex"; default: { kind satisfies never; return ""; } } } function renderModal( integration: LogIntegration | ExceptionReportingIntegration, closeModal: () => void, ) { switch (integration.kind) { case "datadog": { return ( <LogIntegrationModal closeModal={closeModal} title="Configure Datadog" description="Configure your Convex deployment to route logs to Datadog to persist your logs and enable custom log queries and dashboards." > <DatadogConfigurationForm existingConfig={integration.existing?.config ?? null} onClose={closeModal} /> </LogIntegrationModal> ); } case "axiom": return ( <LogIntegrationModal closeModal={closeModal} title="Configure Axiom" description="Configure your Convex deployment to route logs to Axiom to persist your logs and enable custom log queries and dashboards." > <AxiomConfigurationForm existingConfig={integration.existing?.config ?? null} onClose={closeModal} /> </LogIntegrationModal> ); case "webhook": return ( <LogIntegrationModal closeModal={closeModal} title="Configure Webhook" description="Configure your Convex deployment to send JSON logs via POST requests." > <WebhookConfigurationForm onClose={closeModal} existingIntegration={integration.existing?.config ?? null} /> </LogIntegrationModal> ); case "sentry": return ( <Modal onClose={closeModal} title="Configure Sentry"> <div className="flex flex-col gap-4"> <div className="max-w-prose text-xs text-pretty text-content-secondary"> Configure your Convex deployment to route function execution exceptions to Sentry for visibility. </div> <SentryConfigurationForm existingConfig={integration.existing?.config ?? null} onClose={closeModal} /> </div> </Modal> ); default: { integration satisfies never; return null; } } } function LogIntegrationModal({ title, description, closeModal, children, }: { title: string; description: string; closeModal: () => void; children: React.ReactNode; }) { return ( <Modal onClose={closeModal} title={title}> <div className="flex flex-col gap-4"> <div className="max-w-prose text-xs text-pretty text-content-secondary"> {description} </div> {children} </div> </Modal> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/get-convex/convex-backend'

If you have feedback or need assistance with the MCP directory API, please join our Discord server