Skip to content

MCP Servers

Gemini CLI ships with a solid set of built-in tools: read files, write files, run shell commands, search code, browse the web. But your workflow does not stop at the boundary of the terminal. You have databases to query, APIs to call, monitoring dashboards to check, and internal tools that live in their own processes. You could tell Gemini CLI to curl those endpoints and parse the JSON itself, but that is fragile -- one schema change and every prompt breaks. You need a structured, discoverable way to give Gemini CLI access to external systems. That is what MCP servers provide.

Owl mascot

What you'll learn

  • An MCP server is a separate process that exposes tools, resources, and prompts to Gemini CLI through the Model Context Protocol
  • Gemini CLI supports three transports: stdio (subprocess), SSE (server-sent events), and streamable HTTP
  • MCP Prompts exposed by a server automatically become slash commands in Gemini CLI with argument support
  • Server configuration lives in settings.json under mcpServers, with per-server trust, timeout, and tool filtering controls
  • The gemini mcp command group handles add, list, remove, enable, and disable operations from the terminal

The problem: tools that live outside the terminal

Gemini CLI is good at working with what is on your filesystem. It reads your code, runs your build commands, edits your config files. But modern development involves dozens of external services. Your issue tracker is on GitHub or Jira. Your logs are in Cloud Monitoring. Your feature flags are in LaunchDarkly. Your database is on a managed instance that only speaks its own protocol.

Without MCP servers, you have two options. You can copy-paste context from another window into your Gemini CLI session every time you need it. Or you can have Gemini CLI call those services through raw HTTP and shell commands, hoping the tool descriptions are clear enough that it does not hallucinate an endpoint that does not exist. Both approaches waste time and produce unreliable results.

MCP servers solve this by giving each external system a structured interface. The server tells Gemini CLI exactly which tools are available, what parameters they accept, and what they return. Gemini CLI discovers them automatically at startup. You stop wrestling with integration glue and start using your tools directly.

Options and when to use each

The transport you pick determines how Gemini CLI communicates with your MCP server. Each has tradeoffs.

OptionWhat it is good forWhat it costs youWhen to pick it
Stdio transportLocal servers you start as a subprocess; no network setupServer lives and dies with the Gemini CLI session; cannot be shared across sessionsYou are running a one-off server, testing locally, or the server is a simple Python/Node script
SSE transportRemote servers or long-running local servers; server can stay up across sessionsRequires the server to be running and reachable at a URL before you start Gemini CLIYou have a persistent server on localhost or a remote host that multiple sessions should share
Streamable HTTP transportRemote servers, especially behind authentication; bidirectional streamingMore complex setup on the server side; needs proper HTTP endpoint with streaming supportYour server is behind Google Cloud IAP, requires OAuth, or needs HTTP-level authentication headers

After transport, the next decision is trust. MCP servers can execute arbitrary code. A server from a random GitHub repository could read your environment variables and exfiltrate API keys. Gemini CLI gives you controls:

  • Trust mode ("trust": true): Bypasses tool call confirmations for that server. The model can invoke any tool it discovers without asking you first. Use this for servers you wrote yourself or have audited.
  • Untrusted (default, "trust": false): Gemini CLI asks for confirmation before every tool call from that server. You see what the model wants to do and approve or deny it.
  • Tool allowlists (includeTools / excludeTools): Even for trusted servers, you can restrict which tools are available. A database server might expose both query and drop_table -- you probably want only query.
  • Environment sanitization: Gemini CLI automatically redacts sensitive environment variables (*TOKEN*, *SECRET*, *KEY*, *PASSWORD*) from the base environment before spawning MCP server processes. A third-party server cannot accidentally inherit your AWS credentials.

Build it: connecting your first MCP server

You will add an MCP server that gives Gemini CLI the ability to query a PostgreSQL database. The server runs locally via stdio.

Step 1: Create a minimal MCP server

Save this as db_server.py:

python
# db_server.py -- a minimal MCP server for PostgreSQL
import json
import sys
import psycopg2

DB_URL = "postgresql://user:pass@localhost:5432/mydb"

