mcp integration
connect to model context protocol servers and use their tools in your workflows
mcp (model context protocol) is a standard for exposing tools and resources to llms. mcp servers provide tools over stdio, sse, or websockets. this library converts mcp tools into native tool definitions that work with your workflows.
basic usage
first, install the mcp sdk:
then connect to an mcp server and convert its tools:
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import { createMCPTools, compose, model, scope } from "@threaded/ai";
const transport = new StdioClientTransport({
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
});
const client = new Client({
name: "my-agent",
version: "1.0.0",
}, {
capabilities: {},
});
await client.connect(transport);
const tools = await createMCPTools(client);
const workflow = compose(
scope(
{
tools,
},
model(),
),
);
await workflow("list files in the current directory");
here's what's happening:
- StdioClientTransport launches the mcp server as a subprocess (in this case, the filesystem server with
/tmpas working directory) - Client creates an mcp client that communicates with the server over stdio
- client.connect() establishes the connection
- createMCPTools() fetches the server's tool list, converts each mcp tool to threads tool format, and wraps the execute function to call the mcp server
- model can now call these tools like any other tool - when called, the library forwards the request to the mcp server and returns the result
tool naming
tools are prefixed with server name to avoid conflicts between servers
if server name is "filesystem" and it provides a tool called "read_file", the final tool name becomes "filesystem_read_file". model sees this name in tool descriptions.
multiple mcp servers
connect to multiple servers and combine their tools
const fsTransport = new StdioClientTransport({
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
});
const gitTransport = new StdioClientTransport({
command: "npx",
args: ["-y", "@modelcontextprotocol/server-git"],
});
const fsClient = new Client({ name: "fs-client", version: "1.0.0" }, { capabilities: {} });
const gitClient = new Client({ name: "git-client", version: "1.0.0" }, { capabilities: {} });
await fsClient.connect(fsTransport);
await gitClient.connect(gitTransport);
const fsTools = await createMCPTools(fsClient);
const gitTools = await createMCPTools(gitClient);
const workflow = compose(
scope(
{
tools: [...fsTools, ...gitTools],
},
model(),
),
);
await workflow("show git status and list all js files");
model now has access to both filesystem and git operations