MCP Server on the Marketplace¶
One of the most powerful uses of the Cohesity App Marketplace is deploying a persistent MCP (Model Context Protocol) server that exposes your Gaia knowledge bases to external AI tools. Deploy it once to a cluster; every AI assistant on your network can connect to it.
The Use Case¶
Your organization uses Cohesity Gaia to index internal knowledge bases — engineering runbooks, support tickets, financial reports, HR policies. With a Marketplace-hosted MCP server:
- Cursor and Claude Desktop can search your knowledge bases mid-conversation.
- Microsoft Copilot can use your internal docs as context.
- Custom AI agents can call Gaia tools programmatically.
- The Gaia API key stays server-side — users never see it.
How It Works¶
Developer's Laptop / AI Tool
┌─────────────────────────────────┐
│ Cursor / Claude Desktop │
│ ~/.cursor/mcp.json configured │
└────────────────┬────────────────┘
│ HTTP POST /mcp
│ (MCP Streamable HTTP)
▼
Cohesity Cluster (HOST_IP:MCP_NODE_PORT)
┌───────────────────────────────────────────────┐
│ gaia-mcp:latest container │
│ │
│ FastMCP server │
│ ├── list_datasets() │
│ ├── ask(datasets, query) │
│ ├── exhaustive_search(dataset, query) │
│ └── list_conversations() │
│ │
│ GAIA_API_KEY (from appspec.yaml env) │
└────────────────────┬──────────────────────────┘
│ HTTPS
▼
Gaia API (Helios / cluster)
Example 06: Marketplace MCP Server¶
Example 06 is the reference implementation. Here's what makes it work:
server.py — FastMCP + synchronous httpx¶
FastMCP tool functions must be synchronous. The server uses httpx.Client (not the async GaiaClient from the SDK) for all Gaia calls:
import httpx
import fastmcp
from fastapi import FastAPI
mcp = fastmcp.FastMCP("Gaia Knowledge Search")
app = FastAPI()
app.mount("/mcp", mcp.streamable_http_app())
def _gaia_request(method: str, path: str, **kwargs) -> dict:
"""Synchronous Gaia API call (FastMCP tools cannot be async)."""
api_key = os.environ["GAIA_API_KEY"]
base_url = os.getenv("GAIA_BASE_URL", "https://helios.cohesity.com/v2/mcm/gaia")
with httpx.Client(verify=ssl_verify, timeout=timeout) as client:
r = client.request(
method,
f"{base_url}{path}",
headers={"apiKey": api_key},
**kwargs,
)
r.raise_for_status()
return r.json()
@mcp.tool()
def ask(datasets: list[str], query: str, conversation_id: str = "") -> str:
"""Ask a question using Gaia RAG. Returns the answer with source citations."""
body = {"datasetNames": datasets, "query": query}
if conversation_id:
body["conversationId"] = conversation_id
result = _gaia_request("POST", "/ask", json=body)
return result.get("responseString", "No response")
appspec.yaml — cohesityEnv: MCP_NODE_PORT¶
The Marketplace assigns a NodePort dynamically. The cohesityEnv extension injects the actual port number into every pod:
ports:
- port: 8002
protocol: TCP
name: mcp
cohesityTag: ui
cohesityEnv: MCP_NODE_PORT # Injects actual NodePort as env var
app.json — Unrestricted access¶
MCP clients connect without a browser session. The token gate is bypassed.
Landing Page¶
The server provides an HTML landing page at / that shows the correct MCP URL and configuration snippets:
@app.get("/", response_class=HTMLResponse)
async def landing_page():
host_ip = os.getenv("HOST_IP", "localhost")
node_port = os.getenv("MCP_NODE_PORT", os.getenv("PORT", "8002"))
mcp_url = f"http://{host_ip}:{node_port}/mcp"
return f"""
<html>
<body>
<h1>Gaia MCP Server</h1>
<p>MCP endpoint: <code>{mcp_url}</code></p>
<h2>Cursor config</h2>
<pre>{{
"mcpServers": {{
"gaia": {{
"url": "{mcp_url}"
}}
}}
}}</pre>
<h2>Claude Desktop config</h2>
<pre>{{
"mcpServers": {{
"gaia": {{
"url": "{mcp_url}",
"transport": "http"
}}
}}
}}</pre>
</body>
</html>
"""
Deploying Example 06¶
1. Build the image¶
2. Update appspec.yaml¶
Replace YOUR_GAIA_API_KEY:
3. Package and upload¶
docker save gaia-mcp:latest -o gaia-mcp.tar
tar -czf gaia-mcp-bundle.tar.gz appspec.yaml app.json gaia-mcp.tar
# Upload to DevPortal
4. Find your MCP URL¶
After deployment, visit http://HOST_IP:NODE_PORT/ in a browser. The landing page shows the correct URL and ready-to-paste configuration.
Connecting MCP Clients¶
Cursor¶
Add to ~/.cursor/mcp.json:
Replace 192.168.1.10:31234 with your HOST_IP:MCP_NODE_PORT.
Claude Desktop¶
Add to claude_desktop_config.json:
Custom Agent¶
import httpx
MCP_URL = "http://192.168.1.10:31234/mcp"
# Call the ask tool
response = httpx.post(MCP_URL, json={
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "ask",
"arguments": {
"datasets": ["engineering-docs"],
"query": "How do I configure replication?"
}
},
"id": 1
})
Integrating with Microsoft Copilot¶
Microsoft 365 Copilot supports MCP servers through the Copilot extensibility framework. Once your Gaia MCP server is deployed on the cluster:
- Register the MCP server URL in Microsoft 365 admin settings.
- Users can invoke Gaia tools from Copilot chat: "Search engineering-docs for DR procedures".
- Copilot sends the tool call to your cluster's MCP server; the answer comes back with Gaia citations.
This enables enterprise AI workflows where MS Copilot has access to your organization's private Cohesity knowledge bases — without exposing Gaia directly to the internet.
Security Notes¶
Since unrestricted_app_ui_access: true bypasses the Cohesity token gate, protect the MCP endpoint at the network level:
- VPN or private network — The simplest approach. Only VPN-connected devices can reach the cluster NodePort range.
- Cluster network policies — Restrict which source IPs can reach the MCP service port.
- Scoped Gaia API key — Use a Gaia API key that grants access only to the datasets the MCP server should expose.
- Rotate API keys — Update the key in
appspec.yamland redeploy periodically.
Next Steps¶
- Testing & Submission — Validate and submit your app
- Auth in the Marketplace — Deeper dive on auth patterns
- Marketplace Checklist — Pre-submission checklist