Skip to content

Commit

Permalink
Work around langchain changes to BaseTool schema
Browse files Browse the repository at this point in the history
It now requires the schema model actually define pydantic fields.

Update version to 0.1.0

Fixes #1
  • Loading branch information
rectalogic committed Jan 6, 2025
1 parent 26f2897 commit a7f291d
Show file tree
Hide file tree
Showing 3 changed files with 415 additions and 283 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "langchain-mcp"
version = "0.1.0a1"
version = "0.1.0"
description = "Model Context Protocol tool calling support for LangChain"
readme = "README.md"
authors = [
Expand Down
36 changes: 34 additions & 2 deletions src/langchain_mcp/toolkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,35 @@ def get_tools(self) -> list[BaseTool]:
]


TYPEMAP = {
"integer": int,
"number": float,
"array": list,
"boolean": bool,
"string": str,
"null": type(None),
}

FIELD_DEFAULTS = {
int: 0,
float: 0.0,
list: [],
bool: False,
str: "",
type(None): None,
}


def configure_field(name: str, type_: dict[str, t.Any], required: list[str]) -> tuple[type, t.Any]:
field_type = TYPEMAP[type_["type"]]
default_ = FIELD_DEFAULTS.get(field_type) if name not in required else ...
return field_type, default_


def create_schema_model(schema: dict[str, t.Any]) -> type[pydantic.BaseModel]:
# Create a new model class that returns our JSON schema.
# LangChain requires a BaseModel class.
class Schema(pydantic.BaseModel):
class SchemaBase(pydantic.BaseModel):
model_config = pydantic.ConfigDict(extra="allow")

@t.override
Expand All @@ -62,7 +87,14 @@ def __get_pydantic_json_schema__(
) -> JsonSchemaValue:
return schema

return Schema
# Since this langchain patch, we need to synthesize pydantic fields from the schema
# https://github.com/langchain-ai/langchain/commit/033ac417609297369eb0525794d8b48a425b8b33
required = schema.get("required", [])
fields: dict[str, t.Any] = {
name: configure_field(name, type_, required) for name, type_ in schema["properties"].items()
}

return pydantic.create_model("Schema", __base__=SchemaBase, **fields)


class MCPTool(BaseTool):
Expand Down
Loading

0 comments on commit a7f291d

Please sign in to comment.