A transparent discovery signal based on current public GitHub metadata.
Recent activity35% weight
90
Community adoption25% weight
0
Maintenance state20% weight
100
License clarity10% weight
100
Project information10% weight
100
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
README preview
ToolsConnector
One interface, every tool. Connect 68+ APIs to your Python app or AI agent in minutes.
The Problem
Every SaaS API has its own SDK, its own auth dance, its own pagination scheme, and its own error format. If you're building an AI agent, you also need to generate JSON Schema for function calling -- differently for OpenAI, Anthropic, and Gemini. You end up writing glue code instead of product code.
ToolsConnector gives you a single, typed Python interface to 77 connectors and 1,578 actions. It works identically whether you're building a Django app, an OpenAI agent, or an MCP server for Claude Desktop.
Run the Documentation Site
To browse the full connector reference, playground, and guides locally:
from toolsconnector.serve import ToolKit
kit = ToolKit(
["gmail", "slack"],
credentials={"gmail": "ya29.access-token", "slack": "xoxb-bot-token"},
)
# List unread emails
result = kit.execute("gmail_list_emails", {"query": "is:unread", "max_results": 5})
# Send a Slack message
kit.execute("slack_send_message", {"channel": "#general", "text": "Deployed v2.1"})
That's it. Same ToolKit, same .execute(), every connector.
Try the Examples
Want to see real integrations end-to-end? examples/ has 10 copy-pasteable scripts covering every major usage pattern. Pick one closest to what you want to build:
77 connectors, 1,578 actions across 20 categories -- communication, social, databases, DevOps, CRM, AI/ML, AWS infrastructure, and more
Dual-use design -- works for traditional Python apps (Django, Flask, FastAPI) and AI agents (function calling, tool use) with zero code changes
One-line MCP server -- expose any combination of connectors to Claude Desktop, Cursor, or any MCP client
Schema generation -- produces OpenAI, Anthropic, and Gemini function-calling schemas from the same source of truth
Type-safe everywhere -- Pydantic V2 models for all inputs and outputs, with full JSON Schema generation
Async-first, sync-friendly -- every action has both await kit.aexecute() and kit.execute() paths
Circuit breakers -- per-connector failure isolation so one dead API doesn't take down your agent
Timeout budgets -- per-action and per-request deadlines with automatic retry on transient failures
Dry-run mode -- validate destructive actions without executing them
BYOK auth -- bring your own API keys and tokens; no OAuth server required in the library
Minimal dependencies -- core requires only pydantic, httpx, and docstring-parser
Workflows
1. Direct Python Usage
Use connectors directly in any Python application.
from toolsconnector.serve import ToolKit
kit = ToolKit(["github"], credentials={"github": "ghp_your_token"})
# List open issues
issues = kit.execute("github_list_issues", {
"owner": "myorg",
"repo": "myproject",
"state": "open",
})
2. MCP Server (One Line)
Expose connectors to Claude Desktop, Cursor, Windsurf, or any MCP client.
from toolsconnector.serve import ToolKit
kit = ToolKit(
["gmail", "gcalendar", "notion"],
credentials={"gmail": "ya29.token", "gcalendar": "ya29.token", "notion": "ntn_key"},
)
kit.serve_mcp() # stdio transport, ready for Claude Desktop
Or from the command line:
# Stdio (one client per process — Claude Desktop launches it as subprocess)
tc serve mcp gmail gcalendar notion --transport stdio
# Long-lived HTTP daemon — multiple agents share one process
tc serve mcp gmail slack github --transport streamable-http --port 9000
The HTTP transport (streamable-http) accepts many concurrent client
sessions on the same port — one daemon serves N agents. Per-tool
circuit breakers and timeout budgets apply fairly across all clients.
There's no built-in auth on the HTTP transport; put it behind a reverse
proxy before exposing it publicly.
3. OpenAI Function Calling
Generate tool schemas and execute tool calls from OpenAI responses.
from openai import OpenAI
from toolsconnector.serve import ToolKit
client = OpenAI()
kit = ToolKit(["gmail", "slack"], credentials={...})
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Summarize my unread emails"}],
tools=kit.to_openai_tools(),
)
# Execute the tool call the model chose
tool_call = response.choices[0].message.tool_calls[0]
result = kit.execute(tool_call.function.name, tool_call.function.arguments)
4. Anthropic Tool Use
Works the same way with Claude's tool use API.
import anthropic
from toolsconnector.serve import ToolKit
client = anthropic.Anthropic()
kit = ToolKit(["jira", "slack"], credentials={...})
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Create a bug ticket for the login issue"}],
tools=kit.to_anthropic_tools(),
)
# Execute the tool call
for block in response.content:
if block.type == "tool_use":
result = kit.execute(block.name, block.input)
5. Google Gemini
Generate Gemini-compatible function declarations.
from toolsconnector.serve import ToolKit
kit = ToolKit(["gmail"], credentials={...})
declarations = kit.to_gemini_tools()
# Pass to google.generativeai as function_declarations
6. CLI Usage
Manage connectors and execute actions from the terminal.
# List all available connectors
tc list
# List actions for a specific connector
tc gmail actions
# Execute an action
tc gmail list_emails --query "is:unread" --max_results 5
# Export the connector spec
tc gmail spec --format json
7. REST API
Serve connectors as HTTP endpoints with Starlette/ASGI.
from toolsconnector.serve import ToolKit
kit = ToolKit(["stripe", "hubspot"], credentials={...})
app = kit.create_rest_app(prefix="/api/v1")
# Run with uvicorn: uvicorn myapp:app --port 8000
# POST /api/v1/stripe/create_charge {"amount": 5000, "currency": "usd"}
Error Handling
Every connector raises typed exceptions from toolsconnector.errors so
your code can branch on the failure mode instead of parsing HTTP status
codes:
from toolsconnector.errors import (
InvalidCredentialsError, TokenExpiredError, PermissionDeniedError,
NotFoundError, RateLimitError, ValidationError, ServerError,
)
try:
await kit.aexecute("gmail_send_email", {...})
except TokenExpiredError:
await refresh_oauth_token()
# ...retry...
except RateLimitError as e:
await asyncio.sleep(e.retry_after_seconds) # parsed from Retry-After header
# ...retry...
except InvalidCredentialsError:
prompt_user_to_reauthenticate()
except NotFoundError:
return None # 404 — caller decides what "missing" means
except PermissionDeniedError:
request_additional_oauth_scopes()
except ValidationError:
# 400 / 422 — your arguments were rejected by the upstream API
raise
except ServerError:
# 5xx — upstream is having a bad day; retry-eligible
pass
All typed errors carry connector, action, upstream_status, and a
truncated details["body_preview"] — useful for logs and observability.
The full taxonomy lives in src/toolsconnector/errors/ if you want to
match more granular cases (e.g. ConflictError for 409).
Supported Connectors
77 connectors, 1,578 actions across 20 categories.