← Bursar knowledge base

Install Bursar in your MCP client or agent

Blacksands Bursar gives each AI agent its own revocable certificate identity and brokers its access to your private services, so no agent holds a shared API key. This page shows how to add the Bursar MCP server (@blacksandscyber/mcp-server-bursar) to the clients and agent frameworks people use most. Every snippet registers the server under the name bursar and starts it with npx -y @blacksandscyber/mcp-server-bursar.

Checked against vendor documentation on 2026-10-05.

Where a client's documentation says it cannot run a local command, this page says so and points to the remote option, which is not available yet. Where a vendor documents something only partly, the section says what is and is not documented, and does not guess.

Before you start

  • Package version 0.7.0 or newer. Every snippet on this page needs @blacksandscyber/mcp-server-bursar 0.7.0 or newer. Earlier versions do not read the BURSAR_* variable names or the credential variables below, and with an earlier version npx -y @blacksandscyber/mcp-server-bursar can stop with "could not determine executable to run". npm view @blacksandscyber/mcp-server-bursar version shows the newest published version; if it shows an older one, or npx keeps an older copy, the snippets below will not work yet.
  • Node.js 18 or newer has to be on the PATH of the program that launches the server. Desktop apps on macOS often do not see a Node install that lives in a shell profile (nvm, fnm); if the server will not start, put the absolute path to npx in the command field.
  • The free tools need no account. With no credentials the server starts in free local mode: code scans, architecture atlases (downloaded to your machine) and deployment guidance all work immediately. A free install is any snippet below with its env block left out.
  • Connecting an account takes a setup token from your install email or from your Blacksands administrator. For Claude Code and Claude Desktop the simplest route is the install command on your install page: it redeems the token once and registers the server with your environment's endpoints already set. For any other client, pass the token as BURSAR_SETUP_TOKEN (SHIELD_SETUP_TOKEN is accepted as an older alias), together with the two endpoint variables in the next point. On first launch the server redeems the token once and stores your certificate bundle in ~/.blacksands/mcp-certs/; every later launch reuses that bundle and does not redeem the token again. A setup token is single-use and expires, so once the first start has worked you can remove the token from your configuration. Keep the authorizer endpoint.
  • Name your environment's endpoints in every snippet that carries a token. The package's built-in endpoints point at one particular environment. If your install link belongs to a different one, a token sent without your endpoints goes to the wrong place: the other environment's onboarding service receives it and refuses the redemption. Because the package cannot tell which environment you are in, every snippet below sets two more variables, shown as placeholders: BURSAR_SETUP_URL (the scheme and host of your install link, the part before /mcp-install/; the server reads it only when it redeems the token) and BURSAR_AUTHORIZER_URL (your environment's authorizer endpoint, which your administrator or Blacksands support can give you). The server does not store the authorizer endpoint in the certificate bundle and reads it on every launch, so BURSAR_AUTHORIZER_URL must stay in the configuration after the first start; without it, later launches use the built-in default. SHIELD_SETUP_URL and SHIELD_AUTHORIZER_URL are accepted as older aliases.
  • Keep the token out of files you commit. Where a client documents environment-variable references, the snippets below use a reference (${BURSAR_SETUP_TOKEN} or the client's own spelling) for the token and you export the variable in the shell that launches the client. Where a client does not document references, the snippet has a marked placeholder; put the real value only in a file that stays on your machine. The two endpoint variables are not secrets and are always placeholders.
  • A stable egress IP matters. Bursar sessions are bound to the source IP address of the caller. An agent that runs from a laptop on a fixed network, a fixed-IP server or a NAT gateway works; an agent whose outbound address changes between runs, or that shares an address pool with other customers, will lose its session.
  • One identity per home directory. The server keeps a single certificate bundle in ~/.blacksands/mcp-certs/ and redeems a setup token only when that directory holds no bundle. If a bundle is already there, a different setup token is not redeemed, nothing tells you so, and the server runs as the identity already stored. A second client on the same machine, given a second token, therefore still acts as the first identity and reaches the first identity's services. For a second identity on one machine, give that client its own home directory (a separate user account, container or HOME) or use credentials from environment variables. To replace the stored identity, move ~/.blacksands/mcp-certs aside first, so the next start redeems the new token.
  • No durable home directory? Hosted sandboxes, containers without a volume and CI runners lose ~/.blacksands/mcp-certs/ between runs, and a single-use token cannot be redeemed twice. Use credentials from environment variables instead.
  • If a client cannot pass an environment variable to the server, redeem the token once in a terminal: run BURSAR_SETUP_TOKEN=<your-setup-token> BURSAR_SETUP_URL=<your-setup-url> BURSAR_AUTHORIZER_URL=<your-authorizer-url> npx -y @blacksandscyber/mcp-server-bursar, wait for the Bootstrap complete log line (if it never appears and no error is shown, the machine already holds a bundle and the token was not used; see the previous bullet), stop it with Ctrl+C, then register the server with command and args only. The stored bundle is picked up from then on. The server still reads BURSAR_AUTHORIZER_URL on every launch and no bundle stores it, so a client that cannot set an environment variable has to carry it in the command itself. On macOS and Linux set command to env and args to ["BURSAR_AUTHORIZER_URL=<your-authorizer-url>", "npx", "-y", "@blacksandscyber/mcp-server-bursar"]; env sets the variable and then starts npx. On Windows point command at a small launcher script (a .cmd file) that sets the variable and then runs npx -y @blacksandscyber/mcp-server-bursar. If neither route is open to you, that client works only in the package's default environment: without the variable every later launch presents your certificate and auth password to the built-in authorizer, which belongs to one particular environment, and the account tools fail anywhere else.
  • First starts can be slow. A cold npx download plus the token redemption can pass the default start-up timeout of some clients. The sections raise the timeout where the client documents a setting for it.

At a glance

ClientRuns the local server today?Needs the remote endpoint?Where to register
Claude CodeYesNoclaude mcp add, or .mcp.json
Claude DesktopYesNoclaude_desktop_config.json, or the .dxt extension
CursorYes (IDE and CLI)No~/.cursor/mcp.json, .cursor/mcp.json
VS Code with GitHub CopilotYesNo.vscode/mcp.json
Devin Desktop / Devin LocalYesNodevin mcp add, ~/.config/devin/mcp_config.json
Codex CLI, Codex IDE extension, ChatGPT desktop appYesNo~/.codex/config.toml
Grok BuildYesNo~/.grok/config.toml
Gemini CLIYesNo~/.gemini/settings.json
Antigravity CLIYesNo~/.gemini/config/mcp_config.json
ClineYesNo~/.cline/data/settings/cline_mcp_settings.json
ZedYesNocontext_servers in settings.json
KiroYes (IDE and CLI)No~/.kiro/settings/mcp.json
JetBrains JunieYesNo~/.junie/mcp/mcp.json
Muse CodeYesNo~/.config/muse/settings.json
ContinueYesNo.continue/mcpServers/bursar.yaml
OpenClawYesNomcp.servers in ~/.openclaw/openclaw.json
OpenCodeYesNomcp in opencode.json
GooseYesNo~/.config/goose/config.yaml
LibreChatYes (self-hosted)Nolibrechat.yaml
Open WebUIOnly through the mcpo proxyNomcpo, then an OpenAPI tool server
OpenAI Agents SDK (Python, TypeScript)Yes (library)Noin code
LangChain / LangGraph, CrewAI, Vercel AI SDK, Mastra, Pydantic AI, LlamaIndexYes (library)Noin code
Grok BotNo (not documented by xAI)Yes (not available yet)a chat with the Bot
OpenAI dots / ChatGPTChatGPT only, through a private tunnel; dots unverifiedYes (not available yet)ChatGPT Plugins
Meta MuseNo (not documented by Meta)Yes (not available yet)a chat with Muse
xAI API remote MCP toolNoYes (not available yet)tools array of the request
OpenAI API remote MCP toolOnly through a private tunnelYes (not available yet)tools array of the request

Coding agents and IDEs

Claude Code

Add the server to your user configuration with one command. The --transport stdio option sits between --env and the name on purpose: --env would otherwise swallow the server name.

For the free local tools only:

claude mcp add bursar -- npx -y @blacksandscyber/mcp-server-bursar

To connect it to your account, replace the placeholders first (the install command on your install page does this for you). Take the free install out before adding the connected one: both are registered as bursar, and left in place Claude Code either refuses the second one or goes on starting the first. If Bursar is not added yet, the first command only reports that there is nothing to remove. It takes the free install out of the project it is run in: the free install command above has no --scope, so Claude Code keeps it for the project where you ran it. If you added the free install in several projects, run the remove command in each of them, or the free one goes on starting there.

claude mcp remove bursar
claude mcp add --scope user --env BURSAR_SETUP_TOKEN=<your-setup-token> --env BURSAR_SETUP_URL=<your-setup-url> --env BURSAR_AUTHORIZER_URL=<your-authorizer-url> --transport stdio bursar -- npx -y @blacksandscyber/mcp-server-bursar

Check that it registered:

claude mcp list

The --env form writes the token into ~/.claude.json. To keep it out of any file, use a project .mcp.json and export BURSAR_SETUP_TOKEN in the shell that starts Claude Code; ${VAR} references are expanded from that shell.

{
  "mcpServers": {
    "bursar": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "${BURSAR_SETUP_TOKEN}",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}
  • Project-scope servers ask for approval the first time in an interactive session.
  • If the first start is slow, set MCP_TIMEOUT (milliseconds) in the environment before launching claude.
  • Cloud sessions (claude.ai/code, routines) start from a fresh virtual machine each time and send all traffic through a filtering proxy. Anthropic's documentation does not say whether that proxy passes client-certificate TLS through unchanged or keeps an address stable, so treat Bursar's account tools there as untested; the free tools work. See the cloud-session notes under environment variables.

Source: Claude Code MCP documentation, Claude Code on the web, cloud environments.

Claude Desktop

Open Settings, then Developer, then Edit Config. That opens ~/Library/Application Support/Claude/claude_desktop_config.json on macOS or %APPDATA%\Claude\claude_desktop_config.json on Windows. Add the server, save, and quit and restart Claude Desktop completely.

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "<your-setup-token>",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}
  • Claude Desktop's configuration file has no documented way to reference an environment variable, so the token sits in the file as plain text. Delete the BURSAR_SETUP_TOKEN and BURSAR_SETUP_URL lines after the first successful start and keep BURSAR_AUTHORIZER_URL, or leave the token out and use the terminal redemption described above, which also leaves only BURSAR_AUTHORIZER_URL in env.
  • This route needs Node.js installed on the machine. The Blacksands .dxt extension bundle does not: Claude Desktop runs extensions with its own Node.js. The bundle asks for the setup token in its install dialog (the field is marked sensitive) and also accepts a blank token for the free tools. Ask your Blacksands contact for the bundle.
  • Logs are in ~/Library/Logs/Claude/ on macOS (mcp.log and one mcp-server-<name>.log per server).

Source: Connect to local MCP servers, Claude Desktop local MCP help article, MCPB manifest reference.

Cursor

One click installs the free server: Add Bursar to Cursor. The link cannot carry a secret, so connect your account by editing the configuration. Put this in ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project) and export BURSAR_SETUP_TOKEN in the environment that starts Cursor:

