Instructor: So let's go back to the code
and let's go to main.py file,
and we'll start by creating the Stdio client
'cause that's going to be the proxy for our MCP host,
which is going to be our LangGraph agent.
And the client needs to know two things.
It needs to know how to run the MCP Server,
so which commands to execute
in order for the server to work.
And second, it needs to know how it'll communicate with it.
And those two pieces of information, we're going
to supply the Stdio client with the Stdio server parameters.
So when we initialize this variable here,
we give it the information of how to run the MCP Server
and the object itself, the Stdio server parameters,
it has the information that it's going
to communicate via the transport of Stdio.
So it has all of that information.
Anthropic handles this for us,
and this is what's convenient about MCP SDK.
Wonderful so let's go and use the Stdio client
context manager and let's define it
and supply it with the Stdio server params.
So to do that I'm going to write async with
as the context manager, stdio_client,
and I'm going to give it the argument
of the Stdio server params,
and what we're going to get back from this, we're going
to get back two objects here.
One object is going to be the read
and the other is going to be the write transport.
All right, so after we did that,
we want to create the client session
because every client connects to a server via session,
and we're going to feed that session with the write
and read we just got here.
So let's go and use async context manager
with client session.
And here we're going to give it the read stream
of read we got from before,
and the write stream of write we got from before as well.
So now we have a client session ready.
And this MCP client session, this object is what's going
to do the heavy lifting of communicating
between the client and the server.
And to be honest, we don't really need
to understand this in depth
how this communication is working as the users of this SDK.
If you want, please let me know.
I'd be happy to make a deep dive into it,
but we should use it as a black box.
And this is the convenient thing about using frameworks
with abstract information for us, which is not
that relevant because as the developers of the agent,
we don't really care about the ins and outs
about the communication between the client and the server.
We just assume that it's working
and that the Anthropic software engineers did a decent job
implementing this and abstract away this for us.
Cool, so now the client knows exactly how to run
and how to communicate with the MCP Server.
So let's now see the flow in action, the MCP flow.
We first want to initialize this connection here.
So right now we have all the details in order
to make this initialization.
To do that, let's go and await session.initialize.
And let's also print that the session was initialized.
So after the client initializes the connection,
the MCP Server is going to respond with its available tools.
So after we done this initialization,
then the client is going to have the tools
that the MCP Server exposes.
And I'll be more accurate here.
It's not only the tools, it's also the resources
and the prompts which the server exposes.
So if we were to ask the MCP client here, what are the tools
that the MCP Server exposes, it'll have this information
and this is exactly what we're going to do now.
So let's define a variable which is called tools,
and it's going to be equal to the awaiting
of the code routine of sessions.list_tools.
So this is going to list all the available tools
that the client has and let's go and print it.
So now let's go and run this program.
I'll run uvrun main.py
and we can see that session was initialized
And we can see processing request of type ListToolsRequest.
So this log that we see right over here,
this is from the MCP client itself.
And this is from the MCP SDK implementation.
So we didn't write this log.
After we printed the tools,
we can see here we have a list of tools
and we have here with the add tool, the name is going
to be add, we can see all the metadata, all the information,
the description, the input schema, which arguments,
which does it receive, which output does it output,
and all the information relevant
to help the LLM decide whether to call this tool or not.
So we have this information about the adds tool
and we have it about the multiply tool.
So those are the tools that are math MCP Server exposes.
So at this point, we have an MCP Server which is running
because the MCP client ran it.
It then created the connection in order to communicate
with it via Stdio.
The client now knows the tools which can be invoked.
So those are the tools that the MCP Server exposes.
And now we want to create the host application,
which is going to contain this client information.
And in this case, in this example,
the host application is going
to be a LangGraph react agent.
So the user is going to communicate with that.
All righty, so let's go and create our agent.
And we're going to do this by using the LangGraph
pre-built create react agent function.
And this function returns us a LangGraph react agent.
Now I am assuming that you know what's a react agent?
What's LangGraph? Cool.
So the react agent is going to receive the LLM,
which is going to be the default LLM from Chat OpenAI
I think it's GPT-4o mini.
And it's going to receive the tools that we want
to supply our agent with.
And notice in line 27, I gave it the argument of tools,
which is an MCP tool object.
It's not a LangChain tool object.
So by running this right now, we are going to get an error,
and I want to show you this.
So to show you the value of the LangChain MCP adapter
and what it should provide us.
So let me go and run this code over here,
and let me show you that we get an error
and you can see that we get here
that the first argument must be a string
or a callable for tool decorator.
Instead it got a tuple.
And the TLDR for this is the mismatch.
The create react agent of LangChain expect
to get in the arguments, a list of LangChain tools
and instead we gave it a list of or tuple of MCP tools.
So they both are going
to contain the same information about which tools to invoke
and how to invoke them, which arguments,
what's the return values?
But the format is going to be a bit different.
And to mitigate over this,
to translate the MCP tool object into a LangChain tool
object, we're going to use the load mcptools
function of LangChain.
And all this function needs to receive is the MCP session,
which holds the information on the tools
that the MCP Server exposes.
So if we'll now run it, we can see
that we get here coreturn is not returnable.
I forgot to await it.
So let's run it again,
and everything is running right now.
So our agent is ready to work. So now we can even test it.
So let me go now even and print the tools here.
Let me go and print the tools,
and we're going to see that now you're going
to get the LangChain tools
because the structured tool class is a class
from the LangChain library.
Wonderful. So let's go and test our LangGraph react agent.
So here we are going to run the agent.ainvoked
because we are in asynchronous context
and the argument that we're going to give it is going
to be a dictionary, which is going
to hold the key of messages.
So, and here we're going to give a list of messages,
and we're going to put here the human message object.
Again, this is a LangChain construct,
and here the content is going to be what is two plus two.
And don't forget to import it because we did not import it.
So let's go and simply add this import, let's say over here.