MCP Client Guide

Run MCP diagram tools in CI: curl, a stored key, and the calls worth automating

By the engineer who builds Datadef, from client work on data platforms · Reviewed August 21, 2026

A pipeline has no chat window, so the MCP client is curl and the credential is a repository secret. That works well because the Datadef endpoint is a plain HTTP JSON-RPC surface with no session to establish. What takes judgment is not the transport, it is deciding which calls belong in CI at all, because most of what people automate here already happens on its own.

7 min readFor platform engineers wiring diagram or documentation steps into a pipeline

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

133/20003 credits left
Try:

No account needed · Editable canvas, not a picture

The request shape, and the two headers that decide whether it works

Post JSON-RPC to https://datadef.io/mcp. Two headers matter beyond the credential. Content-Type must be application/json, and Accept must list both application/json and text/event-stream, because the streamable HTTP transport may answer either way and a client that accepts only one of them gets rejected before the tool runs.

Never use GET from a script. A GET without an event-stream Accept header is treated as a human or a crawler and returns an HTML page describing the server, which is useful in a browser and useless in a pipeline that expected JSON. Protocol traffic is POST.

There is no session to establish first. The server is stateless, so a single POST carries a complete call. Store the key as a repository or pipeline secret and pass it as a bearer header; keys are created and revoked on the MCP and integrations page, and a revoked key stops working immediately.

curl -sS --fail-with-body https://datadef.io/mcp \
  -H "Authorization: Bearer $DATADEF_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "repo_status",
      "arguments": { "project_id": "'"$DATADEF_PROJECT_ID"'" }
    }
  }'

What actually belongs in a pipeline

Freshness reporting belongs there. repo_status returns the provider, the repository, the branch or tag tracked, the commit reflected, whether daily sync is on, and a plain-language freshness line. A job that reads it and fails or warns when the diagram lags the branch turns documentation staleness into something a pull request can see, which is the whole argument for docs checks in CI.

A refresh after a significant merge belongs there too, with a caveat. repo_refresh regenerates the diagram from the repository, which replaces manual canvas edits, so it is right for projects whose diagram is generated and wrong for ones a human has tuned. Refreshes share a bucket of ten per ten minutes per account, so a matrix job across many projects needs to pace itself.

Generation usually does not belong there. create_diagram spends a credit, takes up to a few minutes, and produces something a person should look at. A pipeline that regenerates a diagram on every push accumulates near-duplicates nobody opens. The exception is a one-off bootstrap job for a new repository.

Two things that make CI usage safe to leave running

Access is rechecked per request rather than trusted from issue time. A key minted while the plan was active stops authenticating once the plan lapses, without anyone revoking it, and the rejection carries a specific explanation rather than the generic challenge that would send an automated client into a pointless re-authorization loop.

Every call is attributed. The agent activity list in Datadef settings records one row per tool call: the credential label, the tool name, the status, the duration, and a short argument excerpt capped at 140 characters. Full prompts are never stored. Giving CI its own key with its own label makes pipeline traffic separable from human traffic at a glance.

The last thing worth saying is that most teams need less of this than they expect. Connected repositories on GitHub, GitLab or Azure DevOps already resync daily on the server side, regenerating both the diagram and its architecture document, and a commit that changes nothing structural does not redraw anything: the sync hashes the parsed structure, the Terraform draw plan or the assembled corpus, and skips generation outright when that fingerprint matches the previous run. A job that fires repo_refresh after a docs-only merge therefore spends a slot from the ten-per-ten-minutes bucket to accomplish nothing. CI is for the gap between a merge and the next scheduled run, not for the schedule itself.

Health checks need no secret

Listings on this endpoint are anonymous, so a monitoring job can POST tools/list with no credential and assert it gets 36 tools back. Only tool calls need the key.

FAQ

Can I call an MCP server from a CI pipeline with plain curl?

Yes. A streamable HTTP MCP endpoint is JSON-RPC over POST, and this one is stateless, so a single request carries a complete tool call with no session to establish first. Send the key as an Authorization bearer header from a pipeline secret.

Which headers does the request need?

Content-Type application/json, and an Accept header that lists both application/json and text/event-stream, because the transport may answer with either, and missing the second one causes a rejection before the tool runs. The Authorization bearer header carrying the API key is the third, and it is the only one of the three that tool calls need and listings do not.

Why does a GET to the endpoint return HTML?

A GET without an event-stream Accept header is treated as a browser or a crawler and served a readable page describing the server and its tools, so assistants that fetch the URL get something useful instead of an authentication error. Protocol traffic is POST and is unaffected.

What happens to a CI key when the plan lapses?

It stops authenticating on the next call, because the plan is rechecked per request rather than trusted from when the key was issued. The rejection carries a specific explanation of the situation instead of a generic challenge, so an automated client does not loop trying to re-authorize.

Should CI regenerate the diagram on every push?

No. Generation costs a credit and produces something a person should review, so a per-push job accumulates near-duplicates. Connected repositories already resync daily on the server side, and a commit with no structural change does not redraw the diagram. Reserve pipeline calls for a freshness check and for a refresh after a significant merge.

Can a monitoring job check the server without a credential?

Yes. The handshake and the listings answer anonymously, so a job can post a tools/list request with no key and assert that the full tool surface comes back. A healthy response lists 36 tools, nine that act on whole diagrams and 27 canvas tools, which makes a completeness check as cheap as an uptime check. Only tool calls require authentication.