{
  "mcpServers": {
    "bursar": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "${env:BURSAR_SETUP_TOKEN}",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}
  • Cursor asks for approval before running MCP tools by default. The command line agent is agent (agent mcp list, agent mcp list-tools bursar).
  • The desktop app and CLI run on your machine, so the home directory and your own egress address apply.
  • Cloud Agents run stdio servers inside a Cursor-managed virtual machine. Cursor does not document whether the home directory survives between runs and does not publish egress addresses, and it says it cannot confirm a stdio server starts until an agent is launched. Use credentials from environment variables, entered in the dashboard (stored encrypted and not readable afterwards).

Source: Cursor MCP documentation, install links, Cloud Agents, CLI MCP commands.

VS Code with GitHub Copilot

Create .vscode/mcp.json in the workspace (or open the user file with the command "MCP: Open User Configuration"). The top-level key in this file is servers, not mcpServers. The inputs entry makes VS Code prompt for the token the first time the server starts and keep it in its secret storage:

{
  "inputs": [
    {
      "type": "promptString",
      "id": "bursar-setup-token",
      "description": "Blacksands Bursar setup token",
      "password": true
    }
  ],
  "servers": {
    "bursar": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "${input:bursar-setup-token}",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}

A link that installs the free server: Add Bursar to VS Code. A workspace-root .mcp.json with the mcpServers layout is also read.

  • VS Code's documentation does not describe ${env:NAME} references in this file, so the snippet uses the prompt instead.
  • The first start shows a trust dialog. Tool calls need approval by default.
  • In Remote-SSH, WSL, dev containers and Codespaces, a server defined in the workspace runs on the remote host, so the home directory and egress address are that host's.
  • The Copilot cloud agent is different: it runs on short-lived GitHub Actions runners with no persistent home and a changing egress address, so use credentials from environment variables there.

Source: VS Code MCP configuration reference, MCP install links for extensions, GitHub: extend the cloud agent with MCP.

Devin Desktop and Devin Local

Windsurf is now Devin Desktop, and Devin Local is its only agent. Register the server for your user, not just the current project:

devin mcp add -s user bursar -- npx -y @blacksandscyber/mcp-server-bursar

Without -s user the command writes to the project's git-ignored .devin/mcp_config.local.json. The command has no flag for environment variables, so add the connected setup by editing ~/.config/devin/mcp_config.json (%APPDATA%\devin\mcp_config.json on Windows):

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "<your-setup-token>",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}
  • Devin documents ${env:VAR} references for some fields but not explicitly inside a stdio server's env block, so this snippet uses a placeholder. Keep a real token in .devin/mcp_config.local.json (git-ignored), never in the checked-in .devin/mcp_config.json.
  • Devin's own pages disagree about the exact configuration path; if the server does not show up, look for it with the app's MCP list.
  • Devin Local asks for approval before calling any MCP tool, and has an optional sandbox: if you turn it on for MCP processes, allow writes to ~/.blacksands/mcp-certs/ and outbound access to Blacksands hosts.

Source: Devin CLI MCP configuration, Devin Desktop FAQ, Devin Desktop changelog.

Codex CLI, the Codex IDE extension and the ChatGPT desktop app

These three share one configuration file, ~/.codex/config.toml (or a trusted project's .codex/config.toml). Configure once and all three see it. In the desktop app you can also use Settings, then MCP servers, then Add server, but that form only covers the name and the command; the environment goes in the file.

[mcp_servers.bursar]
command = "npx"
args = ["-y", "@blacksandscyber/mcp-server-bursar"]
env_vars = ["BURSAR_SETUP_TOKEN"]
startup_timeout_sec = 60
tool_timeout_sec = 120
default_tools_approval_mode = "writes"

[mcp_servers.bursar.env]
BURSAR_SETUP_URL = "<your-setup-url>"
BURSAR_AUTHORIZER_URL = "<your-authorizer-url>"

A server started by Codex receives only a short list of host variables (home, path, user and locale basics). Anything else, including the token, has to be named in env_vars (forwarded from the process that started Codex) or written in an env table. A desktop app launched from the dock may not carry your shell's variables; if the token does not arrive, remove the env_vars line and put the token in the table too, and keep that file private:

[mcp_servers.bursar.env]
BURSAR_SETUP_TOKEN = "<your-setup-token>"
BURSAR_SETUP_URL = "<your-setup-url>"
BURSAR_AUTHORIZER_URL = "<your-authorizer-url>"
  • codex mcp add bursar --env BURSAR_SETUP_TOKEN=<your-setup-token> --env BURSAR_SETUP_URL=<your-setup-url> --env BURSAR_AUTHORIZER_URL=<your-authorizer-url> -- npx -y @blacksandscyber/mcp-server-bursar writes the same command and literal env values. Add the two timeouts by editing the file: the defaults are 10 seconds to start and 60 seconds per tool call.
  • default_tools_approval_mode = "writes" prompts for tools that are not marked read-only.
  • ChatGPT on the web does not read this file. Codex cloud environments have no documented place to register an MCP server, so they are not covered here.
  • Organizations can restrict MCP servers with an allowlist that matches the server name and its command.

Source: Codex MCP documentation, Codex configuration reference.

Grok Build

Grok Build is xAI's grok command line agent. Add the server to ~/.grok/config.toml (or .grok/config.toml in a repository with --scope project). Grok expands ${VAR} when it loads the file, so the token stays in your shell:

[mcp_servers.bursar]
command = "npx"
args = ["-y", "@blacksandscyber/mcp-server-bursar"]
env = { BURSAR_SETUP_TOKEN = "${BURSAR_SETUP_TOKEN}", BURSAR_SETUP_URL = "<your-setup-url>", BURSAR_AUTHORIZER_URL = "<your-authorizer-url>" }
startup_timeout_sec = 60
enabled = true

The command-line equivalent takes one KEY=value per -e flag, before the --. Single quotes stop your shell from expanding the reference, because values given on the command line are stored as typed:

grok mcp add bursar -e 'BURSAR_SETUP_TOKEN=${BURSAR_SETUP_TOKEN}' -e BURSAR_SETUP_URL=<your-setup-url> -e BURSAR_AUTHORIZER_URL=<your-authorizer-url> -- npx -y @blacksandscyber/mcp-server-bursar
grok mcp doctor bursar
  • Stdio servers inherit the environment of the shell that launched Grok, and the env table is layered on top.
  • Grok Build also reads servers already registered for Claude Code (~/.claude.json, .mcp.json) and Cursor, so an existing Claude Code registration may already work.
  • Tool results larger than about 20,000 bytes are cut inline (the full result is saved in the session folder), which matters if you ask for detail: "full" on a scan.
  • On Linux, Grok's stricter sandbox profiles block network access for MCP child processes, which would stop Bursar's outbound TLS. On macOS that restriction is documented as a no-op. The sandbox is off by default.

Source: Grok Build MCP servers, Grok Build settings reference.

Gemini CLI and Antigravity CLI

Gemini CLI. From 2026-06-18 Gemini CLI no longer serves individual Google accounts; it still works with an API key or an enterprise Code Assist licence. Everyone else should use Antigravity below. Gemini CLI strips any inherited variable whose name looks like a secret (token, key, password and similar), so the token has to be listed in the server's own env block, which is trusted:

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "$BURSAR_SETUP_TOKEN",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}

Put it in ~/.gemini/settings.json (all projects) or .gemini/settings.json (one project). References such as $VAR and ${VAR} are expanded from your environment. From the command line, keep the -- before the package arguments so Gemini does not read -y as its own flag:

gemini mcp add -s user -e BURSAR_SETUP_TOKEN=<your-setup-token> -e BURSAR_SETUP_URL=<your-setup-url> -e BURSAR_AUTHORIZER_URL=<your-authorizer-url> bursar npx -- -y @blacksandscyber/mcp-server-bursar

That form stores the literal value. Use the settings file when you want a reference instead. Calls need confirmation unless you set trust: true for the server, which skips every confirmation for it; do not do that for Bursar.

Antigravity CLI (agy). Google's successor to Gemini CLI. Per Google, MCP servers from Gemini CLI are transferred automatically. To add Bursar, edit ~/.gemini/config/mcp_config.json (or .agents/mcp_config.json in a workspace). Antigravity documents literal env values only, so use the placeholder and keep the file private; the /mcp command opens the MCP manager and shows the active file:

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "<your-setup-token>",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}

