The mtw-integrations crate provides ready-to-use connectors for 20 third-party APIs, 10 AI model providers, OAuth2 support for 12 services, and an RSS feed reader.
Source: crates/mtw-integrations/
| Category | Services |
|---|---|
| Code & DevOps | GitHub, GitLab, Jira, Linear, Vercel, Cloudflare, Docker Hub |
| Communication | Slack, Discord, Telegram, Twilio, SendGrid |
| Payments | Stripe, PayPal |
| Storage & BaaS | AWS S3, Google Cloud Storage, Firebase, Supabase |
| Productivity | Notion, Airtable |
Source: crates/mtw-integrations/src/apis/
| Provider | Module | Notable Models |
|---|---|---|
| Anthropic | ai::anthropic |
Claude Opus 4, Sonnet 4 |
| OpenAI | ai::openai |
GPT-4o, GPT-4 Turbo |
ai::google |
Gemini Pro, Gemini Ultra | |
| Mistral | ai::mistral |
Mistral Large, Mixtral |
| Cohere | ai::cohere |
Command R+ |
| DeepSeek | ai::deepseek |
DeepSeek V2 |
| Meta | ai::meta |
Llama 3 |
| xAI | ai::xai |
Grok |
| HuggingFace | ai::huggingface |
Various open models |
| Ollama | ai::ollama |
Any local model |
Source: crates/mtw-integrations/src/ai/
GitHub, GitLab, Slack, Discord, Stripe, PayPal, Google, Notion, Airtable, Jira, Linear, Vercel
Source: crates/mtw-integrations/src/oauth2.rs
Each integration provides a config struct, an IntegrationInfo constant, and a client stub:
use mtw_integrations::apis::github::{GitHubConfig, GitHubClient, GITHUB_INFO};
// Check integration info
println!("API: {}", GITHUB_INFO.name); // "GitHub"
println!("Base URL: {}", GITHUB_INFO.base_url); // "https://api.github.com"
println!("Docs: {}", GITHUB_INFO.docs_url);
println!("OAuth2: {}", GITHUB_INFO.oauth2_supported); // true
// Configure the client
let config = GitHubConfig {
api_token: std::env::var("GITHUB_TOKEN").unwrap(),
base_url: None, // Use default
// ... other config options
};
let client = GitHubClient::new(config);
// Use the client (actual HTTP calls are planned for future phases)
// let repos = client.list_repos("fastslack").await?;Every integration exposes an IntegrationInfo struct:
pub struct IntegrationInfo {
pub id: &'static str, // "github"
pub name: &'static str, // "GitHub"
pub base_url: &'static str, // "https://api.github.com"
pub docs_url: &'static str, // "https://docs.github.com/en/rest"
pub oauth2_supported: bool, // true
}Health checks return:
pub enum IntegrationStatus {
Connected,
Disconnected,
Error(String),
}use mtw_integrations::oauth2::*;
// GitHub
let config = github_oauth2(
"your-client-id".into(),
"your-client-secret".into(),
"http://localhost:3000/callback".into(),
);
// Google
let config = google_oauth2(
"your-client-id".into(),
"your-client-secret".into(),
"http://localhost:3000/callback".into(),
);
// Slack
let config = slack_oauth2("id".into(), "secret".into(), "http://localhost:3000/cb".into());
// All 12 available:
// github_oauth2, gitlab_oauth2, slack_oauth2, discord_oauth2,
// stripe_oauth2, paypal_oauth2, google_oauth2, notion_oauth2,
// airtable_oauth2, jira_oauth2, linear_oauth2, vercel_oauth2use mtw_integrations::oauth2::{OAuth2Client, github_oauth2};
// 1. Create client
let config = github_oauth2("client-id".into(), "secret".into(), "http://localhost:3000/cb".into());
let mut client = OAuth2Client::new(config);
// 2. Generate authorization URL
let state = "random-csrf-token-123";
let auth_url = client.authorization_url(state);
// Redirect user to auth_url
// 3. After user authorizes, exchange the code
let token = client.exchange_code("authorization-code-from-callback").await?;
// 4. Store the token
client.set_token(token);
// 5. Refresh when expired
let new_token = client.refresh_token("refresh-token-value").await?;
client.set_token(new_token);pub struct OAuth2Config {
pub client_id: String,
pub client_secret: String,
pub redirect_uri: String,
pub auth_url: String, // Authorization endpoint
pub token_url: String, // Token endpoint
pub scopes: Vec<String>, // Requested scopes
}| Provider | Default Scopes |
|---|---|
| GitHub | repo, user |
| GitLab | api, read_user |
| Slack | chat:write, channels:read |
| Discord | bot, identify |
| Stripe | read_write |
| PayPal | openid |
devstorage.read_write |
|
| Notion | (none) |
| Airtable | data.records:read, data.records:write |
| Jira | read:jira-work, write:jira-work |
| Linear | read, write |
| Vercel | (none) |
Each AI provider has an AiProviderConfig and model constants:
use mtw_integrations::ai::{AiProviderConfig, AiProviderInfo, ModelInfo};
// Common config for all providers
let config = AiProviderConfig {
api_key: std::env::var("API_KEY").unwrap(),
base_url: None, // Override default URL
default_model: Some("claude-sonnet-4-6".into()),
default_temperature: Some(0.7),
default_max_tokens: Some(4096),
timeout_secs: 120, // Request timeout
};# mtw.toml
# Anthropic
[[modules]]
name = "mtw-ai-anthropic"
config = {
api_key = "${ANTHROPIC_API_KEY}",
default_model = "claude-sonnet-4-6",
timeout_secs = 120
}
# OpenAI
[[modules]]
name = "mtw-ai-openai"
config = {
api_key = "${OPENAI_API_KEY}",
default_model = "gpt-4o",
default_temperature = 0.7
}
# Ollama (local)
[[modules]]
name = "mtw-ai-ollama"
config = {
api_key = "",
base_url = "http://localhost:11434",
default_model = "llama3"
}
# Google Gemini
[[modules]]
name = "mtw-ai-google"
config = {
api_key = "${GOOGLE_AI_KEY}",
default_model = "gemini-pro"
}pub struct AiProviderInfo {
pub id: &'static str, // "anthropic"
pub name: &'static str, // "Anthropic"
pub base_url: &'static str, // "https://api.anthropic.com"
pub docs_url: &'static str, // "https://docs.anthropic.com"
pub supports_streaming: bool,
pub supports_tool_calling: bool,
pub supports_vision: bool,
pub supports_embeddings: bool,
}pub struct ModelInfo {
pub id: &'static str, // "claude-sonnet-4-20250514"
pub name: &'static str, // "Claude Sonnet 4"
pub context_window: usize, // 200000
pub max_output_tokens: usize, // 8192
pub supports_vision: bool,
pub supports_tool_calling: bool,
}use mtw_integrations::rss::{RssConfig, RssFeed, RssItem};
let config = RssConfig {
url: "https://example.com/feed.xml".into(),
// ... config options
};
// RssFeed and RssItem types for parsed feedsSource: crates/mtw-integrations/src/rss.rs
To create a custom integration module:
- Create a config struct:
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MyApiConfig {
pub api_key: String,
pub base_url: Option<String>,
}- Define integration info:
use mtw_integrations::apis::IntegrationInfo;
pub const MY_API_INFO: IntegrationInfo = IntegrationInfo {
id: "my-api",
name: "My API",
base_url: "https://api.myservice.com",
docs_url: "https://docs.myservice.com",
oauth2_supported: false,
};- Create the client:
pub struct MyApiClient {
config: MyApiConfig,
http: reqwest::Client,
}
impl MyApiClient {
pub fn new(config: MyApiConfig) -> Self {
Self {
config,
http: reqwest::Client::new(),
}
}
pub async fn get_data(&self) -> Result<serde_json::Value, mtw_core::MtwError> {
let base = self.config.base_url.as_deref()
.unwrap_or(MY_API_INFO.base_url);
let resp = self.http.get(format!("{}/data", base))
.header("Authorization", format!("Bearer {}", self.config.api_key))
.send()
.await
.map_err(|e| mtw_core::MtwError::Internal(e.to_string()))?;
resp.json()
.await
.map_err(|e| mtw_core::MtwError::Internal(e.to_string()))
}
}- Optionally, package as an mtwRequest module with
MtwModuleimplementation and a manifest.
Combine integrations with mtw-http pipeline stages:
use mtw_http::{MtwRequest, ResponsePipeline, PipelineContext};
let mut pipeline = ResponsePipeline::new();
// Add retry, rate-limit, and cache stages
pipeline.add_stage(Arc::new(retry_stage));
pipeline.add_stage(Arc::new(rate_limit_stage));
let req = MtwRequest::get("https://api.github.com/repos/fastslack/mtw-request")
.header("authorization", format!("Bearer {}", github_token))
.header("accept", "application/vnd.github.v3+json");
let mut ctx = PipelineContext::new(req);
// Execute through the pipeline...- HTTP Pipeline Guide -- response pipeline details
- AI Agents Guide -- use AI providers with agents
- Auth Guide -- OAuth2 for authentication