Skip to content

Commit 80be481

Browse files
saqadriandrew-lastmile
authored andcommitted
Updates to ----
MCP Agent SDK ---- * Overview * Core Components * Configuring your application * Specify secrets * MCPApp * Agents * AugmentedLLM * Connecting to MCP servers (MCP server registry, MCP connection manager, just some examples) * Execution engine * Workflows
1 parent 8411b3c commit 80be481

File tree

8 files changed

+564
-71
lines changed

8 files changed

+564
-71
lines changed

docs/docs.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{
22
"$schema": "https://mintlify.com/docs.json",
33
"name": "mcp-agent",
4+
"logo": {
5+
"light": "/logo/mcp-agent.png",
6+
"dark": "/logo/mcp-agent.png"
7+
},
48
"theme": "willow",
59
"colors": {
610
"primary": "#3B82F6",

docs/mcp-agent-sdk/core-components/configuring-your-application.mdx

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,22 @@ icon: gear
77

88
mcp-agent uses YAML configuration files to manage application settings, MCP servers, and model providers.
99

10-
## Configuration Files
10+
## Configuration files
1111

12-
mcp-agent uses two configuration files:
12+
Start with two YAML files at the root of your project:
1313

1414
<CardGroup cols={2}>
1515
<Card title="mcp_agent.config.yaml" icon="gear">
16-
Application configuration, MCP servers, and non-sensitive settings
16+
Application configuration, MCP servers, logging, execution engine, model defaults
1717
</Card>
1818
<Card title="mcp_agent.secrets.yaml" icon="key">
19-
API keys, secrets, and sensitive credentials (gitignored)
19+
API keys, OAuth credentials, and other secrets (gitignored)
2020
</Card>
2121
</CardGroup>
2222

23-
## Basic Configuration
23+
See [Specify Secrets](/mcp-agent-sdk/core-components/specify-secrets) for credential management patterns and production tips.
24+
25+
## Basic configuration
2426

2527
Here's a minimal configuration:
2628

@@ -138,7 +140,7 @@ mcp:
138140
139141
## Model Providers
140142
141-
Configure your LLM provider:
143+
Configure your LLM provider. Many examples follow this layout—for instance, the [basic finder agent](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/basic/mcp_basic_agent) sets OpenAI defaults exactly this way.
142144
143145
<Tabs>
144146
<Tab title="OpenAI">
@@ -198,6 +200,68 @@ Configure your LLM provider:
198200
</Tab>
199201
</Tabs>
200202
203+
## OAuth configuration
204+
205+
Two places control OAuth behaviour:
206+
207+
1. **Global OAuth settings (`settings.oauth`)** configure token storage and callback behaviour (loopback ports, preload timeouts, Redis support).
208+
2. **Per-server auth (`mcp.servers[].auth.oauth`)** specifies client credentials, scopes, and provider overrides.
209+
210+
```yaml mcp_agent.config.yaml
211+
oauth:
212+
token_store:
213+
backend: redis
214+
redis_url: ${OAUTH_REDIS_URL}
215+
216+
mcp:
217+
servers:
218+
github:
219+
command: "uvx"
220+
args: ["mcp-server-github"]
221+
auth:
222+
oauth:
223+
enabled: true
224+
client_id: ${GITHUB_CLIENT_ID}
225+
client_secret: ${GITHUB_CLIENT_SECRET}
226+
redirect_uri_options:
227+
- "http://127.0.0.1:33418/callback"
228+
include_resource_parameter: false
229+
```
230+
231+
Pair this with secrets in `mcp_agent.secrets.yaml` or environment variables. For concrete walkthroughs, study the [OAuth basic agent](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/basic/oauth_basic_agent) and the [interactive OAuth tool](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/oauth/interactive_tool). The [pre-authorize workflow example](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/oauth/pre_authorize) shows how to seed credentials before a background workflow runs.
232+
233+
## Programmatic configuration
234+
235+
You can bypass file discovery by passing a fully-formed `Settings` object (or a path) to `MCPApp`. This is especially useful for tests and scripts that compose configuration dynamically.
236+
237+
```python
238+
from mcp_agent.app import MCPApp
239+
from mcp_agent.config import Settings, OpenAISettings
240+
241+
settings = Settings(
242+
execution_engine="asyncio",
243+
openai=OpenAISettings(
244+
default_model="gpt-4o-mini",
245+
temperature=0.3,
246+
),
247+
)
248+
249+
app = MCPApp(name="dynamic", settings=settings)
250+
```
251+
252+
Because `Settings` extends `BaseSettings`, environment variables still override any fields you set explicitly.
253+
254+
## Configuration discovery
255+
256+
When `MCPApp` starts, it resolves settings in this order:
257+
- `MCP_APP_SETTINGS_PRELOAD` / `MCP_APP_SETTINGS_PRELOAD_STRICT`
258+
- Explicit `settings` argument passed to `MCPApp`
259+
- `mcp_agent.config.yaml` (or `mcp-agent.config.yaml`) discovered in the working directory, parent directories, `.mcp-agent/` folders, or `~/.mcp-agent/`
260+
- `mcp_agent.secrets.yaml` / `mcp-agent.secrets.yaml` merged on top
261+
- Environment variables (including values from `.env`, using `__` for nesting)
262+
263+
Environment variables override file-based values, while the preload option short-circuits everything else—handy for containerised deployments that mount secrets from a vault. [Specify Secrets](/mcp-agent-sdk/core-components/specify-secrets) covers strategies for each stage.
264+
201265
## Environment Variables
202266

203267
You can reference environment variables in configuration:

docs/mcp-agent-sdk/core-components/connecting-to-mcp-servers.mdx

Lines changed: 134 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,141 @@ description: "Learn how to connect to MCP servers using the MCP server registry
55
icon: plug
66
---
77

8-
<Info>
9-
Content to be migrated covering MCP server registry, MCP connection manager, gen_client, connect/disconnect patterns.
10-
</Info>
11-
128
## Overview
139

14-
mcp-agent provides multiple ways to connect to and manage MCP servers:
10+
Every `MCPApp` initialises a `ServerRegistry` that knows how to start and authenticate each server defined in `mcp_agent.config.yaml`. The registry works hand in hand with `MCPConnectionManager` to provide two patterns:
11+
12+
- Short-lived connections using `gen_client`, perfect for one-off operations.
13+
- Persistent connections managed by the connection manager, ideal for agents and long-running workflows.
14+
15+
Understanding these two layers lets you control connection reuse, lifecycle, and error handling with precision.
16+
17+
## Inspect configured servers
18+
19+
After `app.run()` the registry is accessible via the context:
20+
21+
```python
22+
async with app.run() as running_app:
23+
registry = running_app.server_registry
24+
for name, cfg in registry.registry.items():
25+
running_app.logger.info(
26+
"Server configured",
27+
data={"name": name, "transport": cfg.transport},
28+
)
29+
```
30+
31+
The registry resolves transports (`stdio`, `sse`, `streamable_http`, `websocket`), applies authentication (`api_key` or OAuth), and exposes helpers such as `register_init_hook`.
32+
33+
## Ephemeral sessions with `gen_client`
34+
35+
Use `gen_client` when you need a connection for the duration of a `with` block. It spins up the server process (for stdio transports), performs initialisation, yields an `MCPAgentClientSession`, and tears everything down automatically—a handy pattern for scripts, CLI utilities, or inspection. The [basic finder agent](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/basic/mcp_basic_agent) uses the same underlying helpers when it initialises an agent.
36+
37+
```python
38+
from mcp_agent.mcp.gen_client import gen_client
39+
40+
async with app.run():
41+
async with gen_client(
42+
server_name="fetch",
43+
server_registry=app.server_registry,
44+
context=app.context,
45+
) as session:
46+
tools = await session.list_tools()
47+
print("Fetch tools:", [tool.name for tool in tools.tools])
48+
```
49+
50+
This is the simplest way to script against MCP servers without committing to persistent connections.
51+
52+
## Persistent connections and connection pooling
53+
54+
The `ServerRegistry` owns a `MCPConnectionManager` (`registry.connection_manager`) that maintains long-lived connections in a background task group. You can either interact with it directly or rely on helpers such as `mcp_agent.mcp.gen_client.connect`.
55+
56+
```python
57+
from mcp_agent.mcp.gen_client import connect, disconnect
58+
59+
async with app.run():
60+
session = await connect("filesystem", app.server_registry, context=app.context)
61+
try:
62+
result = await session.list_resources()
63+
print("Roots:", [r.uri for r in result.resources])
64+
finally:
65+
await disconnect("filesystem", app.server_registry)
66+
```
67+
68+
When you need multiple connections simultaneously, open the manager as a context manager to ensure orderly shutdown:
69+
70+
```python
71+
async with app.run():
72+
async with app.server_registry.connection_manager as manager:
73+
fetch_conn = await manager.get_server("fetch")
74+
filesystem_conn = await manager.get_server("filesystem")
75+
await fetch_conn.session.list_tools()
76+
await filesystem_conn.session.list_tools()
77+
# Connections are closed when the block exits
78+
```
79+
80+
## Connection persistence in agents
81+
82+
Agents use the connection manager behind the scenes. Set `connection_persistence=True` (the default) to keep servers warm between tool calls or `False` to close the transport after each request.
83+
84+
```python
85+
agent = Agent(
86+
name="finder",
87+
instruction="Use fetch and filesystem tools",
88+
server_names=["fetch", "filesystem"],
89+
connection_persistence=True,
90+
context=app.context,
91+
)
92+
```
93+
94+
Persistent connections dramatically reduce latency when calling the same server repeatedly.
95+
96+
## Aggregating multiple servers
97+
98+
`MCPAggregator` builds a “server-of-servers” using the same registry and connection manager. You can namespace tool calls or expose a merged surface area:
99+
100+
```python
101+
from mcp_agent.mcp.mcp_aggregator import MCPAggregator
102+
103+
async with app.run():
104+
async with MCPAggregator.create(
105+
server_names=["fetch", "filesystem"],
106+
connection_persistence=True,
107+
context=app.context,
108+
) as aggregator:
109+
await aggregator.list_tools() # Combined tool view
110+
await aggregator.call_tool("fetch_fetch", {"url": "https://example.com"})
111+
await aggregator.call_tool("read_text_file", {"path": "README.md"})
112+
```
113+
114+
This pattern mirrors the [`examples/basic/mcp_server_aggregator`](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/basic/mcp_server_aggregator) sample and is commonly used when turning an entire app into a single MCP server.
115+
116+
## OAuth-aware connections
117+
118+
When server definitions include `auth.oauth`, the registry and connection manager automatically coordinate with the app’s token manager. The OAuth examples highlight three recurring patterns:
119+
120+
- [`examples/basic/oauth_basic_agent`](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/basic/oauth_basic_agent) – an agent maintains persistent connections to the GitHub MCP server using the client-only loopback flow.
121+
- [`examples/oauth/interactive_tool`](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/oauth/interactive_tool) – a client opens a temporary `gen_client` session, receives an `auth/request`, and walks through the browser login.
122+
- [`examples/oauth/pre_authorize`](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/oauth/pre_authorize) – tokens are seeded before an asynchronous workflow runs so the background execution never needs interactive auth.
123+
124+
In each case, you get the same `ClientSession` interface; the difference lies in how tokens are acquired and stored.
125+
126+
## Initialisation hooks and authentication
127+
128+
You can register custom logic that runs immediately after a server initialises. It is perfect for seeding credentials, warming caches, or performing health checks.
129+
130+
```python
131+
def after_start(session, auth):
132+
session.logger.info("Server ready", data={"auth": bool(auth)})
133+
134+
app.server_registry.register_init_hook("fetch", after_start)
135+
```
136+
137+
When a server declares OAuth configuration (`mcp.servers[].auth.oauth`), `MCPApp` automatically injects an `OAuthHttpxAuth` handler so `MCPConnectionManager` can obtain and refresh tokens using the shared `TokenManager`. This means you do not need to ship long-lived access tokens in your config.
138+
139+
## Error handling & retries
15140

16-
- **MCP Server Registry** - Central registry of configured servers
17-
- **MCP Connection Manager** - Lifecycle management for server connections
18-
- **gen_client** - Context manager for temporary connections
19-
- **connect/disconnect** - Persistent connection management
141+
- `MCPConnectionManager` keeps track of connection health and will surface errors via logs (`ProgressAction.FATAL_ERROR`) without crashing your application.
142+
- Call `disconnect_all()` or `close()` if you want to force reconnection after rotating credentials.
143+
- When a connection fails during initialisation, any awaiting `get_server` call unblocks with an exception so that workflows can decide whether to retry or degrade gracefully.
20144

21-
[See MCP Servers documentation for details](/mcp-agent-sdk/core-components/mcp-servers)
145+
[Deep dive into MCP Servers](/mcp-agent-sdk/core-components/mcp-servers)

docs/mcp-agent-sdk/core-components/execution-engine.mdx

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ The Temporal engine provides durable workflow execution with automatic state per
4747
```yaml
4848
execution_engine: temporal
4949
temporal:
50-
server_url: "localhost:7233"
50+
host: "localhost:7233"
5151
namespace: "default"
52+
task_queue: "mcp-agent"
5253
```
5354
5455
**Use cases:**
@@ -58,6 +59,8 @@ temporal:
5859
- Multi-node deployments
5960
- Workflows requiring pause/resume
6061
62+
📌 **Example:** The [Temporal workflow gallery](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/temporal) showcases orchestrator, router, and evaluator/optimizer patterns running on this engine.
63+
6164
## Executors
6265
6366
Executors are the runtime components that actually execute workflows within an engine.
@@ -67,29 +70,38 @@ Executors are the runtime components that actually execute workflows within an e
6770
Handles workflow execution for the asyncio engine:
6871
6972
```python
70-
from mcp_agent.executors.asyncio_executor import AsyncioExecutor
73+
from mcp_agent.executor.executor import AsyncioExecutor
74+
75+
async def greet(name: str) -> str:
76+
return f"Hi {name}"
7177

7278
executor = AsyncioExecutor()
73-
result = await executor.execute_workflow(workflow, params)
79+
result = await executor.execute(greet, "Ada")
80+
print(result) # "Hi Ada"
7481
```
7582

7683
**Features:**
7784
- Direct Python function execution
7885
- Native async/await support
7986
- Minimal overhead
8087

88+
See it in action in the [basic workflows examples](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/workflows) where tasks run entirely in-process.
89+
8190
### TemporalExecutor
8291

8392
Manages workflow execution for the Temporal engine:
8493

8594
```python
86-
from mcp_agent.executors.temporal_executor import TemporalExecutor
87-
88-
executor = TemporalExecutor(
89-
temporal_host="localhost:7233",
90-
namespace="default"
91-
)
92-
result = await executor.execute_workflow(workflow, params)
95+
from mcp_agent.executor.temporal import TemporalExecutor
96+
from mcp_agent.config import TemporalSettings
97+
98+
executor = TemporalExecutor(config=TemporalSettings(
99+
host="localhost:7233",
100+
namespace="default",
101+
task_queue="mcp-agent",
102+
))
103+
handle = await executor.start_workflow("ResearchWorkflow", {"topic": "LLMs"})
104+
result = await handle.result()
93105
```
94106

95107
**Features:**
@@ -98,6 +110,8 @@ result = await executor.execute_workflow(workflow, params)
98110
- Distributed execution
99111
- Workflow queries and signals
100112

113+
The [`examples/oauth/pre_authorize`](https://github.com/lastmile-ai/mcp-agent/tree/main/examples/oauth/pre_authorize) project combines this executor with OAuth-aware workflows.
114+
101115
## Choosing an Execution Engine
102116

103117
### Development Phase
@@ -200,15 +214,27 @@ logger:
200214
```yaml
201215
execution_engine: temporal
202216
temporal:
203-
server_url: "temporal.production.internal:7233"
217+
host: "temporal.production.internal:7233"
204218
namespace: "production"
205219
task_queue: "agent-workflows"
206220
worker_count: 4
207221
max_concurrent_activities: 20
208222
```
209223
224+
## Accessing the executor in an application
225+
226+
`MCPApp` exposes the active executor and engine selection:
227+
228+
```python
229+
async with app.run() as running_app:
230+
executor = running_app.executor
231+
print(executor.execution_engine) # "asyncio" or "temporal"
232+
```
233+
234+
You typically call high-level helpers (`workflow.execute()`, `executor.start_workflow`) rather than invoking executor methods directly, but the property is available when you need advanced control or diagnostics.
235+
210236
## Next Steps
211237

212238
- [Temporal Advanced Features](/advanced/temporal)
213239
- [Workflow Patterns](/workflows/overview)
214-
- [Configuration Guide](/configuration)
240+
- [Configuration Guide](/configuration)

0 commit comments

Comments
 (0)