Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b5d17aa
fix(a11y): name icon-only buttons across product UI (#7975)
BillLeoutsakosvl346 Sep 18, 2026
59a5edf
refactor(emcn): share filled stop icon across chat controls (#7977)
BillLeoutsakosvl346 Sep 18, 2026
ba95235
fix(connectors): save service account changes with source settings (#…
waleedlatif1 Sep 18, 2026
81cd643
refactor(ui): remove styles already supplied by EMCN controls (#7979)
BillLeoutsakosvl346 Sep 18, 2026
4ad9387
fix(traces): make trace backfills bounded and resumable (#7974)
TheodoreSpeaks Sep 18, 2026
ed437fc
fix(settings): stabilize group search and modal dropdowns (#7980)
waleedlatif1 Sep 18, 2026
7a8f39a
fix(connectors): explain disabled settings with tooltips (#7981)
waleedlatif1 Sep 18, 2026
44869df
refactor(ui): centralize bulk-action buttons in EMCN (#7982)
BillLeoutsakosvl346 Sep 18, 2026
80adb13
refactor(emcn): centralize composer action button appearance (#7983)
BillLeoutsakosvl346 Sep 18, 2026
f070a34
refactor(emcn): centralize document file-type icons (#7984)
BillLeoutsakosvl346 Sep 18, 2026
c822ec2
feat(access-requests): remove rollout flag and move feature into ee (…
waleedlatif1 Sep 18, 2026
4b28dff
feat(mcp): Sim MCP server for the full Sim API (#7985)
waleedlatif1 Sep 18, 2026
0b7c6ae
refactor(emcn): centralize product icon-button padding (#7987)
BillLeoutsakosvl346 Sep 18, 2026
2d87824
feat(workflows): add model fallbacks to Agent, Evaluator, and Router …
mzxchandra Sep 18, 2026
3f245d7
improvement(knowledge): cache admitted usage checks on the search pat…
waleedlatif1 Sep 18, 2026
f359031
fix(knowledge): preserve live document jobs during recovery (#7994)
waleedlatif1 Sep 19, 2026
99d6a9f
fix(knowledge): preserve live document processing during recovery (#7…
waleedlatif1 Sep 19, 2026
1f16b03
fix(file-search): avoid foreground GIN cleanup stalls (#7995)
icecrasher321 Sep 19, 2026
305da02
improvement(knowledge): rank inside the permitted set for organizatio…
waleedlatif1 Sep 19, 2026
b01617e
feat(library): Best AI Agent Builders with MCP Support (#7999)
icecrasher321 Sep 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 4 additions & 5 deletions apps/desktop/src/main/terminal/selection.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { sleep } from '@sim/utils/helpers'
import { Terminal } from '@xterm/headless'
import { describe, expect, it } from 'vitest'
import { findSelectedRow } from '@/main/terminal/session'
Expand All @@ -7,14 +6,14 @@ const REVERSE = '\u001b[7m'
const RESET = '\u001b[0m'

/**
* Writes to a real headless emulator and lets it settle, so these exercise the
* same buffer the agent reads rather than a hand-built fake. xterm parses
* asynchronously, hence the flush.
* Writes to a real headless emulator and waits for the queued writes to finish,
* so these exercise the same buffer the agent reads. The trailing empty write's
* callback fires after xterm has parsed every preceding chunk.
*/
async function screen(write: (term: Terminal) => void, rows = 8): Promise<Terminal> {
const term = new Terminal({ cols: 40, rows, allowProposedApi: true })
write(term)
await sleep(30)
await new Promise<void>((resolve) => term.write('', resolve))
return term
}

Expand Down
7 changes: 5 additions & 2 deletions apps/docs/app/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,10 @@ export default async function Page(props: { params: Promise<{ slug?: string[] }>
// width so the lesson hero/video gets the room (chapters live in-page instead).
const isAcademy = slug?.[0] === 'academy'
const isCli = slug?.[0] === 'cli'
const isMcp = slug?.[0] === 'mcp'

const rawNeighbours = findNeighbour(source.pageTree, page.url)
// Academy, API Reference, and CLI are self-contained sections; keep prev/next
// Academy, API Reference, CLI, and MCP are self-contained sections; keep prev/next
// inside the section instead of spilling into the main documentation tree.
// Match both the section's pages (`/<slug>/...`) and its index (`/<slug>`).
const sectionSlug = isApiReference
Expand All @@ -136,7 +137,9 @@ export default async function Page(props: { params: Promise<{ slug?: string[] }>
? 'academy'
: isCli
? 'cli'
: null
: isMcp
? 'mcp'
: null
const inSection = (url?: string) =>
url != null && (url.includes(`/${sectionSlug}/`) || url.endsWith(`/${sectionSlug}`))
const neighbours = sectionSlug
Expand Down
1 change: 1 addition & 0 deletions apps/docs/components/docs-layout/docs-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export function DocsSidebar() {
['Docs', '/introduction'],
['API Reference', '/api-reference/getting-started'],
['CLI', '/cli'],
['MCP', '/mcp'],
['Academy', '/academy'],
].map(([label, href]) => (
<ChipLink key={href} href={href} onNavigate={() => setOpen(false)}>
Expand Down
23 changes: 12 additions & 11 deletions apps/docs/components/navbar/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,20 @@ import { ThemeToggle } from '@/components/ui/theme-toggle'
import { cn } from '@/lib/utils'

/**
* Sections that own a tab, in reading order: the main docs, then the two
* Sections that own a tab, in reading order: the main docs, then the three
* reference surfaces, then Academy. `Documentation` matches by exclusion, so
* every section listed here is one it must not claim.
*/
const SECTION_TABS = ['api-reference', 'academy', 'cli'] as const
const SECTION_TABS = ['api-reference', 'academy', 'cli', 'mcp'] as const

/**
* Whether a pathname is inside a section, matched by whole path segment.
* Whether a pathname is inside a section, matched on its first path segment.
*
* A substring test is wrong: `/integrations/clickup` and
* `/integrations/clickhouse` both contain `/cli`, which lit the CLI tab and
* unlit Documentation on two existing integration pages.
* A substring or suffix test is wrong: `/integrations/clickup` contains `/cli`,
* and `/agents/mcp` ends with `/mcp`, and both belong to Documentation.
*/
function isInSection(pathname: string, section: string): boolean {
return (
pathname === `/${section}` ||
pathname.endsWith(`/${section}`) ||
pathname.includes(`/${section}/`)
)
return pathname === `/${section}` || pathname.startsWith(`/${section}/`)
}

const NAV_TABS = [
Expand All @@ -49,6 +44,12 @@ const NAV_TABS = [
match: (p: string) => isInSection(p, 'cli'),
external: false,
},
{
label: 'MCP',
href: '/mcp',
match: (p: string) => isInSection(p, 'mcp'),
external: false,
},
{
label: 'Academy',
href: '/academy',
Expand Down
70 changes: 70 additions & 0 deletions apps/docs/content/docs/mcp/authentication.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: Authentication
description: Sign in with OAuth, or connect with an API key
---

import { Callout } from 'fumadocs-ui/components/callout'

## OAuth

Most apps sign in with OAuth. The first time you connect, your app opens Sim in
the browser, you sign in, and you approve its access. The app then holds a
token that renews itself; you do not copy any secret.

The approval screen names the app and what it can do:

| Access | Scope | Allows |
| --- | --- | --- |
| Read-only | `api:read` | Reading workspaces, workflows, runs, tables, files, knowledge bases, and logs |
| Full | `api:write` | Everything above, plus creating, changing, running, deploying, and deleting |

Most apps request full access. To connect an app for reads only, configure it
to request the `api:read` scope; changes then fail with an insufficient-scope
error.

Tokens are issued for the Sim MCP server itself. An app cannot take one to
another service and use it there.

### Revoke access

Open **Settings → General → Authorized apps** in Sim, find the app, and revoke
it. The app's next request fails, and you can reconnect at any time. Revoking
does not undo changes the app already made.

## API keys

Apps that cannot sign in through a browser, such as CI jobs and headless
agents, can send a Sim [API key](/api-reference/authentication) in the
`X-API-Key` header, or as `Authorization: Bearer <key>`.

```bash
claude mcp add --transport http sim https://mcp.sim.ai/mcp \
--header "X-API-Key: $SIM_API_KEY"
```

```json title="~/.cursor/mcp.json"
{
"mcpServers": {
"sim": {
"url": "https://mcp.sim.ai/mcp",
"headers": { "X-API-Key": "${env:SIM_API_KEY}" }
}
}
}
```

A personal key acts as you in every workspace you can access. A workspace key
reaches only its own workspace, and a few account-level operations refuse it;
`search_operations` marks them `personalCredentialOnly`.

<Callout type="warn">
An API key does not expire until you revoke it. Prefer OAuth for any app that
can open a browser, and store keys in your app's secret or environment
settings rather than in a shared config file.
</Callout>

## Organization policy

The server follows your organization's access policy. If an administrator turns
off **OAuth apps** or **personal API keys** for your permission group, requests
with that credential are refused in the affected workspaces.
109 changes: 109 additions & 0 deletions apps/docs/content/docs/mcp/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
---
title: Sim MCP
description: Build, run, and manage everything in your Sim workspace from Claude, Codex, Cursor, and other MCP apps
---

import { Callout } from 'fumadocs-ui/components/callout'
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'

The Sim MCP server gives an AI app the whole Sim API through the
[Model Context Protocol](https://modelcontextprotocol.io). Your agent can list
workspaces, run and deploy workflows, query and edit tables, manage files and
knowledge bases, read run logs, and more. It covers the same operations as the
[API](/api-reference/getting-started) and the [CLI](/cli).

| Deployment | Server URL |
| --- | --- |
| Sim Cloud | `https://mcp.sim.ai/mcp` |
| Self-hosted | `https://<your-sim-host>/api/mcp`, or your [`SIM_MCP_URL`](/platform/self-hosting/environment-variables) |

The server uses the Streamable HTTP transport. Sign in with OAuth, the default
in every app below, or send an [API key](/mcp/authentication#api-keys).

## Connect an app

<Tabs items={['Claude Code', 'Claude', 'Codex', 'Cursor', 'VS Code']}>
<Tab value="Claude Code">
```bash
claude mcp add --transport http sim https://mcp.sim.ai/mcp
```

Open `/mcp` in Claude Code, select **sim**, and sign in to Sim in the
browser.
</Tab>
<Tab value="Claude">
Add `https://mcp.sim.ai/mcp` as a custom connector under **Settings →
Connectors**, then connect it and sign in to Sim. For Team or Enterprise,
an owner first adds it under **Organization settings → Connectors**. See
[Claude's custom connector instructions](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp).
</Tab>
<Tab value="Codex">
```bash
codex mcp add sim --url https://mcp.sim.ai/mcp
```

Complete the browser sign-in. To sign in again later, run
`codex mcp login sim`.
</Tab>
<Tab value="Cursor">
Add `sim` to `mcpServers` in `~/.cursor/mcp.json`, then enable it in
Cursor and sign in to Sim:

```json
{
"mcpServers": {
"sim": { "url": "https://mcp.sim.ai/mcp" }
}
}
```
</Tab>
<Tab value="VS Code">
Add `sim` to `.vscode/mcp.json`, then start it and sign in to Sim:

```json
{
"servers": {
"sim": { "type": "http", "url": "https://mcp.sim.ai/mcp" }
}
}
```
</Tab>
</Tabs>

Any other app that supports remote MCP servers with OAuth works the same way:
give it the server URL and choose **Streamable HTTP** if asked.

<Callout type="info">
Claude's hosted connectors call your server from Claude's infrastructure, so a
self-hosted Sim must be reachable from the internet. A `localhost` URL works
only with apps that run on your machine, such as Claude Code, Codex, Cursor,
and VS Code.
</Callout>

## Try it

Ask your app:

- "List my Sim workspaces and the tables in each."
- "Run the `lead-scoring` workflow with this input and show me the result."
- "Find failed runs from the last day and explain what went wrong."
- "Create a table of our open support tickets and add these rows."

The agent finds the right operation, reads its inputs, and calls it. See
[Tools](/mcp/tools) for how that works.

## What your agent can do

The server acts as you. It sees the workspaces you can see, with your role in
each, and every call is authorized, rate limited, and logged exactly like the
same request to the API. Reads leave your resources unchanged, and apps can ask
you to confirm each change. See [Authentication](/mcp/authentication) to limit
an app to reads.

## Other Sim MCP surfaces

This server is for operating Sim. Two other MCP features do different jobs:

- [Search MCP](/search/mcp) searches your organization's indexed sources.
- [MCP deployment](/workflows/deployment/mcp) exposes your own workflows as
tools, and [MCP tools](/agents/mcp) connect external servers to Sim agents.
5 changes: 5 additions & 0 deletions apps/docs/content/docs/mcp/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "MCP",
"root": true,
"pages": ["---Sim MCP---", "index", "authentication", "tools"]
}
55 changes: 55 additions & 0 deletions apps/docs/content/docs/mcp/tools.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
title: Tools
description: How an agent finds, reads, and calls Sim operations through four tools
---

The Sim API has more than 200 operations. Instead of one tool per operation,
which would crowd your app's tool list and your agent's context, the server
exposes four tools. The agent searches for an operation, reads its inputs, and
calls it.

| Tool | Does |
| --- | --- |
| `search_operations` | Finds operations by keyword (`"table rows"`) or by area (`tables`, `workflows`, `knowledge`, …). Returns each operation's name, method, path, summary, and the tool that runs it. |
| `describe_operation` | Returns an operation's description and the JSON Schema of its path parameters, query, body, and headers. |
| `call_read_operation` | Runs an operation that only needs read access, such as `listWorkspaces`, `queryRows`, or `getWorkflowRun`. |
| `call_write_operation` | Runs an operation that needs write access: one that creates, changes, runs, or deletes something, or reaches out to another service, such as `createTable`, `executeWorkflow`, or `listMcpServerTools`. |

Reads and writes are separate tools so your app can approve reads once and still
ask you before each change.

## Calling an operation

Operation names match the [CLI](/cli/reference) and the
[API reference](/api-reference/getting-started). A call names the operation and
fills the parts of the request it needs:

```json
{
"operation": "listTableRows",
"params": { "tableId": "tbl_8f2c" },
"query": { "workspaceId": "ws_91ab", "limit": 50 }
}
```

| Field | Holds |
| --- | --- |
| `params` | Path parameters, such as `tableId` or `workflowId` |
| `query` | Query-string parameters; most operations need `workspaceId` |
| `body` | The JSON request body (write operations only) |
| `headers` | Headers the operation declares, such as `upload-token` |

The result is the same JSON the API returns, usually `{ "data": … }`. List
operations page with `limit` and `cursor`. A failed call returns the API's error,
such as `{ "error": { "code": "NOT_FOUND", "message": "…" } }`, so the agent can
correct its request.

## Limits

- **Same rules as the API.** Permissions, rate limits, and request validation
are the API's own; nothing is looser through MCP.
- **1 MiB per result.** Page through larger lists with `limit` and `cursor`.
- **No streaming.** Run a workflow without `stream: true` to wait for its
result, or with `async: true` and poll `getWorkflowRun`.
- **No file bytes.** Downloads, knowledge base exports, and multipart document
uploads are not available over MCP; use the [CLI](/cli/files) or the API.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import { Callout } from 'fumadocs-ui/components/callout'
| `TRUSTED_ORIGINS` | Comma-separated additional origins to trust for auth (apex + `www`, alias domains) |
| `AUTH_TRUSTED_PROXIES` | Comma-separated reverse-proxy IPs/CIDRs so the client IP cannot be forged through `X-Forwarded-For` |
| `INTERNAL_API_BASE_URL` | Internal URL for server-side self-calls, e.g. `http://sim-app.simstudio.svc.cluster.local:3000`. Optional — falls back to the public base URL. Deliberately ignored inside the Trigger.dev worker runtime, where a cluster-internal address resolves to the worker itself |
| `SIM_MCP_URL` | Public URL of the [Sim MCP server](/mcp) when you serve it on its own host, e.g. `https://mcp.example.com/mcp`. Point that host at the app; Sim serves only the MCP endpoint and its OAuth metadata there, and stops serving `/api/mcp` on the app host so clients use one URL. Optional — defaults to `<NEXT_PUBLIC_APP_URL>/api/mcp` |
| `DATABASE_REPLICA_URL` | Read-replica connection string for log listing, audit logs, and dashboard aggregations. Falls back to the primary when unset |

## AI Providers
Expand Down
5 changes: 4 additions & 1 deletion apps/docs/content/docs/workflows/blocks/agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Answer in two sentences, cite the doc you used, and never guess a price.

### Model

The model that runs the step. Defaults to `claude-sonnet-4-6`. Type or pick any model from OpenAI, Anthropic, Google, xAI, Groq, Cerebras, DeepSeek, Azure, AWS Bedrock, Google Vertex, or OpenRouter, or a local model through Ollama or VLLM.
The model that runs the step. Defaults to `claude-sonnet-5`. Type or pick any model from OpenAI, Anthropic, Google, xAI, Groq, Cerebras, DeepSeek, Azure, AWS Bedrock, Google Vertex, or OpenRouter, or a local model through Ollama or VLLM.

For a custom cloud deployment, enter its provider prefix and model ID: `azure/my-deployment`, `azure-anthropic/my-deployment`, `bedrock/my-inference-profile`, or `vertex/my-gemini-model`. The prefix selects the provider and shows its credential fields even when the ID is absent from the catalog. Bedrock accepts full inference profile ARNs after `bedrock/`; Vertex uses the Gemini API and accepts Google model resource names. The deployment must support the selected provider's API. Custom IDs have no catalog pricing or token limits.

Expand Down Expand Up @@ -87,6 +87,8 @@ Some settings live under advanced, or appear only for models that support them:
- **Reasoning effort / Thinking level.** For models with extended reasoning, how much the model thinks before answering. Higher is more thorough but slower and costs more tokens.
- **Prompt caching.** For Anthropic Claude models, reuses the system prompt and tool definitions between runs instead of re-reading them every time. Cached input costs a tenth of the normal rate, but writing the cache costs 1.25x, so leave it off for one-off runs and turn it on when the same agent runs repeatedly. The cache covers a prefix only if it reaches 1,024 tokens (2,048 on Haiku) — below that Anthropic ignores it and nothing changes. Entries expire after five minutes of no use.
- **API key.** Your key for the chosen provider. Hidden on hosted Sim, which supplies one.
- **Fallback models.** An ordered list of up to five models to try when the request to the selected model fails, whether the provider is overloaded, rate-limited, or down. Sim tries the 2nd choice, then the 3rd, and so on, once each, and `<agent.model>` reports the model that answered. On hosted Sim, hosted models use your workspace's BYOK or platform credentials; local and self-hosted installations may still require a key. A model that needs its own key takes it from a workspace environment variable you pick on the row; a model on the same provider as the selected model reuses the block's key. A stored row key stops applying when its key field is hidden. Providers that require family-specific credentials, such as Vertex, can only be fallbacks for a selected model of the same family. The Auto model cannot be a fallback. A fallback runs with the selected model's settings where its provider accepts them: temperature and max output tokens are clamped to the fallback's limits, and when the fallback has a reasoning effort, thinking level, or verbosity setting that the selected model's value does not fit, the row shows that field so you can pick a value for it; leave it empty and the provider's default applies.
- **Retry on fail.** Retries the selected model after a failure, up to a maximum number of tries with a wait between them. When its tries run out, the fallback models are tried in order, once each, with no wait before the first of them. A fallback is never retried. A failure that happens after the model already called a tool runs that conversation again on the next try or the next model, so keep fallbacks and retry off for agents whose tools must not repeat.

OpenAI and Gemini cache automatically at no extra cost and need no setting; their discount is already reflected in what you are charged.

Expand Down Expand Up @@ -148,4 +150,5 @@ The Agent reads the message from Start with `<start.input>` and returns a result
<FAQ items={[
{ question: "How does max output tokens work with Anthropic models?", answer: "The Agent block uses each Anthropic model's full max output token limit by default (for example, 64,000 tokens). You can override this with the Max Output Tokens setting. For non-streaming requests that exceed the SDK's internal threshold, the provider automatically uses internal streaming to avoid timeouts." },
{ question: "Can I use the Agent block with a custom or self-hosted model?", answer: "Yes. Use any Ollama or VLLM-compatible model by typing the model name directly into the model combobox, as long as it exposes a compatible API endpoint." },
{ question: "What happens when my model's provider is down?", answer: "Add fallback models under Additional fields. When the request to the selected model fails, Sim tries the 2nd choice, then the 3rd, in order, and the block succeeds if any of them answers. The log detail shows the model that answered and the models it fell back from. Turn on Retry on fail as well to give the selected model a few tries first; the fallbacks are tried once each after its last try fails." },
]} />
Loading
Loading