> **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

Call Scalekit's pre-built tools across 100+ connectors. Each tool returns structured, LLM-ready output with no endpoint URLs, auth headers, or parsing needed.
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/).

## Get available tools for a user

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

```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
    page_size=100,                            # fetch beyond the default page
)
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
```

  ### Node.js

```typescript
const { tools } = await scalekit.tools.listScopedTools('user_123', {
  filter: { connectionNames: ['gmail'] },     // use filter: {} to list every connector
  pageSize: 100,                              // fetch beyond the default page
});
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 explore tools interactively, use the playground at [<strong>Scalekit Dashboard</strong>](https://app.scalekit.com) **> AgentKit > Playground**.

## Execute a tool

Use `execute_tool` / `executeTool` to run a named tool for a specific user. Scalekit identifies the connected account with:

- User identifier (`identifier`) + Connection name as shown in the Scalekit Dashboard (`connection_name`), or
- Connected Account ID (`connected_account_id`) — autogenerated by Scalekit and visible in the Scalekit Dashboard

  ### Python

```python
# connected account is selected using the user identifier and the connection name
result = actions.execute_tool(
    tool_name="gmail_fetch_mails",
    identifier="user_123",
    connection_name="gmail",
    tool_input={"query": "is:unread", "max_results": 5},
)
print(result.data)

# alternatively, use the connected account ID
# result = actions.execute_tool(
#     tool_name="gmail_fetch_mails",
#     connected_account_id="ca_xxxxxx",
#     tool_input={"query": "is:unread", "max_results": 5},
# )
```

  ### Node.js

```typescript
// connected account is selected using the user identifier and the connector
const result = await scalekit.actions.executeTool({
  toolName: 'gmail_fetch_mails',
  identifier: 'user_123',
  connector: 'gmail',
  toolInput: { query: 'is:unread', max_results: 5 },
});
console.log(result.data);

// alternatively, use the connected account ID
// const result = await scalekit.actions.executeTool({
//   toolName: 'gmail_fetch_mails',
//   connectedAccountId: 'ca_xxxxxx',
//   toolInput: { query: 'is:unread', max_results: 5 },
// });
```

## Wire into your LLM

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

  ### Python

```python

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"]},
    page_size=100,  # fetch beyond the default page so no connector tools are missed
)
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)}],
        })
```

  ### Node.js

```typescript

const anthropic = new Anthropic();

// 1. Fetch tools scoped to this user
const { tools } = await scalekit.tools.listScopedTools('user_123', {
  filter: { connectionNames: ['gmail'] },
  pageSize: 100, // fetch beyond the default page so no connector tools are missed
});
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.

  ### LangChain

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

tools = actions.langchain.get_tools(
    identifier="user_123",
    connection_names=["gmail"],
    page_size=100,  # avoid missing tools when a connector has more than the default page
)
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"}]})
```

  ### Google ADK

```python
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm

gmail_tools = actions.google.get_tools(
    identifier="user_123",
    connection_names=["gmail"],
    page_size=100,  # avoid missing tools when a connector has more than the default page
)
agent = Agent(
    name="gmail_assistant",
    model=LiteLlm(model="claude-sonnet-4-6"),
    tools=gmail_tools,
)
```

  ### Node.js (Vercel AI SDK)

```typescript

const { tools: scopedTools } = await scalekit.tools.listScopedTools('user_123', {
  filter: { connectionNames: ['gmail'] },
  pageSize: 100, // fetch beyond the default page so no connector tools are missed
});
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;
      },
    }),
  ]),
);
```

> note: MCP-compatible frameworks
>
> Prefer a single interface any MCP client can consume? See [Configure an MCP server](/agentkit/mcp/configure-mcp-server/).

## Troubleshooting

## Connected account stays in <code>PENDING</code>

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

## Tool call fails with resource not found

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

## Connection names differ across environments

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.

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 |
