Venn - Secure Universal MCP (Google Workspace, Jira, GitHub, and more)
by @neil-bd
Search, describe, and execute enterprise tools (Jira, Salesforce, Gmail, Slack, Google Calendar, Google Drive, GitHub, Notion, Box, etc.) via the Venn tool-r...
clawhub install vennπ About This Skill
name: venn description: >- Search, describe, and execute enterprise tools (Jira, Salesforce, Gmail, Slack, Google Calendar, Google Drive, GitHub, Notion, Box, etc.) via the Venn tool-router REST API. Use when the user asks to: (1) query or search data in enterprise SaaS apps, (2) create, update, or manage records (tickets, emails, calendar events, documents), (3) automate multi-step workflows across connected services, or (4) check what integrations are available. Triggers on phrases like "check my Jira tickets", "search Slack", "create a Salesforce lead", "find emails from X", "sync data between apps", or any reference to connected enterprise tools. metadata: {"openclaw": {"requires": {"env": ["VENN_API_KEY"]}, "primaryEnv": "VENN_API_KEY"}}
Venn Tools
Connect to enterprise SaaS tools through the Venn platform REST API.
Setup
This skill is gated on VENN_API_KEY β it won't appear until the key is set.
1. Get your API key from app.venn.ai
2. Add it to the OpenClaw .env file:
echo 'VENN_API_KEY=your-api-key-here' >> ~/.openclaw/.env
3. Restart the gateway (picks up the new env on start):
openclaw gateway restart
Or, for zero-downtime reload without restart:
openclaw secrets reload
Alternatively, use the interactive secrets helper:
openclaw secrets configure --skip-provider-setup
Sandboxed agents: The .env file injects into the host process only. For sandboxed (Docker) sessions, also add VENN_API_KEY to agents.defaults.sandbox.docker.env in openclaw.json, or bake it into your custom sandbox image.
Configuration
VENN_API_KEY (required) β your Venn API keyVENN_API_URL (optional) β defaults to https://app.venn.ai/api/tooliqRequest Format
All requests use POST with JSON. Examples below use this shorthand:
# Full form (shown once):
VENN_URL="${VENN_API_URL:-https://app.venn.ai/api/tooliq}"
curl -s -X POST "${VENN_URL}/tools/search" \
-H "Authorization: Bearer ${VENN_API_KEY}" \
-H "Content-Type: application/json" \
-d '{"query": "..."}'Shorthand (used throughout):
POST /tools/search {"query": "..."}
1. Discovery
List connected servers
# POST /tools/help
{"action": "list_servers"}
Returns result.servers[] with server_id, name, and connection_status.
Other help actions:
getting_started β onboarding guidanceconnector_help β info on connectors (pass server_id for specific one)auth_helper β OAuth re-auth URL for disconnected server (requires server_id)Search for tools
# POST /tools/search
{"query": "jira search issues", "limit": 10}
Returns result.candidates[] with server_id, tool_name, short_description, and (for top results) full inputSchema.
Additional parameters: offset, min_score (0β1, default 0.3), min_results (default 5), include_skills (default true).
Search strategy β broad first, narrow if needed:
1. Start with the full task description in natural language (skills match better): - "create a linear ticket and set it to in progress" - "sync salesforce contacts to a google sheet"
2. If no skill matches, decompose into one search per platform + action: - "query salesforce contacts" + "create google sheets row"
3. For simple single-platform tasks, search directly: "create salesforce lead"
Splitting rules:
If no results, try alternate names:
Choosing from results:
type="skill"), prefer it over assembling toolsinputSchema is the source of truth for parameter names β NEVER guessFor platform-specific query syntax (JQL, SOQL, Gmail search), see references/query-syntax.md.
Describe a tool
# POST /tools/describe
{"tools": [{"server_id": "SERVER_ID", "tool_name": "TOOL_NAME"}]}
Supports batch requests. Returns result.results[] with inputSchema, description, and write_operation type.
2. Execution
Schema adherence (most common source of errors)
1. Copy parameter names verbatim from inputSchema β casing matters
- Schema says maxResults β use maxResults, NOT max_results
2. Match data types exactly:
- "type": "string" β "10", NOT 10
- "type": "integer" β 10, NOT "10"
- "type": "array" β ["value"], NOT "value"
- "type": "object" β {"key": "value"}, NOT "key=value"
3. Include all required fields. Do not add fields not in the schema.
Execute a single tool
# POST /tools/execute
{"server_id": "SERVER_ID", "tool_name": "TOOL_NAME", "tool_args": {...}}
Translating user intent into values (infer rather than ask):
userId: "me"This applies to values only β parameter names and types must come from inputSchema.
Data integrity: NEVER fabricate data. Only present what appears in actual responses.
Handling links: For create/edit operations, surface clickable URLs from fields like url, link, href, web_url, permalink, html_url. Present as Resource Name.
Execute a workflow (multi-step)
Chain multiple tool calls in a Python sandbox:
# POST /tools/execute-workflow
{
"code": "results = call_tool(\"atlassian\", \"searchByJQL\", jql=\"assignee = currentUser() AND status != Done\")\nreturn [{\"key\": i[\"key\"], \"summary\": i[\"fields\"][\"summary\"]} for i in results.get(\"issues\", [])]",
"timeout": 180
}
When to use workflows:
Code rules:
if isinstance(result, dict) and "error" in result: ...nextPageToken/cursorAvailable in sandbox:
call_tool(server_id, tool_name, **kwargs) β sequentialasync_call_tool(server_id, tool_name, **kwargs) β for asyncio.gather()call_skill(skill_id, inputs_dict) / async_call_skill(...) β call skillsasyncio, json, datetime, math, re, collections, itertools, functools, operator, decimal, uuid, base64, hashlibd[k] = d[k] + 1, NOT d[k] += 13. Write Operation Confirmation
Write/delete operations return an audit response instead of executing. To proceed:
1. Show the operation summary to the user and wait for explicit approval
2. Get a confirmation token (expires in 60s):
# POST /tools/confirm
{"server_id": "SERVER_ID", "tool_name": "TOOL_NAME"}
3. Re-send with the token:
# POST /tools/execute
{"server_id": "...", "tool_name": "...", "tool_args": {...}, "confirmed": true, "confirmation_token": "TOKEN"}
Never call confirm without user's typed approval ("yes", "confirm", "proceed").
4. Skills
Skills are pre-built workflow patterns in search results with type: "skill". Prefer skills over assembling individual tools.
Executable skills
Marked executable: true. Run step-by-step:
# POST /tools/execute
{"tool_name": "SKILL_ID", "tool_args": {"step_id": "FIRST_STEP", "inputs": {...}}}
Each step returns outputs and next. If next is not null, read next.reasoning, fill placeholders, make the next call.
Guidance skills
For skills without executable: true, describe to get the pattern:
# POST /tools/describe
{"tools": [{"tool_name": "SKILL_NAME"}]}
Returns tools_involved, all_servers_connected, disconnected_servers, and step-by-step content. If all_servers_connected is false, use help(action="auth_helper") first.
5. Error Recovery
If a tool call fails, debug and retry β do not report failure immediately.
| Error | Action |
|-------|--------|
| Schema/parameter error | Re-read inputSchema, fix names and types, retry |
| 404 / "not found" | Wrong ID or tool; search for correct ID |
| Server not connected / 401 | Call help(action="auth_helper", server_id="...") |
| Empty results | Try fuzzy variations, broader date ranges |
| Same error twice | Try different approach (different tool/parameters) |
| Workflow fails twice | Fall back to sequential execute calls |
Only report failure after at least three different approaches have been tried.
Guardrails
list_servers or search to discover what's connectedinputSchema before executing (from search or describe)session_id and user_intent on calls for tracing (API generates one if omitted)βοΈ Configuration
VENN_API_KEY (required) β your Venn API keyVENN_API_URL (optional) β defaults to https://app.venn.ai/api/tooliq