Durable MCP Connector
Connects MCP clients and Temporal Workflows to Temporal Nexus services: it exposes Nexus operations as MCP tools (inbound) and proxies upstream MCP servers behind a Nexus service so that every upstream call runs in a standalone Temporal activity (outbound). Tool names map to Nexus operation names, with support for both sync Nexus operations and asynchronous workflow-run operations.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
Durable MCP Connector
Expose Temporal Nexus operations as MCP tools, or use Temporal to run calls to existing MCP servers. MCP clients connect over Streamable HTTP or stdio. Temporal Workflows call the same tools directly through Nexus.
The inbound Go library returns a standard MCP server. Your application supplies the Temporal client, service routes, authentication middleware, and server lifecycle. The outbound Go and Python libraries register a proxy on your Worker; each upstream tool call runs as a standalone Activity.
This repository is a prototype. The examples below use its current package names.
Requirements
A Temporal server with Nexus endpoints and standalone Nexus operations enabled. The outbound proxy also needs standalone Activities and Activity callbacks.
Go 1.26.2 or later for the Go libraries.
Python 3.11 or later for the Python libraries.
Related MCP server: SelfHeal MCP
Installation
Work from a checkout while the prototype depends on local SDK forks:
git clone https://github.com/long-nt-tran/durable-mcp-connector.git
cd durable-mcp-connectorGo builds use ../forks/sdk-go and ../forks/nexus-rpc-sdk-go, configured in
go.mod. Python uses ../forks/sdk-python and
../forks/nexus-rpc-sdk-python, configured in pyproject.toml.
Applications using the Go libraries from another module must also configure the
SDK replacements; Go does not inherit a dependency's replacements.
For the Python libraries and examples, install the workspace with uv:
uv syncThe first Python install builds the Temporal Rust bridge and needs Rust and
Protocol Buffers (protoc).
Usage: serve MCP over HTTP
Configure the Nexus service and endpoint you want to expose. The service must
provide list_tools; the authoring helpers
and outbound proxy provide it.
package main
import (
"log"
"net/http"
inbound "github.com/long-nt-tran/durable-mcp-connector/src/inbound/go"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/contrib/envconfig"
)
func main() {
clientOptions, err := envconfig.LoadDefaultClientOptions()
if err != nil {
log.Fatal(err)
}
if clientOptions.Namespace == "" {
clientOptions.Namespace = "default"
}
temporalClient, err := client.Dial(clientOptions)
if err != nil {
log.Fatal(err)
}
defer temporalClient.Close()
server, err := inbound.NewServer(inbound.Options{
Client: temporalClient,
Namespace: clientOptions.Namespace,
Services: []inbound.Service{
{Name: "weather-tools", Endpoint: "weather-endpoint"},
},
})
if err != nil {
log.Fatal(err)
}
handler, err := inbound.NewHTTPHandler(server)
if err != nil {
log.Fatal(err)
}
// Wrap handler with your application's authentication and authorization.
mux := http.NewServeMux()
mux.Handle("/mcp", handler)
log.Fatal(http.ListenAndServe("127.0.0.1:8080", mux))
}Point an MCP client at http://localhost:8080/mcp. NewServer validates the
configuration and returns *mcp.Server; it opens no listener and does not own the
Temporal client. Your application closes the client and shuts down its HTTP server.
For stdio, run the same MCP server with the MCP SDK's mcp.StdioTransport:
if err := server.Run(ctx, &mcp.StdioTransport{}); err != nil {
return err
}Import github.com/modelcontextprotocol/go-sdk/mcp for that transport. Keep stdout
for MCP messages and send application logs to stderr.
Client configuration
The example loads Temporal connection settings from TEMPORAL_* environment
variables and the selected temporal.toml profile. You can instead construct
client.Options in your application. Its address, namespace, TLS, credentials,
and data converter configure the supplied Temporal client.
Set Options.Namespace to that client's namespace. Standalone Nexus operations
and their results belong to this caller namespace. Each configured endpoint
routes to a handler Worker, which may run in a different namespace. Configure
endpoint permissions to admit the caller namespace.
If you use payload encryption, configure the client's data converter or codec to match the handler's encoding. The host supplies any codec credentials.
Server options
Option | Purpose |
| Required Temporal client, supplied and owned by the host. |
| Required caller namespace; must match |
| Required service/endpoint routes. Add an entry for each pair. |
| Initial wait for task-capable callers. Defaults to |
| Prefix every tool with its service name. Defaults to |
| Supply a verified |
tools/list merges the tools from all configured services. Duplicate names become
{service}_{tool}. Set PrefixToolNames: true to use that form for every tool.
Names are preserved verbatim; discovery fails if the resulting names still collide.
See the inbound guide for logging, server naming, operation ID configuration, and task ownership.
Authentication
The host wraps the HTTP handler with OAuth or other authentication middleware and applies any per-tool access policy. The connector uses the supplied Temporal client's credentials for every caller.
The OAuth host example and sample middleware show token verification, scope checks, and protected resource metadata. With a verified caller identity, task reads and cancellation check that the caller owns the task. Without an identity, possession of the task ID grants access. Stdio uses the local process connection.
Long-running tools and cancellation
Caller | Waiting behavior |
MCP client without Tasks | Wait until the operation completes or the caller cancels. |
MCP client with the Tasks extension | Return a task immediately by default. Set |
Temporal Workflow | Await the Nexus result durably, using the Workflow client below. |
Task-capable clients declare io.modelcontextprotocol/tasks in request metadata
and use tasks/get and tasks/cancel with the returned task ID. Temporal stores
the operation and result, so another connector replica can serve the same task.
For MCP 2026-07-28 HTTP clients, closing the response stream cancels a call that is
still waiting. Older HTTP clients and stdio clients use explicit cancellation
notifications. Route each legacy HTTP session to the same replica. After a task
is returned, cancel it with tasks/cancel. Cancellation is best-effort and does
not undo completed work.
Expose a Nexus service as MCP tools
Mark selected Nexus operations as tools. The Python helpers generate discovery, input/output schemas, and tool descriptions from the service and handler types:
from dataclasses import dataclass
import nexusrpc
import nexusrpc.handler
import nexus_backed_mcp as nexus_mcp
from nexus_backed_mcp import handler
from temporalio import nexus
from temporalio.worker import Worker
@dataclass
class WeatherInput:
city: str
@nexusrpc.service(name="weather-tools")
@nexus_mcp.service
class WeatherService:
get_weather: nexusrpc.Operation[WeatherInput, str]
@nexusrpc.handler.service_handler(service=WeatherService)
@handler.service_handler
class WeatherTools:
@handler.tool(title="Get the weather")
@nexus.temporal_operation
async def get_weather(
self,
ctx: nexus.TemporalStartOperationContext,
client: nexus.TemporalNexusClient,
input: WeatherInput,
) -> nexus.TemporalOperationResult[str]:
"""Return the weather for a city."""
return nexus.TemporalOperationResult.sync(f"Sunny in {input.city}.")
worker = Worker(
temporal_client,
task_queue="weather-tools",
nexus_service_handlers=[WeatherTools()],
)Supply your Temporal client and run the Worker through its normal lifecycle. Create a Nexus endpoint targeting its namespace and task queue, then add that endpoint to the inbound server's routes.
Tools are opt-in. Their names are the registered Nexus operation names. Short tools return a synchronous result; long tools can start a backing Workflow with the supplied Nexus-aware client. The connector handles MCP waiting and Tasks.
See the Python authoring guide or Go authoring guide for long-running tools, schemas, timeouts, and error results. Runnable tool Workers include both short and Workflow-backed tools.
Front an existing MCP server
Use the outbound proxy to expose an HTTP or stdio MCP server as a Nexus service. The upstream server needs no changes. This Python example adds a proxy to your Worker and gives a long-running tool a longer Activity timeout:
import os
from contextlib import asynccontextmanager
from datetime import timedelta
import httpx2
from mcp.client import Client as MCPClient
from mcp.client.streamable_http import streamable_http_client
from nexus_proxy_mcp import MCPProxyPlugin, Options, Upstream
from temporalio.worker import Worker
@asynccontextmanager
async def weather_client():
# The factory owns transport and auth. The Activity deadline bounds each call.
headers = {"Authorization": f"Bearer {os.environ['WEATHER_TOKEN']}"}
async with httpx2.AsyncClient(headers=headers, timeout=httpx2.Timeout(30, read=None)) as http:
async with MCPClient(
streamable_http_client("https://weather.example.com/mcp", http_client=http),
read_timeout_seconds=None,
) as client:
yield client
proxy = MCPProxyPlugin(options=Options(upstreams=[
Upstream(
service="weather-tools",
client_factory=weather_client,
activity_options_overrides={
"get_forecast_report": dict(
start_to_close_timeout=timedelta(hours=48),
),
},
),
]))
worker = Worker(temporal_client, task_queue="weather-proxy", plugins=[proxy])Each upstream becomes one Nexus service. Multiple services can share a Worker and endpoint. Expose them through the same inbound server, or call them directly from Workflow code.
Client factories own upstream connections, credentials, and cleanup. Discovery
runs at startup and on list_tools; failures retain the last successful catalog.
Tool calls use standalone Activities with a default one-minute attempt timeout.
Explicit retry policies override the policy inferred from tool annotations.
See the Python proxy guide or Go proxy guide for client factories, stdio, retries, and native Activity options. Runnable proxy Workers show HTTP and stdio upstreams together.
Call tools from a Workflow
Use InWorkflowClient inside Python Workflow code. It returns MCP tool definitions
and results through the Workflow Nexus client, without an HTTP or stdio connection:
from in_workflow_client import InWorkflowClient
client = InWorkflowClient(service="weather-tools", endpoint="weather-endpoint")
tools = await client.list_tools()
result = await client.call_tool("get_weather", {"city": "Boston"})The Workflow awaits long-running operations durably, and cancellation propagates to Nexus. This path bypasses the inbound server and does not use MCP Tasks.
For OpenAI Agents, use the WorkflowNexusMCPServer binding in the
Python Workflow guide. Go Workflows use
workflowtransport.NewClient; see the Go Workflow guide.
Examples and development
The examples guide walks through endpoints, tool Workers, proxy Workers, MCP clients, and an agent Workflow. The example connector hosts the inbound library over stdio or HTTP:
go run ./examples/connector --helpFor local development, install just and Temporal CLI 1.9.1 or later. From the repository root:
just temporal # Start a dev server; leave it running in another terminal.
just build # Build the example connector and Go examples.
just test # Run Go and Python unit tests.
just test-integration # Run integration tests against the dev server.See tests for verification and ARCHITECTURE.md for protocol mappings and implementation details.
License
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Model Context Protocol server for the Apideck Unified API. Connect any MCP-compatible agent framework to 100+ accounting systems, HRIS platforms, file storage providers, and more through one integration. More information https://www.apideck.com/mcp-server
Stateless MCP gateway and OTel span-streaming bridge for hosted MCP servers.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceAn MCP server that proxies tool calls to a running SentinelX Core instance with OIDC/OAuth authentication. It enables secure integration of SentinelX Core's HTTP agent capabilities through the MCP protocol.1MIT
- AlicenseAqualityDmaintenanceSelf-healing proxy for MCP servers that wraps tool calls with automatic retry, circuit breaker protection, and observability.571 npmMIT
- FlicenseAqualityDmaintenanceUniversal MCP proxy server that discovers, searches, and executes tools across all configured MCP servers from a single entry point.7-
- AlicenseAqualityDmaintenanceAn MCP server for interacting with Temporal Cloud workflows across multiple regions, providing tools to list, describe, terminate, and retrieve step results from workflows via natural language.71MIT