> **Building with AI coding agents?** If you're using an AI coding agent, install the official Scalekit plugin. It gives your agent full awareness of the Scalekit API — reducing hallucinations and enabling faster, more accurate code generation.
>
> - **Claude Code**: `/plugin marketplace add scalekit-inc/claude-code-authstack` then `/plugin install <auth-type>@scalekit-auth-stack`
> - **GitHub Copilot CLI**: `copilot plugin marketplace add scalekit-inc/github-copilot-authstack` then `copilot plugin install <auth-type>@scalekit-auth-stack`
> - **Codex**: run the bash installer, restart, then open Plugin Directory and enable `<auth-type>`
> - **Skills CLI** (Windsurf, Cline, 40+ agents): `npx skills add scalekit-inc/skills --list` then `--skill <skill-name>`
>
> `<auth-type>` / `<skill-name>`: `agentkit`, `full-stack-auth`, `mcp-auth`, `modular-sso`, `modular-scim` — [Full setup guide](https://docs.scalekit.com/dev-kit/build-with-ai/)

---

# Scalekit optimized built-in tools

Scalekit ships pre-built tools for every connector in the catalog: Gmail, Slack, GitHub, Salesforce, Notion, Linear, HubSpot, and more. Each tool has an LLM-ready schema and returns structured output. Your agent passes inputs; Scalekit injects the user's credentials and handles the API call.

This page assumes you have an `ACTIVE` connected account for the user. If not, see [Authorize a user](/agentkit/tools/authorize/).

## Find available tools

Use `list_scoped_tools` / `listScopedTools` to get the tools this specific user is authorized to call. **This is the list you pass to your LLM.**

```python
from google.protobuf.json_format import MessageToDict

scoped_response, _ = actions.tools.list_scoped_tools(
    identifier="user_123",
    filter={"connection_names": ["gmail"]},   # optional; omit for all connectors
)
for scoped_tool in scoped_response.tools:
    definition = MessageToDict(scoped_tool.tool).get("definition", {})
    print(definition.get("name"))
    print(definition.get("input_schema"))     # JSON Schema; pass directly to your LLM
```
  ```typescript
const { tools } = await scalekit.tools.listScopedTools('user_123', {
  filter: { connectionNames: ['gmail'] },     // optional; omit for all connectors
});
for (const tool of tools) {
  const { name, input_schema } = tool.tool.definition;
  console.log(name, input_schema);            // JSON Schema; pass directly to your LLM
}
```
  To browse all available tools without filtering by user, use `list_tools` / `listTools`. To explore tools interactively and inspect live response shapes, use the playground at **app.scalekit.com > Agent Auth > Playground**.

## Execute a tool

`execute_tool` / `executeTool` runs a named tool for a specific user. The same pattern works across every connector. Swap `tool_name` and `tool_input`:

| Connector | Tool name | Sample `tool_input` |
|---|---|---|
| `gmail` | `gmail_fetch_mails` | `{ "query": "is:unread", "max_results": 5 }` |
| `slack` | `slack_send_message` | `{ "channel": "#general", "text": "Hello" }` |
| `github` | `github_create_issue` | `{ "repo": "acme/app", "title": "Bug", "body": "…" }` |
| `salesforce` | `salesforce_create_lead` | `{ "first_name": "Ada", "last_name": "Lovelace", "email": "ada@example.com" }` |
**Tool names are illustrative:** Exact tool names and input schemas vary by connector. Call `list_scoped_tools` or check the connector page in the dashboard for the current schema.

```python
result = actions.execute_tool(
    tool_name="gmail_fetch_mails",
    identifier="user_123",
    tool_input={"query": "is:unread", "max_results": 5},
)
print(result.data)
```
  ```typescript
const result = await scalekit.actions.executeTool({
  toolName: 'gmail_fetch_mails',
  identifier: 'user_123',
  toolInput: { query: 'is:unread', max_results: 5 },
});
console.log(result.data);
```
  ## Wire into your LLM

The full agent loop: fetch scoped tools → pass to LLM → execute tool calls → feed results back.

```python
import anthropic
from google.protobuf.json_format import MessageToDict

client = anthropic.Anthropic()

# 1. Fetch tools scoped to this user
scoped_response, _ = actions.tools.list_scoped_tools(
    identifier="user_123",
    filter={"connection_names": ["gmail"]},
)
llm_tools = [
    {
        "name": MessageToDict(t.tool).get("definition", {}).get("name"),
        "description": MessageToDict(t.tool).get("definition", {}).get("description"),
        "input_schema": MessageToDict(t.tool).get("definition", {}).get("input_schema", {}),
    }
    for t in scoped_response.tools
]

# 2. Send to LLM
messages = [{"role": "user", "content": "Summarize my last 5 unread emails"}]
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=llm_tools,
    messages=messages,
)

# 3. Execute tool calls and feed results back
for block in response.content:
    if block.type == "tool_use":
        tool_result = actions.execute_tool(
            tool_name=block.name,
            identifier="user_123",
            tool_input=block.input,
        )
        messages.append({"role": "assistant", "content": response.content})
        messages.append({
            "role": "user",
            "content": [{"type": "tool_result", "tool_use_id": block.id, "content": str(tool_result.data)}],
        })
```
  ```typescript
import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic();

// 1. Fetch tools scoped to this user
const { tools } = await scalekit.tools.listScopedTools('user_123', {
  filter: { connectionNames: ['gmail'] },
});
const llmTools = tools.map((t) => ({
  name: t.tool.definition.name,
  description: t.tool.definition.description,
  input_schema: t.tool.definition.input_schema,
}));

// 2. Send to LLM
const messages: Anthropic.MessageParam[] = [
  { role: 'user', content: 'Summarize my last 5 unread emails' },
];
const response = await anthropic.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  tools: llmTools,
  messages,
});

// 3. Execute tool calls and feed results back
for (const block of response.content) {
  if (block.type === 'tool_use') {
    const toolResult = await scalekit.actions.executeTool({
      toolName: block.name,
      identifier: 'user_123',
      toolInput: block.input as Record<string, unknown>,
    });
    messages.push({ role: 'assistant', content: response.content });
    messages.push({
      role: 'user',
      content: [{ type: 'tool_result', tool_use_id: block.id, content: JSON.stringify(toolResult.data) }],
    });
  }
}
```
  ## Use a framework adapter

For LangChain and Google ADK, Scalekit returns native tool objects in Python with no schema reshaping needed.

```python
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent

tools = actions.langchain.get_tools(
    identifier="user_123",
    providers=["GMAIL"],
    page_size=100,
)
llm = ChatOpenAI(model="claude-sonnet-4-6")
agent = create_agent(model=llm, tools=tools, system_prompt="You are a helpful assistant.")
result = agent.invoke({"messages": [{"role": "user", "content": "Fetch my last 5 unread emails"}]})
```
  ```python
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm

gmail_tools = actions.google.get_tools(
    identifier="user_123",
    providers=["GMAIL"],
    page_size=100,
)
agent = Agent(
    name="gmail_assistant",
    model=LiteLlm(model="claude-sonnet-4-6"),
    tools=gmail_tools,
)
```
  ```typescript
import { generateText, jsonSchema, tool } from 'ai';

const { tools: scopedTools } = await scalekit.tools.listScopedTools('user_123', {
  filter: { connectionNames: ['gmail'] },
});
const tools = Object.fromEntries(
  scopedTools.map((t) => [
    t.tool.definition.name,
    tool({
      description: t.tool.definition.description,
      parameters: jsonSchema(t.tool.definition.input_schema ?? { type: 'object', properties: {} }),
      execute: async (args) => {
        const result = await scalekit.actions.executeTool({
          toolName: t.tool.definition.name,
          toolInput: args,
          identifier: 'user_123',
        });
        return result.data;
      },
    }),
  ]),
);
```
**MCP-compatible frameworks:** Prefer a single interface any MCP client can consume? See [Configure an MCP server](/agentkit/mcp/configure-mcp-server/).

## Troubleshooting

<details>
<summary>Connected account stays in <code>PENDING</code></summary>

The user hasn't completed the OAuth flow yet. Call `get_authorization_link` and redirect the user to the link. Retry after consent completes.

</details>

<details>
<summary>Tool call fails with resource not found</summary>

Check three things:
- The connector name exists in **Agent Auth > Connections**
- The `identifier` matches the one used when creating the connected account
- Call `list_scoped_tools` and only execute tool names it returns

</details>

<details>
<summary>Connection names differ across environments</summary>

Connection names are workspace-specific. Don't hard-code them. Use environment variables (`GMAIL_CONNECTION_NAME`, `GITHUB_CONNECTION_NAME`) and reference those in API calls.

</details>

If you need an endpoint not covered by optimized tools, see [Custom tools](/agentkit/tools/custom-tools/).

---

## More Scalekit documentation

| Resource | What it contains | When to use it |
|----------|-----------------|----------------|
| [/llms.txt](/llms.txt) | Structured index with routing hints per product area | Start here — find which documentation set covers your topic before loading full content |
| [/llms-full.txt](/llms-full.txt) | Complete documentation for all Scalekit products in one file | Use when you need exhaustive context across multiple products or when the topic spans several areas |
| [sitemap-0.xml](https://docs.scalekit.com/sitemap-0.xml) | Full URL list of every documentation page | Use to discover specific page URLs you can fetch for targeted, page-level answers |
