ソースを参照

fix(core): configure Figma MCP OAuth client

Aiden Cline 3 週間 前
コミット
49be2b3a89

+ 25 - 0
opencode.jsonc

@@ -0,0 +1,25 @@
+{
+  "$schema": "https://opencode.ai/config.json",
+  "mcp": {
+    "servers": {
+      "everything": {
+        "type": "local",
+        "command": ["npx", "-y", "@modelcontextprotocol/server-everything"],
+        "disabled": false,
+      },
+      "context7": {
+        "type": "local",
+        "command": ["npx", "-y", "@upstash/context7-mcp"],
+        "disabled": false,
+      },
+      "posthog": {
+        "type": "remote",
+        "url": "https://mcp.posthog.com/mcp",
+      },
+      "figma": {
+        "type": "remote",
+        "url": "https://mcp.figma.com/mcp",
+      },
+    },
+  },
+}

+ 28 - 0
packages/core/src/plugin/figma.ts

@@ -0,0 +1,28 @@
+export * as FigmaPlugin from "./figma"
+
+import { define } from "@opencode-ai/plugin/v2/effect/plugin"
+import { Effect } from "effect"
+import { Config } from "../config"
+
+const CLIENT_ID = "3zVHNs9kINDDrk8loekLZV"
+
+export const Plugin = define({
+  id: "opencode.figma",
+  effect: Effect.fn(function* () {
+    const config = yield* Config.Service
+    const entries = yield* config.entries()
+    entries
+      .filter((entry): entry is Config.Document => entry.type === "document")
+      .flatMap((entry) => Object.values(entry.info.mcp?.servers ?? {}))
+      .forEach((server) => {
+        if (server.type !== "remote" || server.oauth === false) return
+        if (!URL.canParse(server.url) || new URL(server.url).hostname !== "mcp.figma.com") return
+        if (server.oauth?.client_id) return
+        if (server.oauth) {
+          Object.assign(server.oauth, { client_id: CLIENT_ID })
+          return
+        }
+        Object.assign(server, { oauth: { client_id: CLIENT_ID } })
+      })
+  }),
+})

+ 2 - 0
packages/core/src/plugin/internal.ts

@@ -48,6 +48,7 @@ import { WellKnown } from "../wellknown"
 import { WriteTool } from "../tool/write"
 import { AgentPlugin } from "./agent"
 import { CommandPlugin } from "./command"
+import { FigmaPlugin } from "./figma"
 import { ModelsDevPlugin } from "./models-dev"
 import { ProviderPlugins } from "./provider"
 import { PluginRuntime } from "./runtime"
@@ -126,6 +127,7 @@ export type InternalPlugin = Plugin<Requirements | Scope.Scope>
 
 const pre = [
   WellKnownPlugin.Plugin,
+  FigmaPlugin.Plugin,
   AgentPlugin.Plugin,
   CommandPlugin.Plugin,
   SkillPlugin.Plugin,

+ 77 - 0
packages/core/test/config/plugin.test.ts

@@ -7,6 +7,7 @@ import { Config as ConfigSchema } from "@opencode-ai/schema/config"
 import { Plugin } from "@opencode-ai/schema/plugin"
 import { AgentV2 } from "@opencode-ai/core/agent"
 import { Catalog } from "@opencode-ai/core/catalog"
+import { Config } from "@opencode-ai/core/config"
 import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
 import { LayerNode } from "@opencode-ai/util/effect/layer-node"
 import { EventV2 } from "@opencode-ai/core/event"
@@ -258,6 +259,82 @@ describe("PluginSupervisor config", () => {
       }),
     ),
   )
+
+  it.live("adds the OpenCode client ID to configured Figma servers", () =>
+    withLocation(
+      {
+        mcp: {
+          servers: {
+            figma: {
+              type: "remote",
+              url: "https://mcp.figma.com/mcp",
+              oauth: { scope: "mcp:connect" },
+            },
+          },
+        },
+      },
+      Effect.gen(function* () {
+        yield* ready()
+        const config = yield* Config.Service
+        expect(Config.latest(yield* config.entries(), "mcp")?.servers?.figma).toMatchObject({
+          oauth: { client_id: "3zVHNs9kINDDrk8loekLZV", scope: "mcp:connect" },
+        })
+      }),
+    ),
+  )
+
+  it.live("preserves an existing Figma client ID", () =>
+    withLocation(
+      {
+        mcp: {
+          servers: {
+            figma: {
+              type: "remote",
+              url: "https://mcp.figma.com/mcp",
+              oauth: { client_id: "configured-client-id" },
+            },
+          },
+        },
+      },
+      Effect.gen(function* () {
+        yield* ready()
+        const config = yield* Config.Service
+        expect(Config.latest(yield* config.entries(), "mcp")?.servers?.figma).toMatchObject({
+          oauth: { client_id: "configured-client-id" },
+        })
+      }),
+    ),
+  )
+
+  it.live("does not enable OAuth or modify non-Figma servers", () =>
+    withLocation(
+      {
+        mcp: {
+          servers: {
+            disabled: {
+              type: "remote",
+              url: "https://mcp.figma.com/mcp",
+              oauth: false,
+            },
+            other: {
+              type: "remote",
+              url: "https://mcp.example.com/mcp",
+            },
+          },
+        },
+      },
+      Effect.gen(function* () {
+        yield* ready()
+        const config = yield* Config.Service
+        const servers = Config.latest(yield* config.entries(), "mcp")?.servers
+        expect(servers).toMatchObject({
+          disabled: { oauth: false },
+          other: { type: "remote", url: "https://mcp.example.com/mcp" },
+        })
+        expect(servers?.other).not.toHaveProperty("oauth")
+      }),
+    ),
+  )
 })
 
 const ready = Effect.fnUntraced(function* () {