MCP / Tools
Connect third-party apps (GitHub, Slack, Zoho Mail, Zendesk) via OAuth and expose their capabilities as tools to AI agents through the Model Context Protocol (MCP). Each connected app gets its own scoped URL — you choose which apps the model can see on each request.
https://api.assistiv.ai/v1— inference, CRUD, mcp-confighttps://mcp.assistiv.ai— tool execution, OAuth flows
Available Apps
GitHub
Issues, PRs, branches, workflow dispatch, gists, and more (10 tools).
Slack
Send messages, create channels, reactions, user lookup (10 tools).
Zoho Mail
Send emails, create tasks (2 tools).
Zendesk
Ticket CRUD, search, help center articles (10 tools).
ℹFree tier
First 100 MCP tool calls per platform per calendar month are free. No wallet debit, no log row. After the 100th call, per-tool pricing applies. Counter resets on the 1st of each month.
How It Works
Platform admin activates apps(one-time, on the dashboard). Paste OAuth Client ID + Secret, your platform's base URL, and register https://mcp.assistiv.ai/oauth/callback in the provider's OAuth app settings.
End user connects apps (one-time per user per app). Your backend calls GET mcp.assistiv.ai/oauth/authorize?app=github, user approves, Assistiv stores the token encrypted.
Get per-app MCP URLs via GET /v1/me/mcp-config. Returns one scoped URL per connected app.
Use the URLs — pass them as tools in POST /v1/responses, or feed them into any MCP-compatible agent.
OAuth Connection Flow
Platform admin activates the app: In the Assistiv dashboard (or via POST /v1/platforms/{id}/mcp/apps), provide your OAuth Client ID, Client Secret, and your platform's base URL. Paste https://mcp.assistiv.ai/oauth/callback as the Authorization callback URL in your provider's OAuth app.
Get the authorization URL: Call GET mcp.assistiv.ai/oauth/authorize?app=github server-side with the end-user key. Returns a 302 redirect.
Redirect the user: Send the browser to the authorization URL.
Callback handled automatically: Provider redirects to mcp.assistiv.ai/oauth/callback. Assistiv exchanges the code for tokens, encrypts, and stores the connection.
User lands back on your site: Redirected to {your_base_url}/mcp/oauth-callback?app=github&status=connected.
Why server-side? GET /oauth/authorize requires an Authorization header, which browser navigations cannot carry. Fetch server-side, read the 302 Location header, then redirect the browser.
End-User Endpoints
mcp.assistiv.ai/oauth/authorizeReturns a 302 redirect to the provider's OAuth consent page.
Auth: End-user key. Must be called server-side.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| app | string | Required | App slug (e.g. "github", "slack", "zoho_mail", "zendesk"). |
// Server action or backend route
const res = await fetch(
"https://mcp.assistiv.ai/oauth/authorize?app=github",
{
headers: { Authorization: `Bearer ${endUserApiKey}` },
redirect: "manual",
}
);
const authorizeUrl = res.headers.get("location");
// Redirect the browser: window.location.href = authorizeUrlmcp.assistiv.ai/appsLists MCP apps enabled for the authenticated user's platform.
Auth: End-user key.
curl https://mcp.assistiv.ai/apps \
-H "Authorization: Bearer sk-eu_your_key"mcp.assistiv.ai/connectionsLists the authenticated end user's active app connections.
Auth: End-user key. OAuth tokens are never returned.
curl https://mcp.assistiv.ai/connections \
-H "Authorization: Bearer sk-eu_your_key"{
"data": [
{
"id": "uuid",
"appSlug": "github",
"createdAt": "2026-04-12T10:30:00Z"}
]
}mcp.assistiv.ai/connections/:appDisconnects an app by deactivating the stored OAuth credentials.
Auth: End-user key. Returns 204 No Content.
curl -X DELETE https://mcp.assistiv.ai/connections/github \
-H "Authorization: Bearer sk-eu_your_key"Handling the OAuth Landing Page
After OAuth completes, the MCP service redirects the end user's browser to {base}/mcp/oauth-callback with query parameters describing the outcome.
{your_base_url}/mcp/oauth-callbackA route on YOUR website that handles the OAuth outcome. You implement this.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| app | string | Optional | App slug (e.g. "github"). |
| status | "connected" | "error" | Optional | Outcome of the OAuth flow. |
| error | string | Optional | Error code when status is error. |
| error_description | string | Optional | Human-readable error detail. |
// e.g. app/mcp/oauth-callback/page.tsx (Next.js)
export default function OAuthCallback({
searchParams,
}: {
searchParams: { app?: string; status?: string; error?: string; error_description?: string };
}) {
const { app, status, error, error_description } = searchParams;
if (status === "connected") {
return <p>{app} connected successfully. You can close this tab.</p>;
}
return (
<div>
<p>Failed to connect {app}: {error}</p>
{error_description && <p>{error_description}</p>}
</div>
);
}Per-App MCP URLs
Once an end user has connected apps, fetch their scoped MCP config. Each connected app gets its own URL — you choose which apps the model can see.
/v1/me/mcp-configReturns per-app MCP URLs in both standard and OpenAI formats.
Auth: End-user key.
Use the openai format if you're calling /v1/responses — splice directly into your tools array.
Use the standard format for any MCP-compatible agent: Claude Desktop, OpenAI Codex, Cursor, LangChain MultiServerMCPClient, or your own harness.
// GET /v1/me/mcp-config
{
"standard": {
"github": {
"transport": "streamable_http",
"url": "https://mcp.assistiv.ai/mcp/github",
"headers": { "Authorization": "Bearer sk-eu_..."}
},
"slack": {
"transport": "streamable_http",
"url": "https://mcp.assistiv.ai/mcp/slack",
"headers": { "Authorization": "Bearer sk-eu_..."}
}
},
"openai": [
{
"type": "mcp",
"server_label": "github",
"server_url": "https://mcp.assistiv.ai/mcp/github",
"authorization": "Bearer sk-eu_..."},
{
"type": "mcp",
"server_label": "slack",
"server_url": "https://mcp.assistiv.ai/mcp/slack",
"authorization": "Bearer sk-eu_..."}
]
}Hosted MCP via Responses API
Pass per-app MCP tool items in your /v1/responses request. You pick which apps the model can see on each call.
Hosted MCP is only supported on /v1/responses. Sending type: "mcp" to /v1/chat/completions returns 422.
/v1/responsesResponses API with MCP tools. See Responses for full endpoint docs.
Auth: End-user key.
MCP Tool Item Fields
| Name | Type | Required | Description |
|---|---|---|---|
| type | string | Required | Must be "mcp". |
| server_label | string | Required | App slug: "github", "slack", "zoho_mail", "zendesk". |
| server_url | string (URL) | Required | https://mcp.assistiv.ai/mcp/{app_slug} |
| authorization | string | Required | "Bearer sk-eu_..." — the end-user key. |
| require_approval | string | Optional | Must be "never" if set. "always" is not supported in v1. |
curl -X POST https://api.assistiv.ai/v1/responses \
-H "Authorization: Bearer sk-eu_end_user_key" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"input": "Create a GitHub issue in my-org/test-repo titled hello",
"tools": [
{
"type": "mcp",
"server_label": "github",
"server_url": "https://mcp.assistiv.ai/mcp/github",
"authorization": "Bearer sk-eu_end_user_key"
}
]
}'// Include specific apps:
tools: config.openai.filter(t => ["github", "slack"].includes(t.server_label))
// Or include all connected apps:
tools: config.openaiHybrid Execution Semantics
- The model is invoked with both your function tools (if any) and the MCP tools.
- Only MCP tool calls: backend executes them inline, re-invokes the model. Loop continues until a final answer.
- Any function tool call: loop returns immediately so your platform can handle it. MCP calls in the same turn are NOT executed.
- Maximum loop depth: 10 iterations. Each turn debits wallet/budget normally.
Response Output Items
{
"id": "resp_abc",
"object": "response",
"status": "completed",
"model": "gpt-4o",
"output": [
{
"type": "mcp_call",
"id": "mcp_xyz",
"server_label": "github",
"name": "github_create_issue",
"arguments": "{\"owner\":\"my-org\",\"repo\":\"test-repo\",\"title\":\"hello\"}",
"output": "Issue #42 created",
"status": "completed"},
{
"type": "message",
"id": "msg_abc",
"role": "assistant",
"content": [
{ "type": "output_text", "text": "Done — issue #42 is open."}
]
}
],
"usage": { "input_tokens": 120, "output_tokens": 35, "total_tokens": 155 }
}Streaming Events
response.mcp_list_tools.in_progress/.completed— tool discoveryresponse.output_item.added(withitem.type: "mcp_call")response.mcp_call_arguments.delta/.doneresponse.mcp_call.in_progress/.completedresponse.output_text.delta— final answer
Direct Protocol Access (Advanced)
POST mcp.assistiv.ai/mcp/{app_slug} is the raw JSON-RPC 2.0 endpoint over Streamable HTTP transport. Use it only if you're implementing your own MCP client. Requires the standard MCP session handshake (initialize → notifications/initialized → tools/list → tools/call) and emits an mcp-session-id response header. Session TTL is 30 minutes. Tool names follow the pattern {app_slug}_{tool_name} (dashes converted to underscores).
Platform MCP Configuration
Manage which MCP apps are available to your platform's end users. These can be called with a platform key, or configured via the Assistiv dashboard. OAuth client secrets are encrypted at rest with AES-256-GCM.
/v1/platforms/{platformId}/mcp/appsActivates an MCP app for your platform.
Auth: Platform key. Returns 201.
Request Body
| Name | Type | Required | Description |
|---|---|---|---|
| app_slug | string | Required | "github", "slack", "zoho_mail", or "zendesk". |
| oauth_client_id | string | Required | Your OAuth app client ID. |
| oauth_client_secret | string | Required | Your OAuth app client secret. Encrypted at rest. |
| redirect_url | string (URL) | Required | Your platform's base URL. End users land at {base}/mcp/oauth-callback after OAuth. |
| display_name | string | Optional | Human-readable name for dashboard display. |
| scopes | string[] | Optional | OAuth scopes. Defaults to provider's built-in defaults. |
https://mcp.assistiv.ai/oauth/callback.curl -X POST https://api.assistiv.ai/v1/platforms/{platformId}/mcp/apps \
-H "Authorization: Bearer sk-plat_your_key" \
-H "Content-Type: application/json" \
-d '{
"app_slug": "github",
"display_name": "GitHub",
"oauth_client_id": "Iv1.abc123",
"oauth_client_secret": "secret_xyz",
"redirect_url": "https://my-saas.com",
"scopes": ["repo", "user"]
}'/v1/platforms/{platformId}/mcp/apps/{app_slug}Updates an activated MCP app. All fields optional.
Auth: Platform key.
Request Body (all optional)
| Name | Type | Required | Description |
|---|---|---|---|
| display_name | string | Optional | Human-readable name. |
| oauth_client_id | string | Optional | New OAuth client ID. |
| oauth_client_secret | string | Optional | New OAuth client secret. |
| redirect_url | string (URL) | Optional | New post-OAuth base URL. |
| scopes | string[] | Optional | OAuth scopes to request. |
| is_active | boolean | Optional | Toggle the app on/off. |
curl -X PATCH https://api.assistiv.ai/v1/platforms/{platformId}/mcp/apps/github \
-H "Authorization: Bearer sk-plat_your_key" \
-H "Content-Type: application/json" \
-d '{ "redirect_url": "https://new-domain.com" }'/v1/platforms/{platformId}/mcp/appsDeactivates an MCP app. Soft delete — sets is_active=false.
Auth: Platform key. Returns 204.
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| app_slug | string | Required | App slug to deactivate. |
curl -X DELETE "https://api.assistiv.ai/v1/platforms/{platformId}/mcp/apps?app_slug=github" \
-H "Authorization: Bearer sk-plat_your_key"Reference Endpoints
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| GET | mcp.assistiv.ai/apps | sk-eu_* | List available apps |
| GET | mcp.assistiv.ai/connections | sk-eu_* | List user's connections |
| DELETE | mcp.assistiv.ai/connections/{app} | sk-eu_* | Disconnect an app |
| GET | mcp.assistiv.ai/oauth/authorize | sk-eu_* | Start OAuth flow (302) |
| POST | mcp.assistiv.ai/mcp/{app_slug} | sk-eu_* | Per-app MCP endpoint |
| GET | /v1/me/mcp-config | sk-eu_* | Get per-app MCP URLs |
| POST | /v1/responses | sk-eu_* | Inference with MCP tools |