Skip to main content
Glama

dtc-mcp

A code-execution MCP server for Klaviyo + Shopify analytics.

Three tools. Typed SDKs. A V8 sandbox that keeps state across calls so iterative analyses don't re-fetch. Works inside Claude Desktop, Cursor, or any MCP client.

LLM asks → execute_code → V8 sandbox ─→ host bridge ─→ Klaviyo / Shopify
                              ↑                             ↓
                         globalThis state            rate limit + cache
                         persists across calls
npm install -g dtc-mcp

Or get the one-click Claude Desktop extension.


The three tools

execute_code(code)

Runs JavaScript (TypeScript syntax accepted — type annotations are stripped before execution) inside a constrained V8 sandbox. The sandbox exposes typed Klaviyo and Shopify clients; the host handles auth, rate limiting, and caching invisibly.

Globals available inside the sandbox:

klaviyo

get, post, paginate, plus typed namespaces: campaigns, flows, lists, segments, profiles, events, metrics, and reporting.{campaignValues,flowValues}

shopify

gql, ql (ShopifyQL), timezone

console

log / error / warn / info — captured and returned as stdout

pick(v, schema)

Deep projection over objects / arrays

topN(arr, n, by)

Top-N by numeric key, descending

summarize(arr, opts)

Auto-aggregate (count, total, min/max/avg, optional topN)

globalThis.*

Assignments persist across execute_code calls within the same MCP session

Not exposed: fetch, process, require, import, setTimeout, the filesystem, or any env var. The only path out of the sandbox is the typed SDK methods, which route through the host's rate limiter and cache.

Defaults: 30s wall-clock per call, 128 MB heap (sidecar), 256 MB total per session. Opt-in // @timeout 2m at the top of the code extends the wall-clock up to 5 min.

search_docs(query, platform?, limit?)

Full-text BM25 search over the bundled SDK reference. Returns ranked markdown chunks with signatures and runnable examples. Use this when you're discovering methods by intent ("how do I list flows with their actions?").

read_doc(path?, platform?)

Direct fetch of a chunk by exact path, or a full listing when called with no args. Cheaper than search_docs once the LLM knows what it wants. Calling read_doc({}) once at the start of a session is the recommended way to map the whole SDK surface in one shot.

read_doc({})                                            // list all 332 paths
read_doc({ path: "klaviyo.reporting.campaignValues" })  // one chunk verbatim
read_doc({ platform: "shopify" })                       // Shopify only

Related MCP server: MCP QuickJS Runner

Architecture

The sandbox runs in one of two modes, chosen automatically at startup.

Preferred: sidecar with isolated-vm

