glean_mcp.py exposes Glean as an MCP server so Claude Code, Claude Desktop,
and Cursor can call Glean search, chat, and agents as native tools.
It reads the same ~/.gleancode/config.json but forces mode = "live" regardless of what
that file says, so MCP tools call the real API by default. Mock mode is available but must be
asked for explicitly — see Running the MCP server on mock data.
Install the MCP package (one-time):
pip
pip install "mcp[cli]>=1,<2"brew
brew install pipx
pipx install "mcp[cli]>=1,<2"The <2 bound is required — see MCP SDK v2 below.
Claude Code — add to .claude/settings.json in your project, or to
~/.claude/settings.json globally:
{
"mcpServers": {
"glean": {
"command": "python3",
"args": ["/absolute/path/to/glean-code-cli/glean_mcp.py"]
}
}
}Claude Desktop — add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"glean": {
"command": "python3",
"args": ["/absolute/path/to/glean-code-cli/glean_mcp.py"]
}
}
}Cursor — add to .cursor/mcp.json in your project:
{
"mcpServers": {
"glean": {
"command": "python3",
"args": ["/absolute/path/to/glean-code-cli/glean_mcp.py"]
}
}
}Credentials are loaded automatically from ~/.gleancode/config.json (written
by /login in the REPL). You can also pass them as environment variables:
{
"mcpServers": {
"glean": {
"command": "python3",
"args": ["/absolute/path/to/glean-code-cli/glean_mcp.py"],
"env": {
"GLEAN_INSTANCE": "your-instance-be.glean.com",
"GLEAN_TOKEN": "your-token"
}
}
}
}Tools exposed:
| Tool | Description |
|---|---|
search |
Search the Glean index; optional datasource and page_size |
chat |
Chat with the Glean Assistant; pass chat_id to continue a thread |
list_agents |
List available agents; optional query filter |
run_agent |
Run an agent by id and return its output |
get_flow |
The captured investigation graph — sessions, citations, links. See docs/FLOW_MAPPER.md |
get_flow_summary |
What was investigated and what connected to what, in prose |
get_flow_collapsed |
The compact view — threads folded into counted nodes |
Set GLEAN_MOCK on the server entry to serve the mock corpus instead of
your tenant — handy for wiring up an agent and testing the tool loop before you have a token:
{
"mcpServers": {
"glean": {
"command": "python3",
"args": ["/absolute/path/to/glean-code-cli/glean_mcp.py"],
"env": {"GLEAN_MOCK": "1"}
}
}
}Accepted values are 1, true, yes, and on. Every tool response is then prefixed with:
[MOCK MODE] Fictional demo data, not your organisation's real content — do not cite or act on it as real.
The banner is deliberate. An agent cannot tell fabricated results from real ones, and the corpus returns confident-looking documents with plausible URLs — without a label, made-up content launders straight into whatever the agent writes or acts on. The same warning is in each tool's description, so it reaches the model before it calls anything.
For the same reason mock mode is opt-in and never inherited: mode in
~/.gleancode/config.json is ignored by the server, including auto, which would otherwise
flip an agent onto fake data the day a token expires.
Requires Python 3.10+. The REPL itself remains Python 3.9+ and stdlib-only.
The setups above are the normal ones: the client owns the server's lifecycle, spawning
glean_mcp.py over stdio whenever it needs it. Nothing to start by hand.
When you do want a server running independently — to point several clients at one process, to
watch its log while you work, or to check the thing comes up at all — /mcp handles it from
inside glean:
/mcp status # mcp version, compatibility, and any running server
/mcp config claude-code # the JSON block to paste, per client
/mcp start --port 9000 # run it detached over HTTP
/mcp config --url # the JSON block pointing at that running server
/mcp stop
── mcp ─────────────────────────────────────────────────────────────
mcp package 1.29.0 (v1 line, compatible)
server script glean_mcp.py
server running pid 73343, up 4m
endpoint http://127.0.0.1:8791/mcp
would serve mock [MOCK MODE banner active]
tools search, chat, list_agents, run_agent, get_flow,
get_flow_summary, get_flow_collapsed
log ~/.gleancode/mcp.log
────────────────────────────────────────────────────────────────────
/mcp start never uses stdio. stdio is a pipe pair between a client and the server it
spawned; started from the REPL there would be no client on the other end, and the REPL already
owns its own stdin and stdout. start therefore runs streamable-http (default) or sse,
which a client attaches to by URL — /mcp config --url prints that form. This only helps if
your client supports URL-based servers; for a client that spawns commands, use the stdio form.
Details worth knowing:
- Binds
127.0.0.1by default. A live server holds whatever credentials your config has.--hostcan widen that; think before it does. - The server outlives the REPL. It is started in its own session, so
/exitleaves it running. State lives in~/.gleancode/mcp.json, which is how a latergleansession still finds it, and stale entries are cleared automatically when the process is gone. - Mock mode is inherited. Start it while the REPL is in mock mode (or pass
--mock) and the server serves the built-in corpus with the[MOCK MODE]banner on every response. - Logs go to
~/.gleancode/mcp.log. A server that dies on startup — a port already in use, most often — is reported immediately, with the log path for the detail.
Glean ships its own hosted MCP server. It is a different thing from this one: it talks to your
tenant directly, while glean_mcp.py wraps the Client REST API and adds mock mode. /mcp only
manages this repo's server — it never detects, starts, or talks to Glean's.
They collide in exactly one place. Both would naturally be registered under the key glean:
{ "mcpServers": { "glean": { ... } } }Pasting one over the other silently replaces it — no error, you simply end up with a different set of tools than you expected. Use a distinct key to keep both:
/mcp config --name glean-cli
{ "mcpServers": { "glean-cli": { "command": "python3", "args": ["…/glean_mcp.py"] } } }/mcp config warns about this whenever it emits the default name.
glean_mcp.py targets the v1 line of the mcp SDK. Install it with an upper bound:
pip install "mcp[cli]>=1,<2"mcp 2.0.0 (released 2026-07-28) renamed FastMCP to MCPServer and removed the
mcp.server.fastmcp module this server imports. Without the bound, a fresh
pip install "mcp[cli]" resolves to 2.x and the server dies on import:
ModuleNotFoundError: No module named 'mcp.server.fastmcp'
The server detects that case specifically and says so, rather than telling you to reinstall the package that just broke it:
Found the 'mcp' package (version 2.0.0), but it does not provide
mcp.server.fastmcp. That module was removed in mcp 2.0.0, which renamed
FastMCP to MCPServer. glean_mcp.py has not been ported to the v2 API yet.
Pin the v1 line: pip install "mcp[cli]>=1,<2"
An existing 1.x install is unaffected — nothing needs to change until you upgrade.
Outstanding work: port glean_mcp.py to the v2 API (from mcp.server import MCPServer;
the decorator API is unchanged, so the four @mcp.tool() handlers should carry over largely
as-is). Once ported, drop the <2 bound here and in the module docstring.