Connect a Claude client to the bridge
Tutorial 1 put the add-in in Excel, and the ribbon said no AI was connected. This one fixes that: by the end, a Claude client will be able to read the workbook that is open in front of you, and the ribbon will say so.
The bridge speaks MCP, which is simply a way for a Claude app to call tools that run on this machine — here, tools that read and change the workbook Excel already has open. Nothing is uploaded; Claude asks, the bridge reads the live book, and answers.
Prerequisites
- Tutorial 1 finished: you ran
install.cmd(one Unknown publisher click
for that downloaded script), AIBridge.xlam is in Excel's XLSTART folder
and the AI Bridge tab appears on the ribbon.
- A workbook open in Excel and saved to disk. The bridge binds by full path,
so an unsaved Book1 has nothing to bind to. These pages use
TutorialDemo.xlsx, which ships in this folder of the release zip.
- You have decided which of the three routes below you are taking. Release
customers take Route C and press Connect AI; that starts the embedded Python from the unpacked folder. You do not need a venv.
Choosing a route
There are three, and the difference is where Claude runs and who carries the traffic. Take Route A if the Claude app runs on this same machine: the client launches the bridge itself over stdio, and there is no port, no URL and no account to configure. Take Route C if you want claude.ai in a browser: the bridge dials out to a hosted broker, prints one URL, and you paste that URL into claude.ai — no tunnel, no DNS, no cloud console. Route B is the same browser connector run entirely on your own infrastructure; it is the advanced / self-hosted option, and you only need it if you would rather not depend on the hosted broker at all.
Everything from Point it at a workbook onwards is identical on all three routes.
Route A — a Claude app on this machine (stdio)
A local client starts the bridge as a child process and talks to it over that
process's own stdin and stdout. That is the default: src\server.py with no
--http flag serves stdio and never opens a socket.
Add one entry to the client's MCP configuration. Claude Desktop keeps it in
%APPDATA%\Claude\claude_desktop_config.json; Claude Code reads .mcp.json in
the project folder, or writes it for you via claude mcp add. The shape is the
same either way:
{
"mcpServers": {
"excel-ai-bridge": {
"command": "C:\\path\\to\\excel-ai-bridge\\venv\\Scripts\\python.exe",
"args": ["C:\\path\\to\\excel-ai-bridge\\src\\server.py"]
}
}
}
Replace C:\path\to\excel-ai-bridge with wherever you cloned this repository.
Use the interpreter inside venv, not a system python: the bridge imports
fastmcp, pywin32 and xlwings, and a system interpreter almost certainly has
none of them. The backslashes are doubled because this is JSON.
You can pin a workbook at startup instead of binding it later, by adding
"--workbook", "C:\\Users\\you\\Documents\\TutorialDemo.xlsx" to args.
Then restart the client completely — MCP servers are launched at start-up, so
reloading a conversation is not enough. When it comes back, the Excel tools appear
in its tool list: read_range, write_cells, get_active_selection,
analyze_sheet, privacy_report and the rest, alongside bind_workbook. If the
list is empty, the client could not launch the command — check the path and the
interpreter before anything else.
On stdio there is no token and no sign-in, and the audit records the caller as
local. That is not laziness: the client is the parent process, so anything
able to write to this bridge's stdin is already inside the machine.
Route C — the hosted broker (recommended)
This is the short way to claude.ai. With the add-in installed, open a saved
workbook and press Connect AI. If no bridge is running, the ribbon launches
the embedded runtime — python\pythonw.exe with src\server.py --broker from
the unpacked folder (the path install.cmd recorded). The tray icon shows it
running, then the add-in attaches as today. The invite is already in
invite.json at the zip root, so you do not type a code.
From-source developers can still start it by hand:
venv\Scripts\python.exe src\server.py --broker
If you start by hand without invite.json, put the invite in the environment:
set EXCEL_BRIDGE_INVITE=the-code-you-were-given
The bridge registers itself with the broker once, and stores the identity it
gets back — DPAPI-protected, so it is readable only by this Windows account on
this machine — in %LOCALAPPDATA%\ExcelAIBridge\broker.json. Later starts read
that file and need no invite code at all. On the way up it prints four lines on
stderr:
AI Bridge: connector URL https://bridge.ram.sh/<id>/mcp
AI Bridge: Google redirect to register: https://bridge.ram.sh/auth/callback
AI Bridge: accounts allowed: you@example.com
AI Bridge: linked to https://bridge.ram.sh
<id> is this bridge's own 32-hex id, minted at registration and the same on
every later start. The Google redirect is fixed at
https://bridge.ram.sh/auth/callback and is already registered in the shared
OAuth app, so there is nothing for you to add in a Google console.
Then add it in claude.ai:
- Settings → Connectors → Add custom connector.
- Paste the connector URL exactly as printed —
https://bridge.ram.sh/<id>/mcp.
- Press Connect.
- Approve the bridge's consent page when it appears.
- Sign in with Google, using an account that is on the allowlist. The
allowlist is EXCEL_BRIDGE_ALLOWED, a comma-separated list of email
addresses, or the 1Password item Excel AI Bridge - allowed google accounts.
It is the same allowlist Route B uses, and an empty one is fatal on purpose.
Nothing on this machine listens on a port. The bridge opens an outbound
WebSocket to the broker and keeps it, so claude.ai's request arrives down a
connection you dialled — which is why there is no tunnel to run, no port to
forward and no firewall rule to write. The broker only relays bytes between
claude.ai and your bridge: the Google sign-in is checked against your allowlist,
the workbook and the audit log stay on this machine, and the identity in
broker.json never leaves it.
On a machine with no access to the shared vault, set
EXCEL_BRIDGE_GOOGLE_CLIENT_ID and EXCEL_BRIDGE_GOOGLE_CLIENT_SECRET in the
environment instead; those values win over the vault when they are set.
Route B — claude.ai in a browser, self-hosted (advanced)
Route C already gets you a browser connector. Take this route only if you want
to host the public side yourself: it needs a public https:// address you own,
a tunnel you run, and a Google OAuth app whose redirect you register by hand.
Start the bridge in HTTP mode yourself, from the repository folder:
venv\Scripts\python.exe src\server.py --http --port 8765 --google
--google makes the bridge check who is signing in, because this route is
reachable from the internet: it refuses to serve anyone but the Google accounts
you have named. (--google implies --http, so that flag is only there to make
the port explicit.) On the way up the bridge prints the loopback address, the
connector URL and the list of allowed accounts on stderr.
Two things it needs from you before this mode will start:
- A public `https://` address that reaches that port. The bridge binds to
127.0.0.1 only, deliberately. Exposing it is a separate, deliberate act on
your part — a Cloudflare tunnel, an ssh -R to a server you own, ngrok,
whatever you trust. Which one you use is your choice and your responsibility;
this project does not set one up for you and does not ship one.
- `EXCEL_BRIDGE_PUBLIC_URL`, telling the bridge what that address is, so it
can build the OAuth redirect Google has to match exactly. It must begin with
https://; plain http:// is refused rather than quietly carrying an
authorization code in clear text.
set EXCEL_BRIDGE_PUBLIC_URL=https://excel.example.com
Use your own hostname there, not the example one. EXCEL_BRIDGE_ALLOWED — or the
1Password item Excel AI Bridge - allowed google accounts — holds the
comma-separated list of Google accounts allowed in. An empty list is fatal on
purpose, because "no allowlist" must never quietly mean "anyone with a Google
account who finds the URL".
Now add it in claude.ai: Settings → Connectors → Add custom connector, and
give it that same public address with /mcp on the end, for example
https://excel.example.com/mcp. Claude registers itself against the bridge's
authorization server, you sign in with Google once, and the connector goes green.
About the bearer token. --google and the token are two different doors and
you only ever use one of them. claude.ai's connector speaks OAuth and cannot
present a bearer token at all, which is exactly why this route uses --google.
The token guards --http without --google — the mode for anything you drive
yourself, a script or a terminal client. It is minted once and kept in 1Password
under the item Excel AI Bridge - connector token, reused across restarts so that
a connector you configured once does not break on the next start; rotate it by
deleting that item. If you would rather manage it yourself, set
EXCEL_BRIDGE_TOKEN in the environment and that value wins, with no vault
involved at all. Never paste a token into a chat, a commit or a screenshot.
Point it at a workbook, and prove the link
The screenshots below come from a Route B run against TutorialDemo.xlsx. Route A
looks the same from the second step onwards — same tools, same replies — and
differs only in that a local client asks for permission in its own way.
- Ask Claude for anything that needs the workbook, and it stops to ask
permission first. Here the request was *"Bind the workbook at
C:\Users\you\Documents\TutorialDemo.xlsx"*, and Claude will not call
bind_workbook until you say so. Choose Allow once: it grants that single
call and nothing more. The other button grants the tool for good — a standing
permission to reach into your spreadsheet that you will never be reminded
about again. The dialog appears once per new tool, so expect a handful of
them early on and almost none later.
The tool-permission dialog, with Allow once offered
- Claude calls
bind_workbookand answers with what it bound: the full path,
the transport, the port, and whether the file was locked on disk. Give it the
full path, always. bind_workbook accepts nothing else — not a file name,
not "the workbook I have open" — and a path that is not currently open in Excel
is refused rather than guessed at. That refusal is the whole point: with two
revisions of the same budget open, "the active workbook" is whichever one you
happened to click last, and a write can land silently in the wrong copy. A full
path cannot be ambiguous.
Claude reporting the workbook it bound, by full path
- Switch to Excel. The AI Bridge tab now reads AI connected with a green
dot, and the tab strip itself says AI Bridge - connected. That light is not the button remembering it was pressed: the bridge republishes its state every few seconds and the ribbon only reports what it reads, so a bridge that dies goes dark on its own. Two neighbouring states are worth learning now. Waiting for AI, amber, means this workbook was offered but nothing has picked it up yet. Connect here, red, means a bridge is live but holding a different workbook — press it to move the binding to this one.
The Excel ribbon reading AI connected
- Ask "Which workbooks are you holding right now?".
list_bound_workbooks
answers with a name, a full path and a session id for each one. Binding is
additive: a second bind_workbook does not replace the first, it adds to it,
and once more than one workbook is bound every other tool needs a workbook=
argument saying which. This is the call to make whenever you are unsure what
Claude is actually looking at.
Claude listing the workbooks it currently holds
- Back in Excel, select a few cells — here the headcount column,
Budget!C3:C7.
Do not tell Claude which cells you picked. The point of the next step is that it can find out for itself.
Cells selected by hand in the demo workbook
- Ask "What cells do I have selected in Excel right now?".
get_active_selection comes back with the address you just dragged over and
the values inside it. This is the clearest proof the link is live in both
directions: nothing about that selection was ever typed into the chat, so the
only way Claude can know it is by reading the workbook you are sitting in front
of, at the moment you asked.
Claude naming the selection that was made in Excel
- Finish with a plain read: "Read Budget!A2:E7 and show me the rows."
read_range returns the values, the formulas behind them, and — if any of
those cells were marked private — a masked list of the addresses whose values
were replaced by [redacted], plus one sentence saying so. The contents of a
private cell never leave the machine; only the fact that something was hidden
does. Every one of these calls is appended to
%LOCALAPPDATA%\ExcelAIBridge\audit\<workbook-key>.jsonl with the caller's
identity, so you can go back later and see exactly what was read.
Claude reading a range of the workbook back
When it does not work
- The ribbon still says Waiting for AI. Amber means Excel wrote the request
and nothing has answered it. Either no bridge is running, or the one that is running is bound to a different file. Press Status on the AI Bridge tab for the state in words, and read the bridge's own console output.
- The ribbon says Connect here. A bridge is alive but holding another
workbook. This is the wrong-workbook case the whole project exists to prevent,
which is why it is the loud one. Press the button, or ask Claude to call
bind_workbook with this file's full path.
- The connector shows offline in claude.ai. The bridge is loopback-only, so
"offline" nearly always means the tunnel rather than the bridge. Fetch
https://<your-host>/mcp from outside your own network: if that fails, the
tunnel is down and restarting the bridge will not help. Setting
EXCEL_BRIDGE_TUNNEL_CMD to the command that publishes the bridge makes the
bridge supervise and restart it for you.
On Route C there is no tunnel to blame: read the bridge's own console
for AI Bridge: linked to https://bridge.ram.sh. If it says `broker link
down`, the bridge is already retrying by itself and will link again on its
own. If it never links at all, the invite or the id in
%LOCALAPPDATA%\ExcelAIBridge\broker.json may have been revoked — delete
that file and restart with EXCEL_BRIDGE_INVITE set to a fresh code, which
registers this bridge again.
- The tool list looks out of date. claude.ai caches a connector's tool list.
After the bridge gains or loses a tool, disconnect and reconnect the connector in Settings so that it fetches the list again.
- Sign-in is refused after a successful Google login. Your account is not on
the allowlist. Signing in with Google proves you are somebody; the allowlist
is what makes this your bridge rather than everyone's. Add the address to
EXCEL_BRIDGE_ALLOWED and restart.
- The bridge is running but bound to nothing. Entirely normal at startup — a
fresh bridge holds nothing and refuses to guess. Every tool refuses until
something binds a workbook: bind_workbook with a full path, the ribbon's
connect button, or --workbook at launch.
Next: Work back and forth — reading, writing, formatting, undo, and watching the privacy guard refuse.