LangChain — rcp-sdk/adapters/langchain

Convert RCP-discovered tools into LangChain DynamicStructuredTool + LangGraph tools. Handles schema conversion, response mapping, and resolver-bound context injection automatically.

typescript
import { rcpToolsToLangChainTools, loadRcpLangChainTools } from 'rcp-sdk/adapters/langchain';

The LangChain adapter bridges RCP and LangChain/LangGraph. It takes DiscoveredTool[] from rcp.discover() and produces LangChain DynamicStructuredTool instances that work with any LangChain agent or chain.

@langchain/core is an optional peer dependency. The adapter only needs to be installed if you import from rcp-sdk/adapters/langchain.

loadRcpLangChainTools(manifestUrl, client, options?)

One-call helper: discovers the manifest and converts all tools in a single step.

typescript
import { createRcpClient } from 'rcp-sdk/client';
import { loadRcpLangChainTools } from 'rcp-sdk/adapters/langchain';
import { ChatOpenAI } from '@langchain/openai';
import { createAgent } from 'langchain';

const rcp = createRcpClient();
const tools = await loadRcpLangChainTools(
  'https://example.com/rcp/manifest',
  rcp,
  {
    context: { userId: 'u_1' },     // resolver-bound values, hidden from model
    serverName: 'myApi',            // prefixes tool names: myApi__tool_name
  },
);

const model = new ChatOpenAI({ model: 'gpt-4o-mini' });
const agent = createAgent({ model, tools });

Options

OptionTypeNotes
contextRecord<string, unknown> | (() => Record<string, unknown>)Static value or zero-arg function. Passed to rcp.call() as the context for resolvers. Values never reach the model.
serverNamestringPrefix for tool names: "myApi__get_weather". Useful when combining tools from multiple servers.
prefixToolNameWithServerNamebooleanAlias for serverName when you just want the prefix without a custom name.

rcpToolsToLangChainTools(tools, client, options?)

Converts an array of DiscoveredTool instances into LangChain DynamicStructuredTool instances. Use this when you need more control over the discovery step.

typescript
import { createRcpClient } from 'rcp-sdk/client';
import { rcpToolsToLangChainTools } from 'rcp-sdk/adapters/langchain';

const rcp = createRcpClient();
const { tools } = await rcp.discover('https://example.com/rcp/manifest');
const langchainTools = rcpToolsToLangChainTools(tools, rcp);

rcpToolToLangChainTool(tool, client, options?)

Converts a single DiscoveredTool into a LangChain DynamicStructuredTool. Useful when you want to cherry-pick tools.

MultiServerRcpClient

Manages multiple RCP servers, caching discovery per server. Useful when your agent pulls tools from several manifests.

typescript
import { MultiServerRcpClient } from 'rcp-sdk/adapters/langchain';

const multi = new MultiServerRcpClient({
  servers: {
    weather: {
      manifestUrl: 'https://weather.example.com/rcp/manifest',
      client: createRcpClient(),
    },
    users: {
      manifestUrl: 'https://users.example.com/rcp/manifest',
      client: createRcpClient(),
    },
  },
});

// Get all tools from all servers
const tools = await multi.getTools();

// Or get tools from a specific server
const weatherTools = await multi.getToolsForServer('weather');

// Force re-discovery
multi.invalidateCache('weather');

Constructor options

OptionTypeNotes
serversRecord<string, servers config>Required. Map of server name to config.
contextRecord<string, unknown> | (() => Record<string, unknown>)Default context for all servers.
getContextForServerRecord<string, Record<string, unknown>>Per-server context overrides.
serverNamestringDefault prefix for all tool names.
additionalToolNamePrefixstringExtra prefix applied after server name.
throwOnLoadErrorbooleanIf true (default), throws if any server fails to load. If false, skips failed servers.

How it works

The adapter does three things for each tool:

  1. Schema: Converts exposedParams into a Zod object schema — what LangChain's DynamicStructuredTool expects.
  2. Execution: Each tool call delegates to rcpClient.call(tool, args, ctx), which renders the URL, attaches auth, and makes the real HTTP request.
  3. Response: responseMappings are applied automatically — the model gets a clean object, not raw JSON paths.

Related