def handle_request(request):
    method = request.get("method")
    if method == "tools/list":
        return {
            "tools": [
                {
                    "name": "run_query",
                    "description": "Run a read-only SQL query against the database",
                    "inputSchema": {
                        "type": "object",
                        "properties": {
                            "query": {
                                "type": "string",
                                "description": "The SQL SELECT query to execute"
                            }
                        },
                        "required": ["query"]
                    }
                }
            ]
        }
    if method == "tools/call":
        tool_name = request["params"]["name"]
        args = request["params"]["arguments"]
        if tool_name == "run_query":
            conn = psycopg2.connect(DB_URL)
            cur = conn.cursor()
            cur.execute(args["query"])
            rows = cur.fetchall()
            columns = [desc[0] for desc in cur.description]
            return {
                "content": [
                    {"type": "text", "text": json.dumps(
                        [dict(zip(columns, row)) for row in rows],
                        default=str
                    )}
                ]
            }
    return {}

def main():
    while True:
        line = sys.stdin.readline()
        if not line:
            break
        request = json.loads(line)
        response = handle_request(request)
        sys.stdout.write(json.dumps(response) + "\n")
        sys.stdout.flush()

if __name__ == "__main__":
    main()

This is a stdio-based MCP server: it reads JSON-RPC messages from stdin and writes responses to stdout. It exposes one tool, run_query, that takes a SQL query and returns results as JSON.

Step 2: Configure the server in settings.json

Open your Gemini CLI settings file (~/.gemini/settings.json or .gemini/settings.json in your project) and add:

json
{
  "mcpServers": {
    "postgres-db": {
      "command": "python3",
      "args": ["db_server.py"],
      "cwd": "./mcp-servers",
      "timeout": 30000,
      "trust": false
    }
  }
}
  • command and args tell Gemini CLI how to start the server process
  • cwd sets the working directory for the subprocess
  • timeout is in milliseconds (30 seconds here)
  • trust: false means you will confirm every query before it runs

For an SSE server, you would use "url" instead of "command". For streamable HTTP, "httpUrl".

Step 3: Restart Gemini CLI and verify

Start a new Gemini CLI session. During startup you will see connection indicators for your MCP server. Run:

/mcp list

You should see postgres-db with status Connected. Gemini CLI discovered the run_query tool and registered it. Now ask a question that needs database access:

How many users signed up in the last 7 days?

Gemini CLI will call run_query with the appropriate SQL, get the results back, and answer in plain English. The query never left your machine -- the stdio transport runs the server as a child process.

Using gemini mcp add

You can also add servers from the terminal without editing settings.json by hand:

bash
# Add a stdio server
gemini mcp add my-server -- python3 server.py

# Add an SSE server
gemini mcp add --transport sse sse-server http://localhost:8080/sse

# Add an SSE server with an auth header
gemini mcp add --transport sse --header "Authorization: Bearer abc123" secure-sse https://api.example.com/sse/

# List all servers
gemini mcp list

# Disable a server temporarily
gemini mcp disable my-server

# Remove a server
gemini mcp remove my-server

The --scope flag (user or project) controls whether the server is available globally or only in the current project. Default is project.

What goes wrong

MistakeHow you notice itThe fix
Server process exits on startupGemini CLI shows "Disconnected" for the server in /mcp listRun the server command manually in a terminal to see the error. Check your command path, args, and that dependencies are installed
Tool schema is incompatibleGemini CLI discovers the server but individual tool calls fail with schema errorsGemini CLI validates tool schemas against the Gemini API requirements. Ensure your inputSchema uses valid JSON Schema. Avoid unsupported types or deeply nested objects
Sensitive environment leaksA third-party MCP server reads your GEMINI_API_KEY or AWS_SECRETGemini CLI redacts sensitive variables by default. If you need a specific variable exposed to a server, add it explicitly in the server's env block -- only variables listed there are passed through
Too many confirmation promptsEvery MCP tool call from an untrusted server asks for approval, slowing you downSet "trust": true for servers you have audited. Or use "includeTools" to allowlist specific safe tools while keeping the server untrusted
Tool name collisionsTwo MCP servers expose tools with the same name, and one overwrites the otherGemini CLI resolves conflicts when registering tools. Rename the tool in one server, or use excludeTools on one server to suppress the duplicate

Confirm it worked

  1. Run /mcp list inside Gemini CLI -- your server should show as Connected
  2. Ask a question that requires the server's tools -- for example, "How many rows are in the users table?" for a database server
  3. Watch the tool call appear in the session output. If trust is false, you will see a confirmation prompt before execution
  4. Verify the response uses real data from your external system, not a hallucinated answer

If the server shows Disconnected, run the command from your settings.json manually in a terminal (python3 db_server.py) and check for startup errors. Most disconnections are because the server process cannot start.

Next: Custom Slash Commands