Connect an MCP client

How to point any MCP-compatible client at the SnapLogic MCP Server and authenticate using HTTP Basic.

The SnapLogic MCP Server uses the MCP Streamable HTTP transport. Point your client at your region's Tectonic host and the path that matches your use case (/mcp, /mcp/platform, or /mcp/pygen), then add a standard Authorization header. For the full tool catalogue, base URLs, and troubleshooting, see SnapLogic MCP Server tools.

Authentication

All MCP API requests must include an Authorization header. Use HTTP Basic with your SnapLogic login credentials:

Authorization: Basic base64(user:password)

An MCP client config is long-lived. HTTP Basic does not expire, which makes it the reliable default for a persistent client configuration.

Important: HTTP Basic requires HTTPS (all SnapLogic hosts use HTTPS) and is unavailable for MFA-enabled accounts or orgs that have disabled Basic auth. Contact your org administrator if Basic auth is not available for your account.

Client configurations

Claude Code (CLI)

claude mcp add --transport http platform-mcp \
  https://cdn.elastic.snaplogic.com/api/1/rest/public/platform_mcp/mcp/platform \
  --header "Authorization: Basic $(printf '%s' 'USER:PASSWORD' | base64)" \
  --scope project

Claude Code (.mcp.json, project-scoped)

{
  "mcpServers": {
    "platform-mcp": {
      "type": "http",
      "url": "https://cdn.elastic.snaplogic.com/api/1/rest/public/platform_mcp/mcp/platform",
      "headers": { "Authorization": "Basic BASE64_OF_USER_COLON_PASSWORD" }
    }
  }
}

Claude Desktop

Use the same JSON entry as above in claude_desktop_config.json (type: http with a headers object). No mcp-remote shim is needed for a header-authenticated HTTP server.

Python MCP SDK

import base64
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client

async def main():
    url = "https://cdn.elastic.snaplogic.com/api/1/rest/public/platform_mcp/mcp/platform"
    headers = {"Authorization": "Basic " + base64.b64encode(b"USER:PASSWORD").decode()}
    async with streamablehttp_client(url, headers=headers) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            print(len(tools.tools), "tools")
Note: Use cdn.elastic.snaplogic.com for US tenants and cdn.emea.snaplogic.com for EU. Swap /mcp/platform for /mcp/pygen or /mcp as needed.

Choosing which tools you get: the X-MCP-Tool-Profile header

The tool list is not fixed. Two independent settings decide what tools/list returns, and the result is the intersection of both:

  1. The path you connect to/mcp (all registered tools), /mcp/platform, or /mcp/pygen. Set this in your client config.
  2. The profile you request — an optional X-MCP-Tool-Profile request header. With no header you get the environment's configured default.

Built-in profiles:

Profile What it selects Use it when
dev No filtering — every registered tool. You want the full surface, including tools tagged NEW.
snapcode Platform + PyGen + common, minus everything tagged NEW. You want the stable, released surface only.
platform Platform + common. PyGen excluded. Control-plane work; no pipeline-generation helpers.
pygen PyGen + common. Pipeline-generation helpers only.
Important: A profile changes exposure, not authorization. Hiding a tool from tools/list is not a permission boundary — what a caller can actually do is determined by their SnapLogic credentials and org RBAC. Do not treat a narrow profile as a security control.

Add the header alongside Authorization in your client config. For example, to request the dev profile:

Claude Code (CLI)

claude mcp add --transport http platform-mcp \
  https://cdn.elastic.snaplogic.com/api/1/rest/public/platform_mcp/mcp \
  --header "Authorization: Basic $(printf '%s' 'USER:PASSWORD' | base64)" \
  --header "X-MCP-Tool-Profile: dev" \
  --scope project

.mcp.json

{
  "mcpServers": {
    "platform-mcp": {
      "type": "http",
      "url": "https://cdn.elastic.snaplogic.com/api/1/rest/public/platform_mcp/mcp",
      "headers": {
        "Authorization": "Basic BASE64_OF_USER_COLON_PASSWORD",
        "X-MCP-Tool-Profile": "dev"
      }
    }
  }
}

Verify the tool surface in your environment

Run two tools/list calls — one with and one without the X-MCP-Tool-Profile header. If the counts match, the header is not reaching the server.

import base64, json, requests

AUTH = "Basic " + base64.b64encode(b"USER:PASSWORD").decode()
URL  = "https://cdn.elastic.snaplogic.com/api/1/rest/public/platform_mcp/mcp"

def count(profile=None):
    h = {"Authorization": AUTH, "Content-Type": "application/json",
         "Accept": "application/json, text/event-stream"}
    if profile:
        h["X-MCP-Tool-Profile"] = profile
    init = {"jsonrpc": "2.0", "id": 1, "method": "initialize",
            "params": {"protocolVersion": "2025-03-26", "capabilities": {},
                       "clientInfo": {"name": "probe", "version": "1.0"}}}
    r = requests.post(URL, headers=h, json=init, timeout=45)
    h["Mcp-Session-Id"] = r.headers["Mcp-Session-Id"]
    requests.post(URL, headers=h,
                  json={"jsonrpc": "2.0", "method": "notifications/initialized"},
                  timeout=45)
    r = requests.post(URL, headers=h,
                      json={"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
                      timeout=45)
    n = 0
    for line in r.text.splitlines():  # responses are SSE-framed
        if line.startswith("data:"):
            n += len(json.loads(line[5:]).get("result", {}).get("tools", []))
    return n

print("default:", count(), " dev:", count("dev"), " snapcode:", count("snapcode"))

Known issues

  • An unknown profile name silently gives you the environment default. The request is not rejected — a client asking for a profile the environment has not defined ends up with a wider surface while believing it is sandboxed. Profile names are per-environment (MCP_TOOL_PROFILES_JSON); confirm yours exists. The server logs a warning naming the profiles it knows.
  • Send the header on every request, not just initialize — the profile is resolved per request, alongside Mcp-Session-Id.
  • Requires Tectonic 4.45 or later. On an earlier build the proxy does not forward the header downstream, so you silently receive the environment default with no error.
  • Value is sanitized and capped at 64 characters, and dropped entirely if it contains CR/LF. Profile names are matched case-insensitively.
  • STDIO/local runs ignore it — there is no HTTP request to carry a header. Local development defaults to dev (all tools) unless MCP_DEFAULT_TOOL_PROFILE is set.
  • export_project is in the default surface and it writes. Despite the name it is not read-only: it stages a ZIP into the project via SLDB and returns a presigned URL valid for about an hour that requires no authentication. With Account assets opted in, that URL carries encrypted credential material. Treat it as a write operation, not a query. (export_pipeline, by contrast, is a read-only SLP export.)