mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-09 15:58:30 +00:00
feat(web): add hosted and self-host MCP client configs
This commit is contained in:
parent
6da1dd8f86
commit
6b204a2f8c
4 changed files with 350 additions and 154 deletions
|
|
@ -50,16 +50,13 @@ export const metadata: Metadata = {
|
|||
},
|
||||
};
|
||||
|
||||
/* Mirrors surfsense_mcp/README.md: the real Cursor config. */
|
||||
/* The hosted Cursor config; mirrors lib/mcp/clients.ts. */
|
||||
const CURSOR_CONFIG = `{
|
||||
"mcpServers": {
|
||||
"surfsense": {
|
||||
"command": "uv",
|
||||
"args": ["run", "--directory", ".../surfsense_mcp",
|
||||
"python", "-m", "surfsense_mcp"],
|
||||
"env": {
|
||||
"SURFSENSE_BASE_URL": "https://api.surfsense.com",
|
||||
"SURFSENSE_API_KEY": "ss_pat_..."
|
||||
"url": "https://mcp.surfsense.com/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ss_pat_..."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -76,7 +73,7 @@ const STEPS = [
|
|||
icon: TerminalSquare,
|
||||
title: "Add the server to your client",
|
||||
description:
|
||||
"Drop the config into Cursor's mcp.json, run claude mcp add for Claude Code, or paste it into Claude Desktop. Point it at the cloud or your own self-hosted instance.",
|
||||
"Point your client at https://mcp.surfsense.com/mcp with your key in an Authorization header — the hosted config for Cursor, Claude Code, and others is one paste. Prefer stdio? Switch to Self-host and run it against your own backend.",
|
||||
},
|
||||
{
|
||||
icon: Server,
|
||||
|
|
@ -135,7 +132,7 @@ const FAQ: FaqItem[] = [
|
|||
{
|
||||
question: "Which MCP clients does it work with?",
|
||||
answer:
|
||||
"Any MCP client that supports stdio servers. Claude Code, Codex, OpenCode, Cursor, Claude Desktop, VS Code, Windsurf, and Gemini CLI are documented with copy-paste configs on this page, and the same command works in custom agent harnesses built on the MCP SDK.",
|
||||
"Any MCP client that speaks remote (streamable HTTP) or stdio. Claude Code, Codex, OpenCode, Cursor, Claude Desktop, VS Code, Windsurf, and Gemini CLI all have copy-paste configs on this page — Hosted for the one-paste https://mcp.surfsense.com/mcp endpoint, or Self-host for stdio against your own backend.",
|
||||
},
|
||||
{
|
||||
question: "How is usage billed?",
|
||||
|
|
@ -278,9 +275,9 @@ export default function McpServerPage() {
|
|||
Step-by-step setup for every agent
|
||||
</h2>
|
||||
<p className="mt-3 max-w-2xl text-muted-foreground leading-relaxed">
|
||||
Pick your client, follow its two steps, and paste the config. Replace the placeholder
|
||||
path with your surfsense_mcp checkout and the key with one from API Playground → API
|
||||
Keys — or grab a pre-filled config from the playground itself.
|
||||
Pick your client, choose <strong>Hosted</strong> or <strong>Self-host</strong>, and
|
||||
paste the config. Replace the key with one from API Playground → API Keys — or grab a
|
||||
pre-filled config from the playground itself.
|
||||
</p>
|
||||
</Reveal>
|
||||
<Reveal>
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ function buildMcp({ mcpTool }: ApiSample): string {
|
|||
const config = {
|
||||
mcpServers: {
|
||||
surfsense: {
|
||||
url: "https://mcp.surfsense.com",
|
||||
url: "https://mcp.surfsense.com/mcp",
|
||||
headers: { Authorization: "Bearer ${SURFSENSE_API_KEY}" },
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import {
|
|||
DEFAULT_SERVER_DIR,
|
||||
MCP_CLIENTS,
|
||||
type McpSnippetOptions,
|
||||
type McpTransport,
|
||||
REMOTE_URL,
|
||||
} from "@/lib/mcp/clients";
|
||||
|
||||
function CopyButton({ text }: { text: string }) {
|
||||
|
|
@ -38,48 +40,82 @@ function CopyButton({ text }: { text: string }) {
|
|||
);
|
||||
}
|
||||
|
||||
const TRANSPORTS: { id: McpTransport; label: string; hint: string }[] = [
|
||||
{ id: "remote", label: "Hosted", hint: "mcp.surfsense.com — nothing to install" },
|
||||
{ id: "stdio", label: "Self-host", hint: "run the server against your own backend" },
|
||||
];
|
||||
|
||||
/**
|
||||
* Per-agent MCP setup instructions as tabs: pick a client, follow its steps,
|
||||
* copy its exact config. Used on the /mcp-server marketing page and in the
|
||||
* API playground; `options` fills in real values where the caller has them.
|
||||
* Per-agent MCP setup instructions as tabs: pick a client, then Hosted or
|
||||
* Self-host, and copy its exact config. Used on the /mcp-server marketing page
|
||||
* and in the API playground; `options` fills in real values where the caller
|
||||
* has them.
|
||||
*/
|
||||
export function AgentSetupTabs({ options }: { options?: Partial<McpSnippetOptions> }) {
|
||||
const [transport, setTransport] = useState<McpTransport>("remote");
|
||||
|
||||
const resolved: McpSnippetOptions = {
|
||||
baseUrl: options?.baseUrl || "https://api.surfsense.com",
|
||||
remoteUrl: options?.remoteUrl || REMOTE_URL,
|
||||
apiKey: options?.apiKey || API_KEY_PLACEHOLDER,
|
||||
baseUrl: options?.baseUrl || "https://api.surfsense.com",
|
||||
serverDir: options?.serverDir || DEFAULT_SERVER_DIR,
|
||||
};
|
||||
|
||||
const active = TRANSPORTS.find((t) => t.id === transport) ?? TRANSPORTS[0];
|
||||
|
||||
return (
|
||||
<Tabs defaultValue={MCP_CLIENTS[0].id} className="w-full">
|
||||
<TabsList className="flex h-auto flex-wrap justify-start gap-1">
|
||||
{MCP_CLIENTS.map((client) => (
|
||||
<TabsTrigger key={client.id} value={client.id}>
|
||||
{client.label}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
{MCP_CLIENTS.map((client) => {
|
||||
const config = client.buildConfig(resolved);
|
||||
return (
|
||||
<TabsContent key={client.id} value={client.id} className="space-y-3">
|
||||
<ol className="list-decimal space-y-1 pl-5 text-sm leading-relaxed text-muted-foreground">
|
||||
{client.steps.map((step) => (
|
||||
<li key={step}>{step}</li>
|
||||
))}
|
||||
</ol>
|
||||
<div>
|
||||
<p className="mb-1.5 font-mono text-xs text-muted-foreground">{client.configFile}</p>
|
||||
<div className="relative">
|
||||
<CopyButton text={config} />
|
||||
<pre className="overflow-x-auto rounded-lg border bg-muted/50 p-4 font-mono text-xs leading-relaxed">
|
||||
<code>{config}</code>
|
||||
</pre>
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<div className="inline-flex rounded-lg border bg-muted/40 p-0.5">
|
||||
{TRANSPORTS.map((t) => (
|
||||
<Button
|
||||
key={t.id}
|
||||
variant={t.id === transport ? "secondary" : "ghost"}
|
||||
size="sm"
|
||||
className="h-7 px-3 text-xs"
|
||||
onClick={() => setTransport(t.id)}
|
||||
aria-pressed={t.id === transport}
|
||||
>
|
||||
{t.label}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground">{active.hint}</span>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue={MCP_CLIENTS[0].id} className="w-full">
|
||||
<TabsList className="flex h-auto flex-wrap justify-start gap-1">
|
||||
{MCP_CLIENTS.map((client) => (
|
||||
<TabsTrigger key={client.id} value={client.id}>
|
||||
{client.label}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
{MCP_CLIENTS.map((client) => {
|
||||
const snippet = client[transport];
|
||||
const config = snippet.build(resolved);
|
||||
return (
|
||||
<TabsContent key={client.id} value={client.id} className="space-y-3">
|
||||
<ol className="list-decimal space-y-1 pl-5 text-sm leading-relaxed text-muted-foreground">
|
||||
{snippet.steps.map((step) => (
|
||||
<li key={step}>{step}</li>
|
||||
))}
|
||||
</ol>
|
||||
<div>
|
||||
<p className="mb-1.5 font-mono text-xs text-muted-foreground">
|
||||
{snippet.configFile}
|
||||
</p>
|
||||
<div className="relative">
|
||||
<CopyButton text={config} />
|
||||
<pre className="overflow-x-auto rounded-lg border bg-muted/50 p-4 font-mono text-xs leading-relaxed">
|
||||
<code>{config}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
</TabsContent>
|
||||
);
|
||||
})}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,75 @@
|
|||
/**
|
||||
* MCP client setup catalog: one entry per popular agent, with the exact
|
||||
* config file, steps, and snippet needed to connect the SurfSense MCP server.
|
||||
* Shared by the marketing /mcp-server page and the API playground so the
|
||||
* instructions can never drift apart.
|
||||
* MCP client setup catalog: one entry per popular agent, each with a hosted
|
||||
* (remote) snippet and a self-host (stdio) snippet, plus the exact config file
|
||||
* and steps. Shared by the marketing /mcp-server page and the API playground so
|
||||
* the instructions can never drift apart.
|
||||
*
|
||||
* Remote snippets point at the hosted server and pass the key as a Bearer token;
|
||||
* every client's exact remote field is verified against its own docs (Windsurf
|
||||
* uses `serverUrl`, Gemini CLI `httpUrl`, VS Code needs `type: "http"`, OpenCode
|
||||
* `type: "remote"` + `oauth: false`, Codex needs the rmcp flag, and Claude
|
||||
* Desktop has no config-file remote support so it uses the `mcp-remote` bridge).
|
||||
*/
|
||||
|
||||
export type McpTransport = "remote" | "stdio";
|
||||
|
||||
export interface McpSnippetOptions {
|
||||
/** SurfSense backend URL the server should call. */
|
||||
baseUrl: string;
|
||||
/** Hosted MCP endpoint (Bearer-authenticated). */
|
||||
remoteUrl: string;
|
||||
/** API key value or placeholder to show in the snippet. */
|
||||
apiKey: string;
|
||||
/** Absolute path to the surfsense_mcp directory. */
|
||||
/** SurfSense backend URL a self-hosted server should call. */
|
||||
baseUrl: string;
|
||||
/** Absolute path to the surfsense_mcp directory (self-host). */
|
||||
serverDir: string;
|
||||
}
|
||||
|
||||
export interface McpSnippet {
|
||||
/** Where the snippet goes: a file path or "Terminal". */
|
||||
configFile: string;
|
||||
language: "json" | "toml" | "bash";
|
||||
steps: string[];
|
||||
build: (options: McpSnippetOptions) => string;
|
||||
}
|
||||
|
||||
export interface McpClient {
|
||||
id: string;
|
||||
label: string;
|
||||
/** Where the snippet goes: a file path or "Terminal". */
|
||||
configFile: string;
|
||||
language: "json" | "toml" | "bash";
|
||||
steps: string[];
|
||||
buildConfig: (options: McpSnippetOptions) => string;
|
||||
remote: McpSnippet;
|
||||
stdio: McpSnippet;
|
||||
}
|
||||
|
||||
export const REMOTE_URL = "https://mcp.surfsense.com/mcp";
|
||||
export const DEFAULT_SERVER_DIR = "/path/to/SurfSense/surfsense_mcp";
|
||||
export const API_KEY_PLACEHOLDER = "ss_pat_your_key_here";
|
||||
|
||||
function serverArgs(serverDir: string): string[] {
|
||||
return ["run", "--directory", serverDir, "python", "-m", "surfsense_mcp"];
|
||||
}
|
||||
|
||||
function json(value: unknown): string {
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
|
||||
/** The `mcpServers` JSON shape shared by Cursor, Claude Desktop, Windsurf, and Gemini CLI. */
|
||||
function standardJson({ baseUrl, apiKey, serverDir }: McpSnippetOptions): string {
|
||||
function bearer(apiKey: string): string {
|
||||
return `Bearer ${apiKey}`;
|
||||
}
|
||||
|
||||
function serverArgs(serverDir: string): string[] {
|
||||
return ["run", "--directory", serverDir, "python", "-m", "surfsense_mcp"];
|
||||
}
|
||||
|
||||
/** The `mcpServers` remote shape shared by Cursor, Windsurf, and Gemini CLI. */
|
||||
function remoteMcpServers(urlField: "url" | "serverUrl" | "httpUrl") {
|
||||
return ({ remoteUrl, apiKey }: McpSnippetOptions): string =>
|
||||
json({
|
||||
mcpServers: {
|
||||
surfsense: {
|
||||
[urlField]: remoteUrl,
|
||||
headers: { Authorization: bearer(apiKey) },
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** The `mcpServers` stdio shape shared by Cursor, Claude Desktop, Windsurf, Gemini CLI. */
|
||||
function stdioMcpServers({ baseUrl, apiKey, serverDir }: McpSnippetOptions): string {
|
||||
return json({
|
||||
mcpServers: {
|
||||
surfsense: {
|
||||
|
|
@ -52,125 +85,255 @@ export const MCP_CLIENTS: McpClient[] = [
|
|||
{
|
||||
id: "claude-code",
|
||||
label: "Claude Code",
|
||||
configFile: "Terminal",
|
||||
language: "bash",
|
||||
steps: [
|
||||
"Run this command in a terminal (any directory).",
|
||||
"Start Claude Code and run /mcp — surfsense should be listed as connected.",
|
||||
],
|
||||
buildConfig: ({ baseUrl, apiKey, serverDir }) =>
|
||||
[
|
||||
"claude mcp add surfsense \\",
|
||||
` -e SURFSENSE_BASE_URL=${baseUrl} \\`,
|
||||
` -e SURFSENSE_API_KEY=${apiKey} \\`,
|
||||
` -- uv run --directory ${serverDir} python -m surfsense_mcp`,
|
||||
].join("\n"),
|
||||
remote: {
|
||||
configFile: "Terminal",
|
||||
language: "bash",
|
||||
steps: [
|
||||
"Run this command in a terminal (any directory).",
|
||||
"Start Claude Code and run /mcp — surfsense should be listed as connected.",
|
||||
],
|
||||
build: ({ remoteUrl, apiKey }) =>
|
||||
[
|
||||
`claude mcp add --transport http surfsense ${remoteUrl} \\`,
|
||||
` --header "Authorization: ${bearer(apiKey)}"`,
|
||||
].join("\n"),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "Terminal",
|
||||
language: "bash",
|
||||
steps: [
|
||||
"Run this command in a terminal (any directory).",
|
||||
"Start Claude Code and run /mcp — surfsense should be listed as connected.",
|
||||
],
|
||||
build: ({ baseUrl, apiKey, serverDir }) =>
|
||||
[
|
||||
"claude mcp add surfsense \\",
|
||||
` -e SURFSENSE_BASE_URL=${baseUrl} \\`,
|
||||
` -e SURFSENSE_API_KEY=${apiKey} \\`,
|
||||
` -- uv run --directory ${serverDir} python -m surfsense_mcp`,
|
||||
].join("\n"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "codex",
|
||||
label: "Codex",
|
||||
configFile: "~/.codex/config.toml",
|
||||
language: "toml",
|
||||
steps: [
|
||||
"Add this to ~/.codex/config.toml (or run `codex mcp add surfsense -- uv run --directory <dir> python -m surfsense_mcp`).",
|
||||
"Restart Codex; `codex mcp list` should show surfsense.",
|
||||
],
|
||||
buildConfig: ({ baseUrl, apiKey, serverDir }) =>
|
||||
[
|
||||
"[mcp_servers.surfsense]",
|
||||
'command = "uv"',
|
||||
`args = ${JSON.stringify(serverArgs(serverDir))}`,
|
||||
"",
|
||||
"[mcp_servers.surfsense.env]",
|
||||
`SURFSENSE_BASE_URL = "${baseUrl}"`,
|
||||
`SURFSENSE_API_KEY = "${apiKey}"`,
|
||||
].join("\n"),
|
||||
remote: {
|
||||
configFile: "~/.codex/config.toml",
|
||||
language: "toml",
|
||||
steps: [
|
||||
"Add this to ~/.codex/config.toml. The rmcp flag must sit above every [mcp_servers.*] table.",
|
||||
"Restart Codex; `codex mcp list` should show surfsense.",
|
||||
],
|
||||
build: ({ remoteUrl, apiKey }) =>
|
||||
[
|
||||
"experimental_use_rmcp_client = true",
|
||||
"",
|
||||
"[mcp_servers.surfsense]",
|
||||
`url = "${remoteUrl}"`,
|
||||
"",
|
||||
"[mcp_servers.surfsense.http_headers]",
|
||||
`Authorization = "${bearer(apiKey)}"`,
|
||||
].join("\n"),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "~/.codex/config.toml",
|
||||
language: "toml",
|
||||
steps: [
|
||||
"Add this to ~/.codex/config.toml (or run `codex mcp add surfsense -- uv run --directory <dir> python -m surfsense_mcp`).",
|
||||
"Restart Codex; `codex mcp list` should show surfsense.",
|
||||
],
|
||||
build: ({ baseUrl, apiKey, serverDir }) =>
|
||||
[
|
||||
"[mcp_servers.surfsense]",
|
||||
'command = "uv"',
|
||||
`args = ${JSON.stringify(serverArgs(serverDir))}`,
|
||||
"",
|
||||
"[mcp_servers.surfsense.env]",
|
||||
`SURFSENSE_BASE_URL = "${baseUrl}"`,
|
||||
`SURFSENSE_API_KEY = "${apiKey}"`,
|
||||
].join("\n"),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "opencode",
|
||||
label: "OpenCode",
|
||||
configFile: "opencode.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to opencode.json in your project root (or ~/.config/opencode/opencode.json for all projects).",
|
||||
"Note OpenCode's format: the key is `mcp`, the command is one array, and env vars go under `environment`.",
|
||||
],
|
||||
buildConfig: ({ baseUrl, apiKey, serverDir }) =>
|
||||
json({
|
||||
$schema: "https://opencode.ai/config.json",
|
||||
mcp: {
|
||||
surfsense: {
|
||||
type: "local",
|
||||
command: ["uv", ...serverArgs(serverDir)],
|
||||
enabled: true,
|
||||
environment: { SURFSENSE_BASE_URL: baseUrl, SURFSENSE_API_KEY: apiKey },
|
||||
remote: {
|
||||
configFile: "opencode.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to opencode.json in your project root (or ~/.config/opencode/opencode.json for all projects).",
|
||||
"`oauth: false` tells OpenCode to use the Bearer key instead of starting an OAuth flow.",
|
||||
],
|
||||
build: ({ remoteUrl, apiKey }) =>
|
||||
json({
|
||||
$schema: "https://opencode.ai/config.json",
|
||||
mcp: {
|
||||
surfsense: {
|
||||
type: "remote",
|
||||
url: remoteUrl,
|
||||
enabled: true,
|
||||
oauth: false,
|
||||
headers: { Authorization: bearer(apiKey) },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "opencode.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to opencode.json in your project root (or ~/.config/opencode/opencode.json for all projects).",
|
||||
"Note OpenCode's format: the key is `mcp`, the command is one array, and env vars go under `environment`.",
|
||||
],
|
||||
build: ({ baseUrl, apiKey, serverDir }) =>
|
||||
json({
|
||||
$schema: "https://opencode.ai/config.json",
|
||||
mcp: {
|
||||
surfsense: {
|
||||
type: "local",
|
||||
command: ["uv", ...serverArgs(serverDir)],
|
||||
enabled: true,
|
||||
environment: { SURFSENSE_BASE_URL: baseUrl, SURFSENSE_API_KEY: apiKey },
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "cursor",
|
||||
label: "Cursor",
|
||||
configFile: "~/.cursor/mcp.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.cursor/mcp.json (global, keeps the key out of your repo) or a project's .cursor/mcp.json.",
|
||||
"Refresh the server in Cursor Settings → MCP; its 18 tools should appear.",
|
||||
],
|
||||
buildConfig: standardJson,
|
||||
remote: {
|
||||
configFile: "~/.cursor/mcp.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.cursor/mcp.json (global, keeps the key out of your repo) or a project's .cursor/mcp.json.",
|
||||
"Refresh the server in Cursor Settings → MCP; its 18 tools should appear.",
|
||||
],
|
||||
build: remoteMcpServers("url"),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "~/.cursor/mcp.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.cursor/mcp.json (global, keeps the key out of your repo) or a project's .cursor/mcp.json.",
|
||||
"Refresh the server in Cursor Settings → MCP; its 18 tools should appear.",
|
||||
],
|
||||
build: stdioMcpServers,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "claude-desktop",
|
||||
label: "Claude Desktop",
|
||||
configFile: "claude_desktop_config.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Open Settings → Developer → Edit Config to reach claude_desktop_config.json and add this.",
|
||||
"Restart Claude Desktop; surfsense appears under the tools icon.",
|
||||
],
|
||||
buildConfig: standardJson,
|
||||
remote: {
|
||||
configFile: "claude_desktop_config.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Claude Desktop can't take a remote URL directly, so this uses the mcp-remote bridge (needs Node 18+).",
|
||||
"Open Settings → Developer → Edit Config, add this, and restart Claude Desktop.",
|
||||
],
|
||||
build: ({ remoteUrl, apiKey }) =>
|
||||
json({
|
||||
mcpServers: {
|
||||
surfsense: {
|
||||
command: "npx",
|
||||
args: ["-y", "mcp-remote", remoteUrl, "--header", `Authorization: ${bearer(apiKey)}`],
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "claude_desktop_config.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Open Settings → Developer → Edit Config to reach claude_desktop_config.json and add this.",
|
||||
"Restart Claude Desktop; surfsense appears under the tools icon.",
|
||||
],
|
||||
build: stdioMcpServers,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "vscode",
|
||||
label: "VS Code",
|
||||
configFile: ".vscode/mcp.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to .vscode/mcp.json in your workspace (or run the MCP: Add Server command).",
|
||||
"Open Copilot Chat in agent mode and click the tools icon to confirm surfsense is loaded.",
|
||||
],
|
||||
buildConfig: ({ baseUrl, apiKey, serverDir }) =>
|
||||
json({
|
||||
servers: {
|
||||
surfsense: {
|
||||
type: "stdio",
|
||||
command: "uv",
|
||||
args: serverArgs(serverDir),
|
||||
env: { SURFSENSE_BASE_URL: baseUrl, SURFSENSE_API_KEY: apiKey },
|
||||
remote: {
|
||||
configFile: ".vscode/mcp.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to .vscode/mcp.json in your workspace (or run the MCP: Add Server command).",
|
||||
"VS Code requires an explicit `type` field — `http` for the hosted server.",
|
||||
],
|
||||
build: ({ remoteUrl, apiKey }) =>
|
||||
json({
|
||||
servers: {
|
||||
surfsense: {
|
||||
type: "http",
|
||||
url: remoteUrl,
|
||||
headers: { Authorization: bearer(apiKey) },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
},
|
||||
stdio: {
|
||||
configFile: ".vscode/mcp.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to .vscode/mcp.json in your workspace (or run the MCP: Add Server command).",
|
||||
"Open Copilot Chat in agent mode and click the tools icon to confirm surfsense is loaded.",
|
||||
],
|
||||
build: ({ baseUrl, apiKey, serverDir }) =>
|
||||
json({
|
||||
servers: {
|
||||
surfsense: {
|
||||
type: "stdio",
|
||||
command: "uv",
|
||||
args: serverArgs(serverDir),
|
||||
env: { SURFSENSE_BASE_URL: baseUrl, SURFSENSE_API_KEY: apiKey },
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "windsurf",
|
||||
label: "Windsurf",
|
||||
configFile: "~/.codeium/windsurf/mcp_config.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.codeium/windsurf/mcp_config.json (or Windsurf Settings → Cascade → MCP Servers).",
|
||||
"Press the refresh button in the MCP panel to pick up the server.",
|
||||
],
|
||||
buildConfig: standardJson,
|
||||
remote: {
|
||||
configFile: "~/.codeium/windsurf/mcp_config.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.codeium/windsurf/mcp_config.json (or Windsurf Settings → Cascade → MCP Servers).",
|
||||
"Windsurf uses `serverUrl` (not `url`) for remote servers; press refresh in the MCP panel.",
|
||||
],
|
||||
build: remoteMcpServers("serverUrl"),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "~/.codeium/windsurf/mcp_config.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.codeium/windsurf/mcp_config.json (or Windsurf Settings → Cascade → MCP Servers).",
|
||||
"Press the refresh button in the MCP panel to pick up the server.",
|
||||
],
|
||||
build: stdioMcpServers,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "gemini-cli",
|
||||
label: "Gemini CLI",
|
||||
configFile: "~/.gemini/settings.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.gemini/settings.json (or .gemini/settings.json in a project).",
|
||||
"Run /mcp inside Gemini CLI to confirm the surfsense server and its tools.",
|
||||
],
|
||||
buildConfig: standardJson,
|
||||
remote: {
|
||||
configFile: "~/.gemini/settings.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.gemini/settings.json (or .gemini/settings.json in a project).",
|
||||
"Gemini CLI uses `httpUrl` for streamable-HTTP servers; run /mcp to confirm surfsense.",
|
||||
],
|
||||
build: remoteMcpServers("httpUrl"),
|
||||
},
|
||||
stdio: {
|
||||
configFile: "~/.gemini/settings.json",
|
||||
language: "json",
|
||||
steps: [
|
||||
"Add this to ~/.gemini/settings.json (or .gemini/settings.json in a project).",
|
||||
"Run /mcp inside Gemini CLI to confirm the surfsense server and its tools.",
|
||||
],
|
||||
build: stdioMcpServers,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue