feat(opencode): support non-interactive MCP add (#31054)
This commit is contained in:
@@ -437,13 +437,79 @@ async function addMcpToConfig(name: string, mcpConfig: ConfigMCPV1.Info, configP
|
||||
}
|
||||
|
||||
export const McpAddCommand = effectCmd({
|
||||
command: "add",
|
||||
command: "add [name]",
|
||||
describe: "add an MCP server",
|
||||
handler: Effect.fn("Cli.mcp.add")(function* () {
|
||||
builder: (yargs) =>
|
||||
yargs
|
||||
.positional("name", {
|
||||
describe: "name of the MCP server",
|
||||
type: "string",
|
||||
})
|
||||
.option("url", {
|
||||
describe: "URL for a remote MCP server",
|
||||
type: "string",
|
||||
})
|
||||
.option("env", {
|
||||
describe: "environment variable for a local MCP server (KEY=VALUE)",
|
||||
type: "string",
|
||||
array: true,
|
||||
})
|
||||
.option("header", {
|
||||
describe: "HTTP header for a remote MCP server (KEY=VALUE)",
|
||||
type: "string",
|
||||
array: true,
|
||||
}),
|
||||
handler: Effect.fn("Cli.mcp.add")(function* (args) {
|
||||
const maybeCtx = yield* InstanceRef
|
||||
if (!maybeCtx) return yield* Effect.die("InstanceRef not provided")
|
||||
const ctx = maybeCtx
|
||||
yield* Effect.promise(async () => {
|
||||
const command = args["--"] ?? []
|
||||
if (!args.name && (args.url || args.env?.length || args.header?.length || command.length)) {
|
||||
throw new Error("A server name is required for non-interactive MCP configuration")
|
||||
}
|
||||
if (args.name) {
|
||||
if (!!args.url === !!command.length) {
|
||||
throw new Error("Provide either --url <url> or a command after --")
|
||||
}
|
||||
if (args.url && !URL.canParse(args.url)) {
|
||||
throw new Error(`Invalid URL: ${args.url}`)
|
||||
}
|
||||
if (args.url && args.env?.length) {
|
||||
throw new Error("--env is only valid for local MCP servers")
|
||||
}
|
||||
if (command.length && args.header?.length) {
|
||||
throw new Error("--header is only valid for remote MCP servers")
|
||||
}
|
||||
|
||||
const entries = (values: string[], kind: string) =>
|
||||
Object.fromEntries(
|
||||
values.map((entry) => {
|
||||
const index = entry.indexOf("=")
|
||||
if (index < 1) throw new Error(`Invalid ${kind}: ${entry}. Expected KEY=VALUE`)
|
||||
return [entry.slice(0, index), entry.slice(index + 1)]
|
||||
}),
|
||||
)
|
||||
const environment = entries(args.env ?? [], "environment variable")
|
||||
const headers = entries(args.header ?? [], "HTTP header")
|
||||
const mcpConfig: ConfigMCPV1.Info = args.url
|
||||
? {
|
||||
type: "remote",
|
||||
url: args.url,
|
||||
...(Object.keys(headers).length ? { headers } : {}),
|
||||
}
|
||||
: {
|
||||
type: "local",
|
||||
command,
|
||||
...(Object.keys(environment).length ? { environment } : {}),
|
||||
}
|
||||
|
||||
const configPath = await resolveConfigPath(Global.Path.config, true)
|
||||
await addMcpToConfig(args.name, mcpConfig, configPath)
|
||||
prompts.log.success(`MCP server "${args.name}" added to ${configPath}`)
|
||||
return
|
||||
}
|
||||
|
||||
UI.empty()
|
||||
prompts.intro("Add MCP server")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user