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 |
local_search |
Search your own indexed local files. See Glean Personal tools |
local_fetch |
Read one indexed local document in full |
local_sources |
List the local folders that have been indexed |
local_related |
Local documents connected to this one, with shared phrases as evidence |
The four local_* tools read the local content index at ~/.gleancode/personal.db,
built by /personal index <folder> in the REPL. Full guide: docs/PERSONAL.md.
They behave differently from every other tool on this server, in ways worth knowing:
- No credentials, no network. They never call the Glean API. They work with no token, no instance, and no connection.
GLEAN_MOCKdoes not apply. That variable governs the Glean-backed tools. The local tools always read the real local index, because there is no fictional alternative for them to serve.- Every response carries a
[LOCAL INDEX]banner. The content is real, but its scope is whatever folders the user indexed — not organisation-wide Glean. An agent cannot otherwise tell which index answered, and "my Downloads folder" must never be mistaken for company truth. Same reasoning as the mock banner below, different risk: mock data is fabricated, local data is real but narrow. - They return passages, not answers. Retrieval and a content graph; the model is yours. The server has no model in-process and does not pretend to.
If nothing has been indexed yet, each tool says so and names the command that fixes it.
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.