┌─ Claude Desktop (Electron, hardened runtime) ────────────────┐
│                                                               │
│  MCP server (Electron's bundled Node)                         │
│   ├ execute_code      proxies to ↓                            │
│   ├ search_docs       MiniSearch BM25 over data/docs.json     │
│   ├ read_doc          direct fetch by chunk ID                │
│   ├ host SDK          Klaviyo + Shopify (rate limit / cache)  │
│   └ sidecar manager   spawn / lifecycle / NDJSON over stdio   │
│                                                               │
└─────────────────────────────│─────────────────────────────────┘
                              │ newline-delimited JSON-RPC
┌─ Sidecar process (system Node, outside Electron) ────────────┐
│                                                               │
│  isolated-vm loads here (no Library Validation restriction)   │
│                                                               │
│  One long-lived V8 isolate per MCP connection:                │
│   • 256 MB heap, 30 min idle TTL                              │
│   • klaviyo/shopify/pick/topN/summarize injected once         │
│   • globalThis state preserved across execute_code calls      │
│   • host-bridge calls round-trip back to the main process     │
│                                                               │
└───────────────────────────────────────────────────────────────┘

Why a sidecar: Claude Desktop is an Electron app with macOS hardened runtime + Library Validation. Native modules loaded into the Claude Desktop process must share Anthropic's Team ID — which we can't sign with. Spawning the user's /usr/local/bin/node as a child process sidesteps the restriction; the child has its own hardened-runtime status, so isolated-vm loads cleanly.

Node discovery walks: DTC_MCP_NODE_PATH env var → which node / where node → Homebrew (Intel + Apple Silicon) → standard system paths → nvm → Volta → fnm → asdf. Requires Node ≥ 20.

Fallback: in-process node:vm

If no system Node ≥ 20 is found, or the sidecar fails to start, the server falls back to a node:vm runner in the main process. Sandbox surface is identical (same globalThis, same helpers, same state semantics), but isolation is weaker — node:vm is a mistake fence, not a security boundary, and can be escaped via prototype-chain tricks. Acceptable because the threat model is "the user's own LLM might write buggy code," not "an attacker is trying to escape."

Every execute_code result includes "sandbox": "sidecar" or "sandbox": "vm" so you (and the LLM) can see which mode ran.

Stateful sessions

A single sandbox context lives for the lifetime of the MCP connection. globalThis.x = ... in one execute_code call is visible in every later call. const/let declared at the top of a script are scoped to that call only — use globalThis for anything you want to carry forward.

The context is recreated on: connection close, 30 min idle, isolate OOM, or first call after a long gap. When that happens the next result includes "sessionReset": true so the LLM knows prior state is gone.

Output discipline

Klaviyo and Shopify endpoints return verbose JSON. The host caps any execute_code return value at 100 KB (configurable via DTC_MCP_MAX_RESPONSE_KB); oversized returns are replaced with { truncated: true, preview, instructions }. The sandbox-side pick / topN / summarize helpers exist so the LLM can stay under the cap by design — see the guide.output-discipline doc chunk for examples.

Docs delivery

search_docs and read_doc query an in-memory MiniSearch index built from data/docs.json. The bundled copy ships with ~330 chunks (hand-authored guides + recipes + auto-generated reference for every Klaviyo OpenAPI endpoint). A background fetch on startup pulls a fresher copy from https://cdn.jsdelivr.net/gh/rafaelsztutman/dtc-mcp-docs@latest/docs.json (ETag-cached at ~/.cache/dtc-mcp/docs.json), so new API endpoints land without a new MCP release. Set DTC_MCP_DOCS_REFRESH=0 for fully offline use.


Install

Option A — Claude Desktop one-click

  1. Download dtc-mcp.mcpb from the latest GitHub release.

  2. Double-click the file. Claude Desktop opens an install dialog.

  3. Paste your Klaviyo API key (required) and Shopify credentials (optional).

  4. Restart Claude Desktop. Three tools appear in the hammer menu: execute_code, search_docs, read_doc.

Option B — manual config (claude_desktop_config.json, Cursor, etc.)

{
  "mcpServers": {
    "dtc-mcp": {
      "command": "npx",
      "args": ["-y", "dtc-mcp"],
      "env": {
        "KLAVIYO_API_KEY": "pk_your_private_key_here",
        "SHOPIFY_STORE": "your-store.myshopify.com",
        "SHOPIFY_CLIENT_ID": "your_client_id",
        "SHOPIFY_CLIENT_SECRET": "shpss_your_secret"
      }
    }
  }
}

Klaviyo-only mode: omit the SHOPIFY_* variables. shopify.* calls throw a configuration error; klaviyo.* calls work normally.

Option C — npm global install

npm install -g dtc-mcp
dtc-mcp           # runs the MCP server on stdio

Getting credentials

Klaviyo

  1. Log into Klaviyo. Settings → Account → API Keys (left sidebar).

  2. Create Private API Key. Name it dtc-mcp.

  3. Grant read-only scopes: campaigns:read, flows:read, lists:read, segments:read, profiles:read, metrics:read, events:read.

  4. Copy the pk_... key.

Shopify

Two auth modes. Use whichever matches your app type.

Dev Dashboard app (recommended, required for apps created after Jan 2026):

  1. Open your app in the Shopify Partners Dashboard.

  2. Configuration → Client credentials. Copy the Client ID and Client Secret.

  3. Required scopes: read_orders, read_products, read_customers, read_inventory, read_reports.

Env vars:

SHOPIFY_STORE=your-store.myshopify.com
SHOPIFY_CLIENT_ID=your_client_id
SHOPIFY_CLIENT_SECRET=shpss_your_secret

Legacy custom app (apps created before Jan 2026):

  1. Shopify Admin → Settings → Apps and sales channels → Develop apps, open your app.

  2. API credentials → copy the Admin API access token (shpat_...).

Env vars:

SHOPIFY_STORE=your-store.myshopify.com
SHOPIFY_ACCESS_TOKEN=shpat_your_token_here

Do not set both auth modes at once; the server logs a warning and uses Client Credentials if both are present.


Environment

Variable

Required

Description

KLAVIYO_API_KEY

Yes

Klaviyo private API key (pk_...)

SHOPIFY_STORE

For Shopify

*.myshopify.com domain

SHOPIFY_CLIENT_ID

Dev Dashboard auth

App Client ID

SHOPIFY_CLIENT_SECRET

Dev Dashboard auth

App Client Secret (shpss_...)

SHOPIFY_ACCESS_TOKEN

Legacy custom app

Admin API token (shpat_...)

SHOPIFY_API_VERSION

No

Default 2026-01

KLAVIYO_CONVERSION_METRIC_ID

No

Override auto-discovered "Placed Order" metric ID

DTC_MCP_SANDBOX

No

auto (default) | sidecar (require isolated-vm) | vm (force node:vm)

DTC_MCP_NODE_PATH

No

Absolute path to the Node binary used by the sidecar. Skips discovery.

DTC_MCP_MAX_RESPONSE_KB

No

Cap on bytes of execute_code return values (default 100).

DTC_MCP_DOCS_URL

No

Override docs source. Default: jsDelivr → dtc-mcp-docs@latest.

DTC_MCP_DOCS_REFRESH

No

Set to 0 to disable the background docs refresh (offline mode).

LOG_LEVEL

No

debug | info | warn | error (default info)


Development

npm install        # installs deps, builds isolated-vm via node-gyp
npm run build      # tsc → dist/
npm run dev        # tsc --watch
npm test           # vitest (63 tests)
npm run inspect    # MCP Inspector — connect any client to dist/index.js

Building the .mcpb bundle

tools/build-mcpb.sh           # → dtc-mcp-v<version>.mcpb in repo root

Stages prod-only dependencies, ad-hoc code-signs native .node binaries (macOS requirement), and zips into a .mcpb ready for one-click install.

Regenerating bundled docs

npm run codegen:klaviyo   # download Klaviyo OpenAPI, emit chunk JSON
npm run codegen:shopify   # introspect Shopify GraphQL (needs SHOPIFY_* env), emit chunks
npm run codegen:docs      # merge guides + chunks into data/docs.json

In production this runs daily on a GitHub Action in dtc-mcp-docs; the MCP fetches the freshest copy on the next boot.


Benchmark & design notes

bench/ contains a head-to-head benchmark against Klaviyo's official MCP server (9 analytics tasks × both MCPs × 2 trials, judged by Sonnet sub-agents) plus the internal findings that drove the v1.0.5 → v1.0.6 evolution.

Worth reading if you're building MCPs of your own:

  • bench/notes/findings.md — seven lessons about how LLMs use MCPs, grounded in specific bench cells. Includes the v1.0.5 regression and how the v1.0.6 LLM-native-description fix recovered it.

  • bench/notes/description-ablation.md — three rounds of Sonnet sub-agent probes (~63 trials) on candidate tool descriptions. Establishes that one canonical real-API example does ~99% of the teaching; format past that is marginal; prescriptive prose is dead weight.

  • bench/notes/prior-art.md — survey of the prior art on code-execution MCPs (Anthropic Code-Execution MCP, Cloudflare Code Mode, CodeAct, smolagents, BFCL v3, τ²-bench) and how it maps to what we observed.

  • bench/notes/v1.1.0-plan.md — recipe-by-intent discovery, the next leverage point.

The benchmark harness itself (bench/runner/) is reusable. The Sonnet sub-agent probe pattern (bench/runner/probe-descriptions.ts + probe-round3.ts) takes ~5 min and ~$0 to ablate any tool-description change — recommended before committing changes that affect agent behavior.


License

MIT. See LICENSE.

Available Tools

3 tools
execute_codeA

execute_code(code: string) -> { ok, result, stdout, state, durationMs } state: current globalThis stash (auto-populated, summary-form — read this to see what data from prior calls is available without re-fetching)

Sandbox globals: klaviyo, shopify, console, pick, topN, summarize, globalThis (persists across calls)

Discovery: search_docs / read_doc surface SDK paths, parameter shapes, and recipes. The SDK uses JSON:API conventions (sort keys, sparse fieldsets) that differ from typical JS SDKs — search_docs FIRST for unfamiliar methods.

Reference example (real API surface — note JSON:API request shape): const metricId = await klaviyo.getConversionMetricId(); const report = await klaviyo.reporting.campaignValues({ data: { type: 'campaign-values-report', attributes: { timeframe: { key: 'last_30_days' }, conversion_metric_id: metricId, statistics: ['recipients', 'open_rate', 'conversion_value'], }} }); globalThis.report = report; return topN(report.data.attributes.results, 5, r => r.statistics.conversion_value);

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYesJavaScript (or TypeScript-like) to execute in the stateful sandbox. Async; return a value via `return ...`. Globals: klaviyo, shopify, console, pick, topN, summarize, globalThis. No fetch/process/require/import. Add `// @timeout 2m` (max 5m) to extend the 30s wall-clock limit.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond annotations by disclosing that globalThis persists across calls, that state is auto-populated as a summary-form stash, that execution is async with a default 30s wall-clock limit and configurable timeout, and that network/module access is blocked. No contradiction with the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every section earns its place: return shape, persistent state, available globals, discovery direction, and a reference example. The most important operational facts are front-loaded in the signature and state note.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite lacking an output schema, the description fully defines the return object, persistent state behavior, available globals, constraints, and a realistic usage example. An agent can invoke the tool correctly and interpret results without further documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already covers the code parameter well, the description enriches it with execution semantics: async behavior, return value via `return ...`, available globals, forbidden globals, and timeout syntax. This gives an agent concrete guidance far beyond the raw schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action — execute JavaScript/TypeScript-like code in a stateful sandbox — and gives the exact return signature. It clearly distinguishes itself from sibling documentation tools by including a discovery note that routes unfamiliar API questions to search_docs/read_doc.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to use search_docs/read_doc first for unfamiliar SDK methods and discourages running code before checking API conventions. It also lists sandbox constraints (no fetch/process/require/import) and timeout rules, which effectively tell the agent when not to use this tool or how to adapt usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_docA
Read-onlyIdempotent

Fetch a specific SDK docs chunk by exact path, or list all available paths when called with no args.

Use this instead of search_docs when you already know the chunk ID — it's cheaper and more deterministic. Common patterns: • read_doc({}) → list every chunk ID with one-line summaries (use this once at the start of a session to map the SDK surface) • read_doc({ path: "klaviyo.reporting.campaignValues" }) → fetch one method's full doc (signature + JSDoc + example) verbatim • read_doc({ platform: "shopify" }) → list only Shopify chunk IDs

This adopts the "filesystem-as-API" pattern from Anthropic's Code Execution with MCP research: LLMs are faster and more accurate when they can read a typed-source-of-truth doc page directly, rather than re-searching for it on every code generation.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathNoExact chunk ID to fetch (e.g. 'klaviyo.reporting.campaignValues', 'guide.output-discipline'). Omit to list all available paths.
platformNoWhen listing (no `path`), filter to one platform's docs only.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark this read-only, idempotent, and non-destructive, but the description adds meaningful behavioral detail: no-args lists one-line summaries, path fetch returns verbatim full doc, and platform only filters listings. It also explains determinism and the filesystem-as-API rationale, giving the agent useful mental model beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core behavior and routing rule are front-loaded, followed by scannable bullet examples, and then a short rationale. Every sentence earns its place; the research reference is brief and helps explain why direct doc reading is preferable to repeated searching.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Even without an output schema, the description covers all return modes: listing all chunks with summaries, listing by platform, and fetching one full doc verbatim. Required parameters, optional parameters, and parameter combinations are all addressed. No critical gap remains for an agent to choose and call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds substantial value: concrete path examples, 'omit to list all available paths', platform filter scoped to listing mode, and expected return shape per parameter combination. These details are not in the schema and materially improve correct invocation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states a specific verb and resource: 'Fetch a specific SDK docs chunk by exact path' and also describes the no-args listing mode. It explicitly distinguishes this tool from search_docs, so an agent can select it correctly based on the tool's purpose alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit routing guidance: 'Use this instead of search_docs when you already know the chunk ID.' It also provides common usage patterns and a recommendation to call read_doc({}) once at session start to map the SDK surface. This goes beyond vague context into actionable when-to-use instructions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_docsA
Read-onlyIdempotent

Search the bundled SDK reference docs for Klaviyo and Shopify methods exposed inside the execute_code sandbox. Returns ranked markdown chunks: method signatures, parameter descriptions, and runnable code examples.

Use this BEFORE writing code in execute_code — the SDK surface is constrained to registered methods (escape hatches are 'klaviyo.get/post/paginate' and 'shopify.gql/ql').

The docs index is refreshed daily from a CDN-backed source repo, so new Klaviyo/Shopify API revisions land without requiring a new MCP release.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results to return (default 5).
queryYesNatural-language or keyword query. Examples: 'list campaigns', 'shopifyql sales last 30 days', 'flow reporting', 'get conversion metric id'.
platformNoFilter to one platform's docs.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds genuine context on top: it returns markdown chunks with signatures, parameter descriptions, and code examples, and it explains the daily refresh from a CDN-backed source repo. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short paragraphs each serve a distinct purpose: what the tool does, when to use it, and how current the docs are. The purpose is front-loaded and the text is efficient, though the daily-refresh sentence is somewhat optional for invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only search tool with 100% schema coverage and no output schema, the description provides enough context: return format, usage timing, platform scope, and SDK constraints. An agent can select and invoke this tool correctly without further clarification.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all three parameters clearly. The description adds useful query examples and reinforces the platform filter, but it does not meaningfully expand beyond what the schema provides; baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('search') and resource ('bundled SDK reference docs for Klaviyo and Shopify methods'), and clarifies the output format ('ranked markdown chunks'). It explicitly differentiates from execute_code by framing itself as the pre-coding lookup step, and the 'search' vs 'read' distinction separates it from read_doc even without naming it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly instructs the agent to use this tool BEFORE writing code in execute_code and explains why: the SDK surface is constrained to registered methods. It does not explicitly state when to prefer read_doc instead, so it falls short of full when/when-not coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A4.7/5.0
Disambiguation5/5

The three tools occupy clearly distinct roles: execute_code runs sandboxed code, while search_docs finds relevant documentation and read_doc fetches a specific doc chunk. Even though search_docs and read_doc both access documentation, their boundaries are explicit: search for exploration, read for deterministic retrieval by path.

Naming Consistency5/5

All three tools follow a consistent verb_noun snake_case pattern: execute_code, search_docs, read_doc. This makes the tool's action and target immediately predictable.

Tool Count5/5

Three tools are well-scoped for this server's purpose: one for code execution and two complementary docs-access tools. Each tool earnts its place and there is no bloat or redundancy.

Completeness5/5

The server covers its apparent lifecycle completely: discover what is available via read_doc/search_docs, then execute code against the constrained SDK with persistent globalThis state. There are no obvious dead ends or missing operations that would block an agent.

Maintenance

ActivityInactive
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    F
    maintenance
    A secure JavaScript REPL server that enables executing code snippets in a sandboxed environment with memory protection, timeout handling, and comprehensive error reporting.
    1
    17
    122
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides secure execution of arbitrary JavaScript code within a sandboxed QuickJS WASM environment, allowing language models or other MCP clients to safely run JavaScript code snippets without compromising the host system.
    4
  • A
    license
    Not graded
    quality
    B
    maintenance
    MCP server that exposes a V8 JavaScript runtime as a tool for AI agents like Claude and Cursor. Supports persistent heap snapshots via S3 or local filesystem, and is ready for integration with modern AI development environments.
    51
    Rust
    AGPL 3.0
  • A
    license
    B
    quality
    D
    maintenance
    A secure Model Context Protocol server that allows AI assistants and LLM applications to safely execute Python and JavaScript code snippets in containerized environments.
    2
    203
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rafaelsztutman/dtc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server