Skip to main content

Connecting Agent Frameworks to Collate MCP

Every other guide in this section (Claude Desktop, Cursor, VS Code, Goose) assumes a person runs the client interactively and can complete a browser sign-in. This guide covers the opposite case: a programmatic agent framework such as CrewAI, LangChain, the OpenAI Agents SDK, or your own orchestration code. The framework calls the MCP server directly over HTTP with no one present.

When to Use This Guide

  • You’re wiring an agent framework directly to the MCP endpoint, not through one of the interactive clients listed above.
  • Your process runs unattended, on a schedule, or as part of a larger pipeline, so no one is available to complete an OAuth browser login.
  • You need a service identity whose access is separate from any individual’s account.

1. Authenticate with a Bot Token

OAuth 2.0 (see OAuth 2.0 Authentication) requires a person to sign in through a browser, so it doesn’t fit an unattended agent. Use a JWT Token generated from a Bot instead. Collate rejects Personal Access Token generation for Bot accounts, so this is the only credential a Bot can authenticate with:
  1. Follow How to Set Up Bots to create a Bot and assign it the role-based access policy your agent needs.
  2. Generate a JWT Token for that Bot, following Bot JWT Token.
  3. Store the token in an environment variable or secrets manager, never in source control.
Every request to the MCP endpoint carries this token in the Authorization header:

2. Set Up a Raw JSON-RPC Session

Before your first tool call, initialize the connection and confirm it:
From here, call any tool with tools/call:
See the MCP Server Connection Guide for the full protocol reference (headers, tools/list, and prompts) and the Collate MCP Tools Reference for every available tool.

3. Wrap the Session in a LangChain Tool

The snippet below wraps the raw session above as a LangChain StructuredTool. It’s illustrative, not a maintained SDK. A full LangChain or CrewAI MCP adapter, if one becomes available, would replace hand-rolled HTTP calls like these.
Wrap additional tools (get_entity_details, get_entity_lineage, and so on) the same way: one small function per tool, each calling session.call_tool with that tool’s name and arguments.

4. Check isError on Every Response

Because there’s no human watching for a stuck spinner, a headless caller must explicitly check result.isError on every tool call rather than assuming a 200-shaped response succeeded. See Tool Execution Errors for the full envelope shape and a worked example.