#
tokens: 2569/50000 9/9 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── jest.config.js
├── package.json
├── README.md
├── src
│   ├── __tests__
│   │   └── index.test.ts
│   ├── index.ts
│   └── types.ts
├── tsconfig.json
└── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
1 | node_modules/
2 | dist/
3 | coverage/
4 | *.log
5 | .DS_Store
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # mcp-langchain-ts-client
 2 | 
 3 | A LangChain.js client for Model Context Protocol.
 4 | 
 5 | This is a port of [rectalogic/langchain-mcp](https://github.com/rectalogic/langchain-mcp) to the JS/TS LangChain and MCP APIs.
 6 | 
 7 | ## Installation
 8 | 
 9 | ```bash
10 | npm install mcp-langchain-ts-client
11 | ```
12 | 
13 | ## Usage
14 | 
15 | ```typescript
16 | const serverParams = {
17 |   command: "npx",
18 |   args: [
19 |     "-y",
20 |     "@modelcontextprotocol/server-everything"
21 |   ]
22 | }
23 | 
24 | // Initialize the toolkit
25 | const toolkit = new MCPToolkit(serverParams);
26 | await toolkit.initialize();
27 | 
28 | // Extract LangChain.js compatible tools
29 | const tools = toolkit.tools;
30 | 
31 | // Use the tools
32 | import { createReactAgent } from "@langchain/langgraph/prebuilt";
33 | import { ChatAnthropic } from "@langchain/anthropic";
34 | 
35 | const llm = new ChatAnthropic({ model: 'claude-3-5-sonnet-20241022' });
36 | const agent = createReactAgent({ llm, tools });
37 | ```
```

--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------

```typescript
1 | 
```

--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------

```javascript
1 | module.exports = {
2 |   preset: 'ts-jest',
3 |   testEnvironment: 'node',
4 |   testMatch: ['**/__tests__/**/*.test.ts'],
5 | };
```

--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from 'vitest/config'
 2 | 
 3 | export default defineConfig({
 4 |   test: {
 5 |     include: ['src/**/*.test.ts'],
 6 |     coverage: {
 7 |       reporter: ['text', 'json', 'html'],
 8 |     },
 9 |   },
10 | })
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "ESNext",
 5 |     "moduleResolution": "bundler",
 6 |     "outDir": "./dist",
 7 |     "declaration": true,
 8 |     "strict": true,
 9 |     "esModuleInterop": true,
10 |     "skipLibCheck": true,
11 |     "forceConsistentCasingInFileNames": true,
12 |     "rootDir": "./src"
13 |   },
14 |   "include": ["src"],
15 |   "exclude": ["node_modules", "**/__tests__/*"]
16 | }
```

--------------------------------------------------------------------------------
/src/__tests__/index.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { describe, it, expect } from 'vitest';
 2 | import { MCPToolkit } from '../index';
 3 | 
 4 | const serverParams = {
 5 |   command: "npx",
 6 |   args: [
 7 |     "-y",
 8 |     "@modelcontextprotocol/server-everything"
 9 |   ]
10 | }
11 | 
12 | const toolkit = new MCPToolkit(serverParams);
13 | await toolkit.initialize();
14 | 
15 | const toolsByName = toolkit.tools.reduce((acc, tool) => {
16 |   acc[tool.name] = tool;
17 |   return acc;
18 | });
19 | 
20 | describe('MCPToolkit', () => {
21 |   describe('initialize', () => {
22 |     it('should initialize the toolkit', () => {
23 |       expect(toolkit.tools.length).toBeGreaterThan(0);
24 |     });
25 |   });
26 |   describe('tools', () => {
27 |     it('should echo'), async () => {
28 |       const tool = toolsByName['echo'];
29 |       const result = await tool.invoke({ message: 'hello' });
30 |       expect(result).toBe('hello');
31 |     }
32 |   });
33 | });
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-langchain-ts-client",
 3 |   "version": "0.0.2.1",
 4 |   "description": "TypeScript client for MCP Langchain",
 5 |   "type": "module",
 6 |   "main": "./dist/index.js",
 7 |   "module": "./dist/index.js",
 8 |   "types": "./dist/index.d.ts",
 9 |   "exports": {
10 |     ".": {
11 |       "import": "./dist/index.js",
12 |       "types": "./dist/index.d.ts"
13 |     }
14 |   },
15 |   "repository": {
16 |     "type": "git",
17 |     "url": "git+https://github.com/isaacwasserman/mcp-langchain-ts-client.git"
18 |   },
19 |   "bugs": {
20 |     "url": "https://github.com/isaacwasserman/mcp-langchain-ts-client/issues"
21 |   },
22 |   "homepage": "https://github.com/isaacwasserman/mcp-langchain-ts-client#readme",
23 |   "files": [
24 |     "dist"
25 |   ],
26 |   "scripts": {
27 |     "build": "tsc",
28 |     "test": "vitest run",
29 |     "test:watch": "vitest",
30 |     "test:coverage": "vitest run --coverage",
31 |     "prepare": "npm run build"
32 |   },
33 |   "keywords": [
34 |     "typescript",
35 |     "langchain",
36 |     "mcp"
37 |   ],
38 |   "author": "Isaac Wasserman",
39 |   "license": "MIT",
40 |   "devDependencies": {
41 |     "@vitest/coverage-v8": "^1.2.0",
42 |     "typescript": "^5.0.0",
43 |     "vite": "^5.0.0",
44 |     "vitest": "^1.2.0"
45 |   },
46 |   "peerDependencies": {
47 |     "typescript": ">=4.0.0"
48 |   },
49 |   "dependencies": {
50 |     "@modelcontextprotocol/sdk": "^1.0.3"
51 |   }
52 | }
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { CallToolRequest, CallToolResultSchema, ListToolsResult, ListToolsResultSchema } from "@modelcontextprotocol/sdk/types.js";
 2 | import { StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
 3 | import { Client } from "@modelcontextprotocol/sdk/client/index.js";
 4 | import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
 5 | import { BaseToolkit, StructuredToolInterface, StructuredToolParams, tool, Tool } from "@langchain/core/tools";
 6 | import { z } from "zod";
 7 | 
 8 | export { StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js";
 9 | 
10 | export class MCPToolkit extends BaseToolkit {
11 |   tools: Tool[] = [];
12 |   _tools: ListToolsResult | null = null;
13 |   model_config: any;
14 |   transport: StdioClientTransport | null = null;
15 |   client: Client | null = null;
16 |   constructor(serverParams: StdioServerParameters) {
17 |     super();
18 |     this.transport = new StdioClientTransport(serverParams);
19 |   }
20 |   async initialize() {
21 |     if (this._tools === null) {
22 |       this.client = new Client({
23 |         name: "langchain-js-client",
24 |         version: "1.0.0",
25 |       }, {
26 |         capabilities: {}
27 |       });
28 |       if (this.transport === null) {
29 |         throw new Error("Transport is not initialized");
30 |       }
31 |       await this.client.connect(this.transport);
32 |       this._tools = await this.client.request(
33 |         { method: "tools/list" },
34 |         ListToolsResultSchema
35 |       );
36 | 
37 |       this.tools = await this.get_tools();
38 |     }
39 |   }
40 | 
41 |   async get_tools(): Promise<Tool[]> {
42 |     if (this._tools === null || this.client === null) {
43 |       throw new Error("Must initialize the toolkit first");
44 |     }
45 |     const toolsPromises = this._tools.tools.map(async (tool: any) => {
46 |       if (this.client === null) {
47 |         throw new Error("Client is not initialized");
48 |       }
49 |       return await MCPTool({
50 |         client: this.client,
51 |         name: tool.name,
52 |         description: tool.description || "",
53 |         argsSchema: createSchemaModel(tool.inputSchema)
54 |       });
55 |     });
56 |     return Promise.all(toolsPromises);
57 |   }
58 | 
59 | }
60 | 
61 | export async function MCPTool({ client, name, description, argsSchema }: { client: Client, name: string, description: string, argsSchema: any }): Promise<Tool> {
62 |   return tool(
63 |     async (input): Promise<string> => {
64 |       const req: CallToolRequest = { method: "tools/call", params: { name: name, arguments: input } };
65 |       const res = await client.request(req, CallToolResultSchema);
66 |       const content = res.content;
67 |       const contentString = JSON.stringify(content);
68 |       return contentString;
69 |     },
70 |     {
71 |       name: name,
72 |       description: description,
73 |       schema: argsSchema,
74 |     }
75 |   );
76 | }
77 | 
78 | function createSchemaModel(inputSchema: { type: "object"; properties?: import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough"> | undefined; } & { [k: string]: unknown; }): any {
79 |   if (inputSchema.type !== "object" || !inputSchema.properties) {
80 |     throw new Error("Invalid schema type or missing properties");
81 |   }
82 | 
83 |   const schemaProperties = Object.entries(inputSchema.properties).reduce((acc, [key, value]) => {
84 |     acc[key] = z.any(); // You can customize this to map specific types
85 |     return acc;
86 |   }, {} as Record<string, import("zod").ZodTypeAny>);
87 | 
88 |   return z.object(schemaProperties);
89 | }
```