Full transcript
Introduction: Speaker Samuel Colvin introduces himself as the creator of Pydantic.
0:00[Music]
0:14So yeah, I'm talking about uh MCP is all
0:16you need. A bit about who I am before we
0:19get started. I'm best known as the
0:21creator of Pyantic uh data validation
0:24library for Python that is uh fairly
0:26ubiquitous. downloaded about 360 million
0:30times a month. So someone pointed out to
0:32me that's like 140 times a second. Uh
0:35Pantic is used in general Python
0:37development everywhere but also in
0:39Genai. So it's used in all of the SDKs
Pydantic Ecosystem: Introduction to Pydantic the company, the Pydantic AI agent framework, and the Logfire observability platform.
0:42and agent frameworks in Python
0:44basically. Uh Pantic became a company uh
0:48uh beginning of 23 and we have uh built
0:51two things beyond Pantic since then.
0:53Pantic AI uh an agent framework for
0:56Python built on the same principles as
0:58Pantic um and Pantic Logfire
1:02observability platform um which is our
1:04which is the commercial part of what we
1:06do. Um I'm also
1:09a somewhat inactive co-maintainer of the
1:12MCP Python SDK.
1:14Um
1:16so MCP is all you need is obviously a a
Talk Thesis: Explaining the title "MCP is all you need" and the main argument that MCP simplifies agent communication.
1:20play on Jason Lou's talks pantic is all
1:23you need that he gave at AI engineer I
1:26think first of all nearly two years ago
1:28and then the second one pantic is still
1:31all you need maybe this time last year.
1:35Um and it has the same basic idea that
1:37people are over complicating something
1:38that we can use a single tool for. And I
1:41guess also similarly the title is
1:44completely unrealistic. Of course,
1:46padantic is not all you need. Uh and
1:48neither is MCP for everything. But it
1:50has the we have the I think where where
1:52we agree is that there are an awful lot
1:54of things that MCP can do and that
1:56people are over complicating the
1:57situation sometimes trying to come up
1:59with new ways of doing agentto agent
2:01communication.
2:03Um,
MCP's Focus: Clarifying that the talk focuses on MCP for autonomous agents and custom code, not its original desktop automation use case.
2:05I'm talking here specifically about
2:07autonomous agents or code that you're
2:10writing. I'm not talking about the
2:13um,
2:15uh, claw desktop or cursor uh, Z wind
2:19surf, etc. use case of coding agents.
2:21Those were what MCP was originally
2:23primarily designed for. Um, I don't know
2:26whether or not David Pereira would say
2:28that that what we're doing using MCP
2:31from Python is a he definitely wouldn't
2:33say it's a misuse, but it I don't think
2:35it it was the primary uh design use case
2:39for
2:41um for MCP.
2:43So, two of the of the primitives of MCP
2:47prompts and resources probably don't
Tool Calling Primitive: Highlighting that "tool calling" is the most relevant MCP primitive for this context.
2:50come into this use case that much.
2:52They're very useful or or should be very
2:54useful in the kind of cursor type use
2:56case. They don't really apply in what
2:58we're talking about here. Um
3:01but tool calling, the third primitive is
3:04extremely useful for what we're trying
3:05to do here. Um tool calling is a lot
3:08more complicated than you might at first
MCP vs. OpenAPI: Listing the advantages MCP has over a simple OpenAPI specification for tool calls.
3:10think. A lot of people say to me about
3:13MCPR, but couldn't it just be uh open
3:15API? Why do we need this uh custom
3:18protocol for doing it? Um, and there's a
Feature 1: Dynamic Tools: Tools can appear and disappear based on server state.
3:21number of reasons. The idea of dynamic
3:22tools, the tools that come and go during
3:24an agent execution depending on the
Feature 2: Streaming Logs: The ability to return log data to the user while a tool is still executing.
3:26state of the server. Logging, so being
3:28able to return data to the user
3:32while the tool is still executing,
Feature 3: Sampling: A mechanism for a tool (server) to request an LLM call back through the agent (client).
3:35sampling, which I'm going to talk about
3:36a lot today, perhaps the most
3:38confusingly named part of MCP, if not
3:41tech in general right now. Uh, and stuff
3:43like tracing, observability. Um, and I
3:46would also add to that actually the uh
3:49MCP's way of being allowed to operate as
3:51effectively a subprocess over standard
3:52in and standard out is extremely useful
3:54for lots of use cases and open API
3:57wouldn't wouldn't solve those problems.
MCP Architecture Diagram: Visualizing the basic agent-to-tool communication flow.
4:01This is the kind of prototypical
4:04image that you will see from lots of
4:05people of what uh MCP is all about. The
4:08idea is we have some agent, we have any
4:10number of different tools that we can
4:12connect to that agent and the point is
4:14that like the agent doesn't need to be
4:16designed with those particular tools in
4:18mind and those tools can be designed
4:19without knowing anything about the agent
4:21and we can just compose the two together
4:22in the same way that uh I can go and use
4:25a browser and the web application the
4:28website I'm going to doesn't need to
4:29know anything about the browser. I mean
4:30I know we live in a kind of monoculture
4:31of browsers now but like at least the
4:33ideal originally was we could have many
4:35different browsers all connecting over
4:36the same protocol. MCP is following the
4:38same idea.
4:40But it can get more complicated than
4:42this. So we can have situations like
Complex Architecture: Discussing scenarios where tools are themselves agents that need LLM access.
4:44this where uh we have tools within our
4:47system which are themselves agents and
4:50are doing agentic things need access to
4:52an LLM and they of course can then in
4:54turn connect to other tools over MCP or
4:57or directly connecting to tools. This
5:00this works nicely. This is elegant. But
5:01there's a problem.
5:03every single agent in our system needs
5:06access to an LLM. And so we need to go
5:08and configure that. We need to work out
5:10resources for that. And if we are
5:14um using remote MCP servers, if that
5:16remote MCP server needs to
5:20um use an LLM, well, now it's worried
5:22about what the cost is going to be of
5:23doing that. What what if the uh remote
Explaining Sampling: Detailing how sampling solves the problem of every agent needing its own LLM by allowing tools to "piggyback" on the client's LLM access.
5:26agent that's operating as a tool could
5:28effectively piggyback off the
5:32uh the model that the original agent has
5:35access to. That's what sampling gives
5:37us. So as I say, I think sampling is a
5:40somewhat uh that's not making that any
5:43bigger unfortunately. Um is that clear
5:45on screen? I may maybe I'll make it
5:47bigger like that. Um sampling is this
5:50idea of a of a way where within MCP the
5:53protocol the um server can effectively
5:57make a request back through the client
6:00to the LLM. So in this case client makes
6:02a request starts some sort of aantic
6:05query makes a call to the LLM LLM comes
6:07back and says I want to call that
6:08particular tool which is an MCP server.
6:11Uh client takes care of making that call
6:13to the MCP server. The MCP server now
6:16says, "Hey, I actually need to be able
6:18to use an LLM to answer whatever this
6:20question is." So that then gets sent
6:22back to the client. The client proxies
6:24that request to the LLM, receives the
6:27response from the LLM, sends that uh
6:29onto the MCP server, and the MCP server
6:32then returns and we can continue on our
6:35way. Um, sampling is very powerful, not
6:40that widely supported at the moment. Um,
Pydantic AI's Role in Sampling: How the Pydantic AI library supports sampling on both the client and server side.
6:42I'm going to demo it today with Pantic
6:44AI where we have support for sampling.
6:47Well, I'll be honest, it's a PR right
6:49now, but it will be soon it will be
6:50merged. Um, we have support for sampling
6:53both as a uh as the client. So, knowing
6:56how to proxy the those LLM calls and as
7:00a server basically being able to
7:01register use the MCP client as as the
7:04LLM.
7:06So this example
7:09is obviously like all examples
Demo Start: Beginning the demonstration of a research agent that uses an MCP tool to query BigQuery.
7:10trivialized or simplified to be to fit
7:12on screen. The idea is that we we're
7:14building a like research agent which is
7:16going to go and research open source uh
7:19packages or libraries for us. And we
7:22have implemented one of the many tools
7:23that you would in fact need for this.
7:25And that tool is um
7:28making uh I will switch now to code and
7:31show you uh the one tool that we have.
7:36Uh
7:37I'm in completely the wrong file. Here
7:39we are. Um so this tool is querying
7:44BigQuery
7:45BigQuery public data set for uh Pippi to
7:49get uh numbers about the number of
7:51downloads of a particular package. So
7:54this is this is pretty standard padantic
7:56AI uh padantic AI code. We've configured
7:59log file which I'll show you in a
8:00moment. We have the dependencies that
8:02the uh that the agent has access to
8:05while it's running. We said we can do
8:07some retries. So if the agent returns if
8:09the LLM returns the wrong data, we can
8:11send a retry a big system prompt where
8:14we give it basically the schema of the
8:16table. Uh tell it what to do, give it a
8:18few examples, yada yada. But then we get
8:20to this is the probably the powerful
8:22bit. So as an output validator we are
Code Walkthrough: Validation: Showing how Pydantic is used for output validation and automatic retries (model_retry).
8:25going to go and first of all we're going
8:26to strip out uh markdown block quotes
8:30from the SQL um if they're there then we
8:33will uh check that the table name is
8:36right that it's querying against and
8:37tell it that it shouldn't if it it
8:39shouldn't and then we're going to go and
8:41run the query and critically if the
8:43query fails we're going to uh raise
8:46model retry with impantic to go and
8:48retry uh making the um
8:54uh making the request to the um LLM
8:58again saying asking the LLM to to uh
Code Walkthrough: Context Logging: Demonstrating the use of mcp_context.log to send progress updates back to the client.
9:00attempt to to retry this. And what we're
9:02the other thing we're doing throughout
9:03this you'll see here is we have this
9:06context. MCP context.log. So you'll see
9:09here when we defined depths type we said
9:12that that was going to be an instance of
9:14this MCP uh context which is what we get
9:17when you call the MCP server. So what
9:19we're doing here is we're having a we're
9:21providing a type- safe way within in
9:24this case um the agent validator but it
9:27could be in a tool call if you wanted it
9:29to be to access that context. So we can
9:31see here that we know at um in the type
9:34int uh uh that the the type is uh MCP
9:39context. So we have this log function
9:41and we know it's signature and we can go
9:42and make this log call. The point is
9:44this is going to
9:47return to the client and ultimately to
9:49the user watching before the the thing
9:51has completed. So you can get kind of
9:52progress updates as we go. MCP also has
9:55a context concept of progress which I'm
9:58not using here but you can imagine that
9:59also being valuable if you knew how far
10:01through the query you were. You could
10:02show an update in progress. So the idea
10:05I think the original principle of uh
10:07logging like this is that you have the
10:09the cursor style agent running and we
10:12want to be able to give updates to the
10:13user. Don't worry I'm still going before
10:16it's finished and exactly what's
10:17happening. But you could also imagine
10:19this being useful if you were using MCP.
10:21If this was research agent was uh
10:23running as a web application you wanted
10:25to show the user what was going on. This
10:27deep research might take you know
10:29minutes to run. We can give these logs
10:30while the tool call is still executing.
10:34And then we're just going to take the
10:35the output turn it into a list of dict
10:38and then format it as XML. So you get a
10:41nice uh models are very good at
10:44basically reviewing XML data. So we
10:46basically return whatever the query
10:48results are as that kind of XMLish data
10:50which the LLM will then be good at uh
MCP Server Setup: Showing the code for setting up an MCP server using fast_mcp.
10:53interpreting.
10:55Now we get to the MCP bit. So in this
10:57code we are setting up an MCP server
10:59using fast MCP. There are two versions
11:02of first MCP right now. Confusingly,
11:04this is the one from inside the MCP SDK.
11:08Um,
11:10we the dock string for our function. So,
11:12we're registering one tool here, Pippi
11:14downloads, and our dock string from that
11:17function will end up becoming the
11:18description on the tool that is
11:20ultimately fed to the LLM that chooses
11:22to go and call it. Um, and we're going
11:25to pass in the user's question. And I
11:28think one of the one of the important
11:28things to say here is of course you
11:30could set this up to generate the SQL
11:34within your
11:37uh central agent. You could include all
11:39of the um
11:42uh description of the SQL the
11:44instructions within your within the the
11:46description of the tool. Uh models don't
11:49seem to like that much data inside a
11:51tool description. But more to the point,
11:52we're just going to blow up the context
Design Pattern: Inference Inside the Tool: Explaining the benefit of having the tool perform its own LLM inference to reduce the context burden on the main agent.
11:54window of our main agent if we're going
11:56to ship all of this context on how to
11:57make these queries into our main agent.
12:00That's just all overhead in all of our
12:02calls to that agent regardless of
12:03whether we're going to call this
12:04particular tool. So doing this kind of
12:06thing where we're doing the inference
12:08inside a tool is a powerful way of
12:10effectively limiting uh the context
12:12window of the of the main running agent.
12:15And then we're just going to return this
12:16output which will be a string, the value
12:18returned from from here. and we'll just
12:21run the run the MCP server and by
12:24default the MCP server will run over
12:25standard IO. Um, and then we come to our
Main Application Code: Reviewing the client-side code that defines the agent and registers the MCP tool.
12:28our main application. So here we have a
12:32definition of our agent. And you see
12:34we've defined one MCP server that's just
12:36going to run the the script I just
12:38showed you, the Pippi MCP server. Um,
12:43and so then this agent will act as the
12:45client and has that register as a tool
12:46to be able to call. We're also going to
12:48set the give it the current date. Uh so
12:51it doesn't uh assume it's 20 2023 as
12:55they often do. Um and now we can go and
12:58ultimately run our main agent. Ask it
13:01for example how many downloads Pantic
13:03has had this year. And I'm going to be
13:05brave and run it and see what happens.
13:07And it has succeeded and it has uh gone
13:09and told us uh that we had whatever 1.6
13:13billion downloads this year. But
13:14probably more interesting is to come and
13:15look at what that looks like in Logfire.
Observability with Logfire: Switching to the Logfire UI to trace the execution of the agent's query.
13:17So if you look at is it going to come
13:19through to logfire or we having a
13:21failure here as well. This I will admit
13:23this is the run from just before uh I
13:25came on stage but it it would look
13:27exactly the same. So I'm not going to
13:29talk too much about observability and
13:31how we do uh how MCP observability or
13:35tracing works within MCP because I know
13:37there's a talk coming up directly after
13:38me talking about that. So think of this
13:40as a kind of uh spoiler for what's going
13:42to come up. But you can see we we run
13:45our outer agent. it decides to it calls
13:48uh uh GPT40 uh which decides sure enough
13:53I'm going to go and call this tool. Uh
13:55it doesn't need to think about
13:56generating the SQL. It can just have a
13:58natural language description of the
13:59query that we're trying to make. We then
14:02um this is the MCP client as you can see
14:04here. MCP client then calls into the MCP
14:07server. um makes the which then again
Observing Sampling in Action: Pointing out the specific span in the trace that shows the tool making an LLM call back through the client via sampling.
14:11runs a different uh pyantic AI uh agent
14:15which then makes a call to an LLM which
14:18happens through proxing it through the
14:19client. So that's where you can see the
14:21service going client server uh client
14:24server
14:26ultimately if you look at the top level
14:28uh exchange with the model you'll see
14:30here yeah the the the out ultimate
14:35output was it return the the return
14:37response from running the query was was
14:38this kind of XMLish data and then the
14:41LLM was able to turn that into a human
14:43description of what was going on. I
14:45think the other interesting thing
14:46probably is we can go and look in we
Inspecting the SQL Query: Showing how the observability tool can be used to see the exact SQL query that was generated by the internal agent.
14:48should be able to see the actual SQL
14:50that was called. So this is the agent
14:52call inside uh MCP server and you can
14:55see here the SQL it wrote and you can
14:58confirm that it indeed looks correct. Um
15:01I am going to
15:04uh go on from there and say um thank you
15:07very much. Um we are at the booth the
15:10the Pantic booth. So if anyone has any
15:11questions on this, wants to see this
15:13fail in numerous other exciting ways,
Conclusion: Final summary of the talk's points.
15:15very happy to to talk to you. Yeah, come
15:17and say hi.
15:22[Music]