Skip to content

Adding External Tools with MCP

Sidekick can load tools from external Model Context Protocol (MCP) servers. This lets you give the agent capabilities beyond its built-in toolset — file system access, web search, database queries, or any custom tool you write — without modifying Sidekick itself.

MCP tools appear alongside built-in tools in the chat. They go through the same tool permission system, so you approve or reject MCP tool calls the same way you would any other tool.


How it works

  1. You describe your MCP servers and which tools to expose in a JSON configuration file.
  2. When Sidekick starts, it launches each configured server, queries it for available tools, and registers them.
  3. The agent can then call those tools during a conversation. Each call starts the server, sends the request, and returns the result.

MCP servers communicate over stdio — Sidekick starts the server as a subprocess and exchanges JSON-RPC messages over stdin/stdout. Any program that speaks the MCP stdio transport can be a tool server.


Creating the configuration file

Place a file named mcp_tools_config.json in Sidekick's config directory:

$BN_USER_DIRECTORY/sidekick/config/mcp_tools_config.json

See Data Storage for how this path is resolved.

On a fresh plugin install, Sidekick creates this file for you if it is missing and adds a disabled sample_mcp_server entry that points at a bundled sample server copied into $BN_USER_DIRECTORY/sidekick/mcp_servers/mcp_test_server.py. If you already have an MCP config file, Sidekick leaves it untouched.

Minimal example

{
  "version": "1.0",
  "servers": [
    {
      "name": "my_tools",
      "server_config": {
        "command": ["python3", "/path/to/my_mcp_server.py"],
        "timeout": 30
      },
      "tools": [
        { "name": "tool_a", "enabled": true },
        { "name": "tool_b", "enabled": true }
      ],
      "enabled": true
    }
  ]
}

Full schema

Each entry in servers describes one MCP server:

Field Type Default Description
name string (required) A unique identifier for this server. Used only for logging.
enabled boolean true Set to false to skip this server entirely without removing it from the file.
tags string[] ["mcp"] Capability tags assigned to every tool from this server, unless overridden per-tool. See Tags and access control below.
server_config object (required) How to start the server.
server_config.command string[] (required) The command and arguments to start the MCP server process.
server_config.env object {} Additional environment variables passed to the server process. Merged with the current environment.
server_config.timeout number 30 Connection timeout in seconds for the initial handshake.
tools array (required) Which tools from this server to expose.

Each entry in tools selects a tool by the name the server reports:

Field Type Default Description
name string (required) The tool name as reported by the server's tools/list response.
alias string same as name An alternative name to use in Sidekick. Useful if two servers expose tools with the same name.
tags string[] (inherited from server) Override tags for this specific tool. Replaces server-level tags when present.
enabled boolean true Set to false to hide this tool without removing it from the list.

Multiple servers

You can configure as many servers as you need. Each can use a different runtime:

{
  "version": "1.0",
  "servers": [
    {
      "name": "filesystem",
      "tags": ["mcp.filesystem"],
      "server_config": {
        "command": ["uvx", "mcp-server-filesystem", "/home/user/allowed"]
      },
      "tools": [
        { "name": "read_file" },
        { "name": "list_directory", "alias": "list_dir" }
      ]
    },
    {
      "name": "git",
      "tags": ["mcp.git"],
      "server_config": {
        "command": ["uvx", "mcp-server-git", "--repository", "/path/to/repo"],
        "env": { "GIT_CONFIG_GLOBAL": "/dev/null" }
      },
      "tools": [
        { "name": "git_log" },
        { "name": "git_diff" }
      ]
    }
  ]
}

Tags and access control

Every tool in Sidekick is registered with capability tags that control which agents can see it. Built-in tools use tags like database, notebook, and python.binja. MCP tools default to the tag mcp.

The root Sidekick agent imports the mcp tag, which means it can see all MCP tools with the default tag. Subagents (research, transform, suggest) do not import mcp by default — MCP tools are available in chat conversations, not in automated suggest operations.

Custom tags

If you want finer control, assign more specific tags in the config:

{
  "name": "filesystem",
  "tags": ["mcp.filesystem"],
  ...
}

Tag matching is hierarchical: the agent imports mcp, which matches mcp, mcp.filesystem, mcp.git, and any other mcp.* tag. If you ever needed to restrict a subagent to only filesystem MCP tools, you could configure that agent to import mcp.filesystem instead of the broad mcp.

Tool permissions

MCP tools go through the same approval system as built-in tools. By default, the agent must request approval before calling an MCP tool. You can pre-approve MCP tools by tag or by name in Plugins > Sidekick > Configure Tool Permissions... — see Understanding Tool Permissions for details.


