Skip to content

Commit 14cf5ba

Browse files
committed
LangChain: Add example using MCP
1 parent 30e6ec6 commit 14cf5ba

File tree

7 files changed

+143
-7
lines changed

7 files changed

+143
-7
lines changed

.github/workflows/ml-langchain.yml

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@ jobs:
3838
matrix:
3939
os: [ 'ubuntu-latest' ]
4040
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
41-
cratedb-version: [ 'nightly' ]
41+
cratedb-version: [
42+
'nightly',
43+
]
44+
cratedb-mcp-version: [
45+
'pr-50',
46+
]
4247

4348
services:
4449
cratedb:
@@ -48,6 +53,15 @@ jobs:
4853
- 5432:5432
4954
env:
5055
CRATE_HEAP_SIZE: 4g
56+
cratedb-mcp:
57+
image: ghcr.io/crate/cratedb-mcp:${{ matrix.cratedb-mcp-version }}
58+
ports:
59+
- 8000:8000
60+
env:
61+
CRATEDB_MCP_TRANSPORT: streamable-http
62+
CRATEDB_MCP_HOST: 0.0.0.0
63+
CRATEDB_MCP_PORT: 8000
64+
CRATEDB_CLUSTER_URL: http://crate:crate@cratedb:4200/
5165

5266
env:
5367
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
*.sql
21
.env
2+
*.sql
3+
!init.sql

topic/machine-learning/llm-langchain/README.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
by language models. It provides a complete set of powerful and flexible
88
components for building context-aware, reasoning applications.
99

10-
Please refer to the [LangChain documentation] for further information.
10+
[LangGraph] is a low-level orchestration framework for building, managing,
11+
and deploying long-running, stateful agents.
12+
13+
Please refer to the [LangChain documentation] and the [Building Ambient
14+
Agents with LangGraph] academy material for further information.
1115

1216
Common end-to-end use cases are:
1317

1418
- Analyzing structured data
1519
- Chatbots and friends
1620
- Document question answering
21+
- Text-to-SQL (talk to your data)
1722

1823
LangChain provides standard, extendable interfaces and external integrations
1924
for the following modules, listed from least to most complex:
@@ -79,17 +84,21 @@ and [CrateDB].
7984
augmented generation (RAG) pipeline. To implement RAG we use the Python client driver for
8085
CrateDB and vector store support in LangChain.
8186

