d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
186 lines
5.6 KiB
TypeScript
186 lines
5.6 KiB
TypeScript
import { workflowMcpTool } from '@sim/db'
|
|
import { and, eq, isNull, ne, sql } from 'drizzle-orm'
|
|
import type { DbOrTx } from '@/lib/db/types'
|
|
import {
|
|
MAX_MCP_PARAMETER_SCHEMA_BYTES,
|
|
MAX_MCP_SERVER_PARAMETER_SCHEMAS_BYTES,
|
|
MAX_MCP_SERVER_TOOLS_METADATA_BYTES,
|
|
MAX_MCP_TOOL_DESCRIPTION_BYTES,
|
|
MAX_MCP_TOOL_NAME_BYTES,
|
|
} from '@/lib/mcp/constants'
|
|
|
|
function utf8Size(value: string): number {
|
|
return Buffer.byteLength(value, 'utf-8')
|
|
}
|
|
|
|
function jsonSize(value: unknown): number | null {
|
|
try {
|
|
const json = JSON.stringify(value)
|
|
return typeof json === 'string' ? utf8Size(json) : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export interface McpToolMetadataSizes {
|
|
toolNameBytes: number
|
|
toolDescriptionBytes: number
|
|
parameterSchemaBytes: number
|
|
}
|
|
|
|
export interface McpToolMetadataUsage {
|
|
schemaBytes: number
|
|
metadataBytes: number
|
|
}
|
|
|
|
export interface McpToolMetadataUsageRow extends McpToolMetadataSizes {
|
|
id: string
|
|
}
|
|
|
|
export function getMcpToolMetadataSizes(metadata: {
|
|
toolName?: string | null
|
|
toolDescription?: string | null
|
|
parameterSchema?: unknown
|
|
}): McpToolMetadataSizes {
|
|
return {
|
|
toolNameBytes: metadata.toolName ? utf8Size(metadata.toolName) : 0,
|
|
toolDescriptionBytes: metadata.toolDescription ? utf8Size(metadata.toolDescription) : 0,
|
|
parameterSchemaBytes:
|
|
metadata.parameterSchema !== undefined
|
|
? (jsonSize(metadata.parameterSchema) ?? MAX_MCP_PARAMETER_SCHEMA_BYTES + 1)
|
|
: 0,
|
|
}
|
|
}
|
|
|
|
export function addMcpToolMetadataUsage(
|
|
usage: McpToolMetadataUsage,
|
|
tool: {
|
|
toolName?: string | null
|
|
toolDescription?: string | null
|
|
parameterSchema?: unknown
|
|
}
|
|
): McpToolMetadataUsage {
|
|
const sizes = getMcpToolMetadataSizes(tool)
|
|
return {
|
|
schemaBytes: usage.schemaBytes + sizes.parameterSchemaBytes,
|
|
metadataBytes:
|
|
usage.metadataBytes +
|
|
sizes.toolNameBytes +
|
|
sizes.toolDescriptionBytes +
|
|
sizes.parameterSchemaBytes,
|
|
}
|
|
}
|
|
|
|
export function addMcpToolMetadataUsageRow(
|
|
usage: McpToolMetadataUsage,
|
|
row: McpToolMetadataUsageRow
|
|
): McpToolMetadataUsage {
|
|
return {
|
|
schemaBytes: usage.schemaBytes + row.parameterSchemaBytes,
|
|
metadataBytes:
|
|
usage.metadataBytes + row.toolNameBytes + row.toolDescriptionBytes + row.parameterSchemaBytes,
|
|
}
|
|
}
|
|
|
|
export function subtractMcpToolMetadataUsageRow(
|
|
usage: McpToolMetadataUsage,
|
|
row?: McpToolMetadataUsageRow
|
|
): McpToolMetadataUsage {
|
|
if (!row) return usage
|
|
return {
|
|
schemaBytes: usage.schemaBytes - row.parameterSchemaBytes,
|
|
metadataBytes:
|
|
usage.metadataBytes - row.toolNameBytes - row.toolDescriptionBytes - row.parameterSchemaBytes,
|
|
}
|
|
}
|
|
|
|
export function getMcpToolMetadataUsageFromRows(
|
|
rows: McpToolMetadataUsageRow[]
|
|
): McpToolMetadataUsage {
|
|
return rows.reduce(addMcpToolMetadataUsageRow, { schemaBytes: 0, metadataBytes: 0 })
|
|
}
|
|
|
|
export function createMcpToolMetadataUsageRow(tool: {
|
|
id: string
|
|
toolName: string
|
|
toolDescription: string | null
|
|
parameterSchema: unknown
|
|
}): McpToolMetadataUsageRow {
|
|
return { id: tool.id, ...getMcpToolMetadataSizes(tool) }
|
|
}
|
|
|
|
export function validateMcpServerToolMetadataBudget(usage: McpToolMetadataUsage): string | null {
|
|
if (usage.schemaBytes > MAX_MCP_SERVER_PARAMETER_SCHEMAS_BYTES) {
|
|
return `MCP server tool schemas exceed maximum size of ${MAX_MCP_SERVER_PARAMETER_SCHEMAS_BYTES} bytes`
|
|
}
|
|
if (usage.metadataBytes > MAX_MCP_SERVER_TOOLS_METADATA_BYTES) {
|
|
return `MCP server tool metadata exceeds maximum size of ${MAX_MCP_SERVER_TOOLS_METADATA_BYTES} bytes`
|
|
}
|
|
return null
|
|
}
|
|
|
|
export function exceedsMcpServerToolMetadataBudget(
|
|
usage: McpToolMetadataUsage,
|
|
tool: { toolName: string; toolDescription: string | null; parameterSchema: unknown }
|
|
): boolean {
|
|
return validateMcpServerToolMetadataBudget(addMcpToolMetadataUsage(usage, tool)) !== null
|
|
}
|
|
|
|
export async function getMcpServerToolMetadataUsageRows(
|
|
tx: DbOrTx,
|
|
serverId: string,
|
|
excludeToolId?: string
|
|
): Promise<McpToolMetadataUsageRow[]> {
|
|
const rows = await tx
|
|
.select({
|
|
id: workflowMcpTool.id,
|
|
toolNameBytes: sql<number>`octet_length(${workflowMcpTool.toolName})`,
|
|
toolDescriptionBytes: sql<number>`coalesce(octet_length(${workflowMcpTool.toolDescription}), 0)`,
|
|
parameterSchemaBytes: sql<number>`octet_length(${workflowMcpTool.parameterSchema}::text)`,
|
|
})
|
|
.from(workflowMcpTool)
|
|
.where(
|
|
and(
|
|
eq(workflowMcpTool.serverId, serverId),
|
|
isNull(workflowMcpTool.archivedAt),
|
|
excludeToolId ? ne(workflowMcpTool.id, excludeToolId) : undefined
|
|
)
|
|
)
|
|
|
|
return rows.map((row) => ({
|
|
id: row.id,
|
|
toolNameBytes: Number(row.toolNameBytes) || 0,
|
|
toolDescriptionBytes: Number(row.toolDescriptionBytes) || 0,
|
|
parameterSchemaBytes: Number(row.parameterSchemaBytes) || 0,
|
|
}))
|
|
}
|
|
|
|
export function validateMcpToolMetadataForStorage(metadata: {
|
|
toolName?: string | null
|
|
toolDescription?: string | null
|
|
parameterSchema?: unknown
|
|
}): string | null {
|
|
if (metadata.toolName && utf8Size(metadata.toolName) > MAX_MCP_TOOL_NAME_BYTES) {
|
|
return `Tool name exceeds maximum size of ${MAX_MCP_TOOL_NAME_BYTES} bytes`
|
|
}
|
|
|
|
if (
|
|
metadata.toolDescription &&
|
|
utf8Size(metadata.toolDescription) > MAX_MCP_TOOL_DESCRIPTION_BYTES
|
|
) {
|
|
return `Tool description exceeds maximum size of ${MAX_MCP_TOOL_DESCRIPTION_BYTES} bytes`
|
|
}
|
|
|
|
if (metadata.parameterSchema !== undefined) {
|
|
const parameterSchemaBytes = jsonSize(metadata.parameterSchema)
|
|
if (parameterSchemaBytes === null) {
|
|
return 'Tool parameter schema must be JSON serializable'
|
|
}
|
|
if (parameterSchemaBytes > MAX_MCP_PARAMETER_SCHEMA_BYTES) {
|
|
return `Tool parameter schema exceeds maximum size of ${MAX_MCP_PARAMETER_SCHEMA_BYTES} bytes`
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|