Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
9321743
added a workflow as mcp
Dec 17, 2025
a15ac73
fixed the issue of UI rendering for deleted mcp servers
Dec 17, 2025
57f3697
fixing lint issues
Dec 17, 2025
85af046
using mcn components
Dec 17, 2025
2259bfc
fixing merge conflicts
Dec 18, 2025
1f22d7a
fix
Dec 18, 2025
cfbe4a4
fix lint errors
Dec 18, 2025
f2450d3
refactored code to use hasstartblock from the tirgger utils
Dec 18, 2025
896e967
removing unecessary auth
Dec 18, 2025
6c10f31
using official mcp sdk and added description fields
Dec 18, 2025
fe4f895
using normalised input schema function
Dec 18, 2025
9743a2f
Merge branch 'staging' into feat/workflow-as-mcp
Dec 18, 2025
4bb9a8d
ui fixes part 1
Sg312 Dec 19, 2025
b94c716
remove migration before merge
icecrasher321 Dec 20, 2025
e48aab1
Merge branch 'staging' into feat/workflow-as-mcp
icecrasher321 Dec 20, 2025
6771195
fix merge conflicts
icecrasher321 Dec 20, 2025
8b4f2a0
remove migration to prep merge
icecrasher321 Dec 21, 2025
a40243f
Merge branch 'staging' into feat/workflow-as-mcp
icecrasher321 Dec 21, 2025
e90fdb4
re-add migration
icecrasher321 Dec 21, 2025
cfdbcee
cleanup code to use mcp sdk types
icecrasher321 Dec 21, 2025
6856b26
fix discovery calls
icecrasher321 Dec 21, 2025
46f6383
Merge branch 'staging' into feat/workflow-as-mcp
icecrasher321 Dec 21, 2025
8489dd5
add migration
icecrasher321 Dec 21, 2025
da144ab
ui improvements
icecrasher321 Dec 21, 2025
b2153cd
fix lint
icecrasher321 Dec 21, 2025
ab44c11
fix types
icecrasher321 Dec 21, 2025
6dac845
fix lint
icecrasher321 Dec 21, 2025
24d58ea
fix spacing
icecrasher321 Dec 21, 2025
feacd08
remove migration to prep merge
icecrasher321 Dec 26, 2025
90e0b93
Merge branch 'staging' into feat/workflow-as-mcp
icecrasher321 Dec 26, 2025
fe3ed9f
add migration back
icecrasher321 Dec 26, 2025
c50b067
Merge branch 'staging' into feat/workflow-as-mcp
icecrasher321 Dec 26, 2025
fc77143
fix imports
icecrasher321 Dec 26, 2025
1998efa
Merge staging into feat/workflow-as-mcp
icecrasher321 Dec 27, 2025
1c97aab
Merge staging into feat/workflow-as-mcp
icecrasher321 Dec 29, 2025
404b46f
fix tool refresh ux
icecrasher321 Dec 29, 2025
08909ec
fix test failures
icecrasher321 Dec 29, 2025
216fb42
fix tests
icecrasher321 Dec 29, 2025
0346aac
cleanup code
icecrasher321 Dec 30, 2025
d6a0036
styling improvements, ability to edit mcp server description, etc
waleedlatif1 Dec 30, 2025
599a5db
fixed ui in light mode api keys modal
waleedlatif1 Dec 30, 2025
0badbdd
update docs
icecrasher321 Dec 30, 2025
725cdac
Merge branch 'feat/workflow-as-mcp' of github.com:simstudioai/sim int…
icecrasher321 Dec 30, 2025
6b6b57b
deprecated unused input components, shifted to emcn
waleedlatif1 Dec 30, 2025
62bc844
updated playground, simplified components
waleedlatif1 Dec 31, 2025
ae74f83
Merge branch 'staging' into feat/workflow-as-mcp
waleedlatif1 Dec 31, 2025
6a5ffa2
move images and videos
waleedlatif1 Dec 31, 2025
98b9845
updated more docs images
waleedlatif1 Dec 31, 2025
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
129 changes: 129 additions & 0 deletions apps/sim/app/api/mcp/discover/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { db } from '@sim/db'
import { permissions, workflowMcpServer, workspace } from '@sim/db/schema'
import { and, eq, sql } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { checkHybridAuth } from '@/lib/auth/hybrid'
import { getBaseUrl } from '@/lib/core/utils/urls'
import { createLogger } from '@/lib/logs/console/logger'

