langchain-mcp 1.0.0

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,56 @@
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 GitHub/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_langchain_docs` | Search documentation |
41
+ | `search_langchain_code` | Search source code |
42
+ | `search_langchain` | Hybrid search (docs + code) |
43
+
44
+ ## Free Credits
45
+
46
+ New users get **$5 free credits** (~150 searches).
47
+
48
+ ## Links
49
+
50
+ - Website: https://langchain-mcp.xyz
51
+ - GitHub: https://github.com/baixianger/langchain-mcp
52
+ - Sponsor: https://github.com/sponsors/baixianger
53
+
54
+ ## License
55
+
56
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import http from 'http';
4
+ import open from 'open';
5
+ import { loadConfig, saveConfig, deleteConfig, getConfigPath, DEFAULT_API_URL } from '../src/config.js';
6
+ import { APIClient } from '../src/api-client.js';
7
+ const program = new Command();
8
+ program
9
+ .name('langchain-mcp')
10
+ .description('CLI for LangChain MCP server')
11
+ .version('1.0.0');
12
+ /**
13
+ * Login command - supports Google and GitHub OAuth
14
+ */
15
+ program
16
+ .command('login')
17
+ .description('Login to LangChain MCP service')
18
+ .option('--provider <provider>', 'OAuth provider: google or github', 'google')
19
+ .option('--no-browser', 'Print URL instead of opening browser')
20
+ .option('--api-url <url>', 'API server URL', DEFAULT_API_URL)
21
+ .action(async (options) => {
22
+ const existingConfig = loadConfig();
23
+ if (existingConfig) {
24
+ console.log('Already logged in.');
25
+ console.log('Run "langchain-mcp logout" first to log out.');
26
+ return;
27
+ }
28
+ const provider = options.provider.toLowerCase();
29
+ if (provider !== 'google' && provider !== 'github') {
30
+ console.error('Invalid provider. Use --provider google or --provider github');
31
+ process.exit(1);
32
+ }
33
+ await loginWithWebFlow(options.apiUrl, provider, options.browser);
34
+ });
35
+ /**
36
+ * Web Flow login - opens browser for OAuth
37
+ */
38
+ async function loginWithWebFlow(apiUrl, provider, openBrowser) {
39
+ const port = 9876;
40
+ const callbackUrl = `http://localhost:${port}/callback`;
41
+ const server = http.createServer(async (req, res) => {
42
+ const url = new URL(req.url, `http://localhost:${port}`);
43
+ if (url.pathname === '/callback') {
44
+ const apiKey = url.searchParams.get('api_key');
45
+ const userJson = url.searchParams.get('user');
46
+ const error = url.searchParams.get('error');
47
+ if (error) {
48
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
49
+ res.end(`
50
+ <!DOCTYPE html>
51
+ <html>
52
+ <head><title>Login Failed</title></head>
53
+ <body style="font-family: system-ui; text-align: center; padding: 50px;">
54
+ <h1>❌ Login Failed</h1>
55
+ <p>${error}</p>
56
+ </body>
57
+ </html>
58
+ `);
59
+ console.error(`\nLogin failed: ${error}`);
60
+ server.close();
61
+ process.exit(1);
62
+ }
63
+ if (apiKey && userJson) {
64
+ try {
65
+ const user = JSON.parse(userJson);
66
+ // Save config
67
+ saveConfig({
68
+ api_key: apiKey,
69
+ api_url: apiUrl,
70
+ user,
71
+ });
72
+ console.log(`\n✅ Logged in as ${user.email}`);
73
+ console.log(`💰 Credits: $${user.credits.toFixed(2)} remaining`);
74
+ console.log(`📁 Config saved to ${getConfigPath()}`);
75
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
76
+ res.end(`
77
+ <!DOCTYPE html>
78
+ <html>
79
+ <head><title>Login Successful</title></head>
80
+ <body style="font-family: system-ui; text-align: center; padding: 50px;">
81
+ <h1>✅ Login Successful!</h1>
82
+ <p>Welcome, ${user.name || user.email}!</p>
83
+ <p>You can close this window and return to your terminal.</p>
84
+ </body>
85
+ </html>
86
+ `);
87
+ setTimeout(() => {
88
+ server.close();
89
+ process.exit(0);
90
+ }, 1000);
91
+ }
92
+ catch (err) {
93
+ res.writeHead(400);
94
+ res.end('Login failed: invalid response');
95
+ server.close();
96
+ process.exit(1);
97
+ }
98
+ }
99
+ else {
100
+ res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
101
+ res.end(`
102
+ <!DOCTYPE html>
103
+ <html>
104
+ <head><title>Login Failed</title></head>
105
+ <body style="font-family: system-ui; text-align: center; padding: 50px;">
106
+ <h1>❌ Login Failed</h1>
107
+ <p>Missing API key</p>
108
+ </body>
109
+ </html>
110
+ `);
111
+ server.close();
112
+ process.exit(1);
113
+ }
114
+ }
115
+ else {
116
+ res.writeHead(404);
117
+ res.end('Not found');
118
+ }
119
+ });
120
+ server.listen(port, () => {
121
+ // OAuth URL via our API
122
+ const authUrl = `${apiUrl}/auth/${provider}?callback=${encodeURIComponent(callbackUrl)}`;
123
+ const providerName = provider === 'google' ? 'Google' : 'GitHub';
124
+ console.log(`🔐 Logging in with ${providerName}...`);
125
+ if (openBrowser) {
126
+ console.log('Opening browser for login...');
127
+ open(authUrl);
128
+ }
129
+ else {
130
+ console.log('Open this URL in your browser:');
131
+ console.log(authUrl);
132
+ }
133
+ console.log(`\nWaiting for login callback on port ${port}...`);
134
+ });
135
+ // Timeout after 5 minutes
136
+ setTimeout(() => {
137
+ console.log('\n⏰ Login timeout. Please try again.');
138
+ server.close();
139
+ process.exit(1);
140
+ }, 5 * 60 * 1000);
141
+ }
142
+ /**
143
+ * Status command - show current login status and usage
144
+ */
145
+ program
146
+ .command('status')
147
+ .description('Show current login status and usage')
148
+ .action(async () => {
149
+ const config = loadConfig();
150
+ if (!config) {
151
+ console.log('❌ Not logged in.');
152
+ console.log('Run "langchain-mcp login" to log in.');
153
+ return;
154
+ }
155
+ console.log(`👤 Logged in as: ${config.user?.email || 'Unknown'}`);
156
+ console.log(`📁 Config: ${getConfigPath()}`);
157
+ try {
158
+ const client = new APIClient(config.api_url, config.api_key);
159
+ const usage = await client.getUsage();
160
+ console.log(`\n💰 Credits: $${usage.credits.remaining.toFixed(2)} remaining`);
161
+ console.log(`\n📊 Usage:`);
162
+ console.log(` Today: ${usage.usage.today.tokens.toLocaleString()} tokens (${usage.usage.today.requests} requests)`);
163
+ console.log(` This month: ${usage.usage.this_month.tokens.toLocaleString()} tokens (${usage.usage.this_month.requests} requests)`);
164
+ console.log(` All time: ${usage.usage.all_time.tokens.toLocaleString()} tokens (${usage.usage.all_time.requests} requests)`);
165
+ }
166
+ catch (error) {
167
+ console.log(`\n⚠️ Could not fetch usage: ${error.message}`);
168
+ console.log('Your API key may be invalid. Run "langchain-mcp login" to log in again.');
169
+ }
170
+ });
171
+ /**
172
+ * Logout command - remove local credentials
173
+ */
174
+ program
175
+ .command('logout')
176
+ .description('Logout and remove local credentials')
177
+ .action(async () => {
178
+ const config = loadConfig();
179
+ if (!config) {
180
+ console.log('Not logged in.');
181
+ return;
182
+ }
183
+ deleteConfig();
184
+ console.log('✅ Logged out successfully.');
185
+ });
186
+ program.parse();
@@ -0,0 +1,73 @@
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
+ product?: string;
57
+ language?: string;
58
+ }): Promise<SearchResponse>;
59
+ searchCode(input: {
60
+ query: string;
61
+ limit?: number;
62
+ product?: string;
63
+ language?: string;
64
+ code_type?: string;
65
+ }): Promise<SearchResponse>;
66
+ searchHybrid(input: {
67
+ query: string;
68
+ limit?: number;
69
+ include_docs?: boolean;
70
+ include_code?: boolean;
71
+ }): Promise<SearchResponse>;
72
+ getUsage(): Promise<UsageResponse>;
73
+ }
@@ -0,0 +1,42 @@
1
+ export class APIClient {
2
+ baseUrl;
3
+ sessionToken;
4
+ constructor(baseUrl, sessionToken) {
5
+ this.baseUrl = baseUrl;
6
+ this.sessionToken = sessionToken;
7
+ }
8
+ async request(method, endpoint, body) {
9
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
10
+ method,
11
+ headers: {
12
+ 'Authorization': `Bearer ${this.sessionToken}`,
13
+ 'Content-Type': 'application/json',
14
+ },
15
+ body: body ? JSON.stringify(body) : undefined,
16
+ });
17
+ const data = await response.json();
18
+ if (!response.ok) {
19
+ const error = data;
20
+ if (error.error?.code === 'INSUFFICIENT_CREDITS') {
21
+ throw new Error('Insufficient credits. Visit https://langchain-mcp.xyz to add more credits.');
22
+ }
23
+ if (error.error?.code === 'UNAUTHORIZED') {
24
+ throw new Error('Session expired. Run: langchain-mcp login');
25
+ }
26
+ throw new Error(error.error?.message || `API error: ${response.status}`);
27
+ }
28
+ return data;
29
+ }
30
+ async searchDocs(input) {
31
+ return this.request('POST', '/search/docs', input);
32
+ }
33
+ async searchCode(input) {
34
+ return this.request('POST', '/search/code', input);
35
+ }
36
+ async searchHybrid(input) {
37
+ return this.request('POST', '/search/hybrid', input);
38
+ }
39
+ async getUsage() {
40
+ return this.request('GET', '/usage');
41
+ }
42
+ }
@@ -0,0 +1,15 @@
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 function loadConfig(): UserConfig | null;
13
+ export declare function saveConfig(config: UserConfig): void;
14
+ export declare function deleteConfig(): void;
15
+ export declare function getConfigPath(): string;
@@ -0,0 +1,30 @@
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 function loadConfig() {
8
+ try {
9
+ if (!existsSync(CONFIG_FILE)) {
10
+ return null;
11
+ }
12
+ const content = readFileSync(CONFIG_FILE, 'utf-8');
13
+ return JSON.parse(content);
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ export function saveConfig(config) {
20
+ mkdirSync(CONFIG_DIR, { recursive: true });
21
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
22
+ }
23
+ export function deleteConfig() {
24
+ if (existsSync(CONFIG_FILE)) {
25
+ unlinkSync(CONFIG_FILE);
26
+ }
27
+ }
28
+ export function getConfigPath() {
29
+ return CONFIG_FILE;
30
+ }
@@ -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,155 @@
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
+ product: z.enum(['langsmith', 'langchain', 'langgraph', 'deepagents', 'oss']).optional().describe('Filter by product'),
10
+ language: z.enum(['python', 'javascript']).optional().describe('Filter by language'),
11
+ });
12
+ const searchCodeSchema = z.object({
13
+ query: z.string().describe('Search query'),
14
+ limit: z.number().int().min(1).max(20).default(5).describe('Max results (1-20)'),
15
+ product: z.enum(['langchain', 'langgraph', 'deepagents']).optional().describe('Filter by product'),
16
+ language: z.enum(['python', 'javascript']).optional().describe('Filter by language'),
17
+ code_type: z.enum(['function', 'class', 'module']).optional().describe('Filter by code type'),
18
+ });
19
+ const searchHybridSchema = z.object({
20
+ query: z.string().describe('Search query'),
21
+ limit: z.number().int().min(1).max(20).default(10).describe('Max results (1-20)'),
22
+ include_docs: z.boolean().default(true).describe('Include documentation'),
23
+ include_code: z.boolean().default(true).describe('Include source code'),
24
+ });
25
+ function formatDocsResults(results) {
26
+ if (results.length === 0) {
27
+ return 'No results found.';
28
+ }
29
+ return results.map((r, i) => {
30
+ const meta = r.metadata;
31
+ const header = `## ${i + 1}. ${meta.filePath}`;
32
+ const info = [
33
+ meta.product && `Product: ${meta.product}`,
34
+ meta.language && `Language: ${meta.language}`,
35
+ meta.topic && `Topic: ${meta.topic}`,
36
+ ].filter(Boolean).join(' | ');
37
+ const content = r.content.length > 1500 ? r.content.slice(0, 1500) + '...' : r.content;
38
+ return `${header}\n${info}\n\n${content}`;
39
+ }).join('\n\n---\n\n');
40
+ }
41
+ function formatCodeResults(results) {
42
+ if (results.length === 0) {
43
+ return 'No results found.';
44
+ }
45
+ return results.map((r, i) => {
46
+ const meta = r.metadata;
47
+ const lang = meta.language === 'python' ? 'python' : 'typescript';
48
+ const header = `## ${i + 1}. ${meta.filePath}`;
49
+ const info = [
50
+ meta.codeType && `Type: ${meta.codeType}`,
51
+ meta.product && `Product: ${meta.product}`,
52
+ ].filter(Boolean).join(' | ');
53
+ const content = r.content.length > 2000 ? r.content.slice(0, 2000) + '...' : r.content;
54
+ return `${header}\n${info}\n\n\`\`\`${lang}\n${content}\n\`\`\``;
55
+ }).join('\n\n---\n\n');
56
+ }
57
+ const LOGIN_MESSAGE = `## Not logged in
58
+
59
+ Please login first by running this command in your terminal:
60
+
61
+ \`\`\`bash
62
+ langchain-mcp login
63
+ \`\`\`
64
+
65
+ This will open a browser for GitHub/Google authentication.
66
+ After logging in, restart Claude to use the LangChain MCP tools.
67
+
68
+ For more info: https://langchain-mcp.xyz`;
69
+ export function createServer() {
70
+ const config = loadConfig();
71
+ const isLoggedIn = !!config;
72
+ const apiClient = isLoggedIn ? new APIClient(config.api_url, config.api_key) : null;
73
+ const server = new McpServer({
74
+ name: 'langchain-mcp',
75
+ version: '1.0.0',
76
+ });
77
+ // search_langchain_docs
78
+ server.tool('search_langchain_docs', 'Search LangChain documentation. Returns relevant docs based on your query.', searchDocsSchema.shape, async (input) => {
79
+ if (!apiClient) {
80
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
81
+ }
82
+ try {
83
+ const params = searchDocsSchema.parse(input);
84
+ const response = await apiClient.searchDocs(params);
85
+ const formatted = formatDocsResults(response.results);
86
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
87
+ return {
88
+ content: [{ type: 'text', text: formatted + footer }],
89
+ };
90
+ }
91
+ catch (error) {
92
+ return {
93
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
94
+ isError: true,
95
+ };
96
+ }
97
+ });
98
+ // search_langchain_code
99
+ server.tool('search_langchain_code', 'Search LangChain source code. Returns relevant code snippets.', searchCodeSchema.shape, async (input) => {
100
+ if (!apiClient) {
101
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
102
+ }
103
+ try {
104
+ const params = searchCodeSchema.parse(input);
105
+ const response = await apiClient.searchCode(params);
106
+ const formatted = formatCodeResults(response.results);
107
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
108
+ return {
109
+ content: [{ type: 'text', text: formatted + footer }],
110
+ };
111
+ }
112
+ catch (error) {
113
+ return {
114
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
115
+ isError: true,
116
+ };
117
+ }
118
+ });
119
+ // search_langchain
120
+ server.tool('search_langchain', 'Hybrid search across LangChain docs and code.', searchHybridSchema.shape, async (input) => {
121
+ if (!apiClient) {
122
+ return { content: [{ type: 'text', text: LOGIN_MESSAGE }] };
123
+ }
124
+ try {
125
+ const params = searchHybridSchema.parse(input);
126
+ const response = await apiClient.searchHybrid(params);
127
+ // Format mixed results
128
+ const formatted = response.results.map((r, i) => {
129
+ const meta = r.metadata;
130
+ const isCode = r.repo !== 'docs';
131
+ const header = `## ${i + 1}. [${isCode ? 'Code' : 'Docs'}] ${meta.filePath}`;
132
+ if (isCode) {
133
+ const lang = meta.language === 'python' ? 'python' : 'typescript';
134
+ const content = r.content.length > 1500 ? r.content.slice(0, 1500) + '...' : r.content;
135
+ return `${header}\n\n\`\`\`${lang}\n${content}\n\`\`\``;
136
+ }
137
+ else {
138
+ const content = r.content.length > 1500 ? r.content.slice(0, 1500) + '...' : r.content;
139
+ return `${header}\n\n${content}`;
140
+ }
141
+ }).join('\n\n---\n\n');
142
+ const footer = `\n\n---\n_${response.results.length} results | ${response.usage.tokens_used} tokens | $${response.usage.credits_remaining.toFixed(2)} remaining_`;
143
+ return {
144
+ content: [{ type: 'text', text: formatted + footer }],
145
+ };
146
+ }
147
+ catch (error) {
148
+ return {
149
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
150
+ isError: true,
151
+ };
152
+ }
153
+ });
154
+ return server;
155
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "langchain-mcp",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for LangChain documentation and code search",
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
+ }