Bridge Model Context Protocol (MCP) tools with Temporal's reliable workflow execution system via Nexus RPC.
Nexus MCP is a bridge that connects the Model Context Protocol (MCP) with Temporal's Nexus RPC framework. It enables MCP tools to be backed by Temporal's reliable, durable workflow execution system, providing:
- Reliability: Tool executions are backed by Temporal's fault-tolerant workflows
- Durability: Long-running operations survive process restarts and failures
- Observability: Full visibility into tool execution through Temporal's UI
- Scalability: Distribute tool execution across multiple workers
The library acts as an adapter, allowing you to expose Temporal Nexus Operations as MCP tools.
- π Seamless Integration: Bridge MCP and Temporal with minimal configuration
- π οΈ Automatic Tool Discovery: Expose Nexus Operations as MCP tools automatically
- π§ Flexible Filtering: Control which operations are exposed using decorators
- π Rich Metadata: Automatic schema generation from Pydantic models
- π Production Ready: Built on proven Temporal infrastructure
- Python 3.13+
- Access to a Temporal cluster
- MCP-compatible client (e.g., Claude Desktop, custom MCP client)
NOTE: packages not published yet.
uv add nexus-mcppip install nexus-mcpgit clone https://github.com/bergundy/nexus-mcp-python
cd nexus-mcp
uv sync --devimport nexusrpc
from temporalio import workflow
from pydantic import BaseModel
class CalculateRequest(BaseModel):
expression: str
class CalculateResponse(BaseModel):
result: float
@nexusrpc.service(name="Calculator")
class CalculatorService:
"""A simple calculator service exposed via MCP."""
calculate: nexusrpc.Operation[CalculateRequest, CalculateResponse]import nexusrpc
from nexusmcp import MCPServiceHandler
from .service import CalculatorService, CalcluateRequest, CalculateResponse
mcp_service_handler = MCPServiceHandler()
@mcp_service_handler.register
@nexusrpc.handler.service_handler(service=CalculatorService)
class CalculatorHandler:
@nexusrpc.handler.sync_operation
async def calculate(self, _ctx: nexusrpc.handler.StartOperationContext, input: CalculateRequest) -> CalculateResponse:
"""Evaluate a mathematical expression and return the result."""
# Your calculation logic here
result = eval(input.expression) # Don't use eval in production!
return CalculateResponse(result=result)Local dev or self hosted deployment
temporal operator nexus endpoint create \
--name mcp-gateway \
--target-namespace my-handler-namespace \
--target-task-queue mcpTemporal Cloud
TODO
from temporalio.client import Client
from temporalio.worker import Worker
from .service_handler import mcp_service_handler, CalculatorHandler
async def main():
# Connect to Temporal (replace host and namespace as needed).
client = await Client.connect("localhost:7233", namespace="my-handler-namespace")
async with Worker(
client,
# This task queue should be the target of a Nexus endpoint defined above.
task_queue="mcp",
nexus_service_handlers=[CalculatorHandler(), mcp_service_handler],
):
await asyncio.Event().wait()import asyncio
from mcp.server.lowlevel import NotificationOptions, Server
from mcp.server.models import InitializationOptions
from temporalio.client import Client
from nexusmcp import InboundGateway
async def main():
server = Server("nexus-mcp-demo")
# Connect to Temporal (replace host and namespace as needed).
client = await Client.connect("localhost:7233", namespace="my-caller-namespace")
# Create the MCP gateway
gateway = InboundGateway(
client=client,
endpoint="mcp-gateway",
)
gateway.register(server)
async with gateway.run():
# Set up MCP server transport and run here...
if __name__ == "__main__":
asyncio.run(main())Add to your MCP client configuration (e.g., Claude Desktop):
{
"mcpServers": {
"nexus-calculator": {
"command": "python",
"args": ["path/to/your/mcp_server.py"]
}
}
}Control which operations are exposed using the @exclude decorator:
import nexusrpc
from nexusmcp import MCPServiceHandler, exclude
mcp_service_handler = MCPServiceHandler()
@mcp_service_handler.register
@nexusrpc.handler.service_handler()
class CalculatorHandler:
@exclude
@nexusrpc.handler.sync_operation
async def private_operation(self, _ctx: nexusrpc.handler.StartOperationContext, input: SomeModel) -> SomeModel:
"""This won't be available to MCP clients."""
pass
@nexusrpc.handler.sync_operation
async def public_operation(self, _ctx: nexusrpc.handler.StartOperationContext, input: SomeModel) -> SomeModel:
"""This will be available as an MCP tool."""
pass# Install dependencies
uv sync --dev# Run all tests
uv run pytest# Format code
uv run ruff format
# Lint code
uv run ruff check
# Type checking
uv run mypy .This project is licensed under the MIT License. See the LICENSE file for details.