const logger = createLogger('McpDiscoverAPI')

export const dynamic = 'force-dynamic'

/**
* GET - Discover all published MCP servers available to the authenticated user
*
* This endpoint allows external MCP clients to discover available servers
* using just their API key, without needing to know workspace IDs.
*
* Authentication: API Key (X-API-Key header) or Session
*
* Returns all published MCP servers from workspaces the user has access to.
*/
export async function GET(request: NextRequest) {
try {
// Authenticate the request
const auth = await checkHybridAuth(request, { requireWorkflowId: false })

if (!auth.success || !auth.userId) {
return NextResponse.json(
{
success: false,
error: 'Authentication required. Provide X-API-Key header with your Sim API key.',
},
{ status: 401 }
)
}

const userId = auth.userId

// Get all workspaces the user has access to via permissions table
const userWorkspacePermissions = await db
.select({ entityId: permissions.entityId })
.from(permissions)
.where(and(eq(permissions.userId, userId), eq(permissions.entityType, 'workspace')))

const workspaceIds = userWorkspacePermissions.map((w) => w.entityId)

if (workspaceIds.length === 0) {
return NextResponse.json({
success: true,
servers: [],
message: 'No workspaces found for this user',
})
}

// Get all published MCP servers from user's workspaces with tool count
const servers = await db
.select({
id: workflowMcpServer.id,
name: workflowMcpServer.name,
description: workflowMcpServer.description,
workspaceId: workflowMcpServer.workspaceId,
workspaceName: workspace.name,
isPublished: workflowMcpServer.isPublished,
publishedAt: workflowMcpServer.publishedAt,
toolCount: sql<number>`(
SELECT COUNT(*)::int
FROM "workflow_mcp_tool"
WHERE "workflow_mcp_tool"."server_id" = "workflow_mcp_server"."id"
)`.as('tool_count'),
})
.from(workflowMcpServer)
.leftJoin(workspace, eq(workflowMcpServer.workspaceId, workspace.id))
.where(
and(
eq(workflowMcpServer.isPublished, true),
sql`${workflowMcpServer.workspaceId} IN ${workspaceIds}`
)
)
.orderBy(workflowMcpServer.name)

const baseUrl = getBaseUrl()

// Format response with connection URLs
const formattedServers = servers.map((server) => ({
id: server.id,
name: server.name,
description: server.description,
workspace: {
id: server.workspaceId,
name: server.workspaceName,
},
toolCount: server.toolCount || 0,
publishedAt: server.publishedAt,
urls: {
http: `${baseUrl}/api/mcp/serve/${server.id}`,
sse: `${baseUrl}/api/mcp/serve/${server.id}/sse`,
},
}))

logger.info(`User ${userId} discovered ${formattedServers.length} MCP servers`)

return NextResponse.json({
success: true,
servers: formattedServers,
authentication: {
method: 'API Key',
header: 'X-API-Key',
description: 'Include your Sim API key in the X-API-Key header for all MCP requests',
},
usage: {
listTools: {
method: 'POST',
body: '{"jsonrpc":"2.0","id":1,"method":"tools/list"}',
},
callTool: {
method: 'POST',
body: '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"TOOL_NAME","arguments":{}}}',
},
},
})
} catch (error) {
logger.error('Error discovering MCP servers:', error)
return NextResponse.json(
{ success: false, error: 'Failed to discover MCP servers' },
{ status: 500 }
)
}
}
Loading
Loading