Appearance
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.

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.jsonundermcpServers, with per-server trust, timeout, and tool filtering controls - The
gemini mcpcommand 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.
| Option | What it is good for | What it costs you | When to pick it |
|---|---|---|---|
| Stdio transport | Local servers you start as a subprocess; no network setup | Server lives and dies with the Gemini CLI session; cannot be shared across sessions | You are running a one-off server, testing locally, or the server is a simple Python/Node script |
| SSE transport | Remote servers or long-running local servers; server can stay up across sessions | Requires the server to be running and reachable at a URL before you start Gemini CLI | You have a persistent server on localhost or a remote host that multiple sessions should share |
| Streamable HTTP transport | Remote servers, especially behind authentication; bidirectional streaming | More complex setup on the server side; needs proper HTTP endpoint with streaming support | Your 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 bothqueryanddrop_table-- you probably want onlyquery. - 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
}
}
}commandandargstell Gemini CLI how to start the server processcwdsets the working directory for the subprocesstimeoutis in milliseconds (30 seconds here)trust: falsemeans 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 listYou 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-serverThe --scope flag (user or project) controls whether the server is available globally or only in the current project. Default is project.
What goes wrong
| Mistake | How you notice it | The fix |
|---|---|---|
| Server process exits on startup | Gemini CLI shows "Disconnected" for the server in /mcp list | Run the server command manually in a terminal to see the error. Check your command path, args, and that dependencies are installed |
| Tool schema is incompatible | Gemini CLI discovers the server but individual tool calls fail with schema errors | Gemini 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 leaks | A third-party MCP server reads your GEMINI_API_KEY or AWS_SECRET | Gemini 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 prompts | Every MCP tool call from an untrusted server asks for approval, slowing you down | Set "trust": true for servers you have audited. Or use "includeTools" to allowlist specific safe tools while keeping the server untrusted |
| Tool name collisions | Two MCP servers expose tools with the same name, and one overwrites the other | Gemini 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
- Run
/mcp listinside Gemini CLI -- your server should show as Connected - Ask a question that requires the server's tools -- for example,
"How many rows are in the users table?"for a database server - Watch the tool call appear in the session output. If
trustisfalse, you will see a confirmation prompt before execution - 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