langchain-mcp-tools 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
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.
- langchain_mcp_tools/__init__.py +3 -0
- langchain_mcp_tools/langchain_mcp_tools.py +186 -64
- {langchain_mcp_tools-0.2.2.dist-info → langchain_mcp_tools-0.2.4.dist-info}/METADATA +28 -8
- langchain_mcp_tools-0.2.4.dist-info/RECORD +8 -0
- {langchain_mcp_tools-0.2.2.dist-info → langchain_mcp_tools-0.2.4.dist-info}/WHEEL +1 -1
- langchain_mcp_tools-0.2.2.dist-info/RECORD +0 -8
- {langchain_mcp_tools-0.2.2.dist-info → langchain_mcp_tools-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {langchain_mcp_tools-0.2.2.dist-info → langchain_mcp_tools-0.2.4.dist-info}/top_level.txt +0 -0
langchain_mcp_tools/__init__.py
CHANGED
@@ -32,12 +32,37 @@ try:
|
|
32
32
|
from pydantic import BaseModel
|
33
33
|
# from pydantic_core import to_json
|
34
34
|
except ImportError as e:
|
35
|
-
print(f
|
36
|
-
print(
|
35
|
+
print(f"\nError: Required package not found: {e}")
|
36
|
+
print("Please ensure all required packages are installed\n")
|
37
37
|
sys.exit(1)
|
38
38
|
|
39
39
|
|
40
40
|
class McpServerCommandBasedConfig(TypedDict):
|
41
|
+
"""Configuration for an MCP server launched via command line.
|
42
|
+
|
43
|
+
This configuration is used for local MCP servers that are started as child
|
44
|
+
processes using the stdio client. It defines the command to run, optional
|
45
|
+
arguments, environment variables, working directory, and error logging
|
46
|
+
options.
|
47
|
+
|
48
|
+
Attributes:
|
49
|
+
command: The executable command to run (e.g., "npx", "uvx", "python").
|
50
|
+
args: Optional list of command-line arguments to pass to the command.
|
51
|
+
env: Optional dictionary of environment variables to set for the
|
52
|
+
process.
|
53
|
+
cwd: Optional working directory where the command will be executed.
|
54
|
+
errlog: Optional file-like object for redirecting the server's stderr
|
55
|
+
output.
|
56
|
+
|
57
|
+
Example:
|
58
|
+
{
|
59
|
+
"command": "npx",
|
60
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."],
|
61
|
+
"env": {"NODE_ENV": "production"},
|
62
|
+
"cwd": "/path/to/working/directory",
|
63
|
+
"errlog": open("server.log", "w")
|
64
|
+
}
|
65
|
+
"""
|
41
66
|
command: str
|
42
67
|
args: NotRequired[list[str] | None]
|
43
68
|
env: NotRequired[dict[str, str] | None]
|
@@ -46,21 +71,88 @@ class McpServerCommandBasedConfig(TypedDict):
|
|
46
71
|
|
47
72
|
|
48
73
|
class McpServerUrlBasedConfig(TypedDict):
|
74
|
+
"""Configuration for a remote MCP server accessed via URL.
|
75
|
+
|
76
|
+
This configuration is used for remote MCP servers that are accessed via
|
77
|
+
HTTP/HTTPS (Server-Sent Events) or WebSocket connections. It defines the
|
78
|
+
URL to connect to and optional HTTP headers for authentication.
|
79
|
+
|
80
|
+
Attributes:
|
81
|
+
url: The URL of the remote MCP server. For SSE servers,
|
82
|
+
use http:// or https:// prefix. For WebSocket servers,
|
83
|
+
use ws:// or wss:// prefix.
|
84
|
+
headers: Optional dictionary of HTTP headers to include in the request,
|
85
|
+
typically used for authentication (e.g., bearer tokens).
|
86
|
+
|
87
|
+
Example for SSE server:
|
88
|
+
{
|
89
|
+
"url": "https://example.com/mcp/sse",
|
90
|
+
"headers": {"Authorization": "Bearer token123"}
|
91
|
+
}
|
92
|
+
|
93
|
+
Example for WebSocket server:
|
94
|
+
{
|
95
|
+
"url": "wss://example.com/mcp/ws"
|
96
|
+
}
|
97
|
+
"""
|
49
98
|
url: str
|
50
99
|
headers: NotRequired[dict[str, str] | None]
|
51
100
|
|
52
101
|
|
53
|
-
|
54
|
-
|
55
|
-
|
102
|
+
# Type for a single MCP server configuration, which can be either
|
103
|
+
# command-based or URL-based.
|
104
|
+
SingleMcpServerConfig = McpServerCommandBasedConfig | McpServerUrlBasedConfig
|
105
|
+
"""Configuration for a single MCP server, either command-based or URL-based.
|
106
|
+
|
107
|
+
This type represents the configuration for a single MCP server, which can
|
108
|
+
be either:
|
109
|
+
1. A local server launched via command line (McpServerCommandBasedConfig)
|
110
|
+
2. A remote server accessed via URL (McpServerUrlBasedConfig)
|
111
|
+
|
112
|
+
The type is determined by the presence of either the "command" key
|
113
|
+
(for command-based) or the "url" key (for URL-based).
|
114
|
+
"""
|
115
|
+
|
116
|
+
# Configuration dictionary for multiple MCP servers
|
117
|
+
McpServersConfig = dict[str, SingleMcpServerConfig]
|
118
|
+
"""Configuration dictionary for multiple MCP servers.
|
119
|
+
|
120
|
+
A dictionary mapping server names (as strings) to their respective
|
121
|
+
configurations. Each server name acts as a logical identifier used for logging
|
122
|
+
and debugging. The configuration for each server can be either command-based
|
123
|
+
or URL-based.
|
124
|
+
|
125
|
+
Example:
|
126
|
+
{
|
127
|
+
"filesystem": {
|
128
|
+
"command": "npx",
|
129
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
|
130
|
+
},
|
131
|
+
"fetch": {
|
132
|
+
"command": "uvx",
|
133
|
+
"args": ["mcp-server-fetch"]
|
134
|
+
},
|
135
|
+
"remote-server": {
|
136
|
+
"url": "https://example.com/mcp/sse",
|
137
|
+
"headers": {"Authorization": "Bearer token123"}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
"""
|
56
141
|
|
57
142
|
|
58
143
|
def fix_schema(schema: dict) -> dict:
|
59
|
-
"""Converts JSON Schema
|
144
|
+
"""Converts JSON Schema "type": ["string", "null"] to "anyOf" format.
|
145
|
+
|
146
|
+
Args:
|
147
|
+
schema: A JSON schema dictionary
|
148
|
+
|
149
|
+
Returns:
|
150
|
+
Modified schema with converted type formats
|
151
|
+
"""
|
60
152
|
if isinstance(schema, dict):
|
61
|
-
if
|
62
|
-
schema[
|
63
|
-
del schema[
|
153
|
+
if "type" in schema and isinstance(schema["type"], list):
|
154
|
+
schema["anyOf"] = [{"type": t} for t in schema["type"]]
|
155
|
+
del schema["type"] # Remove "type" and standardize to "anyOf"
|
64
156
|
for key, value in schema.items():
|
65
157
|
schema[key] = fix_schema(value) # Apply recursively
|
66
158
|
return schema
|
@@ -76,12 +168,11 @@ Transport: TypeAlias = tuple[
|
|
76
168
|
|
77
169
|
async def spawn_mcp_server_and_get_transport(
|
78
170
|
server_name: str,
|
79
|
-
server_config:
|
171
|
+
server_config: SingleMcpServerConfig,
|
80
172
|
exit_stack: AsyncExitStack,
|
81
173
|
logger: logging.Logger = logging.getLogger(__name__)
|
82
174
|
) -> Transport:
|
83
|
-
"""
|
84
|
-
Spawns an MCP server process and establishes communication channels.
|
175
|
+
"""Spawns an MCP server process and establishes communication channels.
|
85
176
|
|
86
177
|
Args:
|
87
178
|
server_name: Server instance name to use for better logging
|
@@ -97,19 +188,20 @@ async def spawn_mcp_server_and_get_transport(
|
|
97
188
|
"""
|
98
189
|
try:
|
99
190
|
logger.info(f'MCP server "{server_name}": '
|
100
|
-
f
|
191
|
+
f"initializing with: {server_config}")
|
101
192
|
|
102
|
-
url_str = str(server_config.get(
|
103
|
-
headers =
|
193
|
+
url_str = str(server_config.get("url")) # None becomes "None"
|
194
|
+
headers = (cast(McpServerUrlBasedConfig, server_config)
|
195
|
+
.get("headers", None))
|
104
196
|
# no exception thrown even for a malformed URL
|
105
197
|
url_scheme = urlparse(url_str).scheme
|
106
198
|
|
107
|
-
if url_scheme in (
|
199
|
+
if url_scheme in ("http", "https"):
|
108
200
|
transport = await exit_stack.enter_async_context(
|
109
201
|
sse_client(url_str, headers=headers)
|
110
202
|
)
|
111
203
|
|
112
|
-
elif url_scheme in (
|
204
|
+
elif url_scheme in ("ws", "wss"):
|
113
205
|
transport = await exit_stack.enter_async_context(
|
114
206
|
websocket_client(url_str)
|
115
207
|
)
|
@@ -119,21 +211,21 @@ async def spawn_mcp_server_and_get_transport(
|
|
119
211
|
# To avoid confusion, it was decided to automatically append it
|
120
212
|
# to the env if not explicitly set by the config.
|
121
213
|
config = cast(McpServerCommandBasedConfig, server_config)
|
122
|
-
# env = config.get(
|
123
|
-
env_val = config.get(
|
214
|
+
# env = config.get("env", {}) does't work since it can yield None
|
215
|
+
env_val = config.get("env")
|
124
216
|
env = {} if env_val is None else dict(env_val)
|
125
|
-
if
|
126
|
-
env[
|
217
|
+
if "PATH" not in env:
|
218
|
+
env["PATH"] = os.environ.get("PATH", "")
|
127
219
|
|
128
220
|
# Use stdio client for commands
|
129
|
-
# args = config.get(
|
130
|
-
args_val = config.get(
|
221
|
+
# args = config.get("args", []) does't work since it can yield None
|
222
|
+
args_val = config.get("args")
|
131
223
|
args = [] if args_val is None else list(args_val)
|
132
224
|
server_parameters = StdioServerParameters(
|
133
|
-
command=config.get(
|
225
|
+
command=config.get("command", ""),
|
134
226
|
args=args,
|
135
227
|
env=env,
|
136
|
-
cwd=config.get(
|
228
|
+
cwd=config.get("cwd", None)
|
137
229
|
)
|
138
230
|
|
139
231
|
# Initialize stdio client and register it with exit stack for
|
@@ -145,13 +237,14 @@ async def spawn_mcp_server_and_get_transport(
|
|
145
237
|
# `errlog: TextIO`. I once included `stderr: int` for
|
146
238
|
# compatibility with the TypeScript version, but decided to
|
147
239
|
# follow the Python SDK more closely.
|
148
|
-
errlog_val = server_config
|
149
|
-
|
240
|
+
errlog_val = (cast(McpServerCommandBasedConfig, server_config)
|
241
|
+
.get("errlog"))
|
242
|
+
kwargs = {"errlog": errlog_val} if errlog_val is not None else {}
|
150
243
|
transport = await exit_stack.enter_async_context(
|
151
244
|
stdio_client(server_parameters, **kwargs)
|
152
245
|
)
|
153
246
|
except Exception as e:
|
154
|
-
logger.error(f
|
247
|
+
logger.error(f"Error spawning MCP server: {str(e)}")
|
155
248
|
raise
|
156
249
|
|
157
250
|
return transport
|
@@ -163,8 +256,7 @@ async def get_mcp_server_tools(
|
|
163
256
|
exit_stack: AsyncExitStack,
|
164
257
|
logger: logging.Logger = logging.getLogger(__name__)
|
165
258
|
) -> list[BaseTool]:
|
166
|
-
"""
|
167
|
-
Retrieves and converts MCP server tools to LangChain format.
|
259
|
+
"""Retrieves and converts MCP server tools to LangChain format.
|
168
260
|
|
169
261
|
Args:
|
170
262
|
server_name: Server instance name to use for better logging
|
@@ -211,8 +303,8 @@ async def get_mcp_server_tools(
|
|
211
303
|
|
212
304
|
# Define adapter class to convert MCP tool to LangChain format
|
213
305
|
class McpToLangChainAdapter(BaseTool):
|
214
|
-
name: str = tool.name or
|
215
|
-
description: str = tool.description or
|
306
|
+
name: str = tool.name or "NO NAME"
|
307
|
+
description: str = tool.description or ""
|
216
308
|
# Convert JSON schema to Pydantic model for argument validation
|
217
309
|
args_schema: type[BaseModel] = jsonschema_to_pydantic(
|
218
310
|
fix_schema(tool.inputSchema) # Apply schema conversion
|
@@ -221,31 +313,40 @@ async def get_mcp_server_tools(
|
|
221
313
|
|
222
314
|
def _run(self, **kwargs: Any) -> NoReturn:
|
223
315
|
raise NotImplementedError(
|
224
|
-
|
316
|
+
"MCP tools only support async operations"
|
225
317
|
)
|
226
318
|
|
227
319
|
async def _arun(self, **kwargs: Any) -> Any:
|
228
|
-
"""
|
229
|
-
|
320
|
+
"""Asynchronously executes the tool with given arguments.
|
321
|
+
|
230
322
|
Logs input/output and handles errors.
|
323
|
+
|
324
|
+
Args:
|
325
|
+
**kwargs: Arguments to be passed to the MCP tool
|
326
|
+
|
327
|
+
Returns:
|
328
|
+
Formatted response from the MCP tool as a string
|
329
|
+
|
330
|
+
Raises:
|
331
|
+
ToolException: If the tool execution fails
|
231
332
|
"""
|
232
333
|
logger.info(f'MCP tool "{server_name}"/"{tool.name}" '
|
233
|
-
f
|
334
|
+
f"received input: {kwargs}")
|
234
335
|
|
235
336
|
try:
|
236
337
|
result = await session.call_tool(self.name, kwargs)
|
237
338
|
|
238
|
-
if hasattr(result,
|
339
|
+
if hasattr(result, "isError") and result.isError:
|
239
340
|
raise ToolException(
|
240
|
-
f
|
341
|
+
f"Tool execution failed: {result.content}"
|
241
342
|
)
|
242
343
|
|
243
|
-
if not hasattr(result,
|
344
|
+
if not hasattr(result, "content"):
|
244
345
|
return str(result)
|
245
346
|
|
246
347
|
# The return type of `BaseTool`'s `arun` is `str`.
|
247
348
|
try:
|
248
|
-
result_content_text =
|
349
|
+
result_content_text = "\n\n".join(
|
249
350
|
item.text
|
250
351
|
for item in result.content
|
251
352
|
if isinstance(item, mcp_types.TextContent)
|
@@ -259,20 +360,20 @@ async def get_mcp_server_tools(
|
|
259
360
|
|
260
361
|
except KeyError as e:
|
261
362
|
result_content_text = (
|
262
|
-
f
|
263
|
-
f
|
363
|
+
f"Error in parsing result.content: {str(e)}; "
|
364
|
+
f"contents: {repr(result.content)}"
|
264
365
|
)
|
265
366
|
|
266
367
|
# Log rough result size for monitoring
|
267
368
|
size = len(result_content_text.encode())
|
268
369
|
logger.info(f'MCP tool "{server_name}"/"{tool.name}" '
|
269
|
-
f
|
370
|
+
f"received result (size: {size})")
|
270
371
|
|
271
372
|
# If no text content, return a clear message
|
272
373
|
# describing the situation.
|
273
374
|
result_content_text = (
|
274
375
|
result_content_text or
|
275
|
-
|
376
|
+
"No text content available in response"
|
276
377
|
)
|
277
378
|
|
278
379
|
return result_content_text
|
@@ -280,21 +381,21 @@ async def get_mcp_server_tools(
|
|
280
381
|
except Exception as e:
|
281
382
|
logger.warn(
|
282
383
|
f'MCP tool "{server_name}"/"{tool.name}" '
|
283
|
-
f
|
384
|
+
f"caused error: {str(e)}"
|
284
385
|
)
|
285
386
|
if self.handle_tool_error:
|
286
|
-
return f
|
387
|
+
return f"Error executing MCP tool: {str(e)}"
|
287
388
|
raise
|
288
389
|
|
289
390
|
langchain_tools.append(McpToLangChainAdapter())
|
290
391
|
|
291
392
|
# Log available tools for debugging
|
292
393
|
logger.info(f'MCP server "{server_name}": {len(langchain_tools)} '
|
293
|
-
f
|
394
|
+
f"tool(s) available:")
|
294
395
|
for tool in langchain_tools:
|
295
|
-
logger.info(f
|
396
|
+
logger.info(f"- {tool.name}")
|
296
397
|
except Exception as e:
|
297
|
-
logger.error(f
|
398
|
+
logger.error(f"Error getting MCP tools: {str(e)}")
|
298
399
|
raise
|
299
400
|
|
300
401
|
return langchain_tools
|
@@ -302,19 +403,36 @@ async def get_mcp_server_tools(
|
|
302
403
|
|
303
404
|
# A very simple pre-configured logger for fallback
|
304
405
|
def init_logger() -> logging.Logger:
|
406
|
+
"""Creates a simple pre-configured logger.
|
407
|
+
|
408
|
+
Returns:
|
409
|
+
A configured Logger instance
|
410
|
+
"""
|
305
411
|
logging.basicConfig(
|
306
412
|
level=logging.INFO, # logging.DEBUG,
|
307
|
-
format=
|
413
|
+
format="\x1b[90m[%(levelname)s]\x1b[0m %(message)s"
|
308
414
|
)
|
309
415
|
return logging.getLogger()
|
310
416
|
|
311
417
|
|
312
418
|
# Type hint for cleanup function
|
313
419
|
McpServerCleanupFn = Callable[[], Awaitable[None]]
|
420
|
+
"""Type for the async cleanup function returned by
|
421
|
+
convert_mcp_to_langchain_tools.
|
422
|
+
|
423
|
+
This represents an asynchronous function that takes no arguments and returns
|
424
|
+
nothing. It's used to properly shut down all MCP server connections and clean
|
425
|
+
up resources when the tools are no longer needed.
|
426
|
+
|
427
|
+
Example usage:
|
428
|
+
tools, cleanup = await convert_mcp_to_langchain_tools(server_configs)
|
429
|
+
# Use tools...
|
430
|
+
await cleanup() # Clean up resources when done
|
431
|
+
"""
|
314
432
|
|
315
433
|
|
316
434
|
async def convert_mcp_to_langchain_tools(
|
317
|
-
server_configs:
|
435
|
+
server_configs: McpServersConfig,
|
318
436
|
logger: logging.Logger | None = None
|
319
437
|
) -> tuple[list[BaseTool], McpServerCleanupFn]:
|
320
438
|
"""Initialize multiple MCP servers and convert their tools to
|
@@ -329,26 +447,30 @@ async def convert_mcp_to_langchain_tools(
|
|
329
447
|
configurations, where each configuration contains command, args,
|
330
448
|
and env settings
|
331
449
|
logger: Logger instance to use for logging events and errors.
|
332
|
-
|
333
|
-
|
450
|
+
If None, uses module logger with fallback to a pre-configured
|
451
|
+
logger when no root handlers exist.
|
334
452
|
|
335
453
|
Returns:
|
336
454
|
A tuple containing:
|
337
|
-
|
338
|
-
|
339
|
-
|
455
|
+
|
456
|
+
* List of converted LangChain tools from all servers
|
457
|
+
* Async cleanup function to properly shutdown all server connections
|
340
458
|
|
341
459
|
Example:
|
460
|
+
|
342
461
|
server_configs = {
|
343
|
-
|
344
|
-
|
462
|
+
"fetch": {
|
463
|
+
"command": "uvx", "args": ["mcp-server-fetch"]
|
345
464
|
},
|
346
|
-
|
347
|
-
|
465
|
+
"weather": {
|
466
|
+
"command": "npx", "args": ["-y","@h1deya/mcp-server-weather"]
|
348
467
|
}
|
349
468
|
}
|
469
|
+
|
350
470
|
tools, cleanup = await convert_mcp_to_langchain_tools(server_configs)
|
471
|
+
|
351
472
|
# Use tools...
|
473
|
+
|
352
474
|
await cleanup()
|
353
475
|
"""
|
354
476
|
|
@@ -394,13 +516,13 @@ async def convert_mcp_to_langchain_tools(
|
|
394
516
|
|
395
517
|
# Define a cleanup function to properly shut down all servers
|
396
518
|
async def mcp_cleanup() -> None:
|
397
|
-
"""Closes all server connections and cleans up resources"""
|
519
|
+
"""Closes all server connections and cleans up resources."""
|
398
520
|
await async_exit_stack.aclose()
|
399
521
|
|
400
522
|
# Log summary of initialized tools
|
401
|
-
logger.info(f
|
402
|
-
f
|
523
|
+
logger.info(f"MCP servers initialized: {len(langchain_tools)} tool(s) "
|
524
|
+
f"available in total")
|
403
525
|
for tool in langchain_tools:
|
404
|
-
logger.debug(f
|
526
|
+
logger.debug(f"- {tool.name}")
|
405
527
|
|
406
528
|
return langchain_tools, mcp_cleanup
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: langchain-mcp-tools
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.4
|
4
4
|
Summary: Model Context Protocol (MCP) To LangChain Tools Conversion Utility
|
5
5
|
Project-URL: Bug Tracker, https://github.com/hideya/langchain-mcp-tools-py/issues
|
6
6
|
Project-URL: Source Code, https://github.com/hideya/langchain-mcp-tools-py
|
@@ -11,20 +11,31 @@ License-File: LICENSE
|
|
11
11
|
Requires-Dist: jsonschema-pydantic>=0.6
|
12
12
|
Requires-Dist: langchain>=0.3.14
|
13
13
|
Requires-Dist: mcp>=1.6.0
|
14
|
-
Requires-Dist: pyjson5>=1.6.8
|
15
|
-
Requires-Dist: websockets>=15.0.1
|
16
14
|
Provides-Extra: dev
|
17
15
|
Requires-Dist: dotenv>=0.9.9; extra == "dev"
|
16
|
+
Requires-Dist: fastapi>=0.115.12; extra == "dev"
|
17
|
+
Requires-Dist: pyjwt>=2.10.1; extra == "dev"
|
18
18
|
Requires-Dist: langchain-anthropic>=0.3.1; extra == "dev"
|
19
19
|
Requires-Dist: langchain-groq>=0.2.3; extra == "dev"
|
20
20
|
Requires-Dist: langchain-openai>=0.3.0; extra == "dev"
|
21
21
|
Requires-Dist: langgraph>=0.2.62; extra == "dev"
|
22
22
|
Requires-Dist: pytest>=8.3.4; extra == "dev"
|
23
23
|
Requires-Dist: pytest-asyncio>=0.25.2; extra == "dev"
|
24
|
+
Requires-Dist: websockets>=15.0.1; extra == "dev"
|
24
25
|
Dynamic: license-file
|
25
26
|
|
26
27
|
# MCP To LangChain Tools Conversion Utility [](https://github.com/hideya/langchain-mcp-tools-py/blob/main/LICENSE) [](https://pypi.org/project/langchain-mcp-tools/)
|
27
28
|
|
29
|
+
## NOTE
|
30
|
+
|
31
|
+
LangChain's official **LangChain MCP Adapters** library has been released at:
|
32
|
+
- pypi: https://pypi.org/project/langchain-mcp-adapters/
|
33
|
+
- github: https://github.com/langchain-ai/langchain-mcp-adapters
|
34
|
+
|
35
|
+
You may want to consider using the above if you don't have specific needs for using this library...
|
36
|
+
|
37
|
+
## Introduction
|
38
|
+
|
28
39
|
This package is intended to simplify the use of
|
29
40
|
[Model Context Protocol (MCP)](https://modelcontextprotocol.io/)
|
30
41
|
server tools with LangChain / Python.
|
@@ -67,6 +78,11 @@ A typescript equivalent of this utility is available
|
|
67
78
|
pip install langchain-mcp-tools
|
68
79
|
```
|
69
80
|
|
81
|
+
## API docs
|
82
|
+
|
83
|
+
Can be found [here](https://hideya.github.io/langchain-mcp-tools-py/)
|
84
|
+
|
85
|
+
|
70
86
|
## Quick Start
|
71
87
|
|
72
88
|
A minimal but complete working usage example can be found
|
@@ -145,9 +161,9 @@ Note that the key `"url"` may be changed in the future to match
|
|
145
161
|
the MCP server configurations used by Claude for Desktop once
|
146
162
|
it introduces remote server support.
|
147
163
|
|
148
|
-
A usage example can be found [here](https://github.com/hideya/langchain-mcp-tools-py-usage/blob/
|
164
|
+
A usage example can be found [here](https://github.com/hideya/langchain-mcp-tools-py-usage/blob/3bd35d9fb49f4b631fe3d0cc8491d43cbf69693b/src/example.py#L43-L54)
|
149
165
|
|
150
|
-
###
|
166
|
+
### Authentication Support for SSE Connections
|
151
167
|
|
152
168
|
A new key `"headers"` has been introduced to pass HTTP headers to the SSE (Server-Sent Events) connection.
|
153
169
|
It takes `dict[str, str]` and is primarily intended to support SSE MCP servers
|
@@ -163,6 +179,11 @@ that require authentication via bearer tokens or other custom headers.
|
|
163
179
|
The key name `header` is derived from the Python SDK
|
164
180
|
[`sse_client()`](https://github.com/modelcontextprotocol/python-sdk/blob/babb477dffa33f46cdc886bc885eb1d521151430/src/mcp/client/sse.py#L24) argument name.
|
165
181
|
|
182
|
+
A simple example showing how to implement MCP SSE server and client with authentication can be found
|
183
|
+
in [sse-auth-test-client.py](https://github.com/hideya/langchain-mcp-tools-py-usage/tree/main/src/sse-auth-test-client.py)
|
184
|
+
and in [sse-auth-test-server.py](https://github.com/hideya/langchain-mcp-tools-py-usage/tree/main/src/sse-auth-test-server.py)
|
185
|
+
of [this usage examples repo](https://github.com/hideya/langchain-mcp-tools-py-usage).
|
186
|
+
|
166
187
|
### Working Directory Configuration for Local MCP Servers
|
167
188
|
|
168
189
|
The working directory that is used when spawning a local (stdio) MCP server
|
@@ -179,7 +200,7 @@ can be specified with the `"cwd"` key as follows:
|
|
179
200
|
The key name `cwd` is derived from
|
180
201
|
Python SDK's [`StdioServerParameters`](https://github.com/modelcontextprotocol/python-sdk/blob/babb477dffa33f46cdc886bc885eb1d521151430/src/mcp/client/stdio/__init__.py#L76-L77).
|
181
202
|
|
182
|
-
###
|
203
|
+
### stderr Redirection for Local MCP Server
|
183
204
|
|
184
205
|
A new key `"errlog"` has been introduced to specify a file-like object
|
185
206
|
to which local (stdio) MCP server's stderr is redirected.
|
@@ -190,8 +211,7 @@ to which local (stdio) MCP server's stderr is redirected.
|
|
190
211
|
mcp_servers[server_name]["errlog"] = log_file
|
191
212
|
```
|
192
213
|
|
193
|
-
A usage example can be found [here](
|
194
|
-
https://github.com/hideya/langchain-mcp-tools-py-usage/blob/cf96ddc43750708ef3b244bad95714f0f2fe1d28/src/example.py#L91-L108)
|
214
|
+
A usage example can be found [here](https://github.com/hideya/langchain-mcp-tools-py-usage/blob/3bd35d9fb49f4b631fe3d0cc8491d43cbf69693b/src/example.py#L88-L108)
|
195
215
|
|
196
216
|
**NOTE: Why the key name `errlog` was chosen:**
|
197
217
|
Unlike TypeScript SDK's `StdioServerParameters`, the Python
|
@@ -0,0 +1,8 @@
|
|
1
|
+
langchain_mcp_tools/__init__.py,sha256=CYyhniRN10ktRD1z06JyBoeo_m72Q8OIbqHjh-OGoFA,197
|
2
|
+
langchain_mcp_tools/langchain_mcp_tools.py,sha256=LximGy_0QYKuwsKFr5SvUwMZ7475CIJWxLtNDq68b-g,19377
|
3
|
+
langchain_mcp_tools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
langchain_mcp_tools-0.2.4.dist-info/licenses/LICENSE,sha256=CRC91e8v116gCpnp7h49oIa6_zjhxqnHFTREeoZFJwA,1072
|
5
|
+
langchain_mcp_tools-0.2.4.dist-info/METADATA,sha256=RJ00zZEh3UCSe6S6B_aaD4YZRiYd3SemWQrPrO9BM8M,9377
|
6
|
+
langchain_mcp_tools-0.2.4.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
7
|
+
langchain_mcp_tools-0.2.4.dist-info/top_level.txt,sha256=aR_9V2A1Yt-Bca60KmndmGLUWb2wiM5IOG-Gkaf1dxY,20
|
8
|
+
langchain_mcp_tools-0.2.4.dist-info/RECORD,,
|
@@ -1,8 +0,0 @@
|
|
1
|
-
langchain_mcp_tools/__init__.py,sha256=iatHG2fCpz143wgQUZpyFVilgri4yOh2P0vxr22gguE,114
|
2
|
-
langchain_mcp_tools/langchain_mcp_tools.py,sha256=txbtjl7BAjZu1ccNUNhLkLd3HNdCSfKeyTCDX_0PUR0,15078
|
3
|
-
langchain_mcp_tools/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
langchain_mcp_tools-0.2.2.dist-info/licenses/LICENSE,sha256=CRC91e8v116gCpnp7h49oIa6_zjhxqnHFTREeoZFJwA,1072
|
5
|
-
langchain_mcp_tools-0.2.2.dist-info/METADATA,sha256=hxlEr_nyHbnjLMzhxYOsT_rZQ8-j4rTi7EDDUxyvb-A,8458
|
6
|
-
langchain_mcp_tools-0.2.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
7
|
-
langchain_mcp_tools-0.2.2.dist-info/top_level.txt,sha256=aR_9V2A1Yt-Bca60KmndmGLUWb2wiM5IOG-Gkaf1dxY,20
|
8
|
-
langchain_mcp_tools-0.2.2.dist-info/RECORD,,
|
{langchain_mcp_tools-0.2.2.dist-info → langchain_mcp_tools-0.2.4.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|