Dax Raad 8 месяцев назад
Родитель
Сommit
100d6212be

+ 7 - 1
opencode.json

@@ -1,3 +1,9 @@
 {
-  "$schema": "https://opencode.ai/config.json"
+  "$schema": "https://opencode.ai/config.json",
+  "mcp": {
+    "sentry": {
+      "type": "remote",
+      "url": "https://mcp.sentry.dev/sse"
+    }
+  }
 }

+ 3 - 0
packages/opencode/src/cli/error.ts

@@ -1,6 +1,9 @@
 import { Config } from "../config/config"
+import { MCP } from "../mcp"
 
 export function FormatError(input: unknown) {
+  if (MCP.Failed.isInstance(input))
+    return `MCP server "${input.data.name}" failed. Note, opencode does not support MCP authentication yet.`
   if (Config.JsonError.isInstance(input))
     return `Config file at ${input.data.path} is not valid JSON`
   if (Config.InvalidError.isInstance(input))

+ 6 - 0
packages/opencode/src/index.ts

@@ -20,6 +20,9 @@ import { Bus } from "./bus"
 import { Config } from "./config/config"
 import { NamedError } from "./util/error"
 import { FormatError } from "./cli/error"
+import { MCP } from "./mcp"
+
+const cancel = new AbortController()
 
 const cli = yargs(hideBin(process.argv))
   .scriptName("opencode")
@@ -72,6 +75,7 @@ const cli = yargs(hideBin(process.argv))
           }
           const proc = Bun.spawn({
             cmd: [...cmd, ...process.argv.slice(2)],
+            signal: cancel.signal,
             cwd,
             stdout: "inherit",
             stderr: "inherit",
@@ -157,3 +161,5 @@ try {
       "Unexpected error, check log file at " + Log.file() + " for more details",
     )
 }
+
+cancel.abort()

+ 48 - 5
packages/opencode/src/mcp/index.ts

@@ -2,8 +2,22 @@ import { experimental_createMCPClient, type Tool } from "ai"
 import { Experimental_StdioMCPTransport } from "ai/mcp-stdio"
 import { App } from "../app/app"
 import { Config } from "../config/config"
+import { Log } from "../util/log"
+import { NamedError } from "../util/error"
+import { z } from "zod"
+import { Session } from "../session"
+import { Bus } from "../bus"
 
 export namespace MCP {
+  const log = Log.create({ service: "mcp" })
+
+  export const Failed = NamedError.create(
+    "MCPFailed",
+    z.object({
+      name: z.string(),
+    }),
+  )
+
   const state = App.state(
     "mcp",
     async () => {
@@ -12,27 +26,56 @@ export namespace MCP {
         [name: string]: Awaited<ReturnType<typeof experimental_createMCPClient>>
       } = {}
       for (const [key, mcp] of Object.entries(cfg.mcp ?? {})) {
+        log.info("found", { key, type: mcp.type })
         if (mcp.type === "remote") {
-          clients[key] = await experimental_createMCPClient({
+          const client = await experimental_createMCPClient({
             name: key,
             transport: {
               type: "sse",
               url: mcp.url,
             },
-          })
+          }).catch(() => {})
+          if (!client) {
+            Bus.publish(Session.Event.Error, {
+              error: {
+                name: "UnknownError",
+                data: {
+                  message: `MCP server ${key} failed to start`,
+                },
+              },
+            })
+            continue
+          }
+          clients[key] = client
         }
 
         if (mcp.type === "local") {
           const [cmd, ...args] = mcp.command
-          clients[key] = await experimental_createMCPClient({
+          const client = await experimental_createMCPClient({
             name: key,
             transport: new Experimental_StdioMCPTransport({
               stderr: "ignore",
               command: cmd,
               args,
-              env: mcp.environment,
+              env: {
+                ...process.env,
+                ...(cmd === "opencode" ? { BUN_BE_BUN: "1" } : {}),
+                ...mcp.environment,
+              },
             }),
-          })
+          }).catch(() => {})
+          if (!client) {
+            Bus.publish(Session.Event.Error, {
+              error: {
+                name: "UnknownError",
+                data: {
+                  message: `MCP server ${key} failed to start`,
+                },
+              },
+            })
+            continue
+          }
+          clients[key] = client
         }
       }