Documentation Index Fetch the complete documentation index at: https://docs.ensemble.ai/llms.txt
Use this file to discover all available pages before exploring further.
What is MCP?
Model Context Protocol (MCP) is Anthropic’s open protocol for connecting AI systems to external tools and data sources.
With Cloudflare’s announcement of MCP support (November 2024), Conductor implements HTTP-only MCP for secure, scalable tool integration on the edge.
Why MCP?
Standardized - Open protocol for tool integration
Secure - Built-in auth (bearer, OAuth, HMAC)
Scalable - HTTP-based, works on edge
Interoperable - Works with any MCP-compatible system
Bidirectional MCP
Conductor supports MCP in both directions:
Outbound (Consumer) - Call external MCP servers using the tools operation
Inbound (Provider) - Expose ensembles as MCP tools via /mcp endpoints
┌─────────────────────────────────────────────────┐
│ │
│ External MCP Servers (GitHub, Brave, Custom) │
│ │
└────────────────┬────────────────────────────────┘
│
│ HTTP (tools operation)
▼
┌─────────────────────────────────────────────────┐
│ │
│ Conductor Ensembles │
│ │
└────────────────┬────────────────────────────────┘
│
│ HTTP (/mcp endpoints)
▼
┌─────────────────────────────────────────────────┐
│ │
│ External Systems (Claude Desktop, AI Apps) │
│ │
└─────────────────────────────────────────────────┘
Call external MCP servers from your ensembles.
Create conductor.config.ts in your project root:
import type { ConductorConfig } from '@ensemble-edge/conductor'
const config : ConductorConfig = {
mcpServers: {
// GitHub MCP Server
github: {
url: 'https://github-mcp.example.com' ,
auth: {
type: 'bearer' ,
token: process . env . GITHUB_MCP_TOKEN
},
timeout: 15000
},
// Brave Search MCP Server
brave: {
url: 'https://brave-search-mcp.example.com' ,
auth: {
type: 'bearer' ,
token: process . env . BRAVE_API_KEY
}
},
// Custom MCP Server with OAuth
custom: {
url: 'https://custom-mcp.example.com' ,
auth: {
type: 'oauth' ,
clientId: process . env . OAUTH_CLIENT_ID ,
clientSecret: process . env . OAUTH_CLIENT_SECRET ,
tokenUrl: 'https://auth.example.com/oauth/token'
},
timeout: 20000
}
}
}
export default config
2. Set Environment Variables
# .dev.vars (local development)
GITHUB_MCP_TOKEN = ghp_xxx
BRAVE_API_KEY = BSAxxx
OAUTH_CLIENT_ID = client_xxx
OAUTH_CLIENT_SECRET = secret_xxx
# Production (Cloudflare Workers)
wrangler secret put GITHUB_MCP_TOKEN
wrangler secret put BRAVE_API_KEY
wrangler secret put OAUTH_CLIENT_SECRET
ensemble : github-pr-analyzer
agents :
# Call GitHub MCP tool
- name : get-pr
operation : tools
config :
mcp : github # Server name from config
tool : get_pull_request # Tool name
timeout : 10000
# Analyze with AI
- name : analyze
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
Pull Request Data:
${get-pr.output}
Provide a code review.
inputs :
owner : anthropics
repo : anthropic-sdk-typescript
pull_number : 123
outputs :
review : ${analyze.output}
pr_data : ${get-pr.output}
Examples: Common MCP Servers
GitHub MCP
agents :
- name : get-pr
operation : tools
config :
mcp : github
tool : get_pull_request
- name : list-files
operation : tools
config :
mcp : github
tool : list_pull_request_files
- name : get-file
operation : tools
config :
mcp : github
tool : get_file_contents
inputs :
owner : anthropics
repo : anthropic-sdk-typescript
pull_number : 123
file_path : src/index.ts
Brave Search MCP
agents :
- name : search
operation : tools
config :
mcp : brave
tool : web_search
- name : summarize
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
Search Results: ${search.output}
Question: ${input.question}
Provide a comprehensive answer.
inputs :
query : "Model Context Protocol specification"
count : 10
Authentication Options
Bearer Token :
auth : {
type : 'bearer' ,
token : process . env . API_TOKEN
}
OAuth :
auth : {
type : 'oauth' ,
clientId : process . env . CLIENT_ID ,
clientSecret : process . env . CLIENT_SECRET ,
tokenUrl : 'https://auth.example.com/oauth/token'
}
HMAC Signature :
auth : {
type : 'bearer' ,
token : process . env . API_TOKEN
},
secret : process . env . API_SECRET // For signing requests
Make your ensembles available as MCP tools to external systems.
Add expose configuration to your ensemble:
ensemble : github-pr-reviewer
trigger :
- type : mcp
public : false
auth :
type : bearer
tokens :
- ${env.MCP_CLIENT_TOKEN_1}
- ${env.MCP_CLIENT_TOKEN_2}
agents :
- name : review
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
Review this pull request:
Owner: ${input.owner}
Repo: ${input.repo}
PR: ${input.pull_number}
inputs :
owner :
type : string
required : true
description : GitHub repository owner
repo :
type : string
required : true
description : GitHub repository name
pull_number :
type : number
required : true
description : Pull request number
outputs :
review : ${review.output}
approved : ${review.output.approved}
2. Deploy to Cloudflare Workers
# Deploy your ensemble
wrangler deploy
# Set secrets
wrangler secret put MCP_CLIENT_TOKEN_1
wrangler secret put MCP_CLIENT_TOKEN_2
External systems can discover your tools:
# List all available tools
curl https://your-worker.workers.dev/mcp/tools \
-H "Authorization: Bearer ${ MCP_CLIENT_TOKEN }"
Response:
{
"tools" : [
{
"name" : "github-pr-reviewer" ,
"description" : "Reviews GitHub pull requests" ,
"inputSchema" : {
"type" : "object" ,
"properties" : {
"owner" : {
"type" : "string" ,
"description" : "GitHub repository owner"
},
"repo" : {
"type" : "string" ,
"description" : "GitHub repository name"
},
"pull_number" : {
"type" : "number" ,
"description" : "Pull request number"
}
},
"required" : [ "owner" , "repo" , "pull_number" ]
}
}
]
}
# Call the tool
curl https://your-worker.workers.dev/mcp/tools/github-pr-reviewer \
-H "Authorization: Bearer ${ MCP_CLIENT_TOKEN }" \
-H "Content-Type: application/json" \
-d '{
"name": "github-pr-reviewer",
"arguments": {
"owner": "anthropics",
"repo": "anthropic-sdk-typescript",
"pull_number": 123
}
}'
Response:
{
"content" : [
{
"type" : "text" ,
"text" : "{ \" review \" : \" LGTM \" , \" approved \" : true}"
}
],
"isError" : false
}
5. Use in Claude Desktop
Configure Claude Desktop to use your MCP server:
{
"mcpServers" : {
"conductor-tools" : {
"url" : "https://your-worker.workers.dev/mcp" ,
"headers" : {
"Authorization" : "Bearer YOUR_MCP_TOKEN"
}
}
}
}
Now Claude can use your ensembles as tools!
Complete Example: Bidirectional Integration
Build a system that both consumes and provides MCP tools:
Setup: conductor.config.ts
import type { ConductorConfig } from '@ensemble-edge/conductor'
const config : ConductorConfig = {
// Outbound: External MCP servers we consume
mcpServers: {
github: {
url: 'https://github-mcp.example.com' ,
auth: {
type: 'bearer' ,
token: process . env . GITHUB_MCP_TOKEN
}
},
brave: {
url: 'https://brave-search-mcp.example.com' ,
auth: {
type: 'bearer' ,
token: process . env . BRAVE_API_KEY
}
}
}
}
export default config
ensemble : research-assistant
# This ensemble uses external MCP tools
agents :
# Use Brave MCP for web search
- name : search-web
operation : tools
config :
mcp : brave
tool : web_search
# Use GitHub MCP for code search
- name : search-code
operation : tools
config :
mcp : github
tool : search_code
# Synthesize results
- name : synthesize
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
Web Results: ${search-web.output}
Code Results: ${search-code.output}
Question: ${input.question}
Provide a comprehensive answer.
inputs :
question : string
repo : string
outputs :
answer : ${synthesize.output}
sources :
web : ${search-web.output}
code : ${search-code.output}
ensemble : pr-analyzer
# This ensemble is exposed as an MCP tool
trigger :
- type : mcp
public : false
auth :
type : bearer
tokens :
- ${env.MCP_CLIENT_TOKEN}
# Uses external GitHub MCP internally
agents :
- name : get-pr
operation : tools
config :
mcp : github
tool : get_pull_request
- name : get-files
operation : tools
config :
mcp : github
tool : list_pull_request_files
- name : analyze
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
PR: ${get-pr.output}
Files: ${get-files.output}
Analyze this PR and provide feedback.
inputs :
owner :
type : string
required : true
repo :
type : string
required : true
pull_number :
type : number
required : true
outputs :
analysis : ${analyze.output}
file_count : ${get-files.output.length}
Usage
1. Use research-assistant ensemble directly:
curl -X POST https://your-worker.workers.dev/api/v1/execute/ensemble/research-assistant \
-H "X-API-Key: ${ API_KEY }" \
-H "Content-Type: application/json" \
-d '{
"input": {
"question": "How to implement MCP servers?",
"repo": "anthropics/model-context-protocol"
}
}'
2. Use pr-analyzer as MCP tool from Claude Desktop:
// Claude Desktop config
{
"mcpServers" : {
"conductor" : {
"url" : "https://your-worker.workers.dev/mcp" ,
"headers" : {
"Authorization" : "Bearer YOUR_MCP_TOKEN"
}
}
}
}
Then in Claude Desktop:
Analyze PR #123 in anthropics/anthropic-sdk-typescript
Claude will automatically call your pr-analyzer tool!
Authentication Best Practices
1. Use Default-Deny Security
# GOOD: Explicit auth required
trigger :
- type : mcp
auth :
type : bearer
tokens : [ $ { env.TOKEN }]
# GOOD: Explicitly public
trigger :
- type : mcp
public : true
# BAD: No auth, not marked public (will fail)
trigger :
- type : mcp # Error!
2. Rotate Tokens Regularly
# Generate new tokens
wrangler secret put MCP_CLIENT_TOKEN_1
# Update clients
# Remove old tokens after migration
3. Use OAuth for Third-Party Access
trigger :
- type : mcp
auth :
type : oauth
issuer : https://auth.example.com
audience : https://api.example.com
4. Monitor Token Usage
notifications :
- type : webhook
url : https://api.example.com/webhooks/security
events :
- execution.started
- execution.failed
secret : ${env.WEBHOOK_SECRET}
Testing MCP Integration
import { describe , it , expect } from 'vitest'
import { TestConductor } from '@ensemble-edge/conductor/testing'
describe ( 'research-assistant' , () => {
it ( 'should use MCP tools' , async () => {
const conductor = await TestConductor . create ({
mocks: {
tools: {
'brave:web_search' : {
results: [
{ title: 'MCP Docs' , url: 'https://modelcontextprotocol.io' }
]
},
'github:search_code' : {
items: [
{ path: 'src/mcp/server.ts' , repository: { full_name: 'user/repo' } }
]
}
}
}
})
const result = await conductor . executeEnsemble ( 'research-assistant' , {
question: 'How to implement MCP?' ,
repo: 'anthropics/model-context-protocol'
})
expect ( result ). toBeSuccessful ()
expect ( result . output . answer ). toBeDefined ()
})
})
describe ( 'pr-analyzer MCP endpoint' , () => {
it ( 'should list available tools' , async () => {
const response = await fetch ( 'http://localhost:8787/mcp/tools' , {
headers: {
'Authorization' : `Bearer ${ process . env . MCP_CLIENT_TOKEN } `
}
})
const data = await response . json ()
expect ( data . tools ). toContainEqual (
expect . objectContaining ({
name: 'pr-analyzer' ,
description: expect . any ( String )
})
)
})
it ( 'should invoke tool' , async () => {
const response = await fetch ( 'http://localhost:8787/mcp/tools/pr-analyzer' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . MCP_CLIENT_TOKEN } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
name: 'pr-analyzer' ,
arguments: {
owner: 'anthropics' ,
repo: 'anthropic-sdk-typescript' ,
pull_number: 1
}
})
})
const data = await response . json ()
expect ( data . content ). toBeDefined ()
expect ( data . isError ). toBe ( false )
})
})
Common Patterns
Combine multiple MCP tools into one:
ensemble : multi-source-search
trigger :
- type : mcp
auth :
type : bearer
tokens : [ $ { env.MCP_TOKEN }]
agents :
- name : search-brave
operation : tools
config :
mcp : brave
tool : web_search
- name : search-github
operation : tools
config :
mcp : github
tool : search_code
- name : combine
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
Combine these search results:
Web: ${search-brave.output}
Code: ${search-github.output}
inputs :
query : string
outputs :
combined : ${combine.output}
Add AI-powered transformations:
ensemble : smart-pr-reviewer
trigger :
- type : mcp
auth :
type : bearer
tokens : [ $ { env.MCP_TOKEN }]
agents :
- name : fetch-pr
operation : tools
config :
mcp : github
tool : get_pull_request
- name : analyze-sentiment
operation : think
config :
provider : anthropic
model : claude-haiku-4
prompt : "Analyze sentiment: ${fetch-pr.output.body}"
- name : check-conventions
operation : think
config :
provider : anthropic
model : claude-haiku-4
prompt : "Check if follows conventions: ${fetch-pr.output.title}"
- name : generate-summary
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : |
PR: ${fetch-pr.output}
Sentiment: ${analyze-sentiment.output}
Conventions: ${check-conventions.output}
Generate comprehensive review.
outputs :
review : ${generate-summary.output}
Create workflows across MCP servers:
ensemble : research-to-pr
trigger :
- type : mcp
auth :
type : bearer
tokens : [ $ { env.MCP_TOKEN }]
agents :
# Research phase
- name : search
operation : tools
config :
mcp : brave
tool : web_search
- name : synthesize
operation : think
config :
provider : anthropic
model : claude-sonnet-4
prompt : "Summarize: ${search.output}"
# Create PR phase
- name : create-branch
operation : tools
config :
mcp : github
tool : create_branch
- name : create-pr
operation : tools
config :
mcp : github
tool : create_pull_request
outputs :
research : ${synthesize.output}
pr_url : ${create-pr.output.html_url}
Troubleshooting
# Enable caching to reduce discovery calls
agents :
- name : tool-call
operation : tools
config :
mcp : github
tool : get_repo
cacheDiscovery : true
cacheTTL : 3600
Authentication Errors
# Verify token is set
wrangler secret list
# Check token format
echo $GITHUB_MCP_TOKEN | wc -c # Should be non-zero
# Test auth
curl https://github-mcp.example.com/tools \
-H "Authorization: Bearer $GITHUB_MCP_TOKEN "
Timeout Issues
# Increase timeout for slow tools
config :
mcp : external
tool : slow_operation
timeout : 60000 # 60 seconds
OAuth Token Refresh
OAuth tokens are automatically refreshed. Check logs:
wrangler tail --format pretty
Next Steps
tools Operation Detailed tools operation reference
Webhooks Inbound webhook integration
Notifications Outbound webhook notifications
Security Authentication best practices