enlace_connector
Allows the MCP server to validate OAuth 2.1 bearer tokens issued by Auth0 as an identity provider.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@enlace_connectordeploy truffle.mcp:search_trufflepig as a connector"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
enlace_connector
Deploy Python functions as authenticated MCP connectors on an enlace platform — so Claude.ai (and any MCP host) can call them.
A Claude.ai "custom connector" is a remote MCP server. enlace_connector wraps your
tool functions with py2mcp, plugs auth into
the platform's enlace_auth OAuth server,
and follows enlace's app conventions so deployment is one declaration.
from enlace_connector import ConnectorSpec, make_connector_app, scaffold_app
spec = ConnectorSpec(
name="trufflepig",
tools=["truffle.mcp:search_trufflepig", "truffle.mcp:search_wallow"],
auth="enlace", # validate tokens issued by the platform's enlace_auth
extras=["truffle"], # what the connector's own venv must install
)
# Develop locally (stdio, no auth) — Claude Desktop / Claude Code:
make_stdio_server(spec).run()
# The hosted ASGI app (Streamable HTTP + OAuth) a server runs:
app = make_connector_app(spec, issuer="https://apps.thorwhalen.com")
# Or scaffold an enlace mode=process app dir (own venv for heavy deps):
scaffold_app(spec, "tw_platform/apps/trufflepig_mcp", port=8030)Why a separate venv (mode="process")
A connector with heavy dependencies (ML models, large libraries) runs as an enlace
mode="process" app: enlace spawns it as a supervised subprocess in its own venv
and reverse-proxies the route to it — keeping those deps out of the shared platform
backend. The connector validates bearer tokens itself, so enlace treats it as
access="public" (no session gate).
Related MCP server: Remote MCP Server on Cloudflare
Auth is pluggable
The connector is an OAuth 2.1 resource server — it validates the bearer JWTs an authorization server issued. Who that AS is is just config:
| Authorization server | Use |
| the platform's | self-contained platform auth |
| a managed IdP (Auth0, WorkOS, …) | offload OAuth to a vendor |
| — | local stdio / unauthenticated internal pilot |
The resource-server validation is identical regardless — picking an AS doesn't change the connector, only where the token comes from.
Usage logging is a switch, not code
A deployed connector otherwise leaves only the web server's access log. With
py2mcp's usage logger (its ADR-0001) the
connector can keep one record per tool call — time, caller from the OAuth token,
tool, arguments, outcome, result size, latency — and one flagged record per
handshake, so "enabled" and "used" stop looking the same. It is off by default.
The host switches it on with environment variables (the unit file's
Environment= lines), never by editing connector code:
Variable | Meaning |
| absolute directory for the day files, one per connector; unset = off. Use the connector's own data root, off the deploy tree (a relative path is refused) |
| days to keep (default 90; |
| comma-separated argument names to mask (error text is dropped too, since it echoes arguments) |
|
|
make_connector_app(spec) reads them itself; a connector that builds FastMCP
by hand passes middleware=usage_middleware(spec) (an empty list when off). The
spec's version and usage_outcome (a "module:function" ref to the connector's
own (tool, result) -> label | mapping classifier, e.g. one that knows the search
tool's "no match" shape) travel into the records.
The rendered systemd unit ships the CONNECTOR_USAGE_LOG_DIR line commented
out. The arguments are the users' own questions: tell them before you turn it on,
and read the log with py2mcp usage <dir>.
Deploy the whole bundle
generate_deploy_bundle(spec, dest) writes everything a mode="process" connector
needs — the app dir (app.toml + server.py), a systemd unit (runs it in its
own venv), a provisioning script (build that venv + install extras/git_installs
create
datadirs +post_install), the twoplatform.tomlfragments (oauth-server.toml— session longevity;allowlist.toml— fromallowed_users), and a runbook:
spec = ConnectorSpec(
name="acme", tools=["acme.mcp:search"], route="/api/acme_mcp", port=8031,
extras=["ir", "sentence-transformers"], git_installs=["git+ssh://git@github.com/acme/acme"],
data=[("~/.local/share/ir/corpora/acme", "{base}/xdg-data/ir/corpora/acme")],
env={"XDG_DATA_HOME": "{base}/xdg-data", "HF_HOME": "{base}/hf-cache"},
allowed_users=["a@acme.com", "b@acme.com"],
)
generate_deploy_bundle(spec, "apps/acme_mcp") # → app dir + deploy/{unit,provision,toml fragments,runbook}Platform specifics (paths, origin) are parameters with tw_platform defaults; the
package stays connector-type-agnostic (it knows nothing of ir).
Verify before you call it deployed
A connector can be perfectly healthy and completely dead to its users. If the
platform's authorization server does not advertise the refresh_token grant,
every client session dies at the first access-token expiry (typically one hour) and
only a human re-running the interactive browser authorization can bring it back —
while the process stays up, the port answers, and nothing errors anywhere. It has
happened; the first signal was a person saying the connector had been down all day.
So the deployment isn't good until the authorization server is checked:
python -m enlace_connector.preflight https://apps.thorwhalen.com # exit 1 if it would strandfrom enlace_connector import verify_deployment, format_report
results = verify_deployment(spec, issuer="https://apps.thorwhalen.com")
print(format_report(results))
assert all(results) # or pass strict=True to raiseIt fetches {issuer}/.well-known/oauth-authorization-server and asserts what the
deployed server advertises — config claiming refresh is enabled is not evidence,
since the running build may predate the feature. Checks are plain callables of a
PreflightContext (checks= to extend or replace them) and the HTTP fetcher is a
parameter (fetch=), so this is testable offline and CI-friendly.
Configure it from the start too: deploy/oauth-server.toml in the bundle carries the
[auth.oauth_server] refresh_token_ttl_seconds key (30 days by default; 0 disables
the grant), so a new platform doesn't inherit a stranding default.
Cost / LLM note
A connector over ir's core search is offline and free — no LLM, no tokens.
An agentic connector (query reformulation, LLM-selection, synopsis) needs an LLM;
that LLM is an injected callable and can ride the client's Claude subscription via
MCP sampling (where the client supports it) instead of a metered key — see ir's
ir_10 note and issue #1 here.
Status
The connector factory, auth, scaffolding, and full deploy-bundle generation are
stable and tested; auth="enlace" is live in production. Building the connector app
directly (to attach a server icon, custom tools, etc.) is also supported — see the
server_py= override on generate_deploy_bundle.
pip install -e ".[dev]" && pytest -qThis server cannot be deployed
Maintenance
Related MCP Connectors
Build, validate, deploy — HTTP APIs, cron jobs, webhooks and MCP tools — from your AI client.
Hosted MCP server with managed OAuth for 15+ toolkits: Google Workspace, Fitbit, Oura, Kalshi, etc.
Connect any AI agent to 1,000+ apps and 27,000+ actions through one remote MCP server (OAuth).
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceEnables deploying MCP servers on Cloudflare Workers with OAuth authentication and SSE transport. Allows connecting Claude Desktop and other MCP clients to remotely hosted tools via HTTP.-
- FlicenseNot gradedqualityCmaintenanceEnables deploying a Model Context Protocol (MCP) server on Cloudflare Workers with built-in OAuth authentication. It allows local clients like Claude Desktop to securely connect to and use remote tools through an HTTP/SSE transport.-
- AlicenseNot gradedqualityCmaintenanceEnables deploying and connecting to MCP servers on Cloudflare Workers with OAuth login, allowing remote access to tools via MCP clients like Claude Desktop.284 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables deploying a remote Model Context Protocol (MCP) server on Cloudflare Workers with OAuth authentication, allowing tools to be exposed and called from MCP clients like Claude Desktop.-