Deepgram Agentic Tools MCP Server

Deepgram Agentic Tools MCP Server

A self-hosted MCP server that wraps Deepgram's speech-to-text, text-to-speech, text analysis, and usage APIs for use with CyberArk Secure AI Agents (SAIA).

Category
访问服务器

README

Deepgram Agentic Tools — MCP Server for CyberArk Secure AI Agents (SAIA)

A small, self-hosted Model Context Protocol (MCP) server that exposes Deepgram's core developer tools — speech-to-text, text-to-speech, text intelligence, model listing, and usage — so an AI agent can call them through CyberArk Secure AI Agents (SAIA / Idira), with the CyberArk Identity Broker enforcing and auditing access.

It speaks Streamable HTTP MCP and is exposed to SAIA over an HTTPS tunnel (ngrok).


Table of contents


Why this project exists

The goal was to demo CyberArk's Secure AI Agents (SAIA) brokering an agent's access to a real third-party MCP server — specifically Deepgram's speech tools (transcribe_audio, synthesize_speech, analyze_text, list_models, get_usage).

During setup we discovered two things that make a purpose-built server necessary:

  1. Deepgram's published deepgram-mcp package and dg mcp CLI do not actually serve those agentic tools. Both proxy to https://api.dx.deepgram.com/kapa/mcp, which is Deepgram's documentation Q&A server (powered by kapa.ai). A live tools/list against it returns exactly one tool: search_deepgram_knowledge_sources. See the appendix for the evidence.

  2. SAIA registers remote MCP servers by URL (it discovers the server over HTTPS and requires either OAuth 2.1 or "None" auth). Deepgram's real speech tools are only reachable via its REST API with an API key — there is no hosted MCP endpoint for them.

So this project wraps Deepgram's REST API in a proper MCP server that we self-host and expose over HTTPS, then register in SAIA. This is also the cleanest SAIA story: the underlying server has no user-facing auth, so CyberArk becomes the authorization + audit layer.

What it does

deepgram_tools_mcp.py is a FastMCP (Streamable HTTP) server that exposes five tools, each a thin wrapper over a Deepgram REST endpoint:

MCP tool Deepgram REST call Purpose
transcribe_audio POST /v1/listen Speech-to-text (URL or local file)
synthesize_speech POST /v1/speak Text-to-speech (Aura), saved to disk
analyze_text POST /v1/read Summary, sentiment, topics, intents
list_models GET /v1/models List STT/TTS models
get_usage GET /v1/projects/{id}/usage Account usage (needs usage:read)

The Deepgram API key is held server-side (from .env) and is never exposed to the agent or the MCP client.

Architecture

flowchart LR
    subgraph Agent side
      A["AI Agent"]
    end
    subgraph CyberArk
      B["SAIA / Idira<br/>Identity Broker<br/>(authN + authZ + audit)"]
    end
    subgraph Your machine
      N["ngrok tunnel<br/>https://xxxx.ngrok-free.dev"]
      S["deepgram_tools_mcp.py<br/>127.0.0.1:8787/mcp<br/>(Streamable HTTP)"]
    end
    D["Deepgram REST API<br/>api.deepgram.com/v1"]

    A -->|MCP over HTTPS| B
    B -->|forwards to registered<br/>Server URL| N
    N -->|localhost| S
    S -->|Authorization: Token API_KEY| D

Request flow: the agent talks to CyberArk; CyberArk authenticates/authorizes/audits and forwards the MCP call to the registered Server URL (the ngrok HTTPS URL); ngrok forwards to the local MCP server; the server calls Deepgram's REST API using the server-held API key and returns the result back up the chain.

Why ngrok is required