Writing a simple MCP server

An MCP server is any process that reads JSON-RPC messages from stdin and writes responses to stdout. Here is a minimal Python example that exposes two tools:

#!/usr/bin/env python3
"""Minimal MCP tool server."""

import json
import sys
from datetime import datetime, timezone

TOOLS = [
    {
        "name": "echo",
        "description": "Returns the text you send it.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "text": {"type": "string", "description": "Text to echo back"}
            },
            "required": ["text"]
        }
    },
    {
        "name": "get_time",
        "description": "Returns the current UTC time.",
        "inputSchema": {"type": "object", "properties": {}}
    },
]

def handle(msg):
    method = msg.get("method")
    rid = msg.get("id")

    # Notifications (no id) are silently ignored
    if rid is None:
        return

    if method == "initialize":
        respond(rid, {
            "protocolVersion": "2024-11-05",
            "capabilities": {"tools": {}},
            "serverInfo": {"name": "my-server", "version": "1.0.0"}
        })
    elif method == "tools/list":
        respond(rid, {"tools": TOOLS})
    elif method == "tools/call":
        name = msg["params"]["name"]
        args = msg["params"].get("arguments", {})
        if name == "echo":
            respond(rid, {"content": [{"type": "text", "text": args.get("text", "")}]})
        elif name == "get_time":
            now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
            respond(rid, {"content": [{"type": "text", "text": now}]})
        else:
            error(rid, -32601, f"Unknown tool: {name}")
    else:
        error(rid, -32601, f"Unknown method: {method}")

def respond(rid, result):
    sys.stdout.write(json.dumps({"jsonrpc": "2.0", "id": rid, "result": result}) + "\n")
    sys.stdout.flush()

def error(rid, code, message):
    sys.stdout.write(json.dumps({"jsonrpc": "2.0", "id": rid, "error": {"code": code, "message": message}}) + "\n")
    sys.stdout.flush()

while True:
    line = sys.stdin.readline()
    if not line:
        break
    line = line.strip()
    if line:
        handle(json.loads(line))

Save this as my_mcp_server.py and reference it in your config:

{
  "version": "1.0",
  "servers": [
    {
      "name": "my_tools",
      "server_config": {
        "command": ["python3", "/path/to/my_mcp_server.py"]
      },
      "tools": [
        { "name": "echo" },
        { "name": "get_time" }
      ]
    }
  ]
}

After restarting Binary Ninja, the agent will be able to call echo and get_time during chat conversations.


Using community MCP servers

The MCP ecosystem includes many ready-made servers. Any server that supports the stdio transport works with Sidekick. Some popular examples:

  • mcp-server-filesystem — read, write, and search files in allowed directories
  • mcp-server-git — query git repositories (log, diff, status)

Install with uvx (or npx for Node.js servers), then add the command to your config. Refer to each server's documentation for the command syntax and available tools.


Troubleshooting

Tools do not appear in chat

  • Verify the config file is at $BN_USER_DIRECTORY/sidekick/config/mcp_tools_config.json.
  • Check that the server command works standalone: run it in a terminal and paste a JSON-RPC initialize message to stdin.
  • Check the Sidekick log for Loaded N MCP tool(s) messages at startup. If the server failed to start or the handshake timed out, errors will appear in the log.
  • Confirm the server and tool entries have "enabled": true (or omit the field — it defaults to true).

Tool calls fail at runtime

  • Sidekick reuses the server subprocess across tool calls while the process is alive. A new process is started (and the MCP handshake is re-run) only if none exists yet or the previous process has exited. If the server takes too long during that handshake, increase timeout in server_config.
  • During the handshake Sidekick sends an initialize request and waits for the server's response, then sends a notifications/initialized notification to the server. The server does not respond to the notification; it is a one-way signal that the client is ready. Only after this sequence are tools/call messages sent.
  • Check that the server writes exactly one JSON line per response to stdout. Extra output (logging, debug prints) on stdout will break the protocol. Send diagnostic output to stderr instead.

Some tools from a large server are missing

Sidekick loads only the first page of a tools/list response. If the server supports pagination and returns a nextCursor, subsequent pages are not fetched and the additional tools are silently unavailable. A warning is written to the Sidekick log when this occurs. Work around it by listing only the specific tools you need in the tools array of your config, or by running a server that reports all tools on the first page.

Permission denied

  • MCP tools default to requiring approval. If you want the agent to call them without asking, add an allow rule for the mcp tag in Plugins > Sidekick > Configure Tool Permissions....