MCP tools without an explicit setting run in Ask mode (approval required). Removing a server also means deleting its cached folder under ~/.gemini/antigravity-cli/mcp/.

Source: Gemini CLI MCP servers, Gemini CLI extensions, Antigravity MCP, Antigravity getting started.

Cline

Open the Cline panel, choose the MCP Servers icon, then Configure, then Configure MCP Servers; that opens the settings file (~/.cline/data/settings/cline_mcp_settings.json, which CLINE_DATA_DIR can move). Cline has no documented environment-variable references, so the token is a placeholder to replace and keep private:

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "<your-setup-token>",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}
  • An empty autoApprove means every tool call asks first. List only read-only tools there if you want some to run unprompted.
  • Cline Desktop can run its agent on a remote machine over SSH; then Bursar's egress address is that machine's.

Source: Cline: adding and configuring servers, Cline configuration.

Zed

Run the action zed: open settings file and add the server under context_servers. Zed documents literal env values only, so use the placeholder and keep the file private:

{
  "context_servers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "<your-setup-token>",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}
  • You can also use Settings, then AI, then MCP Servers, then Add Server, then Add Local Server.
  • Tool approval is controlled by agent.tool_permissions; the default is to ask. MCP tools are addressed as mcp:bursar:<tool>.
  • Zed does not document whether it passes its own shell environment to these servers, so set what you need in the env block.

Source: Zed MCP documentation, Zed FAQ.

Kiro

Kiro reads ~/.kiro/settings/mcp.json (all workspaces) and .kiro/settings/mcp.json (one workspace; it wins when names clash). In the IDE, the commands "Kiro: Open user MCP config (JSON)" and "Kiro: Open workspace MCP config (JSON)" open them.

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "${BURSAR_SETUP_TOKEN}",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      },
      "disabled": false,
      "autoApprove": []
    }
  }
}
  • Kiro expands ${VAR} only for variable names you list in the IDE setting "Mcp Approved Env Vars", so add BURSAR_SETUP_TOKEN there. Kiro's documentation states this for the IDE and says nothing about the CLI.
  • A one-click link that installs the free server and shows a confirmation dialog first: Add Bursar to Kiro. Links cannot carry the token.
  • Edit the JSON rather than using kiro-cli mcp add: Kiro's documented flags for it do not include a way to pass the arguments as a list.
  • Kiro Web runs in a cloud sandbox. Kiro does not document its egress address or whether Node.js is installed there, so it is untested for Bursar's address-bound sessions.
  • Amazon Q Developer CLI users: the Kiro installer copies the old Q configuration over, so servers you already had keep working.

