Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
28b974e
Work in progress MCP call support
tconley1428 Aug 7, 2025
c197efd
Moving mcp classes into plugin
tconley1428 Aug 7, 2025
c0abe7b
Merge remote-tracking branch 'origin/main' into openai/mcp
tconley1428 Aug 7, 2025
8fff2aa
Updated documentation
tconley1428 Aug 7, 2025
19e57eb
Add local test
tconley1428 Aug 7, 2025
c0a280c
Fix problems since MCP doesn't exist on python 3.9
tconley1428 Aug 7, 2025
f2dcb61
Remove debug log
tconley1428 Aug 7, 2025
2b1e0ac
Best effort import temporal server
tconley1428 Aug 7, 2025
e80cdf7
Delay import of mcp servers
tconley1428 Aug 7, 2025
0ed952a
Change to a stateless implementation
tconley1428 Aug 11, 2025
0fd7886
Include stateful option
tconley1428 Aug 11, 2025
f3acf3f
Add docstrings
tconley1428 Aug 11, 2025
afeaaa5
Merge branch 'main' into openai/mcp
tconley1428 Aug 12, 2025
c7a78a1
Remove merge duplicate
tconley1428 Aug 12, 2025
0475d0c
Some cleanup
tconley1428 Aug 12, 2025
eb86407
Lint
tconley1428 Aug 12, 2025
ce2eb9a
Fix up tests
tconley1428 Aug 12, 2025
c441326
Lint
tconley1428 Aug 13, 2025
4a4378c
Restructure based on feedback - docstring need updating still
tconley1428 Aug 18, 2025
e86e13f
Change workflow function names
tconley1428 Aug 19, 2025
ec8b241
Cleanup
tconley1428 Aug 19, 2025
8c88a59
Merge branch 'main' into openai/mcp
tconley1428 Aug 19, 2025
09aa3f0
Lint
tconley1428 Aug 19, 2025
ab040c3
Fixing python 3.9
tconley1428 Aug 19, 2025
72fbeeb
Lint
tconley1428 Aug 19, 2025
24aecd9
Some name changes and protected get_activities
tconley1428 Aug 19, 2025
65315a8
Merge branch 'main' into openai/mcp
tconley1428 Aug 19, 2025
3c847b6
Addressing feedback
tconley1428 Aug 20, 2025
6f02b01
Change server names, overhaul tests to use a custom MCPServer which t…
tconley1428 Aug 20, 2025
a034867
Fixing 3.9 issues
tconley1428 Aug 20, 2025
783eb9e
Fix await
tconley1428 Aug 20, 2025
c34e7a6
Merge remote-tracking branch 'origin/main' into openai/mcp
tconley1428 Aug 20, 2025
4c54c42
Revert core change
tconley1428 Aug 20, 2025
f1a642c
Merge branch 'main' into openai/mcp
tconley1428 Aug 25, 2025
a272045
Remove print
tconley1428 Aug 25, 2025
95cfbec
Merge remote-tracking branch 'origin/main' into openai/mcp
tconley1428 Sep 17, 2025
d0e7355
Fail fast if stateful server hasn't been started
tconley1428 Sep 17, 2025
8ef444b
Overhaul stateful mcp server
tconley1428 Sep 18, 2025
5f7c644
Trying to fix core commit
tconley1428 Sep 18, 2025
45185b3
Merge remote-tracking branch 'origin/main' into openai/mcp
tconley1428 Sep 18, 2025
39e9d31
Wait for cancellation
tconley1428 Sep 18, 2025
975b2e1
update readme
jssmith Sep 18, 2025
2a999a2
Change stateless to a provider model, add caching option
tconley1428 Sep 18, 2025
58708c0
Remove caching from stateful. Underlying server can handle it
tconley1428 Sep 18, 2025
606f4e8
readme updates
jssmith Sep 19, 2025
6fc01c9
Revert pyproject update
tconley1428 Sep 19, 2025
53c3c39
Fix no worker test
tconley1428 Sep 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ opentelemetry = [
pydantic = ["pydantic>=2.0.0,<3"]
openai-agents = [
"openai-agents>=0.3,<0.4",
"eval-type-backport>=0.2.2; python_version < '3.10'"
"eval-type-backport>=0.2.2; python_version < '3.10'",
"mcp>=1.9.4, <2; python_version >= '3.10'",
]

[project.urls]
Expand Down
118 changes: 113 additions & 5 deletions temporalio/contrib/openai_agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,111 @@ Of course, code running in the workflow can invoke a Temporal activity at any ti
Tools that run in the workflow can also update OpenAI Agents context, which is read-only for tools run as Temporal activities.


## MCP Support

This integration provides support for Model Context Protocol (MCP) servers through two wrapper approaches designed to handle different implications of failures.

While Temporal provides durable execution for your workflows, this durability does not extend to MCP servers, which operate independently of the workflow and must provide their own durability. The integration handles this by offering stateless and stateful wrappers that you can choose based on your MCP server's design.

### Stateless vs Stateful MCP Servers

You need to understand your MCP server's behavior to choose the correct wrapper:

**Stateless MCP servers** treat each operation independently. For example, a weather server with a `get_weather(location)` tool is stateless because each call is self-contained and includes all necessary information. These servers can be safely restarted or reconnected to without changing their behavior.

**Stateful MCP servers** maintain session state between calls. For example, a weather server that requires calling `set_location(location)` followed by `get_weather()` is stateful because it remembers the configured location and uses it for subsequent calls. If the session or the server is restarted, state crucial for operation is lost. Temporal identifies such failures and raises an `ApplicationError` to signal the need for application-level failure handling.

### Usage Example (Stateless MCP)

The code below gives an example of using a stateless MCP server.

#### Worker Configuration

```python
import asyncio
from datetime import timedelta
from agents.mcp import MCPServerStdio
from temporalio.client import Client
from temporalio.contrib.openai_agents import (
ModelActivityParameters,
OpenAIAgentsPlugin,
StatelessMCPServerProvider,
)
from temporalio.worker import Worker

async def main():
# Create the MCP server provider
filesystem_server = StatelessMCPServerProvider(
lambda: MCPServerStdio(
name="FileSystemServer",
params={
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/files"],
},
)
)

# Register the MCP server with the OpenAI Agents plugin
client = await Client.connect(
"localhost:7233",
plugins=[
OpenAIAgentsPlugin(
model_params=ModelActivityParameters(
start_to_close_timeout=timedelta(seconds=60)
),
mcp_servers=[filesystem_server],
),
],
)

worker = Worker(
client,
task_queue="my-task-queue",
workflows=[FileSystemWorkflow],
)
await worker.run()

if __name__ == "__main__":
asyncio.run(main())
```

#### Workflow Implementation

```python
from temporalio import workflow
from temporalio.contrib import openai_agents
from agents import Agent, Runner

@workflow.defn
class FileSystemWorkflow:
@workflow.run
async def run(self, query: str) -> str:
# Reference the MCP server by name (matches name in worker configuration)
server = openai_agents.workflow.stateless_mcp_server("FileSystemServer")

agent = Agent(
name="File Assistant",
instructions="Use the filesystem tools to read files and answer questions.",
mcp_servers=[server],
)

result = await Runner.run(agent, input=query)
return result.final_output
```

The `StatelessMCPServerProvider` takes a factory function that creates new MCP server instances. The server name used in `stateless_mcp_server()` must match the name configured in the MCP server instance. In this example, the name is `FileSystemServer`.

### Stateful MCP Servers

For implementation details and examples, see the [samples repository](https://github.com/temporalio/samples-python/tree/main/openai_agents/mcp).

When using stateful servers, the dedicated worker maintaining the connection may fail due to network issues or server problems. When this happens, Temporal raises an `ApplicationError` and cannot automatically recover because it cannot restore the lost server state.
To recover from such failures, you need to implement your own application-level retry logic.

### Hosted MCP Tool

For network-accessible MCP servers, you can also use `HostedMCPTool` from the OpenAI Agents SDK, which uses an MCP client hosted by OpenAI.

## Feature Support

This integration is presently subject to certain limitations.
Expand Down Expand Up @@ -403,14 +508,17 @@ As described in [Tool Calling](#tool-calling), context propagation is read-only

### MCP

Presently, MCP is supported only via `HostedMCPTool`, which uses the OpenAI Responses API and cloud MCP client behind it.
The OpenAI Agents SDK also supports MCP clients that run in application code, but this integration does not.
The MCP protocol is stateful, but many MCP servers are stateless.
We let you choose between two MCP wrappers, one designed for stateless MCP servers and one for stateful MCP servers.
These wrappers work with all transport varieties.

Note that when using network-accessible MCP servers, you also can also use the tool `HostedMCPTool`, which is part of the OpenAI Responses API and uses an MCP client hosted by OpenAI.

| MCP Class | Supported |
|:-----------------------|:---------:|
| MCPServerStdio | No |
| MCPServerSse | No |
| MCPServerStreamableHttp| No |
| MCPServerStdio | Yes |
| MCPServerSse | Yes |
| MCPServerStreamableHttp| Yes |

### Guardrails

Expand Down
11 changes: 11 additions & 0 deletions temporalio/contrib/openai_agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
Use with caution in production environments.
"""

# Best Effort mcp, as it is not supported on Python 3.9
try:
from temporalio.contrib.openai_agents._mcp import (
StatefulMCPServerProvider,
StatelessMCPServerProvider,
)
except ImportError:
pass

from temporalio.contrib.openai_agents._model_parameters import ModelActivityParameters
from temporalio.contrib.openai_agents._temporal_openai_agents import (
OpenAIAgentsPlugin,
Expand All @@ -27,6 +36,8 @@
"ModelActivityParameters",
"OpenAIAgentsPlugin",
"OpenAIPayloadConverter",
"StatelessMCPServerProvider",
"StatefulMCPServerProvider",
"TestModel",
"TestModelProvider",
"workflow",
Expand Down
Loading
Loading