Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
06fbc29
v0
Sg312 Jan 30, 2026
cb3618a
v1
Sg312 Jan 30, 2026
8b7b331
Basic ss tes
Sg312 Jan 31, 2026
301e25c
Ss tests
Sg312 Jan 31, 2026
4c821d0
Stuff
Sg312 Jan 31, 2026
6cd8f1d
Add mcp
Sg312 Jan 31, 2026
793c877
mcp v1
Sg312 Jan 31, 2026
e04f379
Improvement
Sg312 Feb 1, 2026
4d84c54
Fix
Sg312 Feb 3, 2026
8f17bc4
BROKEN
Sg312 Feb 3, 2026
2d9a7c6
Checkpoint
Sg312 Feb 4, 2026
addc760
Streaming
Sg312 Feb 4, 2026
a58a61b
Fix abort
Sg312 Feb 4, 2026
be7fb8f
Things are broken
Sg312 Feb 4, 2026
b034b1c
Streaming seems to work but copilot is dumb
Sg312 Feb 4, 2026
8c48cdd
Fix edge issue
Sg312 Feb 4, 2026
d8daf3a
LUAAAA
Sg312 Feb 4, 2026
cbd7bb6
Fix stream buffer
Sg312 Feb 4, 2026
89782f6
Fix lint
Sg312 Feb 4, 2026
9a5a494
Checkpoint
Sg312 Feb 5, 2026
7402b38
Initial temp state, in the middle of a refactor
Sg312 Feb 5, 2026
4faa939
Initial test shows diff store still working
Sg312 Feb 5, 2026
7183448
Tool refactor
Sg312 Feb 5, 2026
b3e74e4
First cleanup pass complete - untested
Sg312 Feb 5, 2026
6b40d4f
Continued cleanup
Sg312 Feb 5, 2026
39968be
Refactor
Sg312 Feb 6, 2026
ba8f39f
Refactor complete - no testing yet
Sg312 Feb 6, 2026
fb4afeb
Fix - cursor makes me sad
Sg312 Feb 6, 2026
dd02395
Fix mcp
Sg312 Feb 6, 2026
08a8e14
Clean up mcp
Sg312 Feb 6, 2026
fd1e61b
Updated mcp
Sg312 Feb 6, 2026
69bdffa
Add respond to subagents
Sg312 Feb 6, 2026
74f863a
Fix definitions
Sg312 Feb 6, 2026
3dcd008
Add tools
Sg312 Feb 6, 2026
0c51ce5
Add tools
Sg312 Feb 6, 2026
df3523e
Add copilot mcp tracking
Sg312 Feb 6, 2026
6cb112e
Fix lint
Sg312 Feb 6, 2026
18e493e
Fix mcp
Sg312 Feb 6, 2026
a73e351
Fix
Sg312 Feb 6, 2026
67c2271
Updates
Sg312 Feb 6, 2026
a220455
Clean up mcp
Sg312 Feb 7, 2026
6735eaa
Fix copilot mcp tool names to be sim prefixed
Sg312 Feb 7, 2026
4d4d002
Add opus 4.6
Sg312 Feb 7, 2026
b07b812
Fix discovery tool
Sg312 Feb 7, 2026
220a540
Fix
Sg312 Feb 7, 2026
ebf4e90
Remove logs
Sg312 Feb 7, 2026
7e592e8
Fix go side tool rendering
Sg312 Feb 7, 2026
25d255a
Update docs
Sg312 Feb 9, 2026
b4361b8
Fix hydration
Sg312 Feb 9, 2026
d2c028f
Fix tool call resolution
Sg312 Feb 9, 2026
ed613c3
Fix
Sg312 Feb 9, 2026
4698f73
Fix lint
Sg312 Feb 9, 2026
79af303
Fix superagent and autoallow integrations
Sg312 Feb 9, 2026
c086912
Fix always allow
Sg312 Feb 9, 2026
9a47033
Update block
Sg312 Feb 9, 2026
7200421
Remove plan docs
Sg312 Feb 9, 2026
ab39a4f
Fix hardcoded ff
Sg312 Feb 9, 2026
dba4e61
Fix dropped provider
Sg312 Feb 9, 2026
b14e844
Fix lint
Sg312 Feb 9, 2026
395f890
Fix tests
Sg312 Feb 9, 2026
7458bbd
Fix dead messages array
Sg312 Feb 9, 2026
48c9a3a
Fix discovery
Sg312 Feb 9, 2026
7153141
Fix run workflow
Sg312 Feb 10, 2026
7670cdf
Fix run block
Sg312 Feb 10, 2026
1beb35c
Fix run from block in copilot
Sg312 Feb 10, 2026
18f1d76
Fix lint
Sg312 Feb 10, 2026
8a2eacf
Fix skip and mtb
Sg312 Feb 10, 2026
bd6a103
Fix typing
Sg312 Feb 10, 2026
ddc5164
Fix tool call
Sg312 Feb 10, 2026
bb4e072
Bump api version
Sg312 Feb 10, 2026
98df298
Fix bun lock
Sg312 Feb 10, 2026
621dd23
Nuke bad files
Sg312 Feb 10, 2026
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
98 changes: 97 additions & 1 deletion apps/docs/content/docs/en/copilot/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Switch between modes using the mode selector at the bottom of the input area.
Select your preferred AI model using the model selector at the bottom right of the input area.

