Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
15 changes: 14 additions & 1 deletion apps/docs/content/docs/en/agents/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ Authorization: Bearer {{MCP_API_TOKEN}}

When you type `{{` in the URL or header fields, a dropdown appears showing available workspace environment variables.

### Starter Configurations

The add modal includes starter templates for common MCP servers.

For [Unstructured Transform](https://docs.unstructured.io/transform/quickstart), first add a workspace environment variable named `UNSTRUCTURED_API_KEY`, then choose the Unstructured Transform template. Unstructured Transform converts documents (PDF, DOCX, PPTX, HTML, and images, including scanned or image-only pages via OCR) into clean markdown, JSON, HTML, or text. It also supports RAG preprocessing with chunking, enrichment, and embedding. The template pre-fills:

```
URL: https://mcp.transform.unstructured.io
Authorization: Bearer {{UNSTRUCTURED_API_KEY}}
```

If your self-hosted deployment sets `ALLOWED_MCP_DOMAINS`, include `mcp.transform.unstructured.io` before saving the server.

### Testing and Validation

Click **Test Connection** before saving to verify the server is reachable and discover available tools. The test response shows the number of tools found and the protocol version.
Expand Down Expand Up @@ -169,4 +182,4 @@ import { FAQ } from '@/components/ui/faq'
{ question: "How do I update MCP tool schemas after a server changes its available tools?", answer: "Click the Refresh button on the MCP server in your workspace settings. This fetches the latest tool schemas from the server and automatically updates any agent blocks that use those tools with the new parameter definitions." },
{ question: "Can permission groups restrict access to MCP tools?", answer: "Yes. On Enterprise-entitled workspaces, any workspace admin can create a permission group that disables MCP tools for its members using the disableMcpTools option. When this is enabled, affected users will not be able to add or use MCP tools in workflows that belong to that workspace." },
{ question: "What happens if an MCP server goes offline during workflow execution?", answer: "If the MCP server is unreachable during execution, the tool call will fail and return an error. In an Agent block, the AI may attempt to handle the failure gracefully. In a standalone MCP Tool block, the workflow step will fail. Check MCP server logs and verify the server is running and accessible to troubleshoot connectivity issues." },
]} />
]} />
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@ import {
} from '@sim/emcn'
import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { ChevronDown, ChevronRight } from 'lucide-react'
import { ChevronDown, ChevronRight, Plus } from 'lucide-react'
import type { McpAuthType, McpTransport } from '@/lib/mcp/types'
import {
checkEnvVarTrigger,
EnvVarDropdown,
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/env-var-dropdown'
import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
import { useMcpServerTest } from '@/hooks/queries/mcp'
import {
buildHeadersFromTemplate,
MCP_SERVER_TEMPLATES,
type McpServerTemplate,
} from './mcp-server-templates'

const logger = createLogger('McpServerFormModal')

Expand Down Expand Up @@ -300,6 +305,41 @@ function updateHeadersArray(
return updated.filter((h, i) => i === lastIndex || h.key !== '' || h.value !== '')
}

interface TemplatePickerProps {
onSelect: (template: McpServerTemplate) => void
}

function TemplatePicker({ onSelect }: TemplatePickerProps) {
if (MCP_SERVER_TEMPLATES.length === 0) return null

return (
<ChipModalField type='custom' title='Starter templates'>
<div className='flex flex-col gap-2'>
{MCP_SERVER_TEMPLATES.map((template) => (
<button
key={template.id}
type='button'
onClick={() => onSelect(template)}
className='group flex w-full items-center justify-between gap-3 rounded-md border border-[var(--border-1)] bg-[var(--surface-3)] px-2.5 py-2 text-left transition-colors hover-hover:bg-[var(--surface-4)]'
>
<span className='flex min-w-0 flex-col gap-0.5'>
<span className='truncate font-medium text-[var(--text-primary)] text-sm'>
{template.name}
</span>
<span className='line-clamp-2 text-[var(--text-muted)] text-xs leading-relaxed'>
{template.description}
</span>
</span>
<span className='flex size-6 flex-shrink-0 items-center justify-center rounded-md border border-[var(--border-1)] text-[var(--text-muted)] transition-colors group-hover:text-[var(--text-primary)]'>
<Plus className='size-[14px]' />
</span>
</button>
))}
</div>
</ChipModalField>
)
}

export function McpServerFormModal({
open,
onOpenChange,
Expand Down Expand Up @@ -415,6 +455,23 @@ export function McpServerFormModal({
resetEnvVarState()
}

const handleTemplateSelect = (template: McpServerTemplate) => {
if (testResult) clearTestResult()
if (submitError) setSubmitError(null)
resetEnvVarState()
setFormMode('form')
setFormData((prev) => ({
...prev,
name: template.name,
transport: template.transport,
url: template.url,
timeout: template.timeout,
headers: buildHeadersFromTemplate(template),
}))
setUrlScrollLeft(0)
setHeaderScrollLeft({})
}

const handleHeaderScroll = (key: string, sl: number) => {
setHeaderScrollLeft((prev) => ({ ...prev, [key]: sl }))
}
Expand Down Expand Up @@ -668,6 +725,7 @@ export function McpServerFormModal({
/>
) : (
<>
{mode === 'add' && <TemplatePicker onSelect={handleTemplateSelect} />}
<input
type='text'
name='fakeusernameremembered'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { McpTransport } from '@/lib/mcp/types'

export interface McpServerTemplate {
id: string
name: string
description: string
transport: McpTransport
url: string
headers: readonly {
key: string
value: string
}[]
timeout: number
}

export const MCP_SERVER_TEMPLATES = [
{
id: 'unstructured-transform',
name: 'Unstructured Transform',
description:
'Convert PDFs, DOCX, PPTX, HTML, and images into clean markdown, JSON, HTML, or text with OCR and RAG preprocessing.',
transport: 'streamable-http',
url: 'https://mcp.transform.unstructured.io',
headers: [{ key: 'Authorization', value: 'Bearer {{UNSTRUCTURED_API_KEY}}' }],
timeout: 30000,
},
] as const satisfies readonly McpServerTemplate[]

export function buildHeadersFromTemplate(template: McpServerTemplate) {
return [...template.headers.map((header) => ({ ...header })), { key: '', value: '' }]
}