From e6132fc6a43d1dde2093a251df0cdf8ee238a2ab Mon Sep 17 00:00:00 2001 From: Jay V Date: Wed, 29 Oct 2025 19:07:41 -0400 Subject: docs: enterprise --- packages/web/src/content/docs/enterprise.mdx | 122 ++++++++++++++++----------- 1 file changed, 74 insertions(+), 48 deletions(-) (limited to 'packages/web/src/content/docs') diff --git a/packages/web/src/content/docs/enterprise.mdx b/packages/web/src/content/docs/enterprise.mdx index 0899d4858..6bfc9b7a9 100644 --- a/packages/web/src/content/docs/enterprise.mdx +++ b/packages/web/src/content/docs/enterprise.mdx @@ -1,15 +1,18 @@ --- title: Enterprise -description: Using OpenCode in your organization. +description: Using OpenCode securely in your organization. --- import config from "../../../config.mjs" export const email = `mailto:${config.email}` -OpenCode does not store any of your code or context data. This makes it easy for -you to use OpenCode at your organization. +OpenCode Enterprise is for organizations that want to ensure that their code and data never leaves their infrastructure. It can do this by using a centralized config that integrates with your SSO and internal AI gateway. -To get started, we recommend: +:::note +OpenCode does not store any of your code or context data. +::: + +To get started with OpenCode Enterprise: 1. Do a trial internally with your team. 2. **Contact us** to discuss pricing and implementation options. @@ -18,13 +21,16 @@ To get started, we recommend: ## Trial -Since OpenCode is open source and does not store any of your code or context data, your developers can simply [get started](/docs/) and carry out a trial. +OpenCode is open source and does not store any of your code or context data, so your developers can simply [get started](/docs/) and carry out a trial. --- ### Data handling -**opencode does not store your code or context data.** All processing happens locally or through direct API calls to your AI provider. +**OpenCode does not store your code or context data.** All processing happens locally or through direct API calls to your AI provider. + +This means that as long as you are using a provider you trust, or an internal +AI gateway, you can use OpenCode securely. The only caveat here is the optional `/share` feature. @@ -32,7 +38,7 @@ The only caveat here is the optional `/share` feature. #### Sharing conversations -If a user enables the `/share` feature, the conversation and the data associated with it are sent to the service we use to host these shares pages at opencode.ai. +If a user enables the `/share` feature, the conversation and the data associated with it are sent to the service we use to host these share pages at opencode.ai. The data is currently served through our CDN's edge network, and is cached on the edge near your users. @@ -51,68 +57,93 @@ We recommend you disable this for your trial. ### Code ownership -**You own all code produced by opencode.** There are no licensing restrictions or ownership claims. +**You own all code produced by OpenCode.** There are no licensing restrictions or ownership claims. --- -## FAQ +## Pricing -
-What is OpenCode Enterprise? +We use a per-seat model for OpenCode Enterprise. If you have your own LLM gateway, we do not charge for tokens used. For further details about pricing and implementation options, **contact us**. + +--- -OpenCode Enterprise provides self-hosted deployment options with enhanced security, SSO integration, and dedicated support for organizations that need to maintain full control over their development environment. +## Deployment -
+Once you have completed your trial and you are ready to use OpenCode at +your organization, you can **contact us** to discuss +pricing and implementation options. -
-How does enterprise pricing work? +--- -Enterprise pricing is based on team size and deployment requirements. Contact us at {config.email} for a custom quote based on your organization's needs. +### Central Config -
+We can set up OpenCode to use a single central config for your entire organization. -
-What deployment options are available? +This centralized config can integrate with your SSO provider and ensures all users access only your internal AI gateway. -We offer cloud-hosted, on-premises, and air-gapped deployment options. Each includes SSO integration, private package registry support, and customizable security configurations. +--- -
+### SSO integration + +Through the central config, OpenCode can integrate with your organization's SSO provider for authentication. + +This allows OpenCode to obtain credentials for your internal AI gateway through your existing identity management system. + +--- + +### Internal AI gateway + +With the central config, OpenCode can also be configured to use only your internal AI gateway. + +You can also disable all other AI providers, ensuring all requests go through your organization's approved infrastructure. + +--- + +### Self-hosting + +While we recommend disabling the share pages to ensure your data never leaves +your organization, we can also help you self-host them on your infrastructure. + +This is currently on our roadmap. If you're interested, **let us know**. + +--- + +## FAQ
-Is my data secure with enterprise? +What is OpenCode Enterprise? -Yes. OpenCode does not store your code or context data. All processing happens locally or through direct API calls to your AI provider. Enterprise deployments add SSO protection and can be fully air-gapped for maximum security. +OpenCode Enterprise is for organizations that want to ensure that their code and data never leaves their infrastructure. It can do this by using a centralized config that integrates with your SSO and internal AI gateway.
-Can we integrate with existing tools? +How do I get started with OpenCode Enterprise? -Yes. OpenCode supports private npm registries, custom authentication providers, and can be integrated into your existing CI/CD pipelines and development workflows. +Simply start with an internal trial with your team. OpenCode by default does not store your code or context data, making it easy to get started. -
+Then **contact us** to discuss pricing and implementation options. ---- + -## Deployment +
+How does enterprise pricing work? -Once you have completed your trial and you are ready to self-host opencode at -your organization, you can **contact us** to discuss -pricing and implementation options. +We offer per-seat enterprise pricing. If you have your own LLM gateway, we do not charge for tokens used. For further details, **contact us** for a custom quote based on your organization's needs. ---- +
-### SSO +
+Is my data secure with OpenCode Enterprise? -SSO integration can be implemented for enterprise deployments after your trial. -This will allow your team's session data and shared conversations to be protected -by your enterprise's authentication system. +Yes. OpenCode does not store your code or context data. All processing happens locally or through direct API calls to your AI provider. With central config and SSO integration, your data remains secure within your organization's infrastructure. ---- +
-### Private NPM +
+Can we use our own private NPM registry? -opencode supports private npm registries through Bun's native `.npmrc` file support. If your organization uses a private registry, such as JFrog Artifactory, Nexus, or similar, ensure developers are authenticated before running opencode. +OpenCode supports private npm registries through Bun's native `.npmrc` file support. If your organization uses a private registry, such as JFrog Artifactory, Nexus, or similar, ensure developers are authenticated before running OpenCode. To set up authentication with your private registry: @@ -120,11 +151,11 @@ To set up authentication with your private registry: npm login --registry=https://your-company.jfrog.io/api/npm/npm-virtual/ ``` -This creates `~/.npmrc` with authentication details. opencode will automatically +This creates `~/.npmrc` with authentication details. OpenCode will automatically pick this up. :::caution -You must be logged into the private registry before running opencode. +You must be logged into the private registry before running OpenCode. ::: Alternatively, you can manually configure a `.npmrc` file: @@ -134,11 +165,6 @@ registry=https://your-company.jfrog.io/api/npm/npm-virtual/ //your-company.jfrog.io/api/npm/npm-virtual/:_authToken=${NPM_AUTH_TOKEN} ``` -Developers must be logged into the private registry before running opencode to ensure packages can be installed from your enterprise registry. - ---- +Developers must be logged into the private registry before running OpenCode to ensure packages can be installed from your enterprise registry. -### Self-hosting - -The share feature can be self-hosted and the share pages can be made accessible -only after the user has been authenticated. +
-- cgit v1.2.3 From 3ae75d70310347023f16a7d25156824e630fd9c0 Mon Sep 17 00:00:00 2001 From: Matt Gillard Date: Thu, 30 Oct 2025 17:25:24 +1100 Subject: add optional timeout field to mcp config to allow users to use responding servers (#3558) Co-authored-by: Matt Gillard Co-authored-by: opencode-agent[bot] Co-authored-by: rekram1-node --- packages/opencode/src/config/config.ts | 234 +++++++++++++++++++++----- packages/opencode/src/mcp/index.ts | 2 +- packages/web/src/content/docs/mcp-servers.mdx | 44 ++--- 3 files changed, 220 insertions(+), 60 deletions(-) (limited to 'packages/web/src/content/docs') diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts index 83c518a68..12a5c1624 100644 --- a/packages/opencode/src/config/config.ts +++ b/packages/opencode/src/config/config.ts @@ -12,7 +12,11 @@ import { NamedError } from "../util/error" import matter from "gray-matter" import { Flag } from "../flag/flag" import { Auth } from "../auth" -import { type ParseError as JsoncParseError, parse as parseJsonc, printParseErrorCode } from "jsonc-parser" +import { + type ParseError as JsoncParseError, + parse as parseJsonc, + printParseErrorCode, +} from "jsonc-parser" import { Instance } from "../project/instance" import { LSPServer } from "../lsp/server" import { BunProc } from "@/bun" @@ -46,7 +50,10 @@ export namespace Config { if (value.type === "wellknown") { process.env[value.key] = value.token const wellknown = await fetch(`${key}/.well-known/opencode`).then((x) => x.json()) - result = mergeDeep(result, await load(JSON.stringify(wellknown.config ?? {}), process.cwd())) + result = mergeDeep( + result, + await load(JSON.stringify(wellknown.config ?? {}), process.cwd()), + ) } } @@ -57,7 +64,11 @@ export namespace Config { const directories = [ Global.Path.config, ...(await Array.fromAsync( - Filesystem.up({ targets: [".opencode"], start: Instance.directory, stop: Instance.worktree }), + Filesystem.up({ + targets: [".opencode"], + start: Instance.directory, + stop: Instance.worktree, + }), )), ] @@ -153,10 +164,18 @@ export namespace Config { const gitignore = path.join(dir, ".gitignore") const hasGitIgnore = await Bun.file(gitignore).exists() - if (!hasGitIgnore) await Bun.write(gitignore, ["node_modules", "package.json", "bun.lock", ".gitignore"].join("\n")) + if (!hasGitIgnore) + await Bun.write( + gitignore, + ["node_modules", "package.json", "bun.lock", ".gitignore"].join("\n"), + ) await BunProc.run( - ["add", "@opencode-ai/plugin@" + (Installation.isLocal() ? "latest" : Installation.VERSION), "--exact"], + [ + "add", + "@opencode-ai/plugin@" + (Installation.isLocal() ? "latest" : Installation.VERSION), + "--exact", + ], { cwd: dir, }, @@ -166,7 +185,12 @@ export namespace Config { const COMMAND_GLOB = new Bun.Glob("command/**/*.md") async function loadCommand(dir: string) { const result: Record = {} - for await (const item of COMMAND_GLOB.scan({ absolute: true, followSymlinks: true, dot: true, cwd: dir })) { + for await (const item of COMMAND_GLOB.scan({ + absolute: true, + followSymlinks: true, + dot: true, + cwd: dir, + })) { const content = await Bun.file(item).text() const md = matter(content) if (!md.data) continue @@ -201,7 +225,12 @@ export namespace Config { async function loadAgent(dir: string) { const result: Record = {} - for await (const item of AGENT_GLOB.scan({ absolute: true, followSymlinks: true, dot: true, cwd: dir })) { + for await (const item of AGENT_GLOB.scan({ + absolute: true, + followSymlinks: true, + dot: true, + cwd: dir, + })) { const content = await Bun.file(item).text() const md = matter(content) if (!md.data) continue @@ -239,7 +268,12 @@ export namespace Config { const MODE_GLOB = new Bun.Glob("mode/*.md") async function loadMode(dir: string) { const result: Record = {} - for await (const item of MODE_GLOB.scan({ absolute: true, followSymlinks: true, dot: true, cwd: dir })) { + for await (const item of MODE_GLOB.scan({ + absolute: true, + followSymlinks: true, + dot: true, + cwd: dir, + })) { const content = await Bun.file(item).text() const md = matter(content) if (!md.data) continue @@ -265,7 +299,12 @@ export namespace Config { async function loadPlugin(dir: string) { const plugins: string[] = [] - for await (const item of PLUGIN_GLOB.scan({ absolute: true, followSymlinks: true, dot: true, cwd: dir })) { + for await (const item of PLUGIN_GLOB.scan({ + absolute: true, + followSymlinks: true, + dot: true, + cwd: dir, + })) { plugins.push("file://" + item) } return plugins @@ -280,6 +319,14 @@ export namespace Config { .optional() .describe("Environment variables to set when running the MCP server"), enabled: z.boolean().optional().describe("Enable or disable the MCP server on startup"), + timeout: z + .number() + .int() + .positive() + .optional() + .describe( + "Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds) if not specified.", + ), }) .strict() .meta({ @@ -291,7 +338,18 @@ export namespace Config { type: z.literal("remote").describe("Type of MCP server connection"), url: z.string().describe("URL of the remote MCP server"), enabled: z.boolean().optional().describe("Enable or disable the MCP server on startup"), - headers: z.record(z.string(), z.string()).optional().describe("Headers to send with the request"), + headers: z + .record(z.string(), z.string()) + .optional() + .describe("Headers to send with the request"), + timeout: z + .number() + .int() + .positive() + .optional() + .describe( + "Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds) if not specified.", + ), }) .strict() .meta({ @@ -339,72 +397,148 @@ export namespace Config { export const Keybinds = z .object({ - leader: z.string().optional().default("ctrl+x").describe("Leader key for keybind combinations"), + leader: z + .string() + .optional() + .default("ctrl+x") + .describe("Leader key for keybind combinations"), app_help: z.string().optional().default("h").describe("Show help dialog"), app_exit: z.string().optional().default("ctrl+c,q").describe("Exit the application"), editor_open: z.string().optional().default("e").describe("Open external editor"), theme_list: z.string().optional().default("t").describe("List available themes"), project_init: z.string().optional().default("i").describe("Create/update AGENTS.md"), tool_details: z.string().optional().default("d").describe("Toggle tool details"), - thinking_blocks: z.string().optional().default("b").describe("Toggle thinking blocks"), - session_export: z.string().optional().default("x").describe("Export session to editor"), + thinking_blocks: z + .string() + .optional() + .default("b") + .describe("Toggle thinking blocks"), + session_export: z + .string() + .optional() + .default("x") + .describe("Export session to editor"), session_new: z.string().optional().default("n").describe("Create a new session"), session_list: z.string().optional().default("l").describe("List all sessions"), - session_timeline: z.string().optional().default("g").describe("Show session timeline"), + session_timeline: z + .string() + .optional() + .default("g") + .describe("Show session timeline"), session_share: z.string().optional().default("s").describe("Share current session"), session_unshare: z.string().optional().default("none").describe("Unshare current session"), session_interrupt: z.string().optional().default("esc").describe("Interrupt current session"), session_compact: z.string().optional().default("c").describe("Compact the session"), - session_child_cycle: z.string().optional().default("ctrl+right").describe("Cycle to next child session"), + session_child_cycle: z + .string() + .optional() + .default("ctrl+right") + .describe("Cycle to next child session"), session_child_cycle_reverse: z .string() .optional() .default("ctrl+left") .describe("Cycle to previous child session"), - messages_page_up: z.string().optional().default("pgup").describe("Scroll messages up by one page"), - messages_page_down: z.string().optional().default("pgdown").describe("Scroll messages down by one page"), - messages_half_page_up: z.string().optional().default("ctrl+alt+u").describe("Scroll messages up by half page"), + messages_page_up: z + .string() + .optional() + .default("pgup") + .describe("Scroll messages up by one page"), + messages_page_down: z + .string() + .optional() + .default("pgdown") + .describe("Scroll messages down by one page"), + messages_half_page_up: z + .string() + .optional() + .default("ctrl+alt+u") + .describe("Scroll messages up by half page"), messages_half_page_down: z .string() .optional() .default("ctrl+alt+d") .describe("Scroll messages down by half page"), messages_first: z.string().optional().default("ctrl+g").describe("Navigate to first message"), - messages_last: z.string().optional().default("ctrl+alt+g").describe("Navigate to last message"), + messages_last: z + .string() + .optional() + .default("ctrl+alt+g") + .describe("Navigate to last message"), messages_copy: z.string().optional().default("y").describe("Copy message"), messages_undo: z.string().optional().default("u").describe("Undo message"), messages_redo: z.string().optional().default("r").describe("Redo message"), model_list: z.string().optional().default("m").describe("List available models"), model_cycle_recent: z.string().optional().default("f2").describe("Next recent model"), - model_cycle_recent_reverse: z.string().optional().default("shift+f2").describe("Previous recent model"), + model_cycle_recent_reverse: z + .string() + .optional() + .default("shift+f2") + .describe("Previous recent model"), agent_list: z.string().optional().default("a").describe("List agents"), agent_cycle: z.string().optional().default("tab").describe("Next agent"), agent_cycle_reverse: z.string().optional().default("shift+tab").describe("Previous agent"), input_clear: z.string().optional().default("ctrl+c").describe("Clear input field"), input_paste: z.string().optional().default("ctrl+v").describe("Paste from clipboard"), input_submit: z.string().optional().default("enter").describe("Submit input"), - input_newline: z.string().optional().default("shift+enter,ctrl+j").describe("Insert newline in input"), + input_newline: z + .string() + .optional() + .default("shift+enter,ctrl+j") + .describe("Insert newline in input"), // Deprecated commands - switch_mode: z.string().optional().default("none").describe("@deprecated use agent_cycle. Next mode"), + switch_mode: z + .string() + .optional() + .default("none") + .describe("@deprecated use agent_cycle. Next mode"), switch_mode_reverse: z .string() .optional() .default("none") .describe("@deprecated use agent_cycle_reverse. Previous mode"), - switch_agent: z.string().optional().default("tab").describe("@deprecated use agent_cycle. Next agent"), + switch_agent: z + .string() + .optional() + .default("tab") + .describe("@deprecated use agent_cycle. Next agent"), switch_agent_reverse: z .string() .optional() .default("shift+tab") .describe("@deprecated use agent_cycle_reverse. Previous agent"), - file_list: z.string().optional().default("none").describe("@deprecated Currently not available. List files"), + file_list: z + .string() + .optional() + .default("none") + .describe("@deprecated Currently not available. List files"), file_close: z.string().optional().default("none").describe("@deprecated Close file"), file_search: z.string().optional().default("none").describe("@deprecated Search file"), - file_diff_toggle: z.string().optional().default("none").describe("@deprecated Split/unified diff"), - messages_previous: z.string().optional().default("none").describe("@deprecated Navigate to previous message"), - messages_next: z.string().optional().default("none").describe("@deprecated Navigate to next message"), - messages_layout_toggle: z.string().optional().default("none").describe("@deprecated Toggle layout"), - messages_revert: z.string().optional().default("none").describe("@deprecated use messages_undo. Revert message"), + file_diff_toggle: z + .string() + .optional() + .default("none") + .describe("@deprecated Split/unified diff"), + messages_previous: z + .string() + .optional() + .default("none") + .describe("@deprecated Navigate to previous message"), + messages_next: z + .string() + .optional() + .default("none") + .describe("@deprecated Navigate to next message"), + messages_layout_toggle: z + .string() + .optional() + .default("none") + .describe("@deprecated Toggle layout"), + messages_revert: z + .string() + .optional() + .default("none") + .describe("@deprecated use messages_undo. Revert message"), }) .strict() .meta({ @@ -446,13 +580,23 @@ export namespace Config { autoshare: z .boolean() .optional() - .describe("@deprecated Use 'share' field instead. Share newly created sessions automatically"), + .describe( + "@deprecated Use 'share' field instead. Share newly created sessions automatically", + ), autoupdate: z.boolean().optional().describe("Automatically update to the latest version"), - disabled_providers: z.array(z.string()).optional().describe("Disable providers that are loaded automatically"), - model: z.string().describe("Model to use in the format of provider/model, eg anthropic/claude-2").optional(), + disabled_providers: z + .array(z.string()) + .optional() + .describe("Disable providers that are loaded automatically"), + model: z + .string() + .describe("Model to use in the format of provider/model, eg anthropic/claude-2") + .optional(), small_model: z .string() - .describe("Small model to use for tasks like title generation in the format of provider/model") + .describe( + "Small model to use for tasks like title generation in the format of provider/model", + ) .optional(), username: z .string() @@ -508,7 +652,10 @@ export namespace Config { ) .optional() .describe("Custom provider configurations and model overrides"), - mcp: z.record(z.string(), Mcp).optional().describe("MCP (Model Context Protocol) server configurations"), + mcp: z + .record(z.string(), Mcp) + .optional() + .describe("MCP (Model Context Protocol) server configurations"), formatter: z .record( z.string(), @@ -552,7 +699,10 @@ export namespace Config { error: "For custom LSP servers, 'extensions' array is required.", }, ), - instructions: z.array(z.string()).optional().describe("Additional instruction files or patterns to include"), + instructions: z + .array(z.string()) + .optional() + .describe("Additional instruction files or patterns to include"), layout: Layout.optional().describe("@deprecated Always uses stretch layout."), permission: z .object({ @@ -586,7 +736,10 @@ export namespace Config { .optional(), }) .optional(), - chatMaxRetries: z.number().optional().describe("Number of retries for chat completions on failure"), + chatMaxRetries: z + .number() + .optional() + .describe("Number of retries for chat completions on failure"), disable_paste_summary: z.boolean().optional(), }) .optional(), @@ -616,7 +769,10 @@ export namespace Config { if (provider && model) result.model = `${provider}/${model}` result["$schema"] = "https://opencode.ai/config.json" result = mergeDeep(result, rest) - await Bun.write(path.join(Global.Path.config, "config.json"), JSON.stringify(result, null, 2)) + await Bun.write( + path.join(Global.Path.config, "config.json"), + JSON.stringify(result, null, 2), + ) await fs.unlink(path.join(Global.Path.config, "config")) }) .catch(() => {}) @@ -655,7 +811,9 @@ export namespace Config { if (filePath.startsWith("~/")) { filePath = path.join(os.homedir(), filePath.slice(2)) } - const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(configDir, filePath) + const resolvedPath = path.isAbsolute(filePath) + ? filePath + : path.resolve(configDir, filePath) const fileContent = ( await Bun.file(resolvedPath) .text() diff --git a/packages/opencode/src/mcp/index.ts b/packages/opencode/src/mcp/index.ts index 988426b13..0df6a5a72 100644 --- a/packages/opencode/src/mcp/index.ts +++ b/packages/opencode/src/mcp/index.ts @@ -167,7 +167,7 @@ export namespace MCP { return } - const result = await withTimeout(mcpClient.tools(), 5000).catch(() => {}) + const result = await withTimeout(mcpClient.tools(), mcp.timeout ?? 5000).catch(() => { }) if (!result) { log.warn("mcp client verification failed, dropping client", { name }) return diff --git a/packages/web/src/content/docs/mcp-servers.mdx b/packages/web/src/content/docs/mcp-servers.mdx index ab87449e0..132537b05 100644 --- a/packages/web/src/content/docs/mcp-servers.mdx +++ b/packages/web/src/content/docs/mcp-servers.mdx @@ -45,12 +45,12 @@ with a unique name. You can refer to that MCP by name when prompting the LLM. "mcp": { "name-of-mcp-server": { // ... - "enabled": true + "enabled": true, }, "name-of-other-mcp-server": { // ... - } - } + }, + }, } ``` @@ -72,10 +72,10 @@ Add local MCP servers using `type` to `"local"` within the MCP object. "command": ["npx", "-y", "my-mcp-command"], "enabled": true, "environment": { - "MY_ENV_VAR": "my_env_var_value" - } - } - } + "MY_ENV_VAR": "my_env_var_value", + }, + }, + }, } ``` @@ -91,8 +91,8 @@ For example, here's how I can add the test "mcp_everything": { "type": "local", "command": ["npx", "-y", "@modelcontextprotocol/server-everything"], - } - } + }, + }, } ``` @@ -106,12 +106,13 @@ use the mcp_everything tool to add the number 3 and 4 Here are all the options for configuring a local MCP server. -| Option | Type | Required | Description | -| ------------- | ------- | -------- | ----------------------------------------------------- | -| `type` | String | Y | Type of MCP server connection, must be `"local"`. | -| `command` | Array | Y | Command and arguments to run the MCP server. | -| `environment` | Object | | Environment variables to set when running the server. | -| `enabled` | Boolean | | Enable or disable the MCP server on startup. | +| Option | Type | Required | Description | +| ------------- | ------- | -------- | ----------------------------------------------------------------------------------- | +| `type` | String | Y | Type of MCP server connection, must be `"local"`. | +| `command` | Array | Y | Command and arguments to run the MCP server. | +| `environment` | Object | | Environment variables to set when running the server. | +| `enabled` | Boolean | | Enable or disable the MCP server on startup. | +| `timeout` | Number | | Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds). | --- @@ -139,12 +140,13 @@ Here the `url` is the URL of the remote MCP server and with the `headers` option #### Options -| Option | Type | Required | Description | -| --------- | ------- | -------- | -------------------------------------------------- | -| `type` | String | Y | Type of MCP server connection, must be `"remote"`. | -| `url` | String | Y | URL of the remote MCP server. | -| `enabled` | Boolean | | Enable or disable the MCP server on startup. | -| `headers` | Object | | Headers to send with the request. | +| Option | Type | Required | Description | +| --------- | ------- | -------- | ----------------------------------------------------------------------------------- | +| `type` | String | Y | Type of MCP server connection, must be `"remote"`. | +| `url` | String | Y | URL of the remote MCP server. | +| `enabled` | Boolean | | Enable or disable the MCP server on startup. | +| `headers` | Object | | Headers to send with the request. | +| `timeout` | Number | | Timeout in ms for fetching tools from the MCP server. Defaults to 5000 (5 seconds). | --- -- cgit v1.2.3