**Available Models:**
- Claude 4.5 Opus, Sonnet (default), Haiku
- Claude 4.6 Opus (default), 4.5 Opus, Sonnet, Haiku
- GPT 5.2 Codex, Pro
- Gemini 3 Pro

Expand Down Expand Up @@ -190,3 +190,99 @@ Copilot usage is billed per token from the underlying LLM. If you reach your usa
<Callout type="info">
See the [Cost Calculation page](/execution/costs) for billing details.
</Callout>
## Copilot MCP

You can use Copilot as an MCP server in your favorite editor or AI client. This lets you build, test, deploy, and manage Sim workflows directly from tools like Cursor, Claude Code, Claude Desktop, and VS Code.

### Generating a Copilot API Key

To connect to the Copilot MCP server, you need a **Copilot API key**:

1. Go to [sim.ai](https://sim.ai) and sign in
2. Navigate to **Settings** → **Copilot**
3. Click **Generate API Key**
4. Copy the key — it is only shown once

The key will look like `sk-sim-copilot-...`. You will use this in the configuration below.

### Cursor

Add the following to your `.cursor/mcp.json` (project-level) or global Cursor MCP settings:

```json
{
"mcpServers": {
"sim-copilot": {
"url": "https://www.sim.ai/api/mcp/copilot",
"headers": {
"X-API-Key": "YOUR_COPILOT_API_KEY"
}
}
}
}
```

Replace `YOUR_COPILOT_API_KEY` with the key you generated above.

### Claude Code

Run the following command to add the Copilot MCP server:

```bash
claude mcp add sim-copilot \
--transport http \
https://www.sim.ai/api/mcp/copilot \
--header "X-API-Key: YOUR_COPILOT_API_KEY"
```

Replace `YOUR_COPILOT_API_KEY` with your key.

### Claude Desktop

Claude Desktop requires [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) to connect to HTTP-based MCP servers. Add the following to your Claude Desktop config file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
"mcpServers": {
"sim-copilot": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://www.sim.ai/api/mcp/copilot",
"--header",
"X-API-Key: YOUR_COPILOT_API_KEY"
]
}
}
}
```

Replace `YOUR_COPILOT_API_KEY` with your key.

### VS Code

Add the following to your VS Code `settings.json` or workspace `.vscode/settings.json`:

```json
{
"mcp": {
"servers": {
"sim-copilot": {
"type": "http",
"url": "https://www.sim.ai/api/mcp/copilot",
"headers": {
"X-API-Key": "YOUR_COPILOT_API_KEY"
}
}
}
}
}
```

Replace `YOUR_COPILOT_API_KEY` with your key.

<Callout type="info">
For self-hosted deployments, replace `https://www.sim.ai` with your self-hosted Sim URL.
</Callout>

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NextRequest, NextResponse } from 'next/server'
import { createMcpAuthorizationServerMetadataResponse } from '@/lib/mcp/oauth-discovery'

export async function GET(request: NextRequest): Promise<NextResponse> {
return createMcpAuthorizationServerMetadataResponse(request)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NextRequest, NextResponse } from 'next/server'
import { createMcpAuthorizationServerMetadataResponse } from '@/lib/mcp/oauth-discovery'

export async function GET(request: NextRequest): Promise<NextResponse> {
return createMcpAuthorizationServerMetadataResponse(request)
}
6 changes: 6 additions & 0 deletions apps/sim/app/.well-known/oauth-authorization-server/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NextRequest, NextResponse } from 'next/server'
import { createMcpAuthorizationServerMetadataResponse } from '@/lib/mcp/oauth-discovery'

export async function GET(request: NextRequest): Promise<NextResponse> {
return createMcpAuthorizationServerMetadataResponse(request)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NextRequest, NextResponse } from 'next/server'
import { createMcpProtectedResourceMetadataResponse } from '@/lib/mcp/oauth-discovery'

export async function GET(request: NextRequest): Promise<NextResponse> {
return createMcpProtectedResourceMetadataResponse(request)
}
6 changes: 6 additions & 0 deletions apps/sim/app/.well-known/oauth-protected-resource/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { NextRequest, NextResponse } from 'next/server'
import { createMcpProtectedResourceMetadataResponse } from '@/lib/mcp/oauth-discovery'

