Agently documentation for building AI applications with stable outputs, observable actions, and durable workflows.
Languages: English · 中文
MCP (Model Context Protocol) exposes external tools to AI agents. Agently wires
MCP servers into the action runtime via MCPActionExecutor so the model sees
MCP tools and your own @agent.action_func actions through the same interface.
Use URL / Streamable HTTP MCP endpoints for service integrations, and stdio command configs for local development, desktop clients, or single-user local servers. SSE endpoints remain a legacy compatibility path.
import os
import asyncio
from dotenv import load_dotenv, find_dotenv
from agently import Agently
load_dotenv(find_dotenv())
Agently.set_settings("OpenAICompatible", {
"base_url": "${ENV.OPENAI_BASE_URL}",
"api_key": "${ENV.OPENAI_API_KEY}",
"model": "${ENV.OPENAI_MODEL}",
})
agent = Agently.create_agent()
async def main():
result = (
await agent.use_mcp(f"https://mcp.amap.com/mcp?key={os.environ.get('AMAP_API_KEY')}")
.input("What's the weather like in Shanghai today?")
.async_start()
)
print(result)
asyncio.run(main())
use_mcp(url) registers all tools the MCP server exposes. The agent then plans tool calls against the union of {@agent.action_func, use_tool, use_mcp tools} as if they were one set.
| Method | Behavior |
|---|---|
await agent.use_mcp(url) |
connect to the server, list tools, register them; returns the agent for chaining |
await agent.use_mcp(url, headers={...}) |
with custom HTTP headers (auth tokens, etc.) |
await agent.use_mcp({"mcpServers": {...}}) |
use an MCP config with one or more HTTP or stdio servers |
For the default executor, headers= with a URL is normalized to an MCP config
before FastMCP sees it.
await agent.use_mcp(
"https://example.com/mcp",
headers={"Authorization": f"Bearer {token}"},
)
For local stdio servers, pass MCP config directly:
await agent.use_mcp({
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./workspace"],
}
}
})
@agent.action_func
async def lookup_internal(id: str):
"""Look up a record in the internal database."""
...
await agent.use_mcp("https://example-mcp/server")
agent.use_actions(lookup_internal)
# The model now sees MCP tools + lookup_internal in the same plan
result = await agent.input(question).async_start()
There’s no precedence between MCP-provided tools and locally-defined actions. The model picks based on names, descriptions, and the prompt context.
After a request, see what tools the model actually invoked:
records = agent.get_action_result()
for r in records:
print(r)
Action records are also written to extra.action_logs (or extra.tool_logs on the compat surface).
await: use_mcp(...) is async because it lists tools from the server. Forgetting await returns a coroutine and the registration silently doesn’t happen.MCPActionExecutor is one of the bundled executorsuse_mcp(...) is the same on the compat surface