> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://gtm-tools.sh/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://gtm-tools.sh/_mcp/server.

# LangChain

> Load every GTM Tools tool into a LangChain or LangGraph agent through langchain-mcp-adapters, with buying signals, LinkedIn lookup, and verified emails as standard LangChain tools.

## Getting started

[LangChain](https://www.langchain.com/) is the most widely used framework for building LLM-powered agents. GTM Tools plugs in through [`langchain-mcp-adapters`](https://github.com/langchain-ai/langchain-mcp-adapters), the official adapter that turns any MCP server's tools into standard LangChain tools. One connection gives a LangGraph agent buying-signal detection, LinkedIn company and people lookup, SMTP-verified email finding, and Reddit engagement, with real tool schemas the model can bind to.

There's no `langchain-gtm-tools` package to install. The adapter reads our tool schemas live from the MCP server, so the tool list is always current.

## Use cases

* **Signal-gated prospecting graph:** a node runs `detect_signal`, a conditional edge drops accounts where nothing fired, and only survivors reach the expensive LinkedIn nodes.
* **Enrichment tool for an existing agent:** bind `get_email` and `get_linkedin_profile_url` to an agent that already handles your CRM.
* **Research subgraph:** let the model choose between cheap SERP-only employee search and the full search depending on what the task needs.
* **Human-in-the-loop outreach:** draft with LangGraph's interrupt, then send through `send_linkedin_message` only after approval.

## Prerequisites

1. A GTM Tools API key, from `get_api_key` or `gtm-tools admin login`. See [Get an API key](/integrations/agent-onboarding#get-an-api-key).
2. Python 3.10+ and a LangChain-compatible model provider (an `OPENAI_API_KEY` or `ANTHROPIC_API_KEY`).

## Setup

Install the adapter alongside LangGraph and your model provider:

```bash
pip install langchain-mcp-adapters langgraph "langchain[openai]"
```

Set your keys:

```bash
export GTM_TOOLS_API_KEY="sk_your_api_key"
export OPENAI_API_KEY="sk-..."
```

## Quickstart

Build a ReAct agent with the full toolkit in a few lines:

**`Python`**

```python title="Python"
import asyncio
import os

from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "gtm-tools": {
            "transport": "streamable_http",
            "url": "https://api.gtm-tools.sh/mcp",
            "headers": {
                "Authorization": f"Bearer {os.environ['GTM_TOOLS_API_KEY']}"
            },
        }
    }
)


async def main():
    agent = create_react_agent(
        ChatOpenAI(model="gpt-4o-mini"),
        tools=await client.get_tools(),
    )
    result = await agent.ainvoke(
        {"messages": [("user", "Is gymshark.com showing any buying signals?")]}
    )
    print(result["messages"][-1].content)


asyncio.run(main())
```

You can also pull a single tool in if you don't need the whole toolkit:

**`Python`**

```python title="Python"
tools = {t.name: t for t in await client.get_tools()}

signals = await tools["detect_signal"].ainvoke({"domain": "gymshark.com"})
email = await tools["get_email"].ainvoke(
    {"name": "Ben Francis", "domain": "gymshark.com"}
)
```

## Available tools

The adapter discovers the tool catalog from the server at connection time, so there is no fixed inventory to copy into your code. The server exposes **64 tools**: 8 billing, 19 LinkedIn, 21 Reddit, 3 enrichment, and 13 signals.

See the [MCP tool catalogue](/integrations/mcp#tool-catalogue) for names and parameter shapes, and [Pricing](/pricing) for the credit cost of each. `get_credit_balance` returns the live cost table at runtime.

## Narrow the tool set

Feeding all 64 tools to the model wastes context and invites wrong picks, so narrow to the workflow you are building:

```python
KEEP = {
    "detect_signal",
    "get_linkedin_company_url",
    "list_linkedin_company_employees",
    "get_email",
}

tools = [t for t in await client.get_tools() if t.name in KEEP]
```

Filter after loading, since the adapter fetches the whole catalog in one call.

## Handling errors in a graph

Tool failures surface as exceptions from `ainvoke`, and the message carries the HTTP status. Two worth handling explicitly:

* `402 Insufficient credits`: stop the run rather than retrying. Top up with `buy_credits` or enable `set_auto_reload`.
* A `200` result with `status: "try_again_later"` and `retry_after_seconds`: a provider was busy. Sleep that long before one retry; each attempt is charged.

The full table is in the [Error Reference](/errors).