Source: Kiro MCP configuration, Kiro MCP security, Kiro MCP server directory.

JetBrains Junie

Junie (the IDE plugin and the Junie CLI) reads ~/.junie/mcp/mcp.json for you and .junie/mcp/mcp.json in a project. In the IDE, Settings, then Tools, then Junie, then MCP Settings edits the same file. In the CLI, /mcp lists and manages servers.

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "<your-setup-token>",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}

JetBrains documents literal env values only, so use the placeholder. Keep a real token in the user file and out of the project file, which is meant to be committed.

Other JetBrains clients. JetBrains AI Assistant (Settings, Tools, AI Assistant, Model Context Protocol) accepts a JSON entry for a stdio server and has an "Import from Claude" button that reuses your Claude Desktop configuration. JetBrains documents only command and args there; it does not document an env block, so Blacksands publishes no snippet for it. The safe route is to redeem your token once in a terminal and then register the server with command and args only, carrying BURSAR_AUTHORIZER_URL in them as the "If a client cannot pass an environment variable" bullet in Before you start describes (env as the command, with the variable as its first argument; a launcher script on Windows). The server needs that variable on every launch, and JetBrains does not document whether the server inherits the IDE's own environment, so do not rely on it. Where that route is not open to you, the entry works only in the package's default environment. JetBrains Air documents remote servers only, so there is no stdio snippet for it either.

Source: Junie CLI MCP configuration, Junie plugin MCP settings, JetBrains AI Assistant MCP, JetBrains Air MCP servers.

Muse Code

Muse Code is Meta's terminal coding agent; it runs the local server. Merge this into ~/.config/muse/settings.json. The schema_version line is mandatory, and use only the mcp_servers key (a second mcpServers key in the same file has been reported to disable user servers). Export BURSAR_SETUP_TOKEN in the shell that starts muse.

{
  "schema_version": 1,
  "mcp_servers": {
    "bursar": {
      "transport": "stdio",
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_SETUP_TOKEN": "${BURSAR_SETUP_TOKEN}",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      },
      "mode": "optional"
    }
  }
}
  • mode defaults to required, which aborts the whole run if the server fails to start; optional skips it with a warning instead.
  • Check with /mcp in an interactive session. If you already registered Bursar in Claude Code, the bundled /migrate skill can import it.
  • Meta states that MCP tools are not sandboxed, so Bursar's file writes under ~/.blacksands and its outbound TLS are not limited by Muse Code's network sandbox.
  • Muse Code does not bundle Node.js; npx has to be on your PATH.
  • This is the terminal agent. The consumer Muse app is a different product; see Meta Muse.

Source: Muse Code: extending, Muse Code configuration.

Continue

Create .continue/mcpServers/bursar.yaml in the workspace. MCP tools work only in Continue's Agent mode.

name: Blacksands Bursar
version: 0.0.1
schema: v1
mcpServers:
  - name: bursar
    type: stdio
    command: npx
    args:
      - "-y"
      - "@blacksandscyber/mcp-server-bursar"
    env:
      BURSAR_SETUP_TOKEN: "${{ secrets.BURSAR_SETUP_TOKEN }}"
      BURSAR_SETUP_URL: "<your-setup-url>"
      BURSAR_AUTHORIZER_URL: "<your-authorizer-url>"

Continue's IDE extensions cannot read variables from your shell. For VS Code and JetBrains, put the token in ~/.continue/.env (or .continue/.env in the workspace) as BURSAR_SETUP_TOKEN=<your-setup-token>; the command line client also reads the process environment. BURSAR_SETUP_URL and BURSAR_AUTHORIZER_URL are not secrets and stay in the YAML.

Source: Continue MCP guide, Continue FAQ.

Open-source agents

OpenClaw

OpenClaw reads its configuration from ~/.openclaw/openclaw.json (JSON5; OPENCLAW_CONFIG_PATH moves it) and reloads it live. Add the server to the mcp.servers block. OpenClaw expands ${VAR_NAME} (upper-case names) in any string, reading your environment, ./.env and ~/.openclaw/.env:

{
  "mcp": {
    "servers": {
      "bursar": {
        "command": "npx",
        "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
        "env": {
          "BURSAR_SETUP_TOKEN": "${BURSAR_SETUP_TOKEN}",
          "BURSAR_SETUP_URL": "<your-setup-url>",
          "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
        },
        "requestTimeoutMs": 60000,
        "connectionTimeoutMs": 60000
      }
    }
  }
}
  • The configuration is validated strictly: a key OpenClaw does not know stops it from starting, so copy the keys exactly.
  • Without requestTimeoutMs, listing tools at session start times out after 10 seconds, which a cold npx download can exceed.
  • openclaw mcp doctor bursar --probe checks the server. The command openclaw mcp add bursar --command npx --arg -y --arg @blacksandscyber/mcp-server-bursar registers the free server too. Do not use it to pass the token: an --env value is stored as a literal that doctor warns about, and the command starts the server once to probe it, which redeems the token straight away using only the variables given on that command line, so a token without your endpoints would be sent to the wrong environment. Use the configuration block above.
  • The server runs as the Gateway user on the Gateway host, so Bursar's egress address is that host's. A Gateway shared by a team is one Bursar identity for everyone who uses it.

Source: OpenClaw MCP, OpenClaw MCP registry commands, OpenClaw environment variables.

OpenCode

Add an mcp entry to opencode.json (project) or ~/.config/opencode/opencode.json (global). OpenCode substitutes {env:VAR} from your environment.

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "bursar": {
      "type": "local",
      "command": ["npx", "-y", "@blacksandscyber/mcp-server-bursar"],
      "enabled": true,
      "timeout": 60000,
      "environment": {
        "BURSAR_SETUP_TOKEN": "{env:BURSAR_SETUP_TOKEN}",
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>"
      }
    }
  }
}
  • OpenCode's documentation warns that MCP tool lists use up context. Its tool toggle accepts a glob, for example "tools": { "bursar*": false } globally, then enabled for the agents that need Bursar.
  • OpenCode's documentation does not describe a per-tool approval setting for MCP tools.
  • The child process inherits your full environment, so an already-exported BURSAR_SETUP_TOKEN reaches Bursar even without the mapping.

Source: OpenCode MCP servers, OpenCode configuration.

Goose

Add an extension to ~/.config/goose/config.yaml (%APPDATA%\Block\goose\config\config.yaml on Windows). env_keys names variables to look up when the extension starts: first your process environment, then Goose's secret store, so the token never has to be written in the file.

extensions:
  bursar:
    type: stdio
    name: bursar
    description: Blacksands Bursar MCP server
    enabled: true
    cmd: npx
    args: ["-y", "@blacksandscyber/mcp-server-bursar"]
    env_keys: [BURSAR_SETUP_TOKEN]
    envs:
      BURSAR_SETUP_URL: "<your-setup-url>"
      BURSAR_AUTHORIZER_URL: "<your-authorizer-url>"
    timeout: 300

A link installs the extension after you confirm, and asks you for the token and the two endpoint values in the app instead of carrying them: Add Bursar to Goose.

  • For one session, Goose's documentation shows goose session --with-extension "VAR=value command args" with a single variable, which cannot carry the token and the two endpoint variables; use the configuration entry above for the connected setup.
  • Goose has per-tool permissions (always allow, ask first, never) for extension tools in its manual and smart-approval modes.
  • Node.js has to be installed for npx.

Source: Goose extensions.

LibreChat