SAIA registers remote MCP servers — it needs a publicly reachable HTTPS URL that its Identity Broker (running in CyberArk's cloud) can call. The MCP server in this repo runs locally on 127.0.0.1:8787, which CyberArk cannot reach.

ngrok bridges that gap. It opens a secure outbound tunnel from your machine to ngrok's edge and gives you a public https://<random>.ngrok-free.dev URL that forwards inbound requests to your local server. This lets you demo a locally-hosted MCP server through SAIA without deploying to a cloud host, opening firewall ports, or provisioning a TLS certificate (ngrok terminates TLS at its edge).

Notes and alternatives:

  • The free ngrok URL changes on every restart. Re-paste the new URL into SAIA after each restart, or use a reserved ngrok domain (NGROK_DOMAIN=... ./run.sh) to keep it stable.
  • ngrok is a demo/dev convenience, not a production requirement. For a persistent deployment, host the server on any HTTPS-reachable endpoint (Cloud Run, a VM behind a reverse proxy, etc.) and register that URL instead.
  • Any equivalent tunnel (Cloudflare Tunnel, Tailscale Funnel) would also work.

Authentication model (why "None" in SAIA)

SAIA supports two auth methods for a registered MCP server: OAuth 2.1 or None.

  • This server intentionally exposes no OAuth on the MCP layer. When SAIA runs discovery, the server returns no WWW-Authenticate challenge, so SAIA classifies it as Authentication = None.
  • With None, CyberArk's Identity Broker becomes the authorization service: every agent call is authenticated, authorized, and audited by CyberArk before it reaches the server. The human user, the agent identity, the tool used, and the target server are all captured in CyberArk's audit trail.
  • The Deepgram credential (API key) lives only on the server and is never seen by the agent — CyberArk governs whether the agent may call the tool at all.

This is the intended demo narrative: CyberArk secures and audits access to an otherwise-unauthenticated MCP server.

Prerequisites

Setup

# 1) Clone and enter the repo
git clone <your-repo-url>
cd deepgram-mcp-gateway

# 2) Create a virtual environment and install dependencies
python3 -m venv --copies venv
./venv/bin/python -m pip install --upgrade pip
./venv/bin/python -m pip install -r requirements.txt

# 3) Provide your Deepgram API key (kept out of git by .gitignore)
echo 'DEEPGRAM_API_KEY=your_deepgram_key_here' > .env

# 4) Install ngrok and register your auth token
#    macOS (Homebrew):  brew install --cask ngrok
#    or download from:  https://ngrok.com/download
ngrok config add-authtoken YOUR_NGROK_TOKEN

run.sh auto-detects ngrok from your PATH. If needed, override with NGROK_BIN=/full/path/to/ngrok ./run.sh.

Running it

One command (recommended):

./run.sh

This starts the MCP server and the ngrok tunnel, waits for the public URL, and prints the exact Server URL to paste into SAIA, e.g.:

============================================================
  Deepgram MCP is live.

  Paste this into SAIA -> Register MCP server -> Server URL:

      https://xxxx-xxxx-xxxx.ngrok-free.dev/mcp

  Authentication method: None (CyberArk brokers/audits access)
============================================================

Pin a stable domain (optional):

NGROK_DOMAIN=your-name.ngrok.app ./run.sh

Manual (two terminals):

# terminal 1 — the MCP server
./venv/bin/python deepgram_tools_mcp.py --host 127.0.0.1 --port 8787

# terminal 2 — the tunnel
ngrok http 8787
# then read the https URL from ngrok's dashboard or http://127.0.0.1:4040

Quick local self-test (no SAIA needed):

curl -s -X POST http://127.0.0.1:8787/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Stopping and restarting

Stopping

Press Ctrl+C in the terminal running run.sh. The script traps the signal and cleanly kills both the MCP server and the ngrok tunnel.

If processes were started manually or are stale from a previous session:

pkill -f deepgram_tools_mcp   # stop the MCP server
pkill -f ngrok                # stop the tunnel

Restarting (after a machine sleep/reboot or session end)

Always restart via run.sh from a dedicated Terminal window (not from within Cursor), so the processes stay alive independently of the IDE:

cd /path/to/deepgram-mcp-gateway

# Kill any stale processes first
pkill -f deepgram_tools_mcp 2>/dev/null
pkill -f ngrok 2>/dev/null

# Start fresh
./run.sh

run.sh will print a new https://…/mcp URL. You must update the Server URL in your SAIA MCP server registration whenever the ngrok URL changes (free tier only). If you have a reserved ngrok domain the URL stays constant across restarts.

Why you must restart after a machine sleep

The MCP server process holds an SSL context initialised at startup. After the machine sleeps and wakes, certificate paths in that context may no longer be valid, causing [Errno 2] No such file or directory errors on outbound HTTPS calls to Deepgram. A fresh ./run.sh initialises a new SSL context and clears the problem.

Health check (verify both are running)

# Local server
curl -s -o /dev/null -w "local:  HTTP %{http_code}\n" \
  -X POST http://127.0.0.1:8787/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# Public tunnel (replace URL with yours)
curl -s -o /dev/null -w "tunnel: HTTP %{http_code}\n" \
  -X POST https://xxxx.ngrok-free.dev/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Both should return HTTP 200. If the local server returns 200 but the tunnel returns an error, restart ngrok only:

pkill -f ngrok
ngrok http 8787   # or ./ngrok http 8787

Registering the server in SAIA

  1. In SAIA, open Register MCP server.
  2. MCP server name: e.g. DeepgramTools.
  3. Server URL: the ngrok URL from run.sh, ending in /mcp.
  4. Click Discover. It should set Authentication method = None.
  5. Fill in Category / Owners / Tags as desired and click Register.
  6. Connect the server to your AI agent. The agent will now see all five tools.

If Discover fails or demands OAuth metadata, the server can be extended with a .well-known/oauth-protected-resource discovery route; open an issue / ask before adding it, since a plain "None" server generally should not advertise OAuth.

Testing with Claude

After registering the MCP server in SAIA and adding the Deepgram connector in claude.ai, use these prompts to verify each tool. Every call is brokered and audited by CyberArk.

1. Transcribe audio (speech-to-text)

"Transcribe this recording and give me the text: https://dpgr.am/spacewalk.wav"

Exercises transcribe_audio. Returns the full transcript and confidence score.

2. Transcribe + summarize

"Transcribe https://dpgr.am/spacewalk.wav and summarize the key points in three bullet points."

Exercises transcribe_audio with summarize: true, then Claude summarises the result.

3. Text-to-speech

"Use Deepgram to convert this text to speech with the Aura voice: 'Welcome to the Secure AI Agents demo, powered by CyberArk and Deepgram.'"

Exercises synthesize_speech. Saves an MP3 to output/ on the server. Play it locally with:

afplay output/speech_*.mp3

4. Text intelligence

"Analyze the sentiment and main topics of this text: 'The onboarding was rough at first, but support was fantastic and the API latency is incredible.'"

Exercises analyze_text. Returns sentiment score and extracted topics.

5. Model discovery

"What Deepgram speech-to-text and text-to-speech models are available?"

Exercises list_models. Returns the full STT/TTS model catalog.

Tip: After running any of these, show the corresponding entries in CyberArk's audit trail — human user → agent identity → tool used → target server — to make the SAIA value proposition land in the demo.


The tools

Example arguments (all callable via MCP tools/call):

  • transcribe_audio{ "url": "https://dpgr.am/spacewalk.wav", "model": "nova-3", "smart_format": true, "diarize": false, "summarize": false } (or { "file_path": "/path/to/audio.wav" }). Returns transcript, confidence, and duration.
  • synthesize_speech{ "text": "Hello world", "model": "aura-2-thalia-en" }. Writes an MP3 to output/ and returns the file path and byte size.
  • analyze_text{ "text": "…", "language": "en", "summarize": true, "sentiment": true, "topics": true, "intents": false }.
  • list_models — no args. Returns STT and TTS model lists.
  • get_usage{ "start": "2026-06-01", "end": "2026-07-01" } (both optional). Requires an API key with the usage:read scope (Owner/Admin role); otherwise it returns a clear "insufficient_permissions" message instead of failing.

Corporate TLS inspection / truststore

On corporate networks (e.g., with a TLS-inspection proxy), Python's default certifi CA bundle does not include the corporate root CA, so outbound HTTPS from Python fails with CERTIFICATE_VERIFY_FAILED: self-signed certificate in certificate chain — even though curl works (it uses the OS keychain).

This project uses the truststore package and calls truststore.inject_into_ssl() at startup so Python uses the operating system trust store (which includes your corporate root CA). If you're on a plain network this is a harmless no-op.

Troubleshooting

Symptom Cause / Fix
Claude says "connector's server errored out" The MCP server or tunnel is down. Run ./run.sh from a Terminal window (not Cursor).
[Errno 2] No such file or directory on tool calls Stale SSL context after machine sleep. Restart the server: pkill -f deepgram_tools_mcp && ./run.sh.
421 Invalid Host header through ngrok MCP DNS-rebinding host validation. Already disabled in this server via TransportSecuritySettings.
SSL: CERTIFICATE_VERIFY_FAILED ... self-signed certificate Corporate TLS inspection proxy. Handled by truststore; ensure it's installed (pip install -r requirements.txt).
Tunnel works but tools return errors after wake from sleep Same SSL context issue — fully restart with ./run.sh, don't just restart ngrok.
ngrok URL stopped working / SAIA can't reach server Free ngrok URLs change on every restart. Re-run ./run.sh, copy the new URL, update the Server URL in the SAIA MCP server registration, then retry.
Server starts but tools/list returns empty Check /tmp/dg_mcp_server.log for startup errors. Confirm .env has a valid DEEPGRAM_API_KEY.
get_usage returns insufficient_permissions API key lacks usage:read scope. Create an Owner/Admin key in the Deepgram console.
analyze_text 400 "missing field language" language is required by Deepgram's /v1/read; the server defaults to en. If it still fails, check that the language arg is being passed.
SAIA "discovery failed" on registration Confirm the URL ends in /mcp, the tunnel is up, and you can curl it. If SAIA demands OAuth metadata, open an issue — a .well-known shim can be added.
Processes killed when Cursor IDE closes Run ./run.sh in a standalone Terminal window, not from the Cursor integrated terminal.

Repository layout

.
├── deepgram_tools_mcp.py          # The MCP server (5 tools, Streamable HTTP)
├── run.sh                         # Start server + ngrok, print the SAIA URL
├── requirements.txt               # Python dependencies
├── list_deepgram_mcp_tools.py     # Diagnostic: proves kapa endpoint is docs-only
├── register-deepgram-oauth-client.sh  # (Optional) DCR helper for Deepgram's OAuth docs endpoint
├── README.md
├── .gitignore
├── .env                           # NOT committed — holds DEEPGRAM_API_KEY
├── venv/                          # NOT committed
└── output/                        # NOT committed — generated TTS audio

Security notes

  • Never commit .env (it holds your Deepgram API key). It is git-ignored.
  • The API key stays server-side; it is never sent to the agent or MCP client.
  • ngrok exposes your local server to the public internet while running. The URL is unguessable but unauthenticated at the tunnel layer — in the SAIA demo, access control is enforced by CyberArk. Stop the tunnel (Ctrl+C) when not demoing, and don't leave it running unattended.
  • If a key is ever exposed, rotate it in the Deepgram console.

Appendix: the Deepgram "docs MCP" red herring

Deepgram's docs advertise a dg mcp / deepgram-mcp server with tools like transcribe_audio. In practice, the shipped code (deepgram-mcp 0.1.1 and deepctl's deepctl_cmd_mcp) both call the same run_proxy() that connects to:

https://api.dx.deepgram.com/kapa/mcp

A live tools/list against that endpoint (authenticated with a Deepgram API key) returns a single tool:

search_deepgram_knowledge_sources  — semantic retrieval over Deepgram's docs

That endpoint also identifies itself as deepgram-mcp-relay and is the kapa.ai documentation assistant — not the speech tools. list_deepgram_mcp_tools.py in this repo reproduces that check. This is why we wrap the REST API ourselves rather than reusing Deepgram's MCP package.

Separately, https://api.dx.deepgram.com/kapa/mcp is a fully OAuth 2.1–compliant MCP resource (RFC 9728 protected-resource metadata, dynamic client registration at https://id.dx.deepgram.com/register). register-deepgram-oauth-client.sh can register an OAuth client there — but it only unlocks the docs tool, so it's not used in this demo.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选