DeerFlow supports two types of extensions: Skills (specialized agent workflows) and MCP Servers (external context providers). Both are configured through config.yaml and extensions_config.json.
Configuration Files
config.yaml Skills Directory : Configure where skills are located and how they’re mounted in sandboxes
extensions_config.json Enable/Disable State : Control which skills and MCP servers are active
Skills Configuration
Skills are specialized workflows and prompts that enhance agent capabilities for specific tasks.
Directory Configuration (config.yaml)
skills :
# Path to skills directory on the host
# Relative paths are resolved from current working directory
# If not specified, defaults to ../skills relative to backend directory
path : /absolute/path/to/custom/skills
# Path where skills are mounted in the sandbox container
# This is used by the agent to access skills in both local and Docker sandbox
container_path : /mnt/skills
Path to the skills directory on the host machine.
Can be absolute (/home/user/skills) or relative (../skills)
Relative paths are resolved from the current working directory
If not specified, defaults to ../skills relative to the backend directory
container_path
string
default: "/mnt/skills"
Path where skills are mounted inside the sandbox container. The agent uses this path to access skills in both local and Docker sandboxes.
Skills Directory Structure
skills/
├── public/ # Built-in skills
│ ├── pdf-processing/
│ │ ├── SKILL.md # Skill definition
│ │ └── scripts/ # Helper scripts
│ └── frontend-design/
│ └── SKILL.md
└── custom/ # User-defined skills
└── my-skill/
└── SKILL.md
Enable/Disable Skills (extensions_config.json)
Control which skills are active:
{
"skills" : {
"pdf-processing" : {
"enabled" : true
},
"frontend-design" : {
"enabled" : true
},
"my-custom-skill" : {
"enabled" : false // Disabled
}
}
}
Default Behavior : If a skill is not listed in extensions_config.json, it’s enabled by default for public and custom categories.
Programmatic Access
Check if a skill is enabled:
from src.config.extensions_config import get_extensions_config
config = get_extensions_config()
# Check if skill is enabled
if config.is_skill_enabled( "pdf-processing" , "public" ):
print ( "PDF processing skill is enabled" )
# Get skill container path
from src.config.app_config import get_app_config
app_config = get_app_config()
path = app_config.skills.get_skill_container_path(
skill_name = "pdf-processing" ,
category = "public"
)
print ( f "Skill path in container: { path } " )
# Output: /mnt/skills/public/pdf-processing
MCP (Model Context Protocol) Configuration
MCP servers provide external context, tools, and data sources to agents. DeerFlow supports three transport types:
stdio Local process communication via stdin/stdout
HTTP RESTful HTTP communication
SSE Server-Sent Events for streaming
Configuration (extensions_config.json)
All MCP servers are configured in extensions_config.json:
{
"mcpServers" : {
"filesystem" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [ "-y" , "@modelcontextprotocol/server-filesystem" , "/path/to/allowed/files" ],
"env" : {},
"description" : "Provides filesystem access within allowed directories"
},
"github" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [ "-y" , "@modelcontextprotocol/server-github" ],
"env" : {
"GITHUB_TOKEN" : "$GITHUB_TOKEN"
},
"description" : "GitHub MCP server for repository operations"
},
"postgres" : {
"enabled" : false ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [ "-y" , "@modelcontextprotocol/server-postgres" , "postgresql://localhost/mydb" ],
"description" : "PostgreSQL database access"
}
}
}
Common Fields
enabled
boolean
default: "true"
required
Whether this MCP server is active. Set to false to temporarily disable.
Transport protocol: stdio, http, or sse
Human-readable description of what this MCP server provides
stdio Transport
For local processes that communicate via stdin/stdout:
{
"my-stdio-server" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [ "-y" , "@modelcontextprotocol/server-filesystem" , "/path" ],
"env" : {
"API_KEY" : "$MY_API_KEY"
},
"description" : "Local filesystem access"
}
}
Executable command to start the MCP server (e.g., npx, python, /usr/bin/my-server)
Command-line arguments passed to the command
Environment variables for the MCP server process. Values starting with $ are resolved from the host environment: "env" : {
"API_KEY" : "$MY_API_KEY" , // Resolved from host
"DEBUG" : "true" // Literal value
}
HTTP Transport
For RESTful HTTP-based MCP servers:
{
"my-http-server" : {
"enabled" : true ,
"type" : "http" ,
"url" : "https://api.example.com/mcp" ,
"headers" : {
"Authorization" : "Bearer $API_TOKEN" ,
"X-Custom-Header" : "value"
},
"oauth" : {
"enabled" : true ,
"token_url" : "https://auth.example.com/oauth/token" ,
"grant_type" : "client_credentials" ,
"client_id" : "$MCP_OAUTH_CLIENT_ID" ,
"client_secret" : "$MCP_OAUTH_CLIENT_SECRET"
},
"description" : "External HTTP MCP server"
}
}
Base URL of the MCP server
HTTP headers sent with requests. Supports environment variable resolution with $VAR_NAME.
SSE (Server-Sent Events) Transport
For streaming MCP servers using Server-Sent Events:
{
"my-sse-server" : {
"enabled" : true ,
"type" : "sse" ,
"url" : "https://api.example.com/mcp" ,
"headers" : {
"Authorization" : "Bearer $API_TOKEN"
},
"oauth" : {
"enabled" : true ,
"token_url" : "https://auth.example.com/oauth/token" ,
"grant_type" : "client_credentials" ,
"client_id" : "$MCP_OAUTH_CLIENT_ID" ,
"client_secret" : "$MCP_OAUTH_CLIENT_SECRET" ,
"scope" : "mcp.read mcp.write" ,
"audience" : "https://api.example.com" ,
"refresh_skew_seconds" : 60
},
"description" : "Streaming SSE MCP server"
}
}
SSE servers use the same fields as HTTP servers.
OAuth Configuration
For HTTP and SSE transports, DeerFlow can automatically manage OAuth tokens:
{
"oauth" : {
"enabled" : true ,
"token_url" : "https://auth.example.com/oauth/token" ,
"grant_type" : "client_credentials" ,
"client_id" : "$MCP_OAUTH_CLIENT_ID" ,
"client_secret" : "$MCP_OAUTH_CLIENT_SECRET" ,
"refresh_token" : "$MCP_REFRESH_TOKEN" ,
"scope" : "mcp.read mcp.write" ,
"audience" : "https://api.example.com" ,
"token_field" : "access_token" ,
"token_type_field" : "token_type" ,
"expires_in_field" : "expires_in" ,
"default_token_type" : "Bearer" ,
"refresh_skew_seconds" : 60 ,
"extra_token_params" : {
"resource" : "https://api.example.com"
}
}
}
Enable OAuth token management
oauth.grant_type
string
default: "client_credentials"
OAuth grant type: client_credentials or refresh_token
OAuth client ID (supports $VAR_NAME for environment variables)
OAuth client secret (supports $VAR_NAME)
OAuth refresh token (for refresh_token grant type, supports $VAR_NAME)
OAuth scope (space-separated list of permissions)
OAuth audience (provider-specific, e.g., Auth0)
oauth.token_field
string
default: "access_token"
Field name containing the access token in the token response
oauth.token_type_field
string
default: "token_type"
Field name containing the token type in the token response
oauth.expires_in_field
string
default: "expires_in"
Field name containing the expiry duration (in seconds) in the token response
Default token type when missing in the token response
oauth.refresh_skew_seconds
Refresh the token this many seconds before expiry to avoid race conditions
Additional form parameters sent to the token endpoint
OAuth Grant Types
Client Credentials
Refresh Token
Most common for server-to-server authentication: {
"oauth" : {
"enabled" : true ,
"token_url" : "https://auth.example.com/oauth/token" ,
"grant_type" : "client_credentials" ,
"client_id" : "$CLIENT_ID" ,
"client_secret" : "$CLIENT_SECRET" ,
"scope" : "api.read api.write"
}
}
For long-lived access using a refresh token: {
"oauth" : {
"enabled" : true ,
"token_url" : "https://auth.example.com/oauth/token" ,
"grant_type" : "refresh_token" ,
"client_id" : "$CLIENT_ID" ,
"client_secret" : "$CLIENT_SECRET" ,
"refresh_token" : "$REFRESH_TOKEN"
}
}
Environment Variable Resolution
Both env fields (for stdio) and OAuth configuration support environment variable resolution:
{
"mcpServers" : {
"github" : {
"type" : "stdio" ,
"env" : {
"GITHUB_TOKEN" : "$GITHUB_TOKEN" // Resolved from host environment
}
},
"my-api" : {
"type" : "http" ,
"headers" : {
"Authorization" : "Bearer $API_KEY" // Resolved from host environment
},
"oauth" : {
"client_id" : "$OAUTH_CLIENT_ID" , // Resolved from host environment
"client_secret" : "$OAUTH_SECRET" // Resolved from host environment
}
}
}
}
Set these variables in your environment:
export GITHUB_TOKEN = "ghp_..."
export API_KEY = "key_..."
export OAUTH_CLIENT_ID = "client_..."
export OAUTH_SECRET = "secret_..."
If a referenced environment variable is not set, DeerFlow will raise a ValueError during configuration loading.
Programmatic Access
from src.config.extensions_config import get_extensions_config
config = get_extensions_config()
# Get all enabled MCP servers
enabled_servers = config.get_enabled_mcp_servers()
for name, server_config in enabled_servers.items():
print ( f "Server: { name } " )
print ( f " Type: { server_config.type } " )
print ( f " Description: { server_config.description } " )
# Get specific MCP server
if "github" in config.mcp_servers:
github = config.mcp_servers[ "github" ]
if github.enabled:
print ( f "GitHub MCP: { github.command } { ' ' .join(github.args) } " )
# Check skill status
if config.is_skill_enabled( "pdf-processing" , "public" ):
print ( "PDF processing skill is enabled" )
Examples
Official MCP Servers
Filesystem
GitHub
PostgreSQL
Brave Search
{
"filesystem" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [
"-y" ,
"@modelcontextprotocol/server-filesystem" ,
"/home/user/documents"
],
"description" : "Access to /home/user/documents"
}
}
{
"github" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [
"-y" ,
"@modelcontextprotocol/server-github"
],
"env" : {
"GITHUB_TOKEN" : "$GITHUB_TOKEN"
},
"description" : "GitHub repository operations"
}
}
{
"postgres" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [
"-y" ,
"@modelcontextprotocol/server-postgres" ,
"postgresql://user:pass@localhost/mydb"
],
"description" : "PostgreSQL database access"
}
}
{
"brave-search" : {
"enabled" : true ,
"type" : "stdio" ,
"command" : "npx" ,
"args" : [
"-y" ,
"@modelcontextprotocol/server-brave-search"
],
"env" : {
"BRAVE_API_KEY" : "$BRAVE_API_KEY"
},
"description" : "Brave web search"
}
}
Custom Skills Example
Create a custom skill:
Create skill directory:
mkdir -p skills/custom/my-skill
Create SKILL.md:
skills/custom/my-skill/SKILL.md
# My Custom Skill
This skill provides specialized capabilities for...
## Instructions
When the user asks for..., follow these steps:
1. ...
2. ...
Enable in extensions_config.json:
{
"skills" : {
"my-skill" : {
"enabled" : true
}
}
}
Troubleshooting
Environment variable not found
Ensure all referenced environment variables are set: # Check if variable is set
echo $GITHUB_TOKEN
# Add to .env file
echo "GITHUB_TOKEN=ghp_..." >> .env
MCP server fails to start (stdio)
Verify the command is available: # Test the command manually
npx -y @modelcontextprotocol/server-github --help
# Check npx is installed
which npx
Check the skills path configuration: skills :
path : /absolute/path/to/skills # Ensure this exists
# Verify skills directory exists
ls -la /absolute/path/to/skills
OAuth token refresh fails
Check OAuth configuration:
Verify token_url is correct
Ensure client_id and client_secret are set
Check scope matches provider requirements
Review provider’s OAuth documentation
Next Steps
Memory Configuration Set up the memory system
Creating Skills Build custom skills