mirror of
https://github.com/sst/opencode.git
synced 2025-07-07 16:14:59 +00:00
Merge 7dcac56114
into d87922c0eb
This commit is contained in:
commit
3e2e447681
3 changed files with 97 additions and 5 deletions
|
@ -98,13 +98,45 @@ export namespace MCP {
|
|||
return state().then((state) => state.clients)
|
||||
}
|
||||
|
||||
export async function tools() {
|
||||
export async function tools(providerID?: string) {
|
||||
const result: Record<string, Tool> = {}
|
||||
for (const [clientName, client] of Object.entries(await clients())) {
|
||||
for (const [toolName, tool] of Object.entries(await client.tools())) {
|
||||
result[clientName + "_" + toolName] = tool
|
||||
const clientEntries = Object.entries(await clients())
|
||||
|
||||
for (const [clientName, client] of clientEntries) {
|
||||
try {
|
||||
const clientTools = await client.tools()
|
||||
|
||||
for (const [toolName, tool] of Object.entries(clientTools)) {
|
||||
const toolKey = clientName + "_" + toolName
|
||||
|
||||
if (providerID) {
|
||||
const transformedTool = await transformToolForProvider(tool, providerID)
|
||||
result[toolKey] = transformedTool
|
||||
} else {
|
||||
result[toolKey] = tool
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
log.error('Failed to get tools from MCP client', { clientName, error: error.message })
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async function transformToolForProvider(tool: any, providerID: string): Promise<any> {
|
||||
if (!['openai', 'azure'].includes(providerID)) return tool
|
||||
|
||||
try {
|
||||
const { Provider } = await import("../provider/provider")
|
||||
return Provider.transformMCPToolForProvider(tool, providerID)
|
||||
} catch (error: any) {
|
||||
log.warn('Could not transform MCP tool schema, using as-is', {
|
||||
toolId: tool.id || 'unknown',
|
||||
providerID,
|
||||
error: error.message
|
||||
})
|
||||
return tool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -545,6 +545,66 @@ export namespace Provider {
|
|||
return schema
|
||||
}
|
||||
|
||||
function transformJsonSchema(schema: any): any {
|
||||
// Only handle simple object schemas
|
||||
if (!schema || schema.type !== 'object' || !schema.properties) {
|
||||
return schema // Return as-is for anything we don't understand
|
||||
}
|
||||
|
||||
// If it has oneOf, anyOf, allOf, or other complex stuff - bail out
|
||||
if (schema.oneOf || schema.anyOf || schema.allOf) {
|
||||
log.warn('Complex JSON schema detected, skipping transformation', { schema })
|
||||
return schema
|
||||
}
|
||||
|
||||
// Simple transformation: all properties become required + nullable
|
||||
const required = Object.keys(schema.properties)
|
||||
const properties: Record<string, any> = {}
|
||||
|
||||
for (const [key, prop] of Object.entries(schema.properties)) {
|
||||
if (!schema.required?.includes(key)) {
|
||||
// Make it nullable
|
||||
properties[key] = {
|
||||
anyOf: [prop, { type: 'null' }]
|
||||
}
|
||||
} else {
|
||||
properties[key] = prop
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...schema,
|
||||
required,
|
||||
properties
|
||||
}
|
||||
}
|
||||
|
||||
export function transformMCPToolForProvider(tool: any, providerID: string): any {
|
||||
if (!['openai', 'azure'].includes(providerID)) return tool
|
||||
|
||||
try {
|
||||
// AI SDK converts MCP tools to: { parameters: { jsonSchema: <original_inputSchema> } }
|
||||
if (tool.parameters?.jsonSchema) {
|
||||
const transformedSchema = transformJsonSchema(tool.parameters.jsonSchema)
|
||||
return {
|
||||
...tool,
|
||||
parameters: {
|
||||
...tool.parameters,
|
||||
jsonSchema: transformedSchema
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tool
|
||||
} catch (error: any) {
|
||||
log.warn('Could not transform MCP tool schema, using as-is', {
|
||||
toolId: tool.id || 'unknown',
|
||||
error: error.message
|
||||
})
|
||||
return tool
|
||||
}
|
||||
}
|
||||
|
||||
export const ModelNotFoundError = NamedError.create(
|
||||
"ProviderModelNotFoundError",
|
||||
z.object({
|
||||
|
|
|
@ -549,7 +549,7 @@ export namespace Session {
|
|||
})
|
||||
}
|
||||
|
||||
for (const [key, item] of Object.entries(await MCP.tools())) {
|
||||
for (const [key, item] of Object.entries(await MCP.tools(input.providerID))) {
|
||||
const execute = item.execute
|
||||
if (!execute) continue
|
||||
item.execute = async (args, opts) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue