langchain-mcp 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # langchain-mcp
2
+
3
+ MCP server for searching LangChain, LangGraph & LangSmith documentation and source code.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm i -g langchain-mcp
9
+ langchain-mcp login
10
+ claude mcp add langchain-mcp -- npx langchain-mcp
11
+ ```
12
+
13
+ ## Claude Desktop
14
+
15
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "langchain-mcp": {
21
+ "command": "npx",
22
+ "args": ["langchain-mcp"]
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ ## CLI Commands
29
+
30
+ ```bash
31
+ langchain-mcp login # Login with Google
32
+ langchain-mcp status # Check login status and usage
33
+ langchain-mcp logout # Logout
34
+ ```
35
+
36
+ ## MCP Tools
37
+
38
+ | Tool | Description |
39
+ |------|-------------|
40
+ | `search_docs` | Search documentation, references, and tutorials about LangChain, LangGraph, LangSmith, and DeepAgents |
41
+ | `search_langchain_code` | Search LangChain source code |
42
+ | `search_langgraph_code` | Search LangGraph source code |
43
+ | `search_deepagent_code` | Search DeepAgent source code |
44
+
45
+ ## Free Credits
46
+
47
+ New users get **$5 free credits** (~2000 searches).
48
+
49
+ ## Links
50
+
51
+ - Website: https://langchain-mcp.xyz
52
+ - GitHub: https://github.com/baixianger/langchain-mcp
53
+ - Sponsor: https://ko-fi.com/baixianger
54
+
55
+ ## License
56
+
57
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import http from 'http';
4
+ import open from 'open';
5
+ import { readFileSync } from 'fs';
6
+ import { dirname, resolve } from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
+ import { loadConfig, saveConfig, deleteConfig, getConfigPath, DEFAULT_API_URL, WEBSITE_URL } from '../src/config.js';
10
+ import { APIClient } from '../src/api-client.js';
11
+ import { createServer } from '../src/server.js';
12
+ // Get version from package.json
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8'));
15
+ // ASCII Art Banner - Generated with oh-my-logo (shade style)
16
+ function printBanner() {
17
+ const green = '\x1b[32m';
18
+ const reset = '\x1b[0m';
19
+ console.log(`
20
+ ${green}░█░░░░░██░░█░░█░░███░████░█░░█░░██░░███░█░░█░░░░░░█░░█░████░███░
21
+ ░█░░░░█ █░██░█░█ ░█ ░█░░█░█ █░ █ ░██░█░░░░░░████░█ ░█ █
22
+ ░█░░░░████░█ ██░█░██░█░░░░████░████░░█░░█ ██░████░█ █░█░░░░███░
23
+ ░█░░░░█ █░█░ █░█░ █░█░░░░█ █░█ █░░█░░█░ █░ ░█░░█░█░░░░█░░░
24
+ ░████░█░░█░█░░█░███░░████░█░░█░█░░█░███░█░░█░░░░░░█░░█░████░█░░░${reset}
25
+ `);
26
+ }
27
+ function printDivider(char = '─', length = 70) {
28
+ console.log('\x1b[90m' + char.repeat(length) + '\x1b[0m');
29
+ }
30
+ function printSection(title) {
31
+ console.log(`\n\x1b[1m\x1b[33m${title}\x1b[0m`); // Bold yellow
32
+ }
33
+ const program = new Command();
34
+ program
35
+ .name('langchain-mcp')
36
+ .description('CLI for LangChain MCP server')
37
+ .version(pkg.version);
38
+ /**
39
+ * Default action - start MCP server (when no command given)
40
+ */
41
+ program
42
+ .command('serve', { isDefault: true, hidden: true })
43
+ .description('Start MCP server')
44
+ .action(async () => {
45
+ const server = createServer();
46
+ const transport = new StdioServerTransport();
47
+ await server.connect(transport);
48
+ });
49
+ /**
50
+ * Login command - Google OAuth
51
+ */
52
+ program
53
+ .command('login')
54
+ .description('Login to LangChain MCP service')
55
+ .option('--no-browser', 'Print URL instead of opening browser')
56
+ .option('--api-url <url>', 'API server URL', DEFAULT_API_URL)
57
+ .action(async (options) => {
58
+ const existingConfig = loadConfig();
59
+ if (existingConfig) {
60
+ console.log('Already logged in.');
61
+ console.log('Run "langchain-mcp logout" first to log out.');
62
+ return;
63
+ }
64
+ await loginWithWebFlow(options.apiUrl, options.browser);
65
+ });
66
+ /**
67
+ * Web Flow login - opens browser for Google OAuth
68
+ */
69
+ async function loginWithWebFlow(apiUrl, openBrowser) {
70
+ const port = 9876;
71
+ const callbackUrl = `http://localhost:${port}/callback`;
72
+ const server = http.createServer(async (req, res) => {
73
+ const url = new URL(req.url, `http://localhost:${port}`);
74
+ if (url.pathname === '/callback') {
75
+ const apiKey = url.searchParams.get('api_key');
76
+ const userJson = url.searchParams.get('user');
77
+ const error = url.searchParams.get('error');
78
+ if (error) {
79
+ const failureUrl = new URL(`${WEBSITE_URL}/failure.html`);
80
+ failureUrl.searchParams.set('error', error);
81
+ res.writeHead(302, { 'Location': failureUrl.toString() });
82
+ res.end();
83
+ console.error(`\nLogin failed: ${error}`);
84
+ server.close();
85
+ process.exit(1);
86
+ }
87
+ if (apiKey && userJson) {
88
+ try {
89
+ const user = JSON.parse(userJson);
90
+ // Save config
91
+ saveConfig({
92
+ api_key: apiKey,
93
+ api_url: apiUrl,
94
+ user,
95
+ });
96
+ printBanner();
97
+ printDivider();
98
+ console.log('\n \x1b[32m✓ Login Successful!\x1b[0m\n');
99
+ printSection('👤 User');
100
+ console.log(` Name: ${user.name || 'N/A'}`);
101
+ console.log(` Email: ${user.email}`);
102
+ printSection('💰 Credits');
103
+ const creditColor = user.credits > 5 ? '\x1b[32m' : user.credits > 1 ? '\x1b[33m' : '\x1b[31m';
104
+ console.log(` Remaining: ${creditColor}$${user.credits.toFixed(2)}\x1b[0m`);
105
+ printSection('☕ Support');
106
+ console.log(` Ko-fi: \x1b[36mhttps://ko-fi.com/baixianger\x1b[0m`);
107
+ printSection('⚙️ Config');
108
+ console.log(` Saved to: ${getConfigPath()}`);
109
+ console.log('');
110
+ printDivider();
111
+ console.log('');
112
+ // Redirect to homepage success page
113
+ const successUrl = new URL(`${WEBSITE_URL}/success.html`);
114
+ successUrl.searchParams.set('name', user.name || user.email);
115
+ res.writeHead(302, { 'Location': successUrl.toString() });
116
+ res.end();
117
+ setTimeout(() => {
118
+ server.close();
119
+ process.exit(0);
120
+ }, 1000);
121
+ }
122
+ catch (err) {
123
+ res.writeHead(400);
124
+ res.end('Login failed: invalid response');
125
+ server.close();
126
+ process.exit(1);
127
+ }
128
+ }
129
+ else {
130
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
131
+ res.end(`
132
+ <!DOCTYPE html>
133
+ <html>
134
+ <head><title>Login Failed</title></head>
135
+ <body style="font-family: system-ui; text-align: center; padding: 50px;">
136
+ <h1>❌ Login Failed</h1>
137
+ <p>Missing API key</p>
138
+ </body>
139
+ </html>
140
+ `);
141
+ server.close();
142
+ process.exit(1);
143
+ }
144
+ }
145
+ else {
146
+ res.writeHead(404);
147
+ res.end('Not found');
148
+ }
149
+ });
150
+ server.listen(port, () => {
151
+ const authUrl = `${apiUrl}/auth/google?callback=${encodeURIComponent(callbackUrl)}`;
152
+ console.log('🔐 Logging in with Google...');
153
+ if (openBrowser) {
154
+ console.log('Opening browser for login...');
155
+ open(authUrl);
156
+ }
157
+ else {
158
+ console.log('Open this URL in your browser:');
159
+ console.log(authUrl);
160
+ }
161
+ console.log(`\nWaiting for login callback on port ${port}...`);
162
+ });
163
+ // Timeout after 5 minutes
164
+ setTimeout(() => {
165
+ console.log('\n⏰ Login timeout. Please try again.');
166
+ server.close();
167
+ process.exit(1);
168
+ }, 5 * 60 * 1000);
169
+ }
170
+ /**
171
+ * Status command - show current login status and usage
172
+ */
173
+ program
174
+ .command('status')
175
+ .description('Show current login status and usage')
176
+ .action(async () => {
177
+ const config = loadConfig();
178
+ printBanner();
179
+ printDivider();
180
+ if (!config) {
181
+ console.log('\n \x1b[31m✗ Not logged in\x1b[0m');
182
+ console.log(' Run \x1b[36mlangchain-mcp login\x1b[0m to get started.\n');
183
+ return;
184
+ }
185
+ // User Info Section
186
+ printSection('👤 User');
187
+ console.log(` Name: ${config.user?.name || 'N/A'}`);
188
+ console.log(` Email: ${config.user?.email || 'Unknown'}`);
189
+ console.log(` ID: ${config.user?.id || 'N/A'}`);
190
+ try {
191
+ const client = new APIClient(config.api_url, config.api_key);
192
+ const usage = await client.getUsage();
193
+ // Credits Section
194
+ printSection('💰 Credits');
195
+ const remaining = usage.credits.remaining;
196
+ const creditColor = remaining > 5 ? '\x1b[32m' : remaining > 1 ? '\x1b[33m' : '\x1b[31m';
197
+ console.log(` Remaining: ${creditColor}$${remaining.toFixed(2)}\x1b[0m`);
198
+ // Show Ko-fi prompt when low on credits
199
+ if (remaining <= 1) {
200
+ console.log(`\n \x1b[33m⚠️ Low credits! Support the project:\x1b[0m`);
201
+ console.log(` \x1b[36m☕ https://ko-fi.com/baixianger\x1b[0m`);
202
+ }
203
+ // Token Usage Section
204
+ printSection('📊 Token Usage');
205
+ console.log(` Today: ${usage.usage.today.tokens.toLocaleString().padStart(12)} tokens (${usage.usage.today.requests} requests)`);
206
+ console.log(` This Month: ${usage.usage.this_month.tokens.toLocaleString().padStart(12)} tokens (${usage.usage.this_month.requests} requests)`);
207
+ console.log(` All Time: ${usage.usage.all_time.tokens.toLocaleString().padStart(12)} tokens (${usage.usage.all_time.requests} requests)`);
208
+ // Support Section
209
+ printSection('☕ Support');
210
+ console.log(` Ko-fi: \x1b[36mhttps://ko-fi.com/baixianger\x1b[0m`);
211
+ // Config Section
212
+ printSection('⚙️ Config');
213
+ console.log(` Path: ${getConfigPath()}`);
214
+ console.log(` API: ${config.api_url}`);
215
+ }
216
+ catch (error) {
217
+ console.log(`\n \x1b[33m⚠️ Could not fetch usage: ${error.message}\x1b[0m`);
218
+ console.log(' Your API key may be invalid. Run \x1b[36mlangchain-mcp login\x1b[0m again.');
219
+ }
220
+ console.log('');
221
+ printDivider();
222
+ console.log('');
223
+ });
224
+ /**
225
+ * Logout command - remove local credentials
226
+ */
227
+ program
228
+ .command('logout')
229
+ .description('Logout and remove local credentials')
230
+ .action(async () => {
231
+ const config = loadConfig();
232
+ if (!config) {
233
+ console.log('Not logged in.');
234
+ return;
235
+ }
236
+ deleteConfig();
237
+ console.log('✅ Logged out successfully.');
238
+ });
239
+ program.parse();
@@ -0,0 +1,74 @@
1
+ export interface SearchResult {
2
+ id: string;
3
+ content: string;
4
+ metadata: {
5
+ filePath: string;
6
+ language?: string;
7
+ product?: string;
8
+ topic?: string;
9
+ codeType?: string;
10
+ };
11
+ distance: number;
12
+ repo: string;
13
+ }
14
+ export interface SearchResponse {
15
+ results: SearchResult[];
16
+ usage: {
17
+ tokens_used: number;
18
+ credits_remaining: number;
19
+ };
20
+ }
21
+ export interface UsageResponse {
22
+ clerk_id: string;
23
+ credits: {
24
+ remaining_cents: number;
25
+ remaining: number;
26
+ };
27
+ usage: {
28
+ today: {
29
+ tokens: number;
30
+ requests: number;
31
+ };
32
+ this_month: {
33
+ tokens: number;
34
+ requests: number;
35
+ };
36
+ all_time: {
37
+ tokens: number;
38
+ requests: number;
39
+ };
40
+ };
41
+ }
42
+ export interface APIError {
43
+ error: {
44
+ code: string;
45
+ message: string;
46
+ };
47
+ }
48
+ export declare class APIClient {
49
+ private baseUrl;
50
+ private sessionToken;
51
+ constructor(baseUrl: string, sessionToken: string);
52
+ private request;
53
+ searchDocs(input: {
54
+ query: string;
55
+ limit?: number;
56
+ language?: 'python' | 'javascript';
57
+ }): Promise<SearchResponse>;
58
+ searchLangchainCode(input: {
59
+ query: string;
60
+ limit?: number;
61
+ language?: 'python' | 'javascript';
62
+ }): Promise<SearchResponse>;
63
+ searchLanggraphCode(input: {
64
+ query: string;
65
+ limit?: number;
66
+ language?: 'python' | 'javascript';
67
+ }): Promise<SearchResponse>;
68
+ searchDeepagentCode(input: {
69
+ query: string;
70
+ limit?: number;
71
+ language?: 'python' | 'javascript';
72
+ }): Promise<SearchResponse>;
73
+ getUsage(): Promise<UsageResponse>;
74
+ }
@@ -0,0 +1,67 @@
1
+ // Convert language from user-friendly names to API format
2
+ function mapLanguage(lang) {
3
+ if (!lang)
4
+ return undefined;
5
+ return lang === 'python' ? 'py' : 'js';
6
+ }
7
+ export class APIClient {
8
+ baseUrl;
9
+ sessionToken;
10
+ constructor(baseUrl, sessionToken) {
11
+ this.baseUrl = baseUrl;
12
+ this.sessionToken = sessionToken;
13
+ }
14
+ async request(method, endpoint, body) {
15
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
16
+ method,
17
+ headers: {
18
+ 'Authorization': `Bearer ${this.sessionToken}`,
19
+ 'Content-Type': 'application/json',
20
+ },
21
+ body: body ? JSON.stringify(body) : undefined,
22
+ });
23
+ const data = await response.json();
24
+ if (!response.ok) {
25
+ const error = data;
26
+ if (error.error?.code === 'INSUFFICIENT_CREDITS') {
27
+ throw new Error('Insufficient credits. Visit https://langchain-mcp.xyz to add more credits.');
28
+ }
29
+ if (error.error?.code === 'UNAUTHORIZED') {
30
+ throw new Error('Session expired. Run: langchain-mcp login');
31
+ }
32
+ throw new Error(error.error?.message || `API error: ${response.status}`);
33
+ }
34
+ return data;
35
+ }
36
+ async searchDocs(input) {
37
+ return this.request('POST', '/search/docs', {
38
+ query: input.query,
39
+ limit: input.limit,
40
+ language: mapLanguage(input.language),
41
+ });
42
+ }
43
+ async searchLangchainCode(input) {
44
+ return this.request('POST', '/search/langchain', {
45
+ query: input.query,
46
+ limit: input.limit,
47
+ language: mapLanguage(input.language),
48
+ });
49
+ }
50
+ async searchLanggraphCode(input) {
51
+ return this.request('POST', '/search/langgraph', {
52
+ query: input.query,
53
+ limit: input.limit,
54
+ language: mapLanguage(input.language),
55
+ });
56
+ }
57
+ async searchDeepagentCode(input) {
58
+ return this.request('POST', '/search/deepagent', {
59
+ query: input.query,
60
+ limit: input.limit,
61
+ language: mapLanguage(input.language),
62
+ });
63
+ }
64
+ async getUsage() {
65
+ return this.request('GET', '/usage');
66
+ }
67
+ }
@@ -0,0 +1,16 @@
1
+ export interface UserConfig {
2
+ api_key: string;
3
+ api_url: string;
4
+ user?: {
5
+ id: string;
6
+ email: string;
7
+ name: string | null;
8
+ credits: number;
9
+ };
10
+ }
11
+ export declare const DEFAULT_API_URL: string;
12
+ export declare const WEBSITE_URL: string;
13
+ export declare function loadConfig(): UserConfig | null;
14
+ export declare function saveConfig(config: UserConfig): void;
15
+ export declare function deleteConfig(): void;
16
+ export declare function getConfigPath(): string;
@@ -0,0 +1,31 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ const CONFIG_DIR = join(homedir(), '.config', 'langchain-mcp');
5
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
6
+ export const DEFAULT_API_URL = process.env.LANGCHAIN_MCP_API_URL || 'https://api.langchain-mcp.xyz';
7
+ export const WEBSITE_URL = process.env.LANGCHAIN_MCP_WEBSITE_URL || 'https://langchain-mcp.xyz';
8
+ export function loadConfig() {
9
+ try {
10
+ if (!existsSync(CONFIG_FILE)) {
11
+ return null;
12
+ }
13
+ const content = readFileSync(CONFIG_FILE, 'utf-8');
14
+ return JSON.parse(content);
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ export function saveConfig(config) {
21
+ mkdirSync(CONFIG_DIR, { recursive: true });
22
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
23
+ }
24
+ export function deleteConfig() {
25
+ if (existsSync(CONFIG_FILE)) {
26
+ unlinkSync(CONFIG_FILE);
27
+ }
28
+ }
29
+ export function getConfigPath() {
30
+ return CONFIG_FILE;
31
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { createServer } from './server.js';
4
+ async function main() {
5
+ const server = createServer();
6
+ const transport = new StdioServerTransport();
7
+ await server.connect(transport);
8
+ console.error('LangChain MCP server running on stdio');
9
+ }
10
+ main().catch((error) => {
11
+ console.error('Failed to start server:', error);
12
+ process.exit(1);
13
+ });
@@ -0,0 +1,2 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function createServer(): McpServer;
@@ -0,0 +1,153 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { z } from 'zod';
3
+ import { loadConfig } from './config.js';
4
+ import { APIClient } from './api-client.js';
5
+ // Schemas
6
+ const searchDocsSchema = z.object({
7
+ query: z.string().describe('Search query'),
8
+ limit: z.number().int().min(1).max(20).default(5).describe('Max results (1-20)'),
9
+ language: z.enum(['python', 'javascript']).optional().describe('Filter by language'),
10
+ });
11
+ const searchCodeSchema = z.object({
12
+ query: z.string().describe('Search query'),
13
+ limit: z.number().int().min(1).max(20).default(5).describe('Max results (1-20)'),
14
+ language: z.enum(['python', 'javascript']).optional().describe('Filter by language'),
15
+ });
16
+ function formatDocsResults(results) {
17
+ if (results.length === 0) {
18
+ return 'No results found.';
19
+ }
20
+ return results.map((r, i) => {
21
+ const meta = r.metadata;
22
+ const header = `## ${i + 1}. ${meta.filePath}`;
23
+ const info = [
24
+ meta.product && `Product: ${meta.product}`,
25
+ meta.language && `Language: ${meta.language}`,
26
+ meta.topic && `Topic: ${meta.topic}`,
27
+ ].filter(Boolean).join(' | ');
28
+ const content = r.content.length > 1500 ? r.content.slice(0, 1500) + '...' : r.content;
29
+ return `${header}\n${info}\n\n${content}`;
30
+ }).join('\n\n---\n\n');
31
+ }
32
+ function formatCodeResults(results) {
33
+ if (results.length === 0) {
34
+ return 'No results found.';
35
+ }
36
+ return results.map((r, i) => {
37
+ const meta = r.metadata;
38
+ const lang = meta.language === 'python' || meta.language === 'py' ? 'python' : 'typescript';
39
+ const header = `## ${i + 1}. ${meta.filePath}`;
40
+ const info = [
41
+ meta.codeType && `Type: ${meta.codeType}`,
42
+ meta.product && `Product: ${meta.product}`,
43
+ ].filter(Boolean).join(' | ');
44
+ const content = r.content.length > 2000 ? r.content.slice(0, 2000) + '...' : r.content;
45
+ return `${header}\n${info}\n\n\`\`\`${lang}\n${content}\n\`\`\``;
46
+ }).join('\n\n---\n\n');
47
+ }
48
+ const LOGIN_MESSAGE = `## Not logged in
49
+
50
+ Please login first by running this command in your terminal:
51
+
52
+ \`\`\`bash
53
+ langchain-mcp login
54
+ \`\`\`
55
+
56
+ This will open a browser for Google authentication.
57
+ After logging in, restart Claude to use the LangChain MCP tools.
58
+
59
+ For more info: https://langchain-mcp.xyz`;
60
+ export function createServer() {
61
+ const config = loadConfig();
62
+ const isLoggedIn = !!config;
63
+ const apiClient = isLoggedIn ? new APIClient(config.api_url, config.api_key) : null;
64
+ const server = new McpServer({
65
+ name: 'langchain-mcp',
66
+ version: '1.2.5',
67
+ });
68
+ // search_docs
69
+ server.tool('search_docs', 'Search documentation, references, and tutorials about LangChain, LangGraph, LangSmith, and DeepAgents.', searchDocsSchema.shape, async (input) => {
70
+ if (!apiClient) {
71
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
72
+ }
73
+ try {
74
+ const params = searchDocsSchema.parse(input);
75
+ const response = await apiClient.searchDocs(params);
76
+ const formatted = formatDocsResults(response.results);
77
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
78
+ return {
79
+ content: [{ type: 'text', text: formatted + footer }],
80
+ };
81
+ }
82
+ catch (error) {
83
+ return {
84
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
85
+ isError: true,
86
+ };
87
+ }
88
+ });
89
+ // search_langchain_code
90
+ server.tool('search_langchain_code', 'Search LangChain source code. Returns relevant code snippets.', searchCodeSchema.shape, async (input) => {
91
+ if (!apiClient) {
92
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
93
+ }
94
+ try {
95
+ const params = searchCodeSchema.parse(input);
96
+ const response = await apiClient.searchLangchainCode(params);
97
+ const formatted = formatCodeResults(response.results);
98
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
99
+ return {
100
+ content: [{ type: 'text', text: formatted + footer }],
101
+ };
102
+ }
103
+ catch (error) {
104
+ return {
105
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
106
+ isError: true,
107
+ };
108
+ }
109
+ });
110
+ // search_langgraph_code
111
+ server.tool('search_langgraph_code', 'Search LangGraph source code. Returns relevant code snippets.', searchCodeSchema.shape, async (input) => {
112
+ if (!apiClient) {
113
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
114
+ }
115
+ try {
116
+ const params = searchCodeSchema.parse(input);
117
+ const response = await apiClient.searchLanggraphCode(params);
118
+ const formatted = formatCodeResults(response.results);
119
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
120
+ return {
121
+ content: [{ type: 'text', text: formatted + footer }],
122
+ };
123
+ }
124
+ catch (error) {
125
+ return {
126
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
127
+ isError: true,
128
+ };
129
+ }
130
+ });
131
+ // search_deepagent_code
132
+ server.tool('search_deepagent_code', 'Search DeepAgent source code. Returns relevant code snippets.', searchCodeSchema.shape, async (input) => {
133
+ if (!apiClient) {
134
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
135
+ }
136
+ try {
137
+ const params = searchCodeSchema.parse(input);
138
+ const response = await apiClient.searchDeepagentCode(params);
139
+ const formatted = formatCodeResults(response.results);
140
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
141
+ return {
142
+ content: [{ type: 'text', text: formatted + footer }],
143
+ };
144
+ }
145
+ catch (error) {
146
+ return {
147
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
148
+ isError: true,
149
+ };
150
+ }
151
+ });
152
+ return server;
153
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "langchain-mcp",
3
+ "version": "1.2.5",
4
+ "description": "Give your AI assistant complete LangChain, LangGraph & LangSmith knowledge",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "langchain-mcp": "dist/bin/cli.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "dev": "tsx watch src/index.ts",
16
+ "build": "tsc",
17
+ "start": "node dist/index.js",
18
+ "cli": "tsx bin/cli.ts"
19
+ },
20
+ "keywords": [
21
+ "mcp",
22
+ "langchain",
23
+ "langgraph",
24
+ "langsmith",
25
+ "claude",
26
+ "ai",
27
+ "documentation"
28
+ ],
29
+ "author": "baixianger",
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/baixianger/langchain-mcp"
34
+ },
35
+ "homepage": "https://langchain-mcp.xyz",
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.12.0",
38
+ "commander": "^12.1.0",
39
+ "open": "^10.1.0",
40
+ "zod": "^3.24.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "tsx": "^4.19.0",
45
+ "typescript": "^5.7.0"
46
+ }
47
+ }