fix(core): apply Figma OAuth config before startup
This commit is contained in:
parent
49be2b3a89
commit
d3bb1859e0
7 changed files with 68 additions and 127 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"$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",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ import { Integration } from "../integration"
|
|||
import { IntegrationConnection } from "../integration/connection"
|
||||
import { KeyedMutex } from "../effect/keyed-mutex"
|
||||
import { Location } from "../location"
|
||||
import { FigmaPlugin } from "../plugin/figma"
|
||||
import { waitForAbort } from "@opencode-ai/util/process"
|
||||
import { State } from "../state"
|
||||
import { MCPClient } from "./client"
|
||||
|
|
@ -194,6 +195,7 @@ export const layer = (options?: Options) => Layer.effect(
|
|||
const urlElicitations = new Map<string, Form.ID>()
|
||||
for (const entry of documents) {
|
||||
for (const [name, server] of Object.entries(entry.info.mcp?.servers ?? {})) {
|
||||
FigmaPlugin.apply(server)
|
||||
runtime.set(ServerName.make(name), {
|
||||
config: { ...server, timeout: { ...timeout, ...server.timeout } },
|
||||
status: { status: "pending" },
|
||||
|
|
@ -622,6 +624,7 @@ export const layer = (options?: Options) => Layer.effect(
|
|||
if (previous.integrationID) owned.delete(previous.integrationID)
|
||||
if (previous.registration) yield* previous.registration.dispose
|
||||
}
|
||||
FigmaPlugin.apply(config)
|
||||
const entry: ServerEntry = {
|
||||
config: { ...config, timeout: { ...timeout, ...config.timeout } },
|
||||
status: { status: "pending" },
|
||||
|
|
|
|||
|
|
@ -1,28 +1,17 @@
|
|||
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"
|
||||
|
||||
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 } })
|
||||
})
|
||||
}),
|
||||
})
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ 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"
|
||||
|
|
@ -127,7 +126,6 @@ export type InternalPlugin = Plugin<Requirements | Scope.Scope>
|
|||
|
||||
const pre = [
|
||||
WellKnownPlugin.Plugin,
|
||||
FigmaPlugin.Plugin,
|
||||
AgentPlugin.Plugin,
|
||||
CommandPlugin.Plugin,
|
||||
SkillPlugin.Plugin,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ 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"
|
||||
|
|
@ -260,81 +259,6 @@ 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* () {
|
||||
|
|
|
|||
47
packages/core/test/plugin/figma.test.ts
Normal file
47
packages/core/test/plugin/figma.test.ts
Normal 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()
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue