@gtmi/twilio-gtmi-mcp
v0.1.1
Published
Standalone MCP server exposing Twilio messaging, voice, verify, lookups, and SendGrid email APIs as tools.
Downloads
172
Keywords
Readme
@gtmi/twilio-gtmi-mcp
Standalone MCP server exposing Twilio messaging, voice, verify, lookups, and SendGrid email APIs as tools. Stdio transport — works in Claude Desktop, Cursor, Goose, or anything else that speaks MCP.
Built on the MCP v2 SDK (@modelcontextprotocol/server): it serves the
current spec 2026-07-28 and stays backward-compatible with 2025-11-25
handshake hosts. See MCP protocol.
MCP protocol
Served on the MCP v2 SDK (@modelcontextprotocol/server 2.0.0) via
serveStdio, which selects the protocol era per connection from the
client's opening message — no config decides it:
2026-07-28(current spec) for modern stateless clients —server/discoverplus per-request_metaversion negotiation.2025-11-25for 2025-erainitialize-handshake hosts — Claude Desktop, Cursor, and MCP Inspector today. The same binary answers both, so current hosts connect and negotiate2025-11-25automatically, and pick up2026-07-28once they ship a v2 client.
The stdio launch command is unchanged, so existing host config keeps working.
Architecture
One stdio subprocess exposes tools, prompts, and resources to the MCP client. Two independent credentials do two jobs: the Auth Token signs Twilio API calls, and the API Key authenticates the status-callback relay connection. Status callbacks arrive over an outbound WebSocket to a relay — no ngrok, no inbound port. The numbered edges trace one callback round-trip.
flowchart TB
Client["MCP client<br/>Claude Desktop · Cursor · Code"]
subgraph MCP["@gtmi/twilio-gtmi-mcp · one stdio subprocess"]
Tools["Tools<br/>messages_create · calls_create · agent_pay_*<br/>verify_* · lookups_* · email_*"]
Prompts["Prompts<br/>*_overview · agent_pay_* guidance"]
Resources["Resources<br/>catalogs · twilio://status-callbacks/recent · /{sid}"]
SC["status-callback.ts<br/>getDefaultStatusCallback() · onStatusCallback()<br/>waitForStatus() · ring buffer (last 100)"]
end
Relay["Callback relay<br/>callback-relay.fly.dev<br/>or MCP_CALLBACK_RELAY_HOST"]
Twilio["Twilio<br/>messaging · voice · payments"]
Client -->|"stdio JSON-RPC: tools/call · prompts/get · resources/read"| MCP
SC -->|"1 · WSS connect · auth SID + API_KEY + API_SECRET"| Relay
Relay -->|"1 · hello { publicUrl }"| SC
Tools -->|"2 · API call · auth SID + AUTH_TOKEN · statusCallback = publicUrl"| Twilio
Twilio -->|"3 · POST status update to publicUrl"| Relay
Relay -->|"4 · push callback frame over the open WSS"| SC
SC -->|"5 · onCallback fans out to listeners: ring buffer + waitForStatus"| Resources
Resources -->|"6 · resources/read"| Client
Prompts -.->|"guide the LLM to read status between agent_pay_* steps"| ClientTools
Tool names have no twilio_ / sendgrid_ prefix; the MCP server is named
twilio so the host's qualifier already disambiguates (twilio.messages_create).
Messaging
| Tool | Description | Cost |
|---|---|---|
| messages_create({channel, to, from?, messagingServiceSid?, body?, contentSid?, ...}) | Send via SMS / WhatsApp / RCS | incurs charges |
| messages_fetch({sid}) | Look up a message by SID | free |
| messaging_services_fetch({sid}) | Inspect a Messaging Service's sender pool + flags | free |
| content_templates_fetch({sid}) | Inspect a Content template (HXxxxx) | free |
Voice
| Tool | Description | Cost |
|---|---|---|
| calls_create({to, from, twiml?, url?}) | Place an outbound voice call | incurs charges |
| calls_fetch({sid}) | Look up a call by SID | free |
| voice_say({...}) | Compose a <Say> TwiML fragment | free |
| voice_play({...}) | Compose a <Play> TwiML fragment | free |
| voice_dial({...}) | Compose a <Dial> TwiML fragment | free |
| voice_pay({...}) | Compose a <Pay> TwiML fragment for one-shot IVR card capture | incurs charges on use |
| voice_transcription_start({...}) | Begin real-time transcription on a live call | incurs charges |
| voice_transcription_stop({...}) | End real-time transcription | free |
| agent_pay_start({callSid, ...}) | Start a live-call <Payments> capture (LLM-driven) | incurs charges |
| agent_pay_capture_card({callSid, paymentSid}) | Advance the capture to PAN entry | free |
| agent_pay_capture_exp({callSid, paymentSid}) | Advance to expiration entry | free |
| agent_pay_capture_cvc({callSid, paymentSid}) | Advance to CVC entry | free |
| agent_pay_complete({callSid, paymentSid}) | Finalize (tokenize or charge) | incurs charges on charge |
The two payment paths — voice_pay (TwiML one-shot) and agent_pay_*
(live-call LLM-driven) — coexist by design. See "Agent-assisted payments"
below.
Verify
| Tool | Description | Cost |
|---|---|---|
| verify_send({to, channel, serviceSid}) | Send an OTP via Verify | incurs charges |
| verify_check({to, code, serviceSid}) | Validate the OTP | free |
| verify_services_fetch({sid}) | Inspect a Verify Service | free |
Lookups
| Tool | Description | Cost |
|---|---|---|
| lookups_fetch({phone_number}) | Twilio Lookup v2 — validate + format E.164 | free |
Email — SendGrid
| Tool | Description | Cost |
|---|---|---|
| email_send({to, from, subject?, text?, html?, templateId?, ...}) | Send an email | incurs charges |
| email_fetch({msgId}) | Fetch SendGrid delivery + event timeline (Pro+) | free |
| email_search({query?, ...}) | Search recent SendGrid messages (Pro+) | free |
| email_templates_fetch({templateId?, ...}) | Inspect SendGrid dynamic templates | free |
Prompts
Two flavours:
<service>_overview— zero-arg, returns an opinionated guide to "when to use which tool in this service". An LLM that just connected can fetchprompts/get messaging_overviewand become productive without reading every tool description.- Per-flow prompts — walk the LLM through a specific multi-step task
(templated WhatsApp sends, Messaging Service routing, OTP verification,
dynamic-template email, agent-assisted payment capture). These take args
for the concrete identifiers the flow will use (e.g.
to,from,callSid).
| Prompt | When to fetch | Args |
|---|---|---|
| messaging_overview | LLM is about to send / look up a message | — |
| send_whatsapp_template | Sending a templated WhatsApp message (HX template + variables) | {to, contentSid?} |
| send_via_messaging_service | Sending through an MG SID (sender-pool routing, opt-out, A2P 10DLC) | {to, messagingServiceSid?} |
| send_rcs_with_fallback | RCS message that should gracefully fall back to SMS | {to} |
| voice_overview | LLM is composing TwiML or choosing between the two payment paths | — |
| place_call_with_inline_twiml | Composing inline TwiML from voice_* fragments without a webhook | {to, from} |
| start_call_transcription | Picking real-time STT over Media Streams / ConversationRelay | {callSid?} |
| verify_overview | Before starting an OTP send / check flow | — |
| verify_otp_flow | End-to-end OTP walkthrough (send → wait → check) | {to, channel} |
| lookups_overview | Before validating a phone number | — |
| email_overview | Before sending or searching SendGrid mail | — |
| send_email_with_dynamic_template | Sending a d-… dynamic-template email with Handlebars data | {to, from, templateId?} |
| agent_pay_start_capture | Opening instructions for an agent-assisted payment capture | {callSid} |
| agent_pay_card_number | After agent_pay_capture_card returns | {callSid, paymentSid} |
| agent_pay_expiration | After agent_pay_capture_exp returns | {callSid, paymentSid} |
| agent_pay_security_code | After agent_pay_capture_cvc returns | {callSid, paymentSid} |
| agent_pay_finish | Before agent_pay_complete (read back masked state) | {callSid, paymentSid} |
| agent_pay_completion | After agent_pay_complete succeeds | {callSid, paymentSid, paymentToken?} |
| agent_pay_error | On any errorType from a payment status callback | {callSid, paymentSid, errorType} |
Overview prompts register inside the same creds gates as their tools — if
Twilio creds are absent, the messaging / voice / verify / lookups overviews
and their per-flow siblings do not appear in prompts/list. email_overview
and send_email_with_dynamic_template require SendGrid creds.
Resources
Read-only MCP resources for catalog lookup (so the LLM doesn't have to guess SIDs) and for the in-flight status-callback stream.
| URI | Returns |
|---|---|
| twilio://content-templates | Content templates (HX SIDs) on this account — variables, types, friendly names |
| twilio://messaging-services | Messaging Services (MG SIDs) — sender-pool routing knobs, callback URLs |
| twilio://verify-services | Verify Services (VA SIDs) — code length, channel settings |
| twilio://phone-numbers | Phone numbers owned by the account — capability flags |
| twilio://status-callbacks/recent | Last 100 webhook events received via the status-callback ingress, newest-first |
| twilio://status-callbacks/{sid} | Same buffer filtered by MessageSid / CallSid / PaymentSid / etc. |
| sendgrid://templates | SendGrid dynamic templates (d-…) |
| sendgrid://verified-senders | Verified sender addresses — what email_send.from is allowed to use |
The status-callback resources are populated by Twilio's webhook POSTs
routed through the callback relay — set TWILIO_API_KEY +
TWILIO_API_SECRET to enable. Without them the resource registers but
stays empty.
Twilio resources require TWILIO_ACCOUNT_SID + TWILIO_AUTH_TOKEN;
SendGrid resources require SENDGRID_API_KEY. Same all-or-nothing gating
as tools / prompts.
Agent-assisted payments — walkthrough
agent_pay_* uses Twilio's live-call <Payments> API (POST to
/2010-04-01/Accounts/{AccountSid}/Calls/{CallSid}/Payments.json). Unlike
the TwiML <Pay> verb (which voice_pay emits and Twilio runs
end-to-end as an IVR), <Payments> lets the LLM drive each capture step
and react to status callbacks in between.
Flow (LLM driving a live call):
- Fetch the
agent_pay_start_captureprompt with the live call'sCallSid. Tell the caller what to expect. - Call
agent_pay_start({callSid, chargeAmount?, paymentConnector?, ...}). The tool returns apaymentSid. Hold onto bothcallSidandpaymentSid— every subsequent step needs them. - Call
agent_pay_capture_card({callSid, paymentSid}). Fetch theagent_pay_card_numberprompt to guide your conversation while the caller enters digits. - Repeat for
agent_pay_capture_exp(useagent_pay_expirationprompt) andagent_pay_capture_cvc(useagent_pay_security_codeprompt). - Fetch
agent_pay_finishto read back the masked state and confirm. - Call
agent_pay_complete({callSid, paymentSid}). The tool returns the payment token / final status. Use theagent_pay_completionprompt to close the flow politely. - On any
errorTypearriving via the status-callback path, fetchagent_pay_errorfor retry / escalation guidance.
Prerequisite. The Twilio account needs a configured Pay Connector
(Stripe, Braintree, etc.). Without one, agent_pay_start returns an error
from the Twilio API. The same prerequisite applies to voice_pay.
Status callbacks (optional)
Twilio's voice / messaging / payment APIs accept a statusCallback URL.
This package ships with an opt-in helper that publishes a public HTTPS URL
via @gtmi/mcp-status-callback
(v2). The client opens an outbound WSS to a callback relay, which hands
back a stable HTTPS URL and forwards Twilio's POSTs down that socket — no
ngrok, no inbound port. Every tool that takes receiveStatusCallbacks: true
then routes those POSTs back into the process, where they're forwarded to
MCP listeners. Named mode (subscriptionName: "twilio-gtmi-mcp") keeps the URL
stable across restarts: https://<relay>/callback/AC…/named/twilio-gtmi-mcp.
Prerequisites — these are not drop-in:
- A Twilio API Key. The relay client authenticates with
Basic(SK…:secret), so provision an API Key and setTWILIO_API_KEY(SK…) +TWILIO_API_SECRETin addition to the existingTWILIO_ACCOUNT_SID. The main Twilio client keeps usingTWILIO_AUTH_TOKEN; only the callback client needs the key. - A running relay. Either point at the shared reference deploy
(default
callback-relay.fly.dev) or self-host@twilio-demos/mcp-callback-relayand setMCP_CALLBACK_RELAY_HOST(host only, no scheme).
Self-host the relay for payments.
agent_pay_*status callbacks carry payment state (masked PAN, tokens, confirmation codes) that transits the relay host in flight. Do not route those through a shared third-party relay in production — self-host the relay and pointMCP_CALLBACK_RELAY_HOSTat it.
Without TWILIO_API_KEY + TWILIO_API_SECRET, the callback URL is omitted
from outbound requests — agent_pay_* still works for the Twilio-side
capture but no callback events arrive.
Creds gating
| Group | Required env | Tools | Prompts | Resources |
|---|---|---|---|---|
| Twilio | TWILIO_ACCOUNT_SID + (TWILIO_AUTH_TOKEN or TWILIO_CLIENT_ID + TWILIO_CLIENT_SECRET) | 21 (messaging / voice / verify / lookups, including 5 agent-pay) | 17 (4 overviews + 6 per-flow + 7 agent-pay) | 6 (4 catalogs + 2 status-callback views) |
| SendGrid | SENDGRID_API_KEY | 4 (email) | 2 (email_overview, send_email_with_dynamic_template) | 2 (sendgrid://templates, sendgrid://verified-senders) |
Within a group, missing keys are all-or-nothing — supplying
TWILIO_ACCOUNT_SID alone (without a complete Auth Token or OAuth pair)
registers zero Twilio tools, prompts, and resources. See
Authentication modes for the two ways to satisfy
the Twilio half.
Authentication modes
The main Twilio client supports two ways to authenticate — pick one:
- Auth Token (default).
TWILIO_ACCOUNT_SID+TWILIO_AUTH_TOKEN— HTTP Basic on every request. This is the credential most Twilio accounts already have. - Account OAuth (opt-in, revocable).
TWILIO_ACCOUNT_SID+TWILIO_CLIENT_ID+TWILIO_CLIENT_SECRET— a Client ID/Secret pair from a Twilio Account OAuth App, exchanged for a short-lived access token via client-credentials grant. The SDK fetches, caches, and refreshes the token automatically. Prefer this when you want a credential that's independently revocable without rotating the account's Auth Token.
If both are set, OAuth wins — the server logs a one-line note to stderr and uses the OAuth credential.
Either way authenticates Twilio API calls (messages_create, calls_create,
etc.). Status callbacks are a separate credential in this release — they
still require TWILIO_API_KEY + TWILIO_API_SECRET regardless of which mode
the main client uses (see Status callbacks). A
future release will let an OAuth credential drive callbacks too, removing the
API Key requirement for OAuth users.
Setup
Three ways to run this server. The tables below map field-for-field to the New 3rd Party MCP (or equivalent) dialog in GUI-configured MCP hosts; a copy-paste MCP client JSON config is shown at the end. In every case, put your creds under Extra env — see Env for the full list.
Option 1 — npx (recommended)
Auto-installs on first run, always fetches the latest version.
| Field | Value |
|---|---|
| Name | twilio-mcp |
| Transport | stdio (local subprocess) |
| Command | npx |
| Arguments | -y @gtmi/twilio-mcp |
| Working directory | (empty) |
| Extra env | TWILIO_ACCOUNT_SID=AC…, TWILIO_AUTH_TOKEN=…, … |
The -y is required, not optional. Without it, npx prompts on
stdin the first time it installs the package — but stdin is the MCP
transport, so the prompt corrupts the JSON-RPC stream and the host
reports "server failed to start" with no clear reason. It looks
unnecessary on a warm cache; it isn't.
Option 2 — Global install
Pins a specific version; updates are on you.
npm install -g @gtmi/twilio-gtmi-mcp| Field | Value |
|---|---|
| Name | twilio-mcp |
| Transport | stdio (local subprocess) |
| Command | twilio-mcp |
| Arguments | (empty) |
| Working directory | (empty) |
| Extra env | TWILIO_ACCOUNT_SID=AC…, TWILIO_AUTH_TOKEN=…, … |
Option 3 — Local (from a checkout)
To run from a local checkout instead of the published package — for development or contributing. Two sub-options — pick whichever your host tolerates better.
3a. npm link — short command, needs one-time setup.
cd /path/to/twilio-mcp
npm install # also builds via the `prepare` script
npm link # symlinks `twilio-mcp` onto your global PATH| Field | Value |
|---|---|
| Command | twilio-mcp |
| Arguments | (empty) |
3b. node + absolute path — no linking, robust across renames.
| Field | Value |
|---|---|
| Command | node |
| Arguments | /absolute/path/to/twilio-gtmi-mcp/dist/index.js |
Common to both: npm link and pointing at dist/index.js both use the
compiled output — after editing src/, run npm run build and restart
the host so it respawns the server with the fresh dist/. Run npm test
to check your change against the unit suite before rebuilding — see
Tests.
Troubleshooting stale symlinks. After a package rename, the
twilio-mcp binary can silently keep pointing at the old install
location. The server still starts — it just runs old code from
node_modules/<old-scope>/twilio-mcp. To diagnose:
ls -la $(which twilio-mcp) # shows the target the symlink resolves toTo fix:
npm unlink -g @old-scope/twilio-gtmi-mcp # remove the stale symlink
cd /path/to/twilio-gtmi-mcp
npm link # re-link under the current nameTo remove the symlink entirely later: npm unlink -g @gtmi/twilio-gtmi-mcp.
MCP client config (JSON)
For any host configured by a JSON file — Claude Desktop, Claude Code, Cursor,
Windsurf, VS Code, Goose, etc. — add an entry under mcpServers. This uses the
published NPM via npx (Option 1): no install step, npx fetches
@gtmi/twilio-gtmi-mcp on first run and its optional relay client automatically.
Minimal — messaging / voice / verify / lookups (the only two required keys):
{
"mcpServers": {
"twilio": {
"command": "npx",
"args": ["-y", "@gtmi/twilio-gtmi-mcp"],
"env": {
"TWILIO_ACCOUNT_SID": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"TWILIO_AUTH_TOKEN": "your_auth_token"
}
}
}
}Minimal, OAuth variant — same tools, authenticated with an Account OAuth App's Client ID/Secret instead of the Auth Token (see Authentication modes):
{
"mcpServers": {
"twilio": {
"command": "npx",
"args": ["-y", "@gtmi/twilio-gtmi-mcp"],
"env": {
"TWILIO_ACCOUNT_SID": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"TWILIO_CLIENT_ID": "your_oauth_client_id",
"TWILIO_CLIENT_SECRET": "your_oauth_client_secret"
}
}
}
}If both TWILIO_AUTH_TOKEN and the OAuth pair are set, OAuth wins.
Full — every optional feature switched on; keep only the lines you need.
The TWILIO_API_KEY + TWILIO_API_SECRET pair enables status callbacks
(delivery status for messaging, lifecycle for voice, capture events for
agent_pay_*); SENDGRID_API_KEY enables email; MCP_CALLBACK_RELAY_HOST
points callbacks at a relay you run instead of the default shared one. Delete
any line you don't use, and either set the relay host to your own or drop it —
the placeholder is not a real relay:
{
"mcpServers": {
"twilio": {
"command": "npx",
"args": ["-y", "@gtmi/twilio-gtmi-mcp"],
"env": {
"TWILIO_ACCOUNT_SID": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"TWILIO_AUTH_TOKEN": "your_auth_token",
"TWILIO_API_KEY": "SKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"TWILIO_API_SECRET": "your_api_key_secret",
"SENDGRID_API_KEY": "SG.xxxxxxxxxxxxxxxxxxxxxx",
"MCP_CALLBACK_RELAY_HOST": "relay.yourdomain.com"
}
}
}
}Notes:
- Two credentials, two jobs. The main client's credential (
TWILIO_AUTH_TOKEN, or theTWILIO_CLIENT_ID+TWILIO_CLIENT_SECRETOAuth pair — see Authentication modes) authenticates every Twilio API call (send a message, place a call, run a payment);TWILIO_API_KEY+TWILIO_API_SECRETauthenticate the status-callback relay connection (Basic(SK:secret)). These are deliberately separate: one of the main-client credentials is required for any Twilio tool, the API Key pair is needed only for callbacks — in this release, callbacks need the API Key pair even if the main client is using OAuth. - Required vs optional. Only
TWILIO_ACCOUNT_SIDplus one of the two main-client credentials are required. TheTWILIO_API_KEYpair (callbacks) andSENDGRID_API_KEY(email) are independent opt-ins — enable either, both, or neither. See Env. - Callbacks aren't just payments. The relay carries delivery status for
messaging (
queued → sent → delivered), lifecycle for voice (ringing → answered → completed), and capture events foragent_pay_*— readable viatwilio://status-callbacks/*. Any tool takingreceiveStatusCallbacks: trueuses this path. - Relay host (
MCP_CALLBACK_RELAY_HOST). Optional; omit it to use the default shared relaycallback-relay.fly.dev. Set it (host only, no scheme) when you run your own relay — recommended specifically foragent_pay_*payment callbacks, which carry masked PAN / tokens / confirmation codes that shouldn't transit a shared relay. See Status callbacks. - The
"twilio"key is just a label — the host qualifies tool names with it (twilio.messages_create). Call it whatever you want. - Pin a version by using
@gtmi/[email protected]inargs; the bare name always fetches the latest. - Global-install alternative (Option 2): set
"command": "twilio-mcp"and"args": []instead of thenpxpair.
Env
| Key | Required for | Notes |
|---|---|---|
| TWILIO_ACCOUNT_SID | Twilio tools | AccountSid (AC…) |
| TWILIO_AUTH_TOKEN | Twilio tools (default auth) | Auth Token from the Twilio Console |
| TWILIO_CLIENT_ID | Twilio tools (OAuth alternative) | Client ID from a Twilio Account OAuth App |
| TWILIO_CLIENT_SECRET | Twilio tools (OAuth alternative) | Client Secret paired with TWILIO_CLIENT_ID |
| SENDGRID_API_KEY | SendGrid email tools | API key (prefix SG.) |
| TWILIO_API_KEY | Status callbacks (optional) | API Key SID (SK…); the relay client authenticates with Basic(SK…:secret) |
| TWILIO_API_SECRET | Status callbacks (optional) | API Key secret paired with TWILIO_API_KEY |
| MCP_CALLBACK_RELAY_HOST | Status callbacks (optional) | Relay host override, no scheme. Defaults to callback-relay.fly.dev; self-host for payment callbacks |
Tests
npm test runs the vitest unit suite (test/, mirroring src/'s structure — one file per
tool/prompt/resource/client). These exercise handler logic directly via a fake MCP server
(test/helpers/fakeServer.ts) with dependency-injected fake clients — no live Twilio/SendGrid
credentials or network calls involved, so they run anywhere.
npm test # run once
npm run test:watch # watch mode
npm run test:coverage # with v8 coverage (no thresholds enforced)Unit tests cover module logic; they don't cover the server's wiring (which tools register under which creds) or a real round-trip against Twilio/SendGrid — that's what MCP Inspector below is for.
Testing with MCP Inspector
MCP Inspector is the quickest way to exercise this server end-to-end against real credentials, without wiring it into a chat host. It launches a local web UI that speaks MCP, lists every tool / prompt / resource the server advertises, and lets you invoke them with ad-hoc args.
npm run build
npx @modelcontextprotocol/inspector node dist/index.jsInspector reads env from your shell, so export creds first (or use a
.envrc / direnv setup):
export TWILIO_ACCOUNT_SID=ACxxx
export TWILIO_AUTH_TOKEN=xxx
export SENDGRID_API_KEY=SG.xxx
export TWILIO_API_KEY=SKxxx # optional — enables the status-callback relay
export TWILIO_API_SECRET=xxx # optional — paired with TWILIO_API_KEY
# export MCP_CALLBACK_RELAY_HOST=my-relay.example.com # optional; self-host for payment callbacks
npx @modelcontextprotocol/inspector node dist/index.jsIn the UI:
- Tools tab — pick any tool, fill in the schema-driven form, hit Call.
- Prompts tab — pick a prompt and supply its args; the rendered
messages[]are what the host would feed to the LLM. Required-arg prompts (e.g.send_via_messaging_service) error with-32602until you fill them in — that's a server-side Zod validation rejection. - Resources tab — read any URI listed. Templated URIs
(
twilio://status-callbacks/{sid}) require you to substitute the variable yourself in the URL field.
Inspector logs all JSON-RPC traffic, so it's also a useful debug surface when a host is reporting "tool not found" or similar — invoke the same endpoint via Inspector and compare.
License
MIT
