Skip to content

v0.4.0

Choose a tag to compare

@ryanwithawhy ryanwithawhy released this 06 Oct 20:45
· 14 commits to main since this release

The server can now run as a hosted HTTP service instead of only over stdio, and it grew the operational surface a hosted deployment needs. stdio behavior is unchanged — if you run the server locally per-client, nothing here requires action.

Running over HTTP

Start the server with --transport streamable-http (or MCP_TRANSPORT=streamable-http) and point clients at a URL instead of spawning the process per client:

python /path/to/fivetran-mcp/server.py --transport streamable-http --host 0.0.0.0 --port 8000
Variable Required Default Description
MCP_TRANSPORT No stdio stdio or streamable-http. Same as --transport.
MCP_HOST / --host No 127.0.0.1 Bind host, streamable-http only.
MCP_PORT / --port No 8000 Bind port, streamable-http only.
MCP_ALLOWED_ORIGINS No (empty) Comma-separated allowed Origin header values.
MCP_ALLOWED_HOSTS No (empty) Comma-separated allowed Host header values.

In streamable-http mode credentials come from each request's Authorization header rather than from the environment: the client sends the same API key/secret pair as a Basic auth header. Do not set FIVETRAN_API_KEY / FIVETRAN_API_SECRET for an HTTP deployment — the server refuses to start if it finds them, since a shared key baked into a multi-tenant process would apply one operator's credentials to every caller.

If neither MCP_ALLOWED_ORIGINS nor MCP_ALLOWED_HOSTS is set, the server runs without DNS-rebinding protection and logs a startup warning.

OAuth resource-server support is scaffolding only and not yet functional. Token verification is unimplemented, so leave FIVETRAN_AUTH_ISSUER unset; HTTP mode today works only in its header-forwarding form.

Per-endpoint denials

DISALLOWED_ACTIONS accepts a third form alongside resource:action:

  • resource:action:endpoint_name (e.g. connections:write:sync_connection) denies one specific endpoint, with no cascade. The endpoint must belong to that exact resource:action pair or startup fails.

Operational surface

  • GET /health — unauthenticated, always mounted, returns the version and a manifest checksum computed once at import and cached.
  • Structured logging — one JSON log line per tool invocation carrying request id, mode, tool, endpoint, upstream status, latency, and client, emitted from a finally block so it fires even on an uncaught exception. Logs to stdout in streamable-http mode and stderr in stdio mode, since stdio's stdout is the MCP protocol channel. Only whitelisted fields are logged — never request bodies or headers.
  • A metrics seam — _record_tool_call is the single hook metrics will attach to. No counters or exporter yet.
  • A Dockerfile — single-stage python:3.12-slim, non-root user, defaulting to streamable-http on 0.0.0.0:8000.
  • Upstream status is logged for successful calls as well as errors.

Also in this release

  • MCP tool annotations keyed off the action tier: readOnlyHint on reads, destructiveHint on deletes, openWorldHint=False throughout. Server instructions describe the list_endpoints → get_schema → call discovery flow.
  • Advisory confirmation warnings on write and delete tool descriptions, and a unified error contract across grant, routing, and upstream failures.
  • A request-scoped credential resolver with env, header, and OAuth-stub implementations, wired to the transport.
  • One shared httpx.AsyncClient across outbound Fivetran calls instead of a client per request.
  • endpoint_overrides.json, for prepending text to a specific endpoint's description without regenerating the manifest.
  • account_read carries openai/profile _meta so ChatGPT can disambiguate accounts.
  • configure() is extracted from import time, making startup testable.
  • server.py reorganized into labeled sections.
  • Broader test coverage across configure() paths and concurrency.