mcp.ts 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { cmd } from "./cmd"
  2. import { Client } from "@modelcontextprotocol/sdk/client/index.js"
  3. import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
  4. import * as prompts from "@clack/prompts"
  5. import { UI } from "../ui"
  6. export const McpCommand = cmd({
  7. command: "mcp",
  8. builder: (yargs) => yargs.command(McpAddCommand).demandCommand(),
  9. async handler() {},
  10. })
  11. export const McpAddCommand = cmd({
  12. command: "add",
  13. describe: "add an MCP server",
  14. async handler() {
  15. UI.empty()
  16. prompts.intro("Add MCP server")
  17. const name = await prompts.text({
  18. message: "Enter MCP server name",
  19. validate: (x) => (x && x.length > 0 ? undefined : "Required"),
  20. })
  21. if (prompts.isCancel(name)) throw new UI.CancelledError()
  22. const type = await prompts.select({
  23. message: "Select MCP server type",
  24. options: [
  25. {
  26. label: "Local",
  27. value: "local",
  28. hint: "Run a local command",
  29. },
  30. {
  31. label: "Remote",
  32. value: "remote",
  33. hint: "Connect to a remote URL",
  34. },
  35. ],
  36. })
  37. if (prompts.isCancel(type)) throw new UI.CancelledError()
  38. if (type === "local") {
  39. const command = await prompts.text({
  40. message: "Enter command to run",
  41. placeholder: "e.g., opencode x @modelcontextprotocol/server-filesystem",
  42. validate: (x) => (x && x.length > 0 ? undefined : "Required"),
  43. })
  44. if (prompts.isCancel(command)) throw new UI.CancelledError()
  45. prompts.log.info(`Local MCP server "${name}" configured with command: ${command}`)
  46. prompts.outro("MCP server added successfully")
  47. return
  48. }
  49. if (type === "remote") {
  50. const url = await prompts.text({
  51. message: "Enter MCP server URL",
  52. placeholder: "e.g., https://example.com/mcp",
  53. validate: (x) => {
  54. if (!x) return "Required"
  55. if (x.length === 0) return "Required"
  56. const isValid = URL.canParse(x)
  57. return isValid ? undefined : "Invalid URL"
  58. },
  59. })
  60. if (prompts.isCancel(url)) throw new UI.CancelledError()
  61. const client = new Client({
  62. name: "opencode",
  63. version: "1.0.0",
  64. })
  65. const transport = new StreamableHTTPClientTransport(new URL(url))
  66. await client.connect(transport)
  67. prompts.log.info(`Remote MCP server "${name}" configured with URL: ${url}`)
  68. }
  69. prompts.outro("MCP server added successfully")
  70. },
  71. })