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-bursar0.7.0 or newer. Earlier versions do not read theBURSAR_*variable names or the credential variables below, and with an earlier versionnpx -y @blacksandscyber/mcp-server-bursarcan stop with "could not determine executable to run".npm view @blacksandscyber/mcp-server-bursar versionshows the newest published version; if it shows an older one, ornpxkeeps an older copy, the snippets below will not work yet. - Node.js 18 or newer has to be on the
PATHof 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 tonpxin thecommandfield. - 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
envblock 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_TOKENis 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) andBURSAR_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, soBURSAR_AUTHORIZER_URLmust stay in the configuration after the first start; without it, later launches use the built-in default.SHIELD_SETUP_URLandSHIELD_AUTHORIZER_URLare 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 orHOME) or use credentials from environment variables. To replace the stored identity, move~/.blacksands/mcp-certsaside 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 theBootstrap completelog 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 withcommandandargsonly. The stored bundle is picked up from then on. The server still readsBURSAR_AUTHORIZER_URLon 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 setcommandtoenvandargsto["BURSAR_AUTHORIZER_URL=<your-authorizer-url>", "npx", "-y", "@blacksandscyber/mcp-server-bursar"];envsets the variable and then startsnpx. On Windows pointcommandat a small launcher script (a.cmdfile) that sets the variable and then runsnpx -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
npxdownload 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
| Client | Runs the local server today? | Needs the remote endpoint? | Where to register |
|---|---|---|---|
| Claude Code | Yes | No | claude mcp add, or .mcp.json |
| Claude Desktop | Yes | No | claude_desktop_config.json, or the .dxt extension |
| Cursor | Yes (IDE and CLI) | No | ~/.cursor/mcp.json, .cursor/mcp.json |
| VS Code with GitHub Copilot | Yes | No | .vscode/mcp.json |
| Devin Desktop / Devin Local | Yes | No | devin mcp add, ~/.config/devin/mcp_config.json |
| Codex CLI, Codex IDE extension, ChatGPT desktop app | Yes | No | ~/.codex/config.toml |
| Grok Build | Yes | No | ~/.grok/config.toml |
| Gemini CLI | Yes | No | ~/.gemini/settings.json |
| Antigravity CLI | Yes | No | ~/.gemini/config/mcp_config.json |
| Cline | Yes | No | ~/.cline/data/settings/cline_mcp_settings.json |
| Zed | Yes | No | context_servers in settings.json |
| Kiro | Yes (IDE and CLI) | No | ~/.kiro/settings/mcp.json |
| JetBrains Junie | Yes | No | ~/.junie/mcp/mcp.json |
| Muse Code | Yes | No | ~/.config/muse/settings.json |
| Continue | Yes | No | .continue/mcpServers/bursar.yaml |
| OpenClaw | Yes | No | mcp.servers in ~/.openclaw/openclaw.json |
| OpenCode | Yes | No | mcp in opencode.json |
| Goose | Yes | No | ~/.config/goose/config.yaml |
| LibreChat | Yes (self-hosted) | No | librechat.yaml |
| Open WebUI | Only through the mcpo proxy | No | mcpo, then an OpenAPI tool server |
| OpenAI Agents SDK (Python, TypeScript) | Yes (library) | No | in code |
| LangChain / LangGraph, CrewAI, Vercel AI SDK, Mastra, Pydantic AI, LlamaIndex | Yes (library) | No | in code |
| Grok Bot | No (not documented by xAI) | Yes (not available yet) | a chat with the Bot |
| OpenAI dots / ChatGPT | ChatGPT only, through a private tunnel; dots unverified | Yes (not available yet) | ChatGPT Plugins |
| Meta Muse | No (not documented by Meta) | Yes (not available yet) | a chat with Muse |
| xAI API remote MCP tool | No | Yes (not available yet) | tools array of the request |
| OpenAI API remote MCP tool | Only through a private tunnel | Yes (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 launchingclaude. - 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_TOKENandBURSAR_SETUP_URLlines after the first successful start and keepBURSAR_AUTHORIZER_URL, or leave the token out and use the terminal redemption described above, which also leaves onlyBURSAR_AUTHORIZER_URLinenv. - This route needs Node.js installed on the machine. The Blacksands
.dxtextension 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.logand onemcp-server-<name>.logper 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'senvblock, 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-bursarwrites 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
envtable 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
autoApprovemeans 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 asmcp:bursar:<tool>. - Zed does not document whether it passes its own shell environment to these servers, so set what you need in the
envblock.
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 addBURSAR_SETUP_TOKENthere. 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"
}
}
}
modedefaults torequired, which aborts the whole run if the server fails to start;optionalskips it with a warning instead.- Check with
/mcpin an interactive session. If you already registered Bursar in Claude Code, the bundled/migrateskill can import it. - Meta states that MCP tools are not sandboxed, so Bursar's file writes under
~/.blacksandsand its outbound TLS are not limited by Muse Code's network sandbox. - Muse Code does not bundle Node.js;
npxhas to be on yourPATH. - 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 coldnpxdownload can exceed. openclaw mcp doctor bursar --probechecks the server. The commandopenclaw mcp add bursar --command npx --arg -y --arg @blacksandscyber/mcp-server-bursarregisters the free server too. Do not use it to pass the token: an--envvalue is stored as a literal thatdoctorwarns 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_TOKENreaches 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
~/.blacksandsor 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
~/.blacksandsor 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: trueto gate calls. listTools()shares one set of credentials. Mastra's per-requestlistToolsets()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 putNAME=valuebeforenpxinside 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).
| What | Variables (the first one set wins) | Notes |
|---|---|---|
| Client certificate | BURSAR_CLIENT_CERT_PEM, BURSAR_CLIENT_CERT_B64, BURSAR_CLIENT_CERT (file path) | required |
| Client private key | BURSAR_CLIENT_KEY_PEM, BURSAR_CLIENT_KEY_B64, BURSAR_CLIENT_KEY (file path) | required |
| Auth password | BURSAR_AUTH_PASSWORD | required on a runtime with no files; where the bundle's files are present it may be left out (see below) |
| Organization id | BURSAR_ORG_ID | required, unless it comes from the stored bundle with the password |
| CA bundle | BURSAR_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 endpoint | BURSAR_AUTHORIZER_URL | your 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 |
| Role | BURSAR_ROLE (also accepted as SHIELD_ROLE): consumer or master | required 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 |
*_PEMis the PEM text,*_B64is the base64 of that PEM (easiest for runtimes that dislike multi-line values). Line-break damage from secret stores (literal\ntext, collapsed spaces, stray quotes) is repaired before use. EveryBURSAR_*name is also accepted asSHIELD_*; if both are set, a non-blankBURSAR_*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 whenBS_MCP_KEYSTOREisautooron, then the.auth-passwordfile inSHIELD_CERT_DIR, in the directory of theBURSAR_CLIENT_CERTfile, or in~/.blacksands/mcp-certs/. The bundle's.org-idis 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_ROLEdecides 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 withBURSAR_ROLEunset is shown the full tool list, and the server accepts some of those tools' calls. SetBURSAR_ROLE=consumerfor 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
consumerrole, notmaster. 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 amasterone) 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 theBootstrap completelog line, then stop it with Ctrl+C. On Windows the server takes its home fromUSERPROFILEinstead ofHOME, so pointUSERPROFILEat an empty folder for the redemption and read the files from.blacksands\mcp-certsinside it. The bundle holds everything in the table except the authorizer endpoint, and its.rolefile holds the role. Before you export anything, check that.client-nameholds 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.
Related
- Bursar FAQ covers the auth model, the tool categories and troubleshooting.
- Training guide walks through every tool with example calls.
- Installing the MCP client is the short version for Claude Code and Claude Desktop.
- The Developer Dashboard is where you see your agents, their access, your Receivers and your atlases.