82-
- `cratedb_rag_customer_support_vertexai.ipynb` [![Open on GitHub](https://img.shields.io/badge/Open%20on-GitHub-lightgray?logo=GitHub)](cratedb_rag_customer_support_vertexai.ipynb)[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/crate/cratedb-examples/blob/main/topic/machine-learning/llm-langchain/cratedb_rag_customer_support_vertexai.ipynb)
87+
- `cratedb_rag_customer_support_vertexai.ipynb` [![Open on GitHub](https://img.shields.io/badge/Open%20on-GitHub-lightgray?logo=GitHub)](cratedb_rag_customer_support_vertexai.ipynb)[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/crate/cratedb-examples/blob/main/topic/machine-learning/llm-langchain/cratedb_rag_customer_support_vertexai.ipynb)
8388

8489
This example illustrates the RAG implementation of a customer support scenario.
8590
It is based on the previous notebook, and it illustrates how to use Vertex AI platform
8691
on Google Cloud for RAG pipeline.
87-
8892

93+
- `agent_with_mcp.py`
94+
95+
This example illustrates how to use LangGraph and the `langchain-mcp-adapters`
96+
package to implement an LLM agent that is connecting to the CrateDB MCP server.
97+
The demo program performs Text-to-SQL on timeseries data stored in a CrateDB table.
8998

9099
## Install
91100

92-
In order to properly set up a sandbox environment to explore the example notebooks
101+
To properly set up a sandbox environment to explore the example notebooks
93102
and programs, it is advised to create a Python virtualenv, and install the
94103
dependencies into it. In this way, it is easy to wipe your virtualenv and start
95104
from scratch anytime.
@@ -126,6 +135,26 @@ a cloud-based development environment is up and running. As soon as your project
126135
easily move to a different cluster tier or scale horizontally.
127136

128137

138+
### MCP
139+
140+
Spin up the [CrateDB MCP server], connecting it to CrateDB on localhost.
141+
```bash
142+
export CRATEDB_CLUSTER_URL=http://crate:crate@localhost:4200/
143+
export CRATEDB_MCP_TRANSPORT=streamable-http
144+
uvx cratedb-mcp serve
145+
```
146+
147+
Run the code using OpenAI API:
148+
```bash
149+
export OPENAI_API_KEY=<YOUR_OPENAI_API_KEY>
150+
python agent_with_mcp.py
151+
```
152+
Expected output:
153+
```text
154+
Query was: What is the average value for sensor 1?
155+
Answer was: The average value for sensor 1 is approximately 17.03. If you need more details or a different calculation, let me know!
156+
```
157+
129158
## Testing
130159

131160
Run all tests.
@@ -139,22 +168,25 @@ pytest -k document_loader
139168
pytest -k "notebook and loader"
140169
```
141170

142-
In order to force a regeneration of the Jupyter Notebook, use the
171+
To force a regeneration of the Jupyter Notebook, use the
143172
`--nb-force-regen` option.
144173
```shell
145174
pytest -k document_loader --nb-force-regen
146175
```
147176

148177

149178
[Agents]: https://python.langchain.com/docs/modules/agents/
179+
[Building Ambient Agents with LangGraph]: https://academy.langchain.com/courses/ambient-agents/
150180
[Callbacks]: https://python.langchain.com/docs/modules/callbacks/
151181
[Chains]: https://python.langchain.com/docs/modules/chains/
152182
[CrateDB]: https://github.com/crate/crate
153183
[CrateDB Cloud]: https://console.cratedb.cloud
184+
[CrateDB MCP server]: https://cratedb.com/docs/guide/integrate/mcp/cratedb-mcp.html
154185
[`FLOAT_VECTOR`]: https://crate.io/docs/crate/reference/en/master/general/ddl/data-types.html#float-vector
155186
[`KNN_MATCH`]: https://crate.io/docs/crate/reference/en/master/general/builtins/scalar-functions.html#scalar-knn-match
156187
[LangChain]: https://www.langchain.com/
157188
[LangChain documentation]: https://python.langchain.com/
189+
[LangGraph]: https://langchain-ai.github.io/langgraph/
158190
[Memory]: https://python.langchain.com/docs/modules/memory/
159191
[Model I/O]: https://python.langchain.com/docs/modules/model_io/
160192
[Retrieval]: https://python.langchain.com/docs/modules/data_connection/
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""
2+
Exercise LangChain/LangGraph with the CrateDB MCP server.
3+
4+
## Synopsis
5+
6+
# Install prerequisites.
7+
pip install -U -r requirements.txt
8+
9+
# Start database.
10+
docker run --rm -it --publish=4200:4200 crate/crate:nightly
11+
12+
# Start MCP server.
13+
export CRATEDB_MCP_TRANSPORT=streamable-http
14+
export CRATEDB_MCP_HOST=0.0.0.0
15+
export CRATEDB_MCP_PORT=8000
16+
export CRATEDB_CLUSTER_URL=http://crate:crate@localhost:4200/
17+
docker run --rm -it --network=host --publish=8000:8000 ghcr.io/crate/cratedb-mcp:pr-50
18+
19+
# Run program.
20+
export OPENAI_API_KEY=<your_openai_api_key>
21+
python agent_with_mcp.py
22+
"""
23+
import asyncio
24+
25+
from langchain_mcp_adapters.client import MultiServerMCPClient
26+
from langgraph.prebuilt import create_react_agent
27+
28+
29+
async def amain():
30+
client = MultiServerMCPClient(
31+
{
32+
"cratedb": {
33+
"transport": "streamable_http",
34+
"url": "http://localhost:8000/mcp/"
35+
},
36+
}
37+
)
38+
tools = await client.get_tools()
39+
agent = create_react_agent("openai:gpt-4.1", tools)
40+
41+
QUERY_STR = "What is the average value for sensor 1?"
42+
response = await agent.ainvoke({"messages": QUERY_STR})
43+
answer = response["messages"][-1].content
44+
45+
print("Query was:", QUERY_STR)
46+
print("Answer was:", answer)
47+
48+
49+
def main():
50+
asyncio.run(amain())
51+
52+
53+
if __name__ == "__main__":
54+
main()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
DROP TABLE IF EXISTS time_series_data;
2+
3+
CREATE TABLE IF NOT EXISTS time_series_data (
4+
timestamp TIMESTAMP,
5+
value DOUBLE,
6+
location STRING,
7+
sensor_id INT
8+
);
9+
10+
INSERT INTO time_series_data (timestamp, value, location, sensor_id)
11+
VALUES
12+
('2023-09-14T00:00:00', 10.5, 'Sensor A', 1),
13+
('2023-09-14T01:00:00', 15.2, 'Sensor A', 1),
14+
('2023-09-14T02:00:00', 18.9, 'Sensor A', 1),
15+
('2023-09-14T03:00:00', 12.7, 'Sensor B', 2),
16+
('2023-09-14T04:00:00', 17.3, 'Sensor B', 2),
17+
('2023-09-14T05:00:00', 20.1, 'Sensor B', 2),
18+
('2023-09-14T06:00:00', 22.5, 'Sensor A', 1),
19+
('2023-09-14T07:00:00', 18.3, 'Sensor A', 1),
20+
('2023-09-14T08:00:00', 16.8, 'Sensor A', 1),
21+
('2023-09-14T09:00:00', 14.6, 'Sensor B', 2),
22+
('2023-09-14T10:00:00', 13.2, 'Sensor B', 2),
23+
('2023-09-14T11:00:00', 11.7, 'Sensor B', 2);
24+
25+
REFRESH TABLE time_series_data;

topic/machine-learning/llm-langchain/requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
crash
22
google-cloud-aiplatform<2
33
langchain-cratedb<0.1.2
4+
langchain-mcp-adapters<0.2
45
langchain-google-vertexai<3
56
langchain-openai<0.4
67
langchain-text-splitters<0.4
8+
langgraph<0.6
79
pueblo[cli,nlp]>=0.0.10
810
pypdf<6
911
python-dotenv<2

topic/machine-learning/llm-langchain/test.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ def reset_database(cratedb):
2929
time.sleep(0.01)
3030

3131

32+
@pytest.fixture(scope="function", autouse=True)
33+
def init_database(cratedb):
34+
"""
35+
Initialize database.
36+
"""
37+
cratedb.run_sql((HERE / "init.sql").read_text())
38+
39+
3240
def pytest_generate_tests(metafunc):
3341
"""
3442
Generate pytest test case per Jupyter Notebook.

0 commit comments

Comments
 (0)