Stdio servers can only be defined in librechat.yaml; the admin interface and the database reject them. Restart LibreChat after editing. ${ENV_VAR} resolves from the LibreChat server's environment (.env or your compose file), so the secret stays out of the YAML. This form is one Bursar identity shared by everyone on the instance:

mcpServers:
  bursar:
    type: stdio
    command: npx
    args:
      - "-y"
      - "@blacksandscyber/mcp-server-bursar"
    timeout: 60000
    initTimeout: 60000
    env:
      BURSAR_SETUP_TOKEN: "${BURSAR_SETUP_TOKEN}"
      BURSAR_SETUP_URL: "<your-setup-url>"
      BURSAR_AUTHORIZER_URL: "<your-authorizer-url>"
  • Do not pass a setup token per user (for example through LibreChat's customUserVars) to give each user their own identity. The server keeps one certificate bundle per home directory and redeems a token only when no bundle is there yet, so on a shared host the first user's token is redeemed and every later user's server runs as that first identity, with no error, while their own token goes unused until it expires. For one Bursar identity per user, give each user a separate container or home directory, or supply that user's certificate, key, auth password and organization id as credentials from environment variables, which the server uses in place of any stored bundle. LibreChat's documentation does not say whether it starts a separate stdio process per user, so Blacksands publishes no per-user snippet.
  • The server runs inside the LibreChat process or container. A container's home directory is lost when it is recreated, so mount a volume for ~/.blacksands or use credentials from environment variables.
  • Egress is the LibreChat host's address.

Source: LibreChat MCP servers reference, LibreChat MCP feature.

Open WebUI, through mcpo

Open WebUI never launches a stdio command. Its own MCP support is Streamable HTTP only, so today Bursar reaches it through mcpo, a proxy that starts the local server and exposes it as an OpenAPI tool server. mcpo passes its own environment on to the server it starts. Describe the server in a Claude-style file, bursar-mcpo.json:

{
  "mcpServers": {
    "bursar": {
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"]
    }
  }
}

Then run mcpo with the token and the two endpoint variables in its environment:

BURSAR_SETUP_TOKEN=<your-setup-token> BURSAR_SETUP_URL=<your-setup-url> BURSAR_AUTHORIZER_URL=<your-authorizer-url> \
  uvx mcpo --port 8000 --api-key "$MCPO_KEY" --config bursar-mcpo.json

The stock mcpo container image already includes Node.js, so npx works inside it; mount the file and pass the variable through if you run it that way.

Then in Open WebUI: Settings, Admin, Integrations, External Tool Servers, Add Connection. Choose the OpenAPI type, set the URL to http://<mcpo-host>:8000/bursar (the per-server route, not the bare root), the spec to openapi.json, and the authentication to Bearer with your mcpo key.

  • Anything that can reach mcpo can call Bursar's tools, so protect that endpoint. One mcpo process is one Bursar identity shared by all Open WebUI users. To give each team its own identity, run one mcpo per team, each with its own home directory or container, or with that team's credentials from environment variables; two mcpo processes that share a home directory share the first redeemed identity.
  • Tools arrive as OpenAPI operations, so MCP-only features (resources, prompts) are not available.
  • In Docker, mount a volume for ~/.blacksands or use credentials from environment variables.

Source: Open WebUI MCP, Open WebUI with mcpo, mcpo repository.

Agent frameworks

For every framework below: the MCP client library starts the server as a child process and passes it only a short list of host variables (home, path, user and a few others), so the token and the two endpoint variables have to be handed over explicitly in the env option, as the snippets do. Home-directory persistence depends on where your application runs; on an ephemeral host use credentials from environment variables. Egress is whatever address your application's host has, so run it from a fixed-IP host. Use a model identifier of your own where a snippet shows <model-id>.

OpenAI Agents SDK, Python

MCPServerStdio has a five-second default session timeout, which a first start can exceed; raise it.

import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStdio


async def main() -> None:
    async with MCPServerStdio(
        name="bursar",
        params={
            "command": "npx",
            "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
            "env": {
                "BURSAR_SETUP_TOKEN": os.environ["BURSAR_SETUP_TOKEN"],
                "BURSAR_SETUP_URL": "<your-setup-url>",
                "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
            },
        },
        client_session_timeout_seconds=60,
        cache_tools_list=True,
    ) as server:
        agent = Agent(
            name="Bursar operator",
            instructions="Use the Bursar tools to answer questions about my apps.",
            mcp_servers=[server],
        )
        result = await Runner.run(agent, "List my Bursar organizations.")
        print(result.final_output)


asyncio.run(main())

The server object also takes require_approval and tool_filter to limit what the agent may call.

Source: OpenAI Agents SDK (Python): MCP.

OpenAI Agents SDK, TypeScript

import { Agent, MCPServerStdio, run } from "@openai/agents";

const server = new MCPServerStdio({
  name: "bursar",
  command: "npx",
  args: ["-y", "@blacksandscyber/mcp-server-bursar"],
  env: {
    BURSAR_SETUP_TOKEN: process.env.BURSAR_SETUP_TOKEN!,
    BURSAR_SETUP_URL: "<your-setup-url>",
    BURSAR_AUTHORIZER_URL: "<your-authorizer-url>",
  },
  clientSessionTimeoutSeconds: 60, // the default is 5
  cacheToolsList: true,
});

await server.connect();
try {
  const agent = new Agent({
    name: "Bursar operator",
    instructions: "Use the Bursar tools to answer questions about my apps.",
    mcpServers: [server],
  });
  const result = await run(agent, "List my Bursar organizations.");
  console.log(result.finalOutput);
} finally {
  await server.close();
}

Source: OpenAI Agents SDK (TypeScript): MCP.

LangChain and LangGraph

Use client.session(...) to keep one server process alive. The get_tools() shorthand opens a new session, and for a stdio server a new npx process, for every tool call.

import os
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_mcp_adapters.tools import load_mcp_tools
from langchain.agents import create_agent

client = MultiServerMCPClient({
    "bursar": {
        "transport": "stdio",
        "command": "npx",
        "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
        "env": {
            "BURSAR_SETUP_TOKEN": os.environ["BURSAR_SETUP_TOKEN"],
            "BURSAR_SETUP_URL": "<your-setup-url>",
            "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
        },
    }
})

async with client.session("bursar") as session:
    tools = await load_mcp_tools(session)
    agent = create_agent("<model-id>", tools)
    result = await agent.ainvoke(
        {"messages": [{"role": "user", "content": "List my Bursar apps"}]}
    )

The library's own documentation warns that stdio was designed for apps on a user's machine; think twice before using it in a web-server deployment.

Source: langchain-mcp-adapters.

CrewAI

CrewAI's MCPServerStdio connects with fixed 30-second limits and skips a server that is not ready by then, with only a warning. If a cold npx download can take longer, install the package first (npm install -g @blacksandscyber/mcp-server-bursar) or use the adapter, which has a configurable connect timeout.

import os
from crewai import Agent
from crewai.mcp import MCPServerStdio

agent = Agent(
    role="Security analyst",
    goal="Use Bursar to inspect and protect apps",
    backstory="Works with the Blacksands platform",
    mcps=[
        MCPServerStdio(
            command="npx",
            args=["-y", "@blacksandscyber/mcp-server-bursar"],
            env={
                "BURSAR_SETUP_TOKEN": os.environ["BURSAR_SETUP_TOKEN"],
                "BURSAR_SETUP_URL": "<your-setup-url>",
                "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
            },
            cache_tools_list=True,
        )
    ],
)
import os
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters

params = StdioServerParameters(
    command="npx",
    args=["-y", "@blacksandscyber/mcp-server-bursar"],
    env={
        **os.environ,
        "BURSAR_SETUP_TOKEN": os.environ["BURSAR_SETUP_TOKEN"],
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
    },
)
with MCPServerAdapter(params, connect_timeout=60) as tools:
    ...  # pass `tools` to an Agent

Source: CrewAI MCP overview, CrewAI stdio servers.

Vercel AI SDK

Vercel's documentation says the stdio transport is for local servers only. On serverless platforms such as Vercel Functions, a child process and an npx download on every cold start are impractical, so do not host Bursar over stdio there; use a long-lived host.

import { createMCPClient } from "@ai-sdk/mcp";
import { Experimental_StdioMCPTransport as StdioClientTransport } from "@ai-sdk/mcp/mcp-stdio";
import { generateText } from "ai";

const mcpClient = await createMCPClient({
  transport: new StdioClientTransport({
    command: "npx",
    args: ["-y", "@blacksandscyber/mcp-server-bursar"],
    env: {
      BURSAR_SETUP_TOKEN: process.env.BURSAR_SETUP_TOKEN!,
      BURSAR_SETUP_URL: "<your-setup-url>",
      BURSAR_AUTHORIZER_URL: "<your-authorizer-url>",
    },
  }),
});
try {
  const tools = await mcpClient.tools();
  const { text } = await generateText({
    model: "<model-id>",
    tools,
    prompt: "List my Bursar apps",
  });
  console.log(text);
} finally {
  await mcpClient.close();
}

Source: AI SDK: MCP tools.

Mastra

import { MCPClient } from "@mastra/mcp";
import { Agent } from "@mastra/core/agent";

export const mcpClient = new MCPClient({
  id: "bursar-client",
  servers: {
    bursar: {
      command: "npx",
      args: ["-y", "@blacksandscyber/mcp-server-bursar"],
      env: {
        BURSAR_SETUP_TOKEN: process.env.BURSAR_SETUP_TOKEN!,
        BURSAR_SETUP_URL: "<your-setup-url>",
        BURSAR_AUTHORIZER_URL: "<your-authorizer-url>",
      },
    },
  },
});

export const assistant = new Agent({
  id: "assistant",
  name: "Assistant",
  instructions: "Use the Bursar tools to inspect and protect apps.",
  model: "<model-id>",
  tools: await mcpClient.listTools(),
});
  • Mastra's default client timeout is 60 seconds, enough for a cold npx.
  • A server entry can set requireToolApproval: true to gate calls.
  • listTools() shares one set of credentials. Mastra's per-request listToolsets() pattern starts a server per user, but on one host with one home directory every one of those servers finds the first user's stored certificate bundle and ignores a different setup token, so every user would act as the first redeemed identity, with no error. For one Bursar identity per user, give each user's server that user's own certificate, key, auth password and organization id as credentials from environment variables, or a separate home directory.

Source: Mastra MCP overview, Mastra MCPClient reference.

Pydantic AI

import os
from fastmcp.client.transports import StdioTransport
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPToolset

toolset = MCPToolset(
    StdioTransport(
        command="npx",
        args=["-y", "@blacksandscyber/mcp-server-bursar"],
        env={
            "BURSAR_SETUP_TOKEN": os.environ["BURSAR_SETUP_TOKEN"],
            "BURSAR_SETUP_URL": "<your-setup-url>",
            "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
        },
    )
)
agent = Agent("<model-id>", toolsets=[toolset])

The transport keeps one process alive across uses, which suits the one-time token redemption. To load servers from a Claude-style file instead, load_mcp_toolsets("mcp_config.json") reads a file in which ${VAR} in env is expanded from the full process environment, so treat that file as trusted input.

Source: Pydantic AI MCP client.

LlamaIndex

import os
from llama_index.tools.mcp import BasicMCPClient, McpToolSpec

client = BasicMCPClient(
    "npx",
    args=["-y", "@blacksandscyber/mcp-server-bursar"],
    env={
        "BURSAR_SETUP_TOKEN": os.environ["BURSAR_SETUP_TOKEN"],
        "BURSAR_SETUP_URL": "<your-setup-url>",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
    },
    timeout=60,
)
tools = await McpToolSpec(client=client).to_tool_list_async()

The default timeout is 30 seconds; the snippet raises it. Inside a running event loop use the async method, as shown.

Source: llama-index-tools-mcp.

Hosted always-on agents

Agents that run in a vendor's cloud and can only take a remote URL cannot start a local command, so they cannot run the package above. These agents connect to a remote address with browser sign-in. The Bursar remote endpoint is not available yet: it has not been switched on, so none of the hosted agents below can connect to Bursar today. Contact us at info@blacksandsinc.com to be told when it opens. When the endpoint is switched on, its address will be listed in this paragraph.

On its first day the remote endpoint is meant to offer read-only account tools after you sign in. The local package stays the way to scan code and the way for an agent to call a protected service, because those need a client certificate and a stable source address, and the hosted agents below do not document a way to present a certificate of yours or a dedicated egress address.

Grok Bot

Grok Bot is the always-on agent xAI built with Cursor. In the Bot you register a custom MCP server by asking it in chat; it shows an Add MCP Server card (name, type Remote HTTPS, server address, headers, OAuth), and the server then appears under your plugins and is shared by all your Bots.

  • Cursor staff have said Grok Bot does not attach servers that run on your own machine, whether stdio or localhost, and that a custom server needs a public HTTPS address (streamable HTTP or SSE).
  • A third-party guide claims a stdio command can run on the Bot's own cloud computer. That is not in xAI's documentation and Blacksands does not present it as supported; do not type a setup token into a chat to try it, because it would enter the transcript.
  • Grok Bot computers share static egress addresses across customers; dedicated addresses are not available, and the ranges come from your account team.
  • Authentication options for a remote server are static headers or OAuth. No client-certificate option is documented.
  • Grok Bot will connect through the Bursar remote endpoint (not available yet), described above. To use Bursar locally with xAI today, use Grok Build, which runs the local server.
  • The Grok app's custom connectors (grok.com, Settings, Connectors) are remote-only as well: they require a server reachable over the public internet.

Source: Grok Bot overview, Grok Bot security, Grok Bot private networks, Grok connectors.

OpenAI dots and ChatGPT

What OpenAI documents. A dot (the always-on agent in ChatGPT) uses the plugins installed and enabled for your account. A plugin for the public directory has to wrap an MCP server at a public HTTPS address using streamable HTTP; stdio is not accepted there. In ChatGPT, Plugins, then the plus button, then Create custom MCP server lets you add one yourself, with a server address (streamable HTTP or SSE) or a tunnel, and authentication of OAuth or none. ChatGPT presents its own OpenAI-managed client certificate to your server; it cannot present a certificate you provide, so Bursar's own identity cannot travel through ChatGPT.

What it means for Bursar. ChatGPT and dots will connect through the Bursar remote endpoint (not available yet), described above. OpenAI does not publish an egress address for a dot's cloud computer. OpenAI's pages do not say whether a dot can call a personal or tunnel-backed plugin; that is unverified.

A private, single-organization option that works with the local server today: Secure MCP Tunnel. OpenAI's tunnel client runs the stdio server on a machine you control and connects it to ChatGPT through an outbound connection, so Bursar's own certificate traffic leaves from your machine, which can have a fixed address. You need an OpenAI Platform organization with tunnel permissions, a tunnel created in its settings, and a runtime key.

brew install openai/tools/tunnel-client

export CONTROL_PLANE_API_KEY="<runtime key with Tunnels Read and Use>"
export BURSAR_SETUP_TOKEN="<your-setup-token>"
export BURSAR_SETUP_URL="<your-setup-url>"
export BURSAR_AUTHORIZER_URL="<your-authorizer-url>"

tunnel-client init --sample sample_mcp_stdio_local --profile bursar \
  --tunnel-id tunnel_<id-from-your-tunnel-settings> \
  --mcp-command "npx -y @blacksandscyber/mcp-server-bursar"
tunnel-client doctor --profile bursar --explain
tunnel-client run --profile bursar

Then in ChatGPT: Plugins, plus, Create custom MCP server, Connection: Tunnel, choose the tunnel, set authentication, and Create as a plugin.

  • Limits, stated plainly: everyone who uses that tunnel acts as one shared Bursar identity, the tunnel is not for public distribution (OpenAI says it does not support plugin submission), and it is unverified whether a dot can call a tunnel-backed plugin.
  • Only one tunnel client may run per tunnel; if it stops, calls fail.
  • OpenAI's documentation does not say whether the server process inherits the tunnel client's environment. The client's own source passes the environment through, which is why the exports above work; confirm with tunnel-client doctor. The command string is split into arguments without a shell, so do not put NAME=value before npx inside it.
  • The desktop app and Codex run the local server directly; see Codex.

Source: Secure MCP Tunnel guide, tunnel-client repository, connect ChatGPT to your server, custom MCP servers in ChatGPT, dots: computers and apps.

Meta Muse

The consumer Muse agent runs in a per-user cloud virtual machine, and its outbound traffic goes through a Meta proxy that checks each request. You ask Muse in chat to create a custom connector; Meta's help pages describe connectors built from a service's APIs or command line tools and do not mention MCP. Guides from third parties describe a remote MCP server over streamable HTTP working this way, with sign-in through OAuth. Treat that as unofficial.

  • Meta documents no way to run a local command for the consumer Muse agent, so it cannot use the local package.
  • Meta says its proxy decodes outbound requests, which suggests it may interrupt the client-certificate TLS Bursar uses for its own calls. Meta does not say; it would need testing.
  • Egress addresses are not documented, and no client-certificate option is mentioned.
  • Credentials go through a separate secure prompt, not the chat. Never paste a setup token into the chat.
  • To use Bursar locally with Meta today, use Muse Code, the terminal agent.
  • Muse will connect through the Bursar remote endpoint (not available yet), described above.

Source: Meta Help Center: connectors, Meta: security of Muse agents, Muse platform.

xAI API: remote MCP tool

xAI's Responses API takes MCP servers in the tools array of a request. It accepts only streamable HTTP and SSE (no stdio), authenticates with a token in an authorization field or custom headers (no client certificate), and makes the call from xAI's side; the documentation does not publish the address those calls come from. That will pair with the Bursar remote endpoint (not available yet), described above, not with the local package. There is no snippet because there is no public address to put in it yet.

Source: xAI remote MCP tools.

OpenAI API: remote MCP tool

The Responses API mcp tool takes either a public server_url (which will be the Bursar remote endpoint (not available yet), described above) or a tunnel_id that points at a Secure MCP Tunnel running the local server. The tunnel form works today and has the same shared-identity limit:

{
  "type": "mcp",
  "server_label": "bursar",
  "tunnel_id": "tunnel_0123456789abcdef0123456789abcdef",
  "require_approval": "always"
}

Put that object in the tools array of a responses.create call. There is no field for a client certificate, so Bursar's identity has to live behind the tunnel. require_approval defaults to asking before each MCP call; keep it that way for Bursar.

Source: OpenAI: MCP and connectors, Secure MCP Tunnel guide.

Running with credentials from environment variables

Hosted runtimes (cloud agent sandboxes, containers without a volume, CI jobs) deliver secrets as environment variables and lose their files between runs. For those, skip the setup token and give the server the certificate bundle directly. When all of the certificate, the key, the auth password and the organization id are present, the server uses them in place of any stored bundle in ~/.blacksands/mcp-certs/. One thing can still come from that folder: the small .role file, which only decides which tools are listed. On a runtime with no home directory that file is not there, so set the role yourself, and the authorizer endpoint too, which no bundle stores (see the table).

WhatVariables (the first one set wins)Notes
Client certificateBURSAR_CLIENT_CERT_PEM, BURSAR_CLIENT_CERT_B64, BURSAR_CLIENT_CERT (file path)required
Client private keyBURSAR_CLIENT_KEY_PEM, BURSAR_CLIENT_KEY_B64, BURSAR_CLIENT_KEY (file path)required
Auth passwordBURSAR_AUTH_PASSWORDrequired on a runtime with no files; where the bundle's files are present it may be left out (see below)
Organization idBURSAR_ORG_IDrequired, unless it comes from the stored bundle with the password
CA bundleBURSAR_CA_CERT_PEM, BURSAR_CA_CERT_B64, BURSAR_CA_CERT (file path)optional; the Blacksands CA chain bundled with the package is used when absent
Authorizer endpointBURSAR_AUTHORIZER_URLyour environment's authorizer endpoint (a placeholder in the snippets below); no bundle stores it, so set it here. Left unset, the server uses its built-in default, which belongs to one particular environment
RoleBURSAR_ROLE (also accepted as SHIELD_ROLE): consumer or masterrequired for a consumer certificate (set it to consumer); sets which tools the server lists. Left unset, the server falls back to the .role file and then to master, so a consumer agent would be shown the full tool set
  • *_PEM is the PEM text, *_B64 is the base64 of that PEM (easiest for runtimes that dislike multi-line values). Line-break damage from secret stores (literal \n text, collapsed spaces, stray quotes) is repaired before use. Every BURSAR_* name is also accepted as SHIELD_*; if both are set, a non-blank BURSAR_* value wins.
  • Where the bundle's files are on disk, the auth password does not have to be in the configuration. With the certificate and key given and no BURSAR_AUTH_PASSWORD, the server uses the password stored with the bundle: the operating system's keychain when BS_MCP_KEYSTORE is auto or on, then the .auth-password file in SHIELD_CERT_DIR, in the directory of the BURSAR_CLIENT_CERT file, or in ~/.blacksands/mcp-certs/. The bundle's .org-id is used with it when no organization id is set.
  • If a certificate, a key or an auth password is present but something required is missing (in the environment and with the bundle), or a value cannot be used, the server stops with one message naming what is missing. It never quietly drops to free mode in that case. The organization id on its own does not count: with none of the certificate, key or auth password set, the server carries on as usual (setup token, stored bundle, or free mode).
  • The role is mostly a tool list, so always set it for a consumer certificate. BURSAR_ROLE decides which tools the server registers. Blacksands also checks the certificate's role on a defined set of account actions and refuses them for a consumer certificate: issuing, changing and revoking certificates, issuing setup tokens, granting and revoking an agent's access to services, creating and changing Receivers and the services behind them, emergency lockdown, and creating or changing apps and endpoints. It does not check every tool this way, so the role is not a security boundary against an agent you do not trust: a consumer certificate with BURSAR_ROLE unset is shown the full tool list, and the server accepts some of those tools' calls. Set BURSAR_ROLE=consumer for every consumer certificate, give each runtime its own identity, and keep it at the lowest role that does the job.
  • Where the values come from. Ask your Blacksands administrator for a setup token dedicated to this runtime, issued under a client name of its own. An agent that only scans code and calls services it was granted needs the consumer role, not master. Redeem the token once on a machine you control, under an empty home directory. The server redeems a setup token only when ~/.blacksands/mcp-certs/ holds no bundle, and it says nothing when it skips the redemption. On a machine that already has a bundle, which is the usual case for someone who already uses Bursar, a plain redemption does not run at all, and the export commands below would read that machine's existing identity (often a master one) into the runtime's secret store while the dedicated token expired unused. The first block below redeems the token under a temporary home, so the bundle it writes is the dedicated identity and nothing else; wait for the Bootstrap complete log line, then stop it with Ctrl+C. On Windows the server takes its home from USERPROFILE instead of HOME, so point USERPROFILE at an empty folder for the redemption and read the files from .blacksands\mcp-certs inside it. The bundle holds everything in the table except the authorizer endpoint, and its .role file holds the role. Before you export anything, check that .client-name holds the client name the token was issued for; if it does not, or the folder is missing because the token was not redeemed, stop and store nothing. To turn the bundle into variables on macOS or Linux, run the second block in the same shell as the first. The second block exports into your current shell only and stores nothing, and its second line prints .client-name, so read that name before you store any value it exports. Paste each block as it is; it carries no comments, because the zsh that macOS ships does not treat # as a comment at its prompt.
export BURSAR_EXPORT_HOME="$(mktemp -d)"
HOME="$BURSAR_EXPORT_HOME" BURSAR_SETUP_TOKEN=<your-setup-token> BURSAR_SETUP_URL=<your-setup-url> BURSAR_AUTHORIZER_URL=<your-authorizer-url> npx -y @blacksandscyber/mcp-server-bursar
cd "$BURSAR_EXPORT_HOME/.blacksands/mcp-certs"
cat .client-name; echo
export BURSAR_CLIENT_CERT_B64="$(base64 < "$(cat .client-name).crt" | tr -d '\n')"
export BURSAR_CLIENT_KEY_B64="$(base64 < "$(cat .client-name).key" | tr -d '\n')"
export BURSAR_AUTH_PASSWORD="$(cat .auth-password)"
export BURSAR_ORG_ID="$(cat .org-id)"
[ -f .role ] && export BURSAR_ROLE="$(cat .role)"
export BURSAR_AUTHORIZER_URL="<your-authorizer-url>"

The role line exports BURSAR_ROLE only when the bundle has a .role file, which the redemption writes; if it is missing, set consumer or master yourself. No bundle stores the authorizer endpoint, so replace the placeholder in the last line with your environment's.

Store those values in the runtime's secret store (include BURSAR_ROLE and BURSAR_AUTHORIZER_URL; a plain environment setting is enough for those two, since neither is a secret), and run npx -y @blacksandscyber/mcp-server-bursar as the server command. Once they are stored, leave the temporary home and delete it, because it holds the private key: cd ~ && rm -r "$BURSAR_EXPORT_HOME".

  • The source-address binding still applies: a runtime whose outbound address changes, or is shared with other customers, will lose sessions. Free tools do not need a session.
  • Anything running in the same sandbox as the server can read these variables. A prompt-injected agent could try to send them elsewhere, so give each runtime its own identity and the lowest role that does the job.

Claude Code cloud sessions

Only the repository's .mcp.json is loaded in a cloud session, and ${VAR} there reads variables you set on the cloud environment. Anyone who can use that environment can read them. BURSAR_ROLE is set to consumer here, which lists only the free tools and broker_request; use master only for an agent that needs the account-management tools. This is untested for Bursar's account tools (see the Claude Code section).

{
  "mcpServers": {
    "bursar": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "env": {
        "BURSAR_CLIENT_CERT_B64": "${BURSAR_CLIENT_CERT_B64}",
        "BURSAR_CLIENT_KEY_B64": "${BURSAR_CLIENT_KEY_B64}",
        "BURSAR_AUTH_PASSWORD": "${BURSAR_AUTH_PASSWORD}",
        "BURSAR_ORG_ID": "${BURSAR_ORG_ID}",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
        "BURSAR_ROLE": "consumer"
      }
    }
  }
}

