-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
feat: add anthropic mcp endpoint #5148
Conversation
CodSpeed Performance ReportMerging #5148 will degrade performances by 43.07%Comparing Summary
Benchmarks breakdown
|
while exc: | ||
if isinstance(exc, pydantic.ValidationError): | ||
return exc | ||
exc = getattr(exc, "__cause__", None) or getattr(exc, "__context__", None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exc = getattr(exc, "__cause__", None) or getattr(exc, "__context__", None) | |
exc = getattr(exc, "__cause__", None) | |
if exc is None: | |
exc = getattr(exc, "__context__", None) |
⚡️ Codeflash found optimizations for this PR📄 16% (0.16x) speedup for
|
Test | Status |
---|---|
⚙️ Existing Unit Tests | 🔘 None Found |
🌀 Generated Regression Tests | ✅ 10 Passed |
⏪ Replay Tests | 🔘 None Found |
🔎 Concolic Coverage Tests | 🔘 None Found |
📊 Tests Coverage | undefined |
🌀 Generated Regression Tests Details
import pydantic
# imports
import pytest # used for our unit tests
from langflow.api.v1.mcp import find_validation_error
# unit tests
def test_no_validation_error_simple():
"""Test with a simple exception that is not a pydantic.ValidationError."""
exc = Exception("Simple")
codeflash_output = find_validation_error(exc)
def test_no_validation_error_complex_chain():
"""Test with a complex exception chain that does not contain a pydantic.ValidationError."""
exc = Exception("Outer")
exc.__cause__ = Exception("Middle")
exc.__cause__.__context__ = Exception("Inner")
codeflash_output = find_validation_error(exc)
def test_none_input():
"""Test with None as input."""
exc = None
codeflash_output = find_validation_error(exc)
def test_empty_exception_chain():
"""Test with an exception that has __cause__ and __context__ set to None."""
exc = Exception("Empty")
exc.__cause__ = None
exc.__context__ = None
codeflash_output = find_validation_error(exc)
def test_non_exception_object():
"""Test with a non-exception object."""
exc = "Not an exception"
codeflash_output = find_validation_error(exc)
import pydantic
# imports
import pytest # used for our unit tests
from langflow.api.v1.mcp import find_validation_error
# unit tests
# Basic Functionality
def test_no_validation_error():
# No pydantic.ValidationError in Chain
generic_exception = Exception("Generic exception")
codeflash_output = find_validation_error(generic_exception)
# Exception Chaining
def test_cause_and_context_no_validation_error():
# Cause and Context with No ValidationError
cause_exception = Exception("Cause exception")
context_exception = Exception("Context exception")
cause_exception.__cause__ = context_exception
context_exception.__context__ = Exception("Another exception")
codeflash_output = find_validation_error(cause_exception)
# Edge Cases
def test_non_exception_input():
# Non-Exception Input
codeflash_output = find_validation_error(None)
codeflash_output = find_validation_error("string")
codeflash_output = find_validation_error(123)
""" | ||
if schema.get("type") != "object": | ||
msg = "JSON schema must be of type 'object' at the root level." | ||
raise ValueError(msg) | ||
|
||
fields = {} | ||
properties = schema.get("properties", {}) | ||
required_fields = set(schema.get("required", [])) | ||
|
||
for field_name, field_def in properties.items(): | ||
# Extract type | ||
field_type_str = field_def.get("type", "str") # Default to string type if not specified | ||
field_type = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
""" | |
if schema.get("type") != "object": | |
msg = "JSON schema must be of type 'object' at the root level." | |
raise ValueError(msg) | |
fields = {} | |
properties = schema.get("properties", {}) | |
required_fields = set(schema.get("required", [])) | |
for field_name, field_def in properties.items(): | |
# Extract type | |
field_type_str = field_def.get("type", "str") # Default to string type if not specified | |
field_type = { | |
:raises ValueError: If the schema type is not 'object' at the root level. | |
raise ValueError("JSON schema must be of type 'object' at the root level.") | |
field_type = TYPE_MAPPING.get(field_type_str, Any) |
⚡️ Codeflash found optimizations for this PR📄 31,318% (313.18x) speedup for
|
Test | Status |
---|---|
⚙️ Existing Unit Tests | 🔘 None Found |
🌀 Generated Regression Tests | ✅ 4 Passed |
⏪ Replay Tests | 🔘 None Found |
🔎 Concolic Coverage Tests | 🔘 None Found |
📊 Tests Coverage | undefined |
🌀 Generated Regression Tests Details
from typing import Any
# imports
import pytest # used for our unit tests
from langflow.components.tools.mcp_stdio import \
create_input_schema_from_json_schema
# function to test
from pydantic import BaseModel, Field, ValidationError, create_model
# unit tests
def test_invalid_schemas():
# Non-Object Root Type
schema = {
"type": "array",
"items": {"type": "string"}
}
with pytest.raises(ValueError):
create_input_schema_from_json_schema(schema)
# Malformed Schema
schema = {
"properties": {
"name": {"type": "string"}
}
}
with pytest.raises(ValueError):
create_input_schema_from_json_schema(schema)
from typing import Any
# imports
import pytest # used for our unit tests
from langflow.components.tools.mcp_stdio import \
create_input_schema_from_json_schema
# function to test
from pydantic import BaseModel, Field, ValidationError, create_model
# unit tests
# Basic Valid Input
def test_empty_schema():
schema = {}
with pytest.raises(ValueError):
create_input_schema_from_json_schema(schema)
def test_non_object_root_type():
schema = {"type": "array", "items": {"type": "string"}}
with pytest.raises(ValueError):
create_input_schema_from_json_schema(schema)
|
||
def find_validation_error(exc): | ||
"""Searches for a pydantic.ValidationError in the exception chain.""" | ||
while exc: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while exc: | |
fields = {"__cause__", "__context__"} | |
for field in fields: | |
exc = getattr(exc, field, None) | |
if exc: | |
break |
⚡️ Codeflash found optimizations for this PR📄 539% (5.39x) speedup for
|
Test | Status |
---|---|
⚙️ Existing Unit Tests | 🔘 None Found |
🌀 Generated Regression Tests | ✅ 7 Passed |
⏪ Replay Tests | 🔘 None Found |
🔎 Concolic Coverage Tests | 🔘 None Found |
📊 Tests Coverage | undefined |
🌀 Generated Regression Tests Details
import pydantic
# imports
import pytest # used for our unit tests
from langflow.api.v1.mcp import find_validation_error
# unit tests
def test_no_validation_error_single_exception():
"""Test with a single non-ValidationError exception."""
error = ValueError("Some error")
codeflash_output = find_validation_error(error)
def test_no_validation_error_nested_exceptions():
"""Test with a nested chain of non-ValidationError exceptions."""
error = ValueError("Some error")
nested_error = TypeError("Another error")
nested_error.__cause__ = error
codeflash_output = find_validation_error(nested_error)
def test_empty_exception_chain():
"""Test with an empty exception chain (None)."""
codeflash_output = find_validation_error(None)
def test_large_exception_chain_without_validation_error():
"""Test with a large exception chain without any pydantic.ValidationError."""
nested_error = ValueError("Nested error")
for _ in range(1000):
new_error = ValueError("Another nested error")
new_error.__cause__ = nested_error
nested_error = new_error
codeflash_output = find_validation_error(nested_error)
import pydantic
# imports
import pytest # used for our unit tests
from langflow.api.v1.mcp import find_validation_error
from pydantic import ValidationError
# unit tests
def test_single_non_validation_error():
# Test a single non-ValidationError
exc = Exception("Just a regular exception")
codeflash_output = find_validation_error(exc)
def test_nested_non_validation_error():
# Test nested non-ValidationError exceptions
nested_exc = Exception("Inner exception")
exc = Exception("Outer exception")
exc.__cause__ = nested_exc
codeflash_output = find_validation_error(exc)
def test_empty_exception_chain():
# Test an empty exception chain
codeflash_output = find_validation_error(None)
msg = "JSON schema must be of type 'object' at the root level." | ||
raise ValueError(msg) | ||
|
||
fields = {} | ||
properties = schema.get("properties", {}) | ||
required_fields = set(schema.get("required", [])) | ||
|
||
for field_name, field_def in properties.items(): | ||
# Extract type | ||
field_type_str = field_def.get("type", "str") # Default to string type if not specified | ||
field_type = { | ||
"string": str, | ||
"str": str, | ||
"integer": int, | ||
"int": int, | ||
"number": float, | ||
"boolean": bool, | ||
"array": list, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
msg = "JSON schema must be of type 'object' at the root level." | |
raise ValueError(msg) | |
fields = {} | |
properties = schema.get("properties", {}) | |
required_fields = set(schema.get("required", [])) | |
for field_name, field_def in properties.items(): | |
# Extract type | |
field_type_str = field_def.get("type", "str") # Default to string type if not specified | |
field_type = { | |
"string": str, | |
"str": str, | |
"integer": int, | |
"int": int, | |
"number": float, | |
"boolean": bool, | |
"array": list, | |
raise ValueError("JSON schema must be of type 'object' at the root level.") | |
fields = {} | |
field_type_str = field_def.get("type", "str") | |
field_type = TYPE_MAPPING.get(field_type_str, Any) |
⚡️ Codeflash found optimizations for this PR📄 25,782% (257.82x) speedup for
|
Test | Status |
---|---|
⚙️ Existing Unit Tests | 🔘 None Found |
🌀 Generated Regression Tests | ✅ 5 Passed |
⏪ Replay Tests | 🔘 None Found |
🔎 Concolic Coverage Tests | 🔘 None Found |
📊 Tests Coverage | undefined |
🌀 Generated Regression Tests Details
from typing import Any
# imports
import pytest # used for our unit tests
from langflow.components.tools.mcp_stdio import \
create_input_schema_from_json_schema
from pydantic import BaseModel, Field, ValidationError, create_model
# unit tests
# Basic Valid Input
def test_empty_schema():
schema = {}
with pytest.raises(ValueError):
create_input_schema_from_json_schema(schema)
def test_non_object_root_type():
schema = {
"type": "array",
"items": {"type": "string"}
}
with pytest.raises(ValueError):
create_input_schema_from_json_schema(schema)
def test_malformed_schema():
schema = ["type", "object"]
with pytest.raises(AttributeError):
create_input_schema_from_json_schema(schema)
# Large Scale Test Cases
from typing import Any, Type
# imports
import pytest # used for our unit tests
from langflow.components.tools.mcp_stdio import \
create_input_schema_from_json_schema
from pydantic import BaseModel, Field, ValidationError, create_model
# unit tests
def test_empty_schema():
schema = {}
with pytest.raises(ValueError, match="JSON schema must be of type 'object' at the root level."):
create_input_schema_from_json_schema(schema)
def test_invalid_root_type():
schema = {
"type": "array",
"items": {
"type": "string"
}
}
with pytest.raises(ValueError, match="JSON schema must be of type 'object' at the root level."):
create_input_schema_from_json_schema(schema)
* mcp WIP * [autofix.ci] apply automated fixes * logging and flow user check * mcp stdio client component * handle disconnect better * initialization * session fix and type fix * [autofix.ci] apply automated fixes * defensive against mcp server bugs * [autofix.ci] apply automated fixes * notifications and sse component * enabled flags and resource support * remove unneeded print * extract json schema util * [autofix.ci] apply automated fixes * ruff * fix tools [] bug and db asysnc session api change * Tool instead of StructuredTool * ruff fixes * ruff * validation optimization * fix frontend test * another playwright fix * Update src/frontend/tests/extended/features/notifications.spec.ts Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> * mcp component descriptions * mypy fixes * fix setup_database_url test --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
* mcp WIP * [autofix.ci] apply automated fixes * logging and flow user check * mcp stdio client component * handle disconnect better * initialization * session fix and type fix * [autofix.ci] apply automated fixes * defensive against mcp server bugs * [autofix.ci] apply automated fixes * notifications and sse component * enabled flags and resource support * remove unneeded print * extract json schema util * [autofix.ci] apply automated fixes * ruff * fix tools [] bug and db asysnc session api change * Tool instead of StructuredTool * ruff fixes * ruff * validation optimization * fix frontend test * another playwright fix * Update src/frontend/tests/extended/features/notifications.spec.ts Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> * mcp component descriptions * mypy fixes * fix setup_database_url test --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Anthropic released model context protocol a few days ago https://modelcontextprotocol.io/introduction
It's an open protocol for LLM applications (first one being the claude desktop ui) and external data sources and tools. In this integration, any flow in langflow becomes a tool in mcp and can be accessed directly by claude from claude desktop. Here's a screenshot from mcp inspector https://github.com/modelcontextprotocol/inspector
This pull request introduces the integration of the
mcp
module into the project. The changes include adding themcp
dependency, updating the API routing to includemcp
, and implementing themcp
server functionality.Key changes include:
Dependency Addition
mcp
version0.9.1
to the project dependencies inpyproject.toml
.API Routing Updates
mcp_router
in the API router configurations insrc/backend/base/langflow/api/router.py
. [1] [2]mcp_router
to the list of routers insrc/backend/base/langflow/api/v1/__init__.py
. [1] [2]MCP Server Implementation
src/backend/base/langflow/api/v1/mcp.py
to implement themcp
server with endpoints for handling tool listings, tool execution requests, and server-sent events (SSE).MCP Client components
Also includes two new components for mcp clients sse and stdio