Merge remote-tracking branch 'origin/dev' into codemode-opencode-adapter

# Conflicts:
#	packages/opencode/src/mcp/index.ts
This commit is contained in:
Aiden Cline
2026-07-03 03:07:36 -05:00
21 changed files with 519 additions and 51 deletions
+12 -20
View File
@@ -1,7 +1,6 @@
import path from "node:path"
import { pathToFileURL } from "node:url"
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
import { type Tool } from "ai"
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
import { serviceUse } from "@opencode-ai/core/effect/service-use"
import { Client, type ClientOptions } from "@modelcontextprotocol/sdk/client/index.js"
@@ -154,12 +153,19 @@ export interface ServerInstructions {
tools: string[]
}
/** An MCP tool in its native shape; consumers adapt it to their own tool format. */
export interface McpTool {
/** Shared cached definition; consumers must copy rather than mutate it. */
readonly def: MCPToolDef
readonly client: MCPClient
readonly timeout?: number
}
export interface Interface {
readonly status: () => Effect.Effect<Record<string, Status>>
readonly clients: () => Effect.Effect<Record<string, MCPClient>>
readonly instructions: () => Effect.Effect<ServerInstructions[]>
readonly tools: () => Effect.Effect<Record<string, Tool>>
readonly defs: () => Effect.Effect<Record<string, MCPToolDef>>
readonly tools: () => Effect.Effect<Record<string, McpTool>>
readonly prompts: () => Effect.Effect<Record<string, PromptInfo & { client: string }>>
readonly resources: (clientName?: string) => Effect.Effect<Record<string, ResourceInfo & { client: string }>>
readonly resourceTemplates: (
@@ -653,7 +659,7 @@ const layer = Layer.effect(
}
const tools = Effect.fn("MCP.tools")(function* () {
const result: Record<string, Tool> = {}
const result: Record<string, McpTool> = {}
const s = yield* InstanceState.get(state)
const cfg = yield* cfgSvc.get()
@@ -669,21 +675,8 @@ const layer = Layer.effect(
continue
}
const timeout = requestTimeout(s, clientName, mcpConfig, defaultTimeout)
for (const mcpTool of listed) {
const key = McpCatalog.toolName(clientName, mcpTool.name)
result[key] = McpCatalog.convertTool(mcpTool, client, timeout)
}
}
return result
})
const defs = Effect.fn("MCP.defs")(function* () {
const result: Record<string, MCPToolDef> = {}
const s = yield* InstanceState.get(state)
for (const [clientName, listed] of Object.entries(s.defs)) {
if (s.status[clientName]?.status !== "connected") continue
for (const mcpTool of listed) {
result[McpCatalog.toolName(clientName, mcpTool.name)] = mcpTool
for (const def of listed) {
result[McpCatalog.toolName(clientName, def.name)] = { def, client, timeout }
}
}
return result
@@ -991,7 +984,6 @@ const layer = Layer.effect(
clients,
instructions,
tools,
defs,
prompts,
resources,
resourceTemplates,
+3 -1
View File
@@ -3,6 +3,7 @@ import { SessionV1 } from "@opencode-ai/core/v1/session"
import { Provider } from "@/provider/provider"
import { ProviderTransform } from "@/provider/transform"
import { MCP } from "@/mcp"
import { McpCatalog } from "@/mcp/catalog"
import { Permission } from "@/permission"
import { Tool } from "@/tool/tool"
import { ToolJsonSchema } from "@/tool/json-schema"
@@ -381,7 +382,8 @@ export const resolve = Effect.fn("SessionTools.resolve")(function* (input: {
})
}
for (const [key, item] of Object.entries(yield* mcp.tools())) {
for (const [key, entry] of Object.entries(yield* mcp.tools())) {
const item = McpCatalog.convertTool(entry.def, entry.client, entry.timeout)
const execute = item.execute
if (!execute) continue