Compare commits

...
5 changed files with 97 additions and 1 deletions
+6 -1
View File
@@ -12,7 +12,12 @@
"description": "Contains opencode logs and data",
},
},
"mcp": {},
"mcp": {
"figma": {
"type": "remote",
"url": "https://mcp.figma.com/mcp",
},
},
"tools": {
"github-triage": false,
"github-pr-search": false,
+37
View File
@@ -0,0 +1,37 @@
export * as FigmaPlugin from "./figma"
import { define } from "@opencode-ai/plugin/v2/effect/plugin"
import { Effect } from "effect"
import { Config } from "../config"
import { ConfigMCP } from "../config/mcp"
import { MCP } from "../mcp/index"
const CLIENT_ID = "3zVHNs9kINDDrk8loekLZV"
export function apply(server: typeof ConfigMCP.Server.Type) {
if (server.type !== "remote" || server.oauth === false) return server
if (!URL.canParse(server.url) || new URL(server.url).hostname !== "mcp.figma.com") return server
if (server.oauth?.client_id) return server
if (server.oauth) {
Object.assign(server.oauth, { client_id: CLIENT_ID })
return server
}
Object.assign(server, { oauth: { client_id: CLIENT_ID } })
return server
}
export const Plugin = define({
id: "opencode.figma",
effect: Effect.fn(function* () {
const config = yield* Config.Service
const mcp = yield* MCP.Service
const documents = (yield* config.entries()).filter((entry): entry is Config.Document => entry.type === "document")
for (const entry of documents) {
for (const [name, server] of Object.entries(entry.info.mcp?.servers ?? {})) {
if (server.type !== "remote" || !URL.canParse(server.url) || new URL(server.url).hostname !== "mcp.figma.com")
continue
yield* mcp.add(name, apply(server))
}
}
}),
})
+5
View File
@@ -24,6 +24,7 @@ import { Integration } from "../integration"
import { Location } from "../location"
import { LocationMutation } from "../location-mutation"
import { ModelsDev } from "../models-dev"
import { MCP } from "../mcp/index"
import { Npm } from "@opencode-ai/util/npm"
import { PermissionV2 } from "../permission"
import { Reference } from "../reference"
@@ -48,6 +49,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"
@@ -73,6 +75,7 @@ const services = Effect.fn("PluginInternal.services")(function* () {
const location = yield* Location.Service
const locationMutation = yield* LocationMutation.Service
const models = yield* ModelsDev.Service
const mcp = yield* MCP.Service
const npm = yield* Npm.Service
const permission = yield* PermissionV2.Service
const runtime = yield* PluginRuntime.Service
@@ -102,6 +105,7 @@ const services = Effect.fn("PluginInternal.services")(function* () {
Context.make(Location.Service, location),
Context.make(LocationMutation.Service, locationMutation),
Context.make(ModelsDev.Service, models),
Context.make(MCP.Service, mcp),
Context.make(Npm.Service, npm),
Context.make(PermissionV2.Service, permission),
Context.make(PluginRuntime.Service, runtime),
@@ -126,6 +130,7 @@ export type InternalPlugin = Plugin<Requirements | Scope.Scope>
const pre = [
WellKnownPlugin.Plugin,
FigmaPlugin.Plugin,
AgentPlugin.Plugin,
CommandPlugin.Plugin,
SkillPlugin.Plugin,
+2
View File
@@ -23,6 +23,7 @@ import { Integration } from "../integration"
import { Location } from "../location"
import { LocationMutation } from "../location-mutation"
import { ModelsDev } from "../models-dev"
import { MCP } from "../mcp/index"
import { Npm } from "@opencode-ai/util/npm"
import { PermissionV2 } from "../permission"
import { PluginV2 } from "../plugin"
@@ -292,6 +293,7 @@ export const node = makeLocationNode({
Location.node,
LocationMutation.node,
ModelsDev.node,
MCP.node,
Npm.node,
PermissionV2.node,
PluginRuntime.node,
+47
View File
@@ -0,0 +1,47 @@
import { describe, expect, test } from "bun:test"
import { ConfigMCP } from "@opencode-ai/core/config/mcp"
import { FigmaPlugin } from "@opencode-ai/core/plugin/figma"
describe("plugin.figma", () => {
test("adds the OpenCode client ID to configured Figma servers", () => {
const server = new ConfigMCP.Remote({
type: "remote",
url: "https://mcp.figma.com/mcp",
oauth: new ConfigMCP.OAuth({ scope: "mcp:connect" }),
})
FigmaPlugin.apply(server)
expect(server.oauth).toEqual({ client_id: "3zVHNs9kINDDrk8loekLZV", scope: "mcp:connect" })
})
test("preserves an existing client ID", () => {
const server = new ConfigMCP.Remote({
type: "remote",
url: "https://mcp.figma.com/mcp",
oauth: new ConfigMCP.OAuth({ client_id: "configured-client-id" }),
})
FigmaPlugin.apply(server)
expect(server.oauth).toEqual({ client_id: "configured-client-id" })
})
test("does not enable OAuth or modify non-Figma servers", () => {
const disabled = new ConfigMCP.Remote({
type: "remote",
url: "https://mcp.figma.com/mcp",
oauth: false,
})
const other = new ConfigMCP.Remote({
type: "remote",
url: "https://mcp.example.com/mcp",
})
FigmaPlugin.apply(disabled)
FigmaPlugin.apply(other)
expect(disabled.oauth).toBe(false)
expect(other.oauth).toBeUndefined()
})
})