Source: Claude Code on the web, Claude Code MCP documentation.

GitHub Copilot cloud agent

Configure it in the repository's Settings, Copilot, MCP servers. Only secrets whose names start with COPILOT_MCP_ are exposed to the configuration, and $NAME references work in env. The tools list is mandatory. BURSAR_ROLE is set to consumer here (use master only for an agent that needs the account-management tools). The agent's runner is short-lived and its firewall has an allowlist, so allow the Blacksands hosts there. This setup is not verified by Blacksands.

{
  "mcpServers": {
    "bursar": {
      "type": "local",
      "command": "npx",
      "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
      "tools": ["*"],
      "env": {
        "BURSAR_CLIENT_CERT_B64": "$COPILOT_MCP_BURSAR_CLIENT_CERT_B64",
        "BURSAR_CLIENT_KEY_B64": "$COPILOT_MCP_BURSAR_CLIENT_KEY_B64",
        "BURSAR_AUTH_PASSWORD": "$COPILOT_MCP_BURSAR_AUTH_PASSWORD",
        "BURSAR_ORG_ID": "$COPILOT_MCP_BURSAR_ORG_ID",
        "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
        "BURSAR_ROLE": "consumer"
      }
    }
  }
}

Source: GitHub: extend the cloud agent with MCP.