export async function GET(request: NextRequest): Promise<NextResponse> {
return createMcpProtectedResourceMetadataResponse(request)
}
16 changes: 13 additions & 3 deletions apps/sim/app/api/billing/update-cost/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const UpdateCostSchema = z.object({
model: z.string().min(1, 'Model is required'),
inputTokens: z.number().min(0).default(0),
outputTokens: z.number().min(0).default(0),
source: z.enum(['copilot', 'mcp_copilot']).default('copilot'),
})

/**
Expand Down Expand Up @@ -75,12 +76,14 @@ export async function POST(req: NextRequest) {
)
}

const { userId, cost, model, inputTokens, outputTokens } = validation.data
const { userId, cost, model, inputTokens, outputTokens, source } = validation.data
const isMcp = source === 'mcp_copilot'

logger.info(`[${requestId}] Processing cost update`, {
userId,
cost,
model,
source,
})

// Check if user stats record exists (same as ExecutionLogger)
Expand All @@ -96,7 +99,7 @@ export async function POST(req: NextRequest) {
return NextResponse.json({ error: 'User stats record not found' }, { status: 500 })
}

const updateFields = {
const updateFields: Record<string, unknown> = {
totalCost: sql`total_cost + ${cost}`,
currentPeriodCost: sql`current_period_cost + ${cost}`,
totalCopilotCost: sql`total_copilot_cost + ${cost}`,
Expand All @@ -105,17 +108,24 @@ export async function POST(req: NextRequest) {
lastActive: new Date(),
}

// Also increment MCP-specific counters when source is mcp_copilot
if (isMcp) {
updateFields.totalMcpCopilotCost = sql`total_mcp_copilot_cost + ${cost}`
updateFields.currentPeriodMcpCopilotCost = sql`current_period_mcp_copilot_cost + ${cost}`
}

await db.update(userStats).set(updateFields).where(eq(userStats.userId, userId))

logger.info(`[${requestId}] Updated user stats record`, {
userId,
addedCost: cost,
source,
})

// Log usage for complete audit trail
await logModelUsage({
userId,
source: 'copilot',
source: isMcp ? 'mcp_copilot' : 'copilot',
model,
inputTokens,
outputTokens,
Expand Down
5 changes: 1 addition & 4 deletions apps/sim/app/api/copilot/api-keys/generate/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getSession } from '@/lib/auth'
import { SIM_AGENT_API_URL_DEFAULT } from '@/lib/copilot/constants'
import { SIM_AGENT_API_URL } from '@/lib/copilot/constants'
import { env } from '@/lib/core/config/env'

const GenerateApiKeySchema = z.object({
Expand All @@ -17,9 +17,6 @@ export async function POST(req: NextRequest) {

const userId = session.user.id

// Move environment variable access inside the function
const SIM_AGENT_API_URL = env.SIM_AGENT_API_URL || SIM_AGENT_API_URL_DEFAULT

const body = await req.json().catch(() => ({}))
const validationResult = GenerateApiKeySchema.safeParse(body)

Expand Down
1 change: 1 addition & 0 deletions apps/sim/app/api/copilot/api-keys/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe('Copilot API Keys API Route', () => {

vi.doMock('@/lib/copilot/constants', () => ({
SIM_AGENT_API_URL_DEFAULT: 'https://agent.sim.example.com',
SIM_AGENT_API_URL: 'https://agent.sim.example.com',
}))

vi.doMock('@/lib/core/config/env', async () => {
Expand Down
6 changes: 1 addition & 5 deletions apps/sim/app/api/copilot/api-keys/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { SIM_AGENT_API_URL_DEFAULT } from '@/lib/copilot/constants'
import { SIM_AGENT_API_URL } from '@/lib/copilot/constants'
import { env } from '@/lib/core/config/env'

export async function GET(request: NextRequest) {
Expand All @@ -12,8 +12,6 @@ export async function GET(request: NextRequest) {

const userId = session.user.id

const SIM_AGENT_API_URL = env.SIM_AGENT_API_URL || SIM_AGENT_API_URL_DEFAULT

const res = await fetch(`${SIM_AGENT_API_URL}/api/validate-key/get-api-keys`, {
method: 'POST',
headers: {
Expand Down Expand Up @@ -68,8 +66,6 @@ export async function DELETE(request: NextRequest) {
return NextResponse.json({ error: 'id is required' }, { status: 400 })
}

const SIM_AGENT_API_URL = env.SIM_AGENT_API_URL || SIM_AGENT_API_URL_DEFAULT

const res = await fetch(`${SIM_AGENT_API_URL}/api/validate-key/delete`, {
method: 'POST',
headers: {
Expand Down
Loading