OpenAI Agents API hosted sandbox

OpenAI's Agents API can run a stdio server inside a hosted sandbox. That sandbox is deleted after an hour without activity, so the home directory does not survive and the credential variables are required, along with BURSAR_AUTHORIZER_URL and BURSAR_ROLE (set to consumer here; use master only for an agent that needs the account-management tools). Values go in the environment, and their names go in the transport's env_vars; the sandbox needs network access set to enabled. OpenAI's guide words the placement of tools as "add to agent.tools", so check the exact request shape against its API reference. The sandbox's egress address is not published, which conflicts with source-address-bound sessions; a self-hosted sandbox on your own machine gives you a fixed address.

{
  "agent": {
    "model": "<model-id>",
    "tools": [
      {
        "type": "mcp",
        "server_label": "bursar",
        "transport": {
          "type": "stdio",
          "command": "npx",
          "args": ["-y", "@blacksandscyber/mcp-server-bursar"],
          "cwd": "/workspace",
          "env_vars": [
            "BURSAR_CLIENT_CERT_B64",
            "BURSAR_CLIENT_KEY_B64",
            "BURSAR_AUTH_PASSWORD",
            "BURSAR_ORG_ID",
            "BURSAR_AUTHORIZER_URL",
            "BURSAR_ROLE"
          ]
        },
        "required": true
      }
    ]
  },
  "environment": {
    "type": "openai_hosted",
    "network": { "access": "enabled" },
    "env": {
      "BURSAR_CLIENT_CERT_B64": "<base64 certificate>",
      "BURSAR_CLIENT_KEY_B64": "<base64 key>",
      "BURSAR_AUTH_PASSWORD": "<auth password>",
      "BURSAR_ORG_ID": "<organization id>",
      "BURSAR_AUTHORIZER_URL": "<your-authorizer-url>",
      "BURSAR_ROLE": "consumer"
    }
  }
}

Source: OpenAI Agents API: MCP tools, OpenAI-hosted environments, Agents API plugins.