Grounded Vibe Coding with MCP and Qdrant

Richard Cotton and Casper Wukowski show how to build safer AI-assisted coding using MCP and Qdrant. They demo a RAG workflow that grounds Claude in up-to-date code snippets, avoiding hallucinations and outdated knowledge. The setup uses Cursor IDE, a local Qdrant vector database, and an MCP server to let the AI retrieve relevant code before generating new code.
Chapters
Sam foreign. Hello everyone and thank you for joining today's session. My name is Rhys and I'll be your moderator today. We are just about to get started. We are going to be getting going in a couple of minutes at the top of the hour. For the moment we're just waiting so everyone has a chance to join. If you haven't done so already, please do register for for this session. The link to do so is in the comments. You can also head over to datacamp.com forward/webinars where you'll find this session as well as all of our future sessions as well. We've got lots of events set up for August and for Data and AI Literacy Month, AKA September, so go and check those out now. But pertaining to this session, we do have a resources document set up for you. The link to that is in the chat. If you don't see it already, I will repost it again. Now there are a few bits of setup for today's session if you want to code along with us live that those are detailed in the resources document. So go check that out. But yeah, in the resources document we have a link to the GitHub repo, we have a link to some slides and you will also need access to an LLM, an IDE of your choice. We're going to be using Cursor today and then you'll also need to have Docker installed as well. So yeah, those are the three things that you'll need in order to code along live with us. However, if you do just want to watch along and then check out the replay, make sure you register for the session as that will be going out to your email address tomorrow. And to register you can either scan the QR code or you can find the link in the chat or you can head over to datacamp.comwebinars as well. I'm going to repeat these messages once more for anyone that's just joined. So if you just joined hello and welcome to the session. My name is Rhys and I'll be a moderator today. We are going to get started in about a minute or so. We're just waiting so everyone has a chance to join. If you haven't registered for this session already, please do. The link to do so is in the chat. I'll be posting it again now. I will do that for everyone now and then for everyone on LinkedIn. You'll just have to wait one second for me to repost it. Cool. So yeah, please do register for the session. If you haven't done so already we do have a resources document set up for you that's going to contain everything you need, plus a few relevant bits to what we're going to be covering today. So please check that out in the comments as well. If you're on YouTube, it's also in the video description. If you want to code along live with us today, check out that resources document. We've got a link to the slides we're going to be covering. We've got a link to the GitHub repo that's going to be relevant to what we're covering. You're also going to need access to your own LLM and Ideal. We're going to be using Cursor and then you also need to be able to use Docker as well. So, yeah, if you want to code along live, have those three bits ready. We're also going to be covering the setup at the start of the session as well. So you've got a little bit of time. But here is your warning also, if you do just want to watch along, make sure you register because we'll follow up with the recording tomorrow. And then, yeah, you can go along in your own time at your own leisure.
Brilliant.
I think that's everything from me. So I'll now hand you over to your host for today's session, Richie. Richie, please take it away.
Hi there, Data Scamps and Data Champs, this is Richie. So Vibe coding is maybe one of the most controversial ideas in AI and software development this year. And the idea is pretty simple. Generative AI is really good at creating code. So with Vibe coding, you push the limits of getting AI to write your code as far as possible. Now, the problem comes when AI generates bad code and you have to figure out what's gone wrong. So today we're going to be looking at sensible workflows for Vibe coding, where you get the productivity boost of AI, but you get less pain and disaster. That is. We're doing grounded Vibe coding and the thing we're building is also on trend. So Model Context Protocol is a standard for how agents interact with tools, and it's fast becoming an essential tech to understand. So you're going to be building a retrieval augmented generation system that lets an LLM access data via the MCP protocol. Actually, I think I've just doubled the acronym there. So the Model Context Protocol rather than the MCP protocol. Too many P's there.
All right.
Anyway, we're also going to be using the Cursor ID to do it. So there we go. We got all the buzzwords in one code long we got. So yeah, Mc Cursor, we got five. Coding, we got everything Rag, we've got everything. All right, now our guest is Casper Wukowski. He's a senior developer advocate at the vector search platform Quadrant. And Casper helps developers make use of Quadrant. And he's got a decade of experience both as a data scientist and a data engineer. Two jobs in one, that's pretty impressive. And Casca also founded the AI Embassy and AI Education ngo. So with that, please take it away.
Kasper, thank you. Richie, thanks for this great introduction. Yeah, and it's a pleasure to join for this data camp code along session. So today I would like to present a way of how to use AI to boost your productivity while coding. Obviously, the introduction of the large language models has changed the way we build software. And even less technical people can now code an app over a weekend. However, mature developers know there are lots of rules of building reliable and secure software. And just using the models to generate a code might be tempting yet dangerous. And there are various levels of how AI can support us in that process. From fully autonomous coding where humans don't even review the outputs of the of the model, to rigorous processes where AI works just as a smarter autocomplete with human in their loop at every single stage. So hallucinations are still a thing. And many of us can't just trust AI enough to let it write lots of code that we only skim through. So let's find the middle ground and see how AI can potentially be used in more programming like approach, making it rather an iterative process, easier to understand and digest. Not just one shop, app generation using a single prompt as an input and producing a fully running application because that rarely works. Let's just start with introducing some of the concepts because I will be definitely using a lot of buzzwords today, as RITI has already mentioned, and Vibe coding is the first one and this is actually a development approach that was introduced by Andrej Karpathy. By the way, he also introduced the concept of hallucinations, so it's good to follow him if you're looking for even more buzzwords in the future. But in Vibe coding, developers surrender to intuition rather than control over the outcomes. So with Vibe coding we leverage AI coding assistance for implementation and we only focus on the outcomes in terms of functionalities, not necessarily the code quality and things like we typically consider while we develop a typical software product. And sometimes people even use voice interfaces so they don't really need to type anything on their keyboard. But it's more like speaking to the machine and seeing if the outputs reflect what we actually had in mind while we ask it to generate a particular functionality or view. And that may sound appealing, but creating the applications is never the code itself. There are different requirements of the applications we create, dependencies, needs to connect to some external services in order to achieve what we actually want to do. And if you work in a bigger organization that might be even harder because you may have some specific coding guidelines, some internal tools and libraries in very specific versions that cannot be upgraded because they would possibly break some existing parts of the code. And that's why Vibe coding itself has rather limited applicability. And even though it can help you to build a nice looking website in a few hours, building a really complicated full stack application with lots of functional and non functional requirements might be just harder. And Cursor that we'll use for today's session is probably the best known AI coding assistant out there. And assuming you have no to little experience with using Quadrant, you could simply ask it to implement search over a certain collection. By the way, collection in Quadrant is a set of points with vector embeddings and some optional metadata that we use to organize the data. So these vectors are used to run semantic search queries over your documents to find some relevant Items. So quadrant 1.15 is the most recent version. So if I used Cursor and didn't know much about Quadrant, I would possibly ask the following question. Give it the following task. Implement certain Quadrant collection called my collection. Suggest a model from fastembed. This is another library from Quadrant that provides you the embedding models that take some input data like text and produce vector embeddings out of it and the generated code may look okay at the first glance. It uses search method as you can clearly see. However, it only proves that Cursor and the underlying LLM didn't read our release notes published last month because even though Cursor generated a lot of code, the search method has been deprecated as we unify all the interfaces in our Universal Query API. And there is another preferred way of how to search over a collection. However, even the best model couldn't have been trained on the most recent version of the Quadrant documentation because of the knowledge cutoff in the training data of this kind of models. And that's the biggest idea, that's the biggest issue of the AI assisted coding. These models don't have direct access to real time data and they somehow need to access these external services to be Kept up to date. And in the past, different LLM providers were allowing us to give these capabilities to their models, but in a different way. So we were providing some tools, we had mechanisms such as tool calling, but we had to implement that differently depending on the model provider and model context Protocol has changed that significantly and it became the common standard for major providers, making it a lot of easier no matter which model you use at model context Protocol MCP was introduced by Anthropic, the company behind Claude. It's an open protocol that standardizes how applications provide context to large language models. And MCP is often presented as a USB C ports for AI applications. So it's a standardized way of connecting your LLMs with external resources, similar to USB C being a standard for connecting your devices to accessories. And many projects adopted MCP as a preferred way of incorporating external services into the products. And in that case, MCP acts as a standardized plugin system. So let's just briefly discuss how the MCP servers work. So imagine there is an MCP server that exposes different types of capabilities like here tools, resources, prompt and sampling. It does it through the standardized interface. So actually any MCP client just knows how to discover all these capabilities of the server because it's just standardized. And these capabilities may include tools which are some sort of functions that usually communicate with external services to perform a specific task. And each tool comes with a set of parameters of specific types the model has to provide. So when you create an MCP server, you typically just write a python function with some type hints and this gets automatically translated into the protocol definition of that particular tool. But from the protocol perspective, it's a bit more complicated because model has to know how to provide these parameters. There might be also resources which are in turn like file like documents that AI can incorporate into its context with no side effects. So there is no communication with some external services and changing in the state. So just to give you an example, placing an order in an E commerce system will be a tool and a list of products will be rather a resource because that's a static document that AI can just access directly. They might be also prompts which are more like a template for the interactions with the model. Or there is also something mechanism that allows the MCP server to connect and prompt the underlying LLM of the client, because clients usually use some sort of LLM under the hood. And each MCP server might be used by multiple clients at the same time. Those might be LLMs directly, some AI coding assistance like cursor or maybe Some custom applications, because actually client protocol is also open source. So anybody can write an application that uses MCP Server somehow. And this is screenshots of the feature support matrix. As you can see, most of the tools focus on tools only, or some of them use resources. But. But tools are actually the standard way of exposing some capabilities and those are. We can expect those to be just supported by all existing clients. Quadrant has its official NCP server and we'll use it today, today to build a knowledge base for our AI assisted coding. And if you want to use it, it's called MCP Server Quadrant and that's the only official one that we support. There is a GitHub repository containing the source code of the MCP server and you can use it either as a Python dependency, so you can extend its capabilities, maybe add some new tools if you prefer, some new models for creating the embeddings or anything you would like to use. But this is just a base for building an MCP on top of Quadrant. Or you can use it as a standalone tool that integrates with your Quadrant instance and provides semantic search capabilities over your custom data to the LLMs.
Oh, just to interrupt, there's one question for the audience, so might be worth explaining a bit about what is Quadrant?
Yep. Well, I should have started. I hope everybody knows that. Yeah, so Quadrant is a vector database, so we provide vector search capabilities. So you should use Quadrant if you really want to perform semantic search over your data in cases where, let's say you have lots of documents and you don't only want to find the most relevant ones based on the presence of some particular keywords. But semantic search goes beyond that and it allows to find relevant documents even though we use completely different words, because it understands the intents. And this is done by using the embedding models that converts data, which might be text, images, audio, video, signals, whatever you want. Actually two fixed dimensional vectors, and by comparing the similarity of these vectors, we can perform semantic search. So that's what Quadrant provides and we'll be using that for sure. That's definitely important part of the whole stack that we use today. But we won't be building another MCP server. We will just use Quadrant's MCP server that comes with two basic tools and that should be enough in many cases. So the first tool is called Quadrant Store. It can take a textual document, pass it through the embedding model, create a vector out of it, and then store in a specified Quadrant collection, along with original document, the text that was used to generate vector so we can also revert that process later on. It's just a regular insert operation at the end of the day. So we can just build our knowledge base in a gradual manner simply by prompting the LLM or whenever the model actually thinks and decides that it makes sense to remember something. There is also Quadrant Find tool, which is a search operation. Similarly, it accepts a textual query, it embeds it into a vector, and then uses this vector to perform semantic search and return the most relevant documents that has been previously indexed. So eventually we receive a list of top n relevant documents, top n matches, which are sent back to the MCP client and it decides what to do with that data. But typically this data is just used straight to the is just put straight to the context of the LLM to the prompt of it, and this context is used to produce the output. So it's actually like bringing some facts that we know to be accurate directly to the prompt. And you might be still wondering, how does that apply to AI assisted coding? So let me just answer that question. Coming back to the previous example. If we put the same request to our AI coding assistant, but include some relevant examples of how a particular functionality might be implemented based on for example, Quadrant's documentation, then we expect it to be able to do it in a proper up to date way. However, the challenge here is that we need to put that information. In fact, it's still generated a lot of code, but it used the query points method, which is a preferred way of how to implement it in Quadrant how to implement search. But obviously we don't want to put these examples manually into the prompt that we sent to Cursor or any different ID that we use. And Quadrant MCP server can help us to automate this process. We can for example, extract some useful code snippets from the documentation of a particular library and then let the model query that collection directly. And that makes a lot of sense because maybe if you use a library that is unknown to you, you don't want to just search using particular words that were used on the in the documentation of that specific tool, but you just prefer to express your intents in a more generic way. And that's why semantic search seems to be like a reasonable way of how to implement it. And this MCP server of Quadrant actually builds a retrieval augmented generation system by providing this indexing and retrieval components, which are both different tools. And it enables the model to extract up to date knowledge from our knowledge base based on the query we provide. And that might be the documentation of the particular version of the library you have to use or maybe some internal documentation that has all the guidelines the developer should know while working on the project. And we will use the power of the MCP to build retrieval augmented generation application using Quadrant again and we will assume you know nothing about the interfaces of Quadrant. So that should hopefully present how you can build applications using certain tools even if you don't know them. Because that's the whole goal of pipe coding. So in the resources you have a link to the repository, it contains the pretty empty repository with an empty main file at some coding rules. And that's ultimately what we'll do, what we'll use to to implement our application. And let's just dive straight into the coding part. Let me just start with a short review of what we have there. So here is my cursor window. And this is just VS code for so. So probably many of you should be already familiar with how it looks like the main file is actually empty. So that's just an initial state of the repository and we'll be just using Cursor to build this application. So we have some configuration here. Like there is cursor that we use for the rules like some specific guidelines of how to write the code. That's what we typically create. When you use this kind of AI coding assistance that should include some general information of how you prefer your code to be to be written. And I have to tell that from the very beginning that Cursor has this tendency to write end to end applications. If it sees that there is like nothing in the repository, it just tends to create an end to end application even though you ask for a very specific, specific thing. And it actually follows this vibe coding patterns. When we have a very vague description of what we want to achieve. Build something from the very beginning and then we just iterate on it by fixing some errors. But I believe that's not the way of how it should be done. Especially if you have any experience with creating software, you know that it's more like a gradual process. So introduce feature by feature and by using it that way it's definitely way easier to just understand what's exactly happening and be able to maybe ask a follow up question, ask it to solve a problem in a slightly different way just because we understand what's going on. And that's why I prefer my idea to be rather concise and do not create a whole application from the very beginning. It's just better for me at least to do it step by step. So it's Technically not a vibe coding of an application, but more like per programming process. So imagine you had like a junior engineer that will be just writing all the code. You will be only doing the reviews of the pull request. So that's more of. Of. That's more this kind of of of programming when we specify the rules from the very beginning. However, we also need to use the MCP server for the reasons I mentioned. So let me just start with a very short introduction of all the required tools. Definitely you need some sort of IDE that is capable of using AI to create code. So Cursor is my preferred choice for today. But you can simply use Windserve plot code or maybe argument code. These are the tools that I enjoyed working with too, but Cursor is probably the most popular one. And we also need to have a running Quadrant instance. And for that I have prepared some scripts that will help us to do that. They are just here. There are two scripts that we run for the, for these purposes. So let me just open the terminal window and here I just need to go straight to the scripts and run the first one that just creates a new container in Docker. And this Docker container will just run this very specific version of Quadrant so we can use it for storing all the, all the data. And once we have Quadrants running, we need to import a snapshot of the data that I have prepared. This is Quadrant Snippets. It's also part of the repository we shared with you. So the main point here is that we don't really want to build this knowledge base. Our time is limited. But we definitely want to have some, some, some data inside of our Quadrant collection. So let's just open the web UI Dashboard. It might be accessed like this. So it's. Your Quadrant instance is just running on localhost and Slash Dashboard points you to the web UI that we have. You can just see all the collections we have here. You can access the console, possibly run some operations directly from the web ui. But what is most important for us is the ability to upload the snapshot. And our collection should be called Quadrant Snippets. You can also use a different name. I will just present in a second how you can change that. So everything should be fine. But this is the one that I set everything up for. And when I enter the collection name, I can also upload a very specific snapshot that I that I meant I need to search for it and that should import the collection that I prepared. Let's just have a quick look how it Looks like. So each point, that's the basic unit of how we store the data in Quadrant, each point has an ID and some payload information and a vector. So here there is like a textual description of what a particular piece of code implements and then we have a snippet of code that actually does this particular thing. So it's pretty interesting because we have also like a textual description of the result of a particular piece of code. So we actually encode this to a vector and then we retrieve an example of how to implement that in Python. So this is how it looks like when you open the web ui. And the next thing is that we will run the MCP server. That's another script which sets up the connection to Quadrant running on your local host. Here is a collection name that you can easily change if you decided to name your collection differently. And we also run this MCP server in an in read only mode. The thing is that we already have a snapshot of some relevant code examples and we don't want the system to put any new examples into the collection we have. So that's why we set Quadrant read only flag to true and then we only provide the description for Find tool, Quadrant Find tool that actually performs search operation on our behalf. So it describes what are the cases where when our agent should use this particular tool. So we actually also describe how the parameters look like and what to put here. But we only have a query parameter and this is the default description you can also find on the MCP server Quadrant documentation. We use UVX to run that. So so please make sure you have it installed. It's also list that as one of the prerequisites in the readme. So let's just run it and see whether we can see any output. So UV is pretty fast, so all the dependencies will be installed automatically. It will also download the model because ultimately we need some embedding model to create the vectors. And this is it. The application is running here is a URL, so we can expect it to be available. And if you use cursor you can set up the MCP servers either globally or for the very specific project. And this is what this MCP JSON in dot cursor directory is used for. It actually sets up all the MCP servers you want to have for that particular project. So there is a name of the tool and there's a URL which is actually the same like here, just different notation. Instead of local like the the IP address, I just use localhost. But that's ultimately the same address. And right now the only missing piece is this configuration of cursor. Let me just open cursor, cursor, window and here under Settings and Tools and integrations. Yeah, I just edited this MCP JSON by mistake. But let me just come back and here you can see that one of the tools is enabled. We actually have just a single tool right now because of this really only mode and this is green, so that indicates that everything is running. And if you just see the the repository we have, there is also a list of prompts I will be using today. So I have to say that from the very beginning, Vibe coding is hardly reproducible. It's really hard to create a sequence of prompts you will be sending to the system that will produce even like similar output. So I tried running that a couple of times and it consistently tries to use different libraries. So it's not perfect, but just for simplicity I just decided to keep them simple. So I'm not asking it to use a very specific library like we'll be building CLI applications or a bunch of different libraries you could potentially use for that. There are also some built in capabilities of Python like Arc Parse should be enough for that. But there is Qlik typer for example and you can expect to see a completely different output than I. Then I will produce here. So please just try to follow the outputs and adjust those prompts accordingly. So let me just come back to the cursor window we have and open the chat. I will also focus on the main file and here I can just put a prompt that will hopefully produce some some output. That is a CLI application that is able to communicate with Quadrant. So let's start with a basic application structure. So my prompt is like following. So let's create a basic structure for a CLI application that will support two commands. First of all, storing some information. So I expect to accept some text and storage in Quadrant eventually, but right now it should be just a structure. So an application with two commands with no implementation and the second one asking a question and getting an answer to it, and I'm asking specifically to not implement the actual logic. I don't want it to produce an end to end application because if it just starts creating dozens of files, I won't be even able to read them properly. So let's just keep things simple. And when I ask it to do just scans, the repository reads the release the project and as you can see it decided to use qlik, which is a kind of popular library for creating Command line interface applications. And this is okay, so we have it. We have some basic structure. So there is a store method, a store command and ask command and it automatically runs that application. So that looks okay. It also. Yeah, it decided to put it in a different, different file eventually, which is okay. I. There is also a storage storage module, which is also fine. It's always good. It's always a good idea to just keep things separated. Yeah, let's just wait until it finishes its work and we'll hopefully get a very basic version of that application that actually does nothing. So let me just open another terminal window. And also asks to run the main file, which is also fine for me. Okay, so the model was added to the project requirements, but was not installed, so I expect it to install it directly from here, so there is no interaction needed. Pip install click. I'm actually using UV to manage my dependencies, so let me just reject it and ask it to use UV instead, because that's ultimately a package manager that we decided to use for that specific.
Project.
And that should be okay. UV sync will install the. Yeah, and right now it tries to use UV to run the main file. And as you can see, there is some output. There are two commands available, ask and store. That's something I expected. It also checks whether the help of both methods is available, which is fine. But yeah, here we are. I actually skip it because we already have some code generated. We have our storage, we have our cli, and it doesn't make much sense to just test all the possible outputs. That's also what I meant. Like cursor has a tendency to just focus on all the possible edge cases. And sometimes it's not something we really want to have. But this is okay. We already have a storage. It doesn't connect to Quadrant yet. So let's just focus on the integration with Quadrant, because that's something we want to do. And I always start a new chat when I work with Cursor because there is this context window length that we cannot exceed. And if we just continue adding some new requirements, then we will easily fill in up the whole context. So it's always better when you start working on a new feature to just start a new chat, a new session, because then we start with no memories. Let me just keep all the. All the changes that it created. I will just stop the production here and then I will keep all the changes. So yeah, let's assume this is done. And now the next prompt is to create Quadrant as a search backend. So we want to Use Quadrant. We want to possibly create a class that will have this helper methods to store and retrieve. So let's create a new file. Actually that's the first time I could see it happens already. It already created the storage. So let's just modify this prompt slightly. I won't be asking you to produce a new file. It already has some methods, but let's just change that to a class. And I'm specifically asking to iteratively create this class. So maybe it doesn't create all the functionalities, but ultimately I don't want to cover all the possible use cases of Quadrant. So let's create a class and add a constructor that connects to Quadrant. So this is my requirement here. So I just simplified the version that you can see in the in the repo. But actually that's something you have to do because typically you will get different outputs. And that's what happened for me since I tested that for the last time. So yeah, we have it here. There is a class that can connect to Quadrant. It also summarized all the changes made. Well, I believe it should be fine. There is an API key that you need to use if you use Quadrant Cloud and the URL. However, that's not enough. I think that our connector should also accept collection name because you can have multiple collections in Quadrant and it also should accept a model that we want to use to vectorize the data. So let's just extend the initializer with both collection name and the model. And here I didn't start a new session, I just want to iterate on the same feature. So I just tend to put some new requirements and that should change the connector class that we are building to include this additional components. I would probably change the order of the parameters because you connect to a service, it's probably easier to follow when you just pass a URL than all the configuration that applies to that particular URL. But that's okay, I guess. And right now since we already have a model name here and I want to use fastembed, which is a lightweight library for creating the vectors. Another follow up request would be to use fastembed for creating these vectors. And we already have a model name. So this model name might be used to create a model instance. So it will download all the weights of an embedding model. So that's what we expect this what we expect cursor to do next. So we will create a model instance directly when we initialize the Quadrant connector. And yep, right now you can see it used Quadrant Find for the first time and this is desired. We wanted the MCP server to act as a knowledge base of how to use Quadrants properly. And since it didn't have that information, it decided to use that and and it sent this particular query so fast embed model initialization, embedding and as a result it got some examples of how to use Quadrant with different types of models and we don't really need to follow that. Then it tried to search for fastembed in our repository. It could find that it's part of the dependencies so it's okay.
But.
And here is how it initialized the model and it's actually a correct way of how to do it. And having this documentation provided by the MCP server helped a lot because if something changed and we would have access to the latest documentation, it should also be reflected in the knowledge base of the MCP server. However, we cannot expect the model that Cursor uses to create the to generate the text to have all this up to date information that never happens. Those models are just trained, but they are not trained every single day to incorporate the new facts. And we have it. So right now we can also start incorporating the methods that we want to have because we definitely just initialize the connection to Quadrant. But what we ultimately want to have are two methods. So we want to have a store and search methods and both should accept a string that we will either save or use as a query. So we'll either save a document or search using the query and we will use the same model for both of these methods. So I just copied the prompt you can see in the readme of our repository and right now I would expect it to add these models to add these methods again. It will query our MCP server to see what are the best ways of how to absurd store points with vectors. And that's actually what I expected it to do. It also called it differently because when it tried for the first time it could find some relevant information, but just wanted to reformulate the query because it could see that there is a query points method and it just wanted to make sure it might be used for that. So it is great because it's not just a single call to the MCP server, but whenever model decides that it might be just good to create the output properly. So we have our store method which creates an embedding vector out of the content that we pass, which is okay point ID that has to be either integer or UU ID like string. So this is also fine. And the payload will contain the Content then it uses the absurd method. That's something I expected to happen. And for the search, yeah, I actually didn't mention the limit parameter, but it's also a nice addition. Sometimes you just want to see that the first search result but sometimes you want to get 100. So it's nice to have it even though I didn't mention it. Yeah, it creates the vectors in the same way. It uses query points and that's something I wanted to have from the very beginning. And then it outputs some dictionaries and actually I didn't want to export like all the, all the documents as dictionaries. I prefer to have a list of strings. So let me just ask this follow up request. So the search method should return actually this search method should return a list of strings with the text used to generate the closest vectors, which is actually only this content fields out of the payload. So let's just do it. And like I don't really want to have the score, I don't want to have the ID because ultimately it's not necessarily needed for, for what we built. So it also changed the signature of the method. So right now it's just a list of string and it's just way easier to follow. Okay, this is it. Let me just accept all the changes. By the way, this helper method like store content and get stored content were used were kept because I didn't specifically ask to remove them. And that may also happen when you wipe code the applications ultimately it will just produce new code even though some parts of the code might be just never used anywhere else. It's better to have some static analysis of your code to detect these cases early on. And right now we can start connecting the application to Quadrant. So here we have this very basic main. But CLI has more, more logic because it should actually call the methods of the Quadrant connector. But I can already see it also accepts some metadata. I don't want to have that here. So let me just make some updates. Let me also remove some of the code. We have it. We have here question and limit. That's okay I guess but I just don't want to have that calls of this method that we want to use. Yeah, let's just start a new chat and let's ask it to incorporate the connector. So connect to Quadrant in the CLI app. So we want to use the Quadrant collector. So use Quadrant connector. Please use one of the available models. So fastembet has plenty of models available and connect to a local Docker Quadrant instance. So this is Fine. We have Quadrant running for the purposes of the MCP server itself. So let's just see if it can solve that problem too. Yeah, so it was actually trying to use the Quadrant Find tool to find whether Quadrant Connector is part of our official SDK. It's not. It's something that we created on our own, but it was able to find it in a different file. So it is okay, it can connect to. Yeah, you can also like. It also incorporated some new parameters, so you can actually use that to connect to multiple instances. You just need to provide a different URL, different collection. But this is okay. Like those defaults are fine. We can use that. And it creates the instances of Quadrant Connector in both methods and then call answer question, which is actually. Yeah, there is another module that we haven't really created yet. I just missed it somehow. Yeah, but it should be right now able to connect to Quadrant running on your local machine. So let's just keep these changes. Yeah, probably the only missing piece is to implement this Q and A because here we are just taking the answer, taking this answers and producing some content. But let's just try to run this application maybe. I think that makes a lot of sense to just test it right now. So let me just clear this. This window and close that for the time being. So if I just run uv, run Python main, it should output the help. So let's just store some information. What's the. Okay, so I just need to pass. The question by using this. Pass the content. So let's say Paris is a capital of France, So it downloads the model that should be cached later on. Okay, so there is an error of connecting to Quadrant. Quadrant should be running, but let me just check that quickly. Yeah, so it actually starts. But yeah, it doesn't make sure that there is such a collection. So that's the whole problem here. So let's just fix it quickly. Let's just open another. Yeah, we also have the previous session, so we can just continue it. So we do not create the collection to keep the data. So that's the main issue. Let me just put this prompt. We didn't create a collection, so the connector should verify the collection exists and created with the correct configuration. So let's just do it again. It uses Quadrant Find to find some relevant snippets of how to create the collection, which is fine. And here it calls Ensure collection exists. So it checks whether there is such a collection. It creates a dummy embedding with a specific model that we have and then create the collection. If it doesn't exist. So it looks okay at the first glance. Let me just see whether we can use it. I already have the previous call that wasn't successful, so let me just call store once again and it was able to store that in our collection. So now if I open the dashboard, there should be two collections because one of them is for the quadrant snippets and another one is for the document. And yeah, we can see we have the fact that we wanted to store here, which sounds like a success. Okay, let's just put another fact. Maybe Berlin is the capital of Germany. We have it. And right now if we use the ask method and we provide a question, what is the capital of Germany? I would expect it to produce the set of results. Okay, there are some errors with the format answer method, but let me just simplify this. Maybe we don't really need to have this format answer. Okay, so there is question, there is answer. Okay. The easiest thing that we can, we can do is to copy the error directly to the cursor and that's ultimately what the session that we used to create that functionality. So let's see whether it is able to fix it. Okay, I'm not even checking the changes, I'm just trying whether it worked. Yeah, and Berlin is the capital of France and this is based on two relevant documents. Actually we just asked for five, so that's why we got both documents. And that's basically it when it comes to taking documents in order to create the retrieval part. But still it doesn't use any sort of LLM to, to produce the answer. And I don't really want to have like a list of relevant documents. They might be possibly long. So let me just build this Q and A and ask another. Create another task for cursor. This time I will ask it to extend the answer question function so it takes the extracted text and send them to Claude API, which is one of the LLMs that we can use for this kind of purposes. And the model will answer this question based on the document we pass along to this, to this API. So let's just try whether it can perform this task too. So it even tries to get some access. The API of Anthropic, I'm not really sure if that will be successful, but it will also try to find some libraries that are needed and actually build what I expected to build. So it should be okay. As long as it can really use the API of Claude. It seems like it can connect and it also expect the anthropic API key and that's what I expected too. Here the end of example is actually you should just copy it and create the dot and the file that should contain the real API key. You don't really need to do it right now because you already had the retrieval part and you maybe want to experiment with different models like Gemini or GPT from OpenAI. But here I would actually expect it to work and the only thing that is missing in my opinion is that we try to load that from the environmental variables, which is okay, but still this variable should be also loaded from the env file. So let me just ask the following follow up question. Let's load the ENV variables from env and it will also add Python ENV to the list of the requirements, which is a correct behavior. Hopefully it will also. Okay, I will skip it. I already have an env file so I don't need it. Skip it. And what's exactly happening? Yeah, it will just load the dotenv, which was something I expected to happen. So let's just see whether our questions can be now answered by the LLM instead of just producing a fixed response. So I would just keep it. That should already work. It summarized all the changes. I see it didn't install all the dependencies, so let me just start another terminal window. We will do it on our own and UV Sync actually installs all the dependencies that has happened. And right now. When I run this command I would expect to have an answer produced by the LLM. But let's see. Okay, we have an issue with connecting to Cloud API and I believe that's unfortunately not something we can fix right now because we are running out of time. But I hope you get an idea of how to use the MCP server to provide this relevant context. Probably it would just work better if I just put the cloth documentation together with Quadrant documentation to the same MCP server because it could also use the same search capabilities to search over the cloud documentation. Unfortunately it didn't work. But you can also see like there is an example of what may go wrong if you don't have access to the latest docs of the tools you want to use. Cursor has this web search functionalities that's actually implemented by us running some commands in the command line like curl or something like this. But ultimately it's not really able to find the relevant information. At least it wasn't able to find it in our case. If you just have a look at the changes made here, it's actually okay, at least at the first glance. But apparently it doesn't work. So in that case I will just undo all the changes made in that particular session and we'll just try to run Terminal again and see whether we can still get the same response like we had when I called it for the, in the previous. For the previous time. Yeah. So it's actually getting the, the answers from quadrunner. It's not, not producing the output using the LLM. So that's an issue of LLM based coding that you may encounter. And MCP servers are actually one of the ways you can try to mitigate that, that, that risks. Thank you very much. I'm looking forward to the questions you could possibly have. Feel free to ask them.
All right, thank you, Casper. That was very cool stuff, I have to say, like coming from a background where you sort of writing code directly in the ide, like the idea that you're almost just watching the code window and everything you're doing is sort of is prompting. It's weird, but it's very, very cool. I also like that there are ways of dealing with things that go wrong. So for example, just copying and pasting the error and saying what is this? Please go and fix it. That kind of works. And you can roll back sessions when things go wrong. So having those escape strategies does seem very important. We've got one question from the audience. Before we go to that. I just want to announce some upcoming webinars. So on Thursday we've got a session called pricing and monetizing your AI products. So I've got a couple of people discussing like different pricing strategies. Whether you like want to provide subscriptions for your AI features and products or provide usage based billing. You've got a few different options and what the trade offs are so very important if you're building stuff in a work environment or you want to make money out of AI products. Next Tuesday we've got another code along with some from crewai. So CREWAI is, is a like a commercial agent creation platform. So yeah, please do come back for that. That if you enjoyed today's session and then next Wednesday we've got a code along on building a referral pipeline for go to market. So if you're interested in how marketing works in a quantitative way and want to build around that, then please do come back for that. All right. Actually before we go to the origin, I guess as I was watching you it seemed like there's a, a trade off between you ask the. You're supposed to do like create a big chunk of things and, and it Generates lots. So you're very productive, but sometimes it gets things wrong. Or you can give it sort of more like tighter specific questions and generates a little chunk, but it's more likely to get it right. Do you have a sense of like how you judge what an appropriate scope for your prompt is, like how much code you want to generate and in any one go?
Yeah, I think it's a bit easier for me because I have some software development background. So I actually prefer it to produce a single feature at a time. So I'm not expecting to make lots of changes across multiple files. It's always better to just iteratively build, let's say a class because ultimately as developers we just try to type down our thoughts and create a logic that implements our thinking process, so it's better to follow it. However, for less technical people, it might be just easier to wipe code the whole applications. Actually there isn't. It is possible, however, you will struggle at some point with the deployment. So I prefer this iterative approach and scoping, throwing down the scope of feature I want to implement. But anything that works for you is fine as long as you can build a product.
Okay, yeah. So I guess it's gonna be a matter of personal taste and just whether you prefer spending more time debugging or more time sort of thinking about what you want to build up front.
Exactly.
Okay.
All right, wonderful. So there are a couple of questions from the audience. So this is a complicated one from Mehdi, so maybe we'll break this down into a few sections. So first of all, can you talk about what are tenants in the context of vector databases? I think maybe we'll take this one in sections. So, yeah, do you want to talk about what are tenants and why you might want multiple tenants?
Yeah, of course. So it's a typical scenario when you build a real enterprise grade system. So if you have data coming from multiple customers, for example, and you just don't want to mix the data, so you don't want to like search over the data coming from customer A if a customer B is making a request. So in multi tenant environments, it's all about like stitching up the collection in a way that single organization, a single user cannot access the data coming from a different one. And the good practice when you use Quadrants is to still use a single collection, but to create additional index similarly to what you would build with relational databases too. Like, you won't be having a separate table for each customer. You typically have a column that will be used for the filtering and you will apply this filter for all the queries you send. And similarly here in Quadrant you will have a payload index and payload field probably or user id and you will be always filtering by that field when you will have some queries. I can also try to answer that question directly.
Yeah, sure.
Actually it's not that different. The model context protocol, the MCP server we have is not that different from just using query run directly because it's ultimately just calling the function under the hood is just providing the list of tools in a way that is easy to digest by the LLM. So if we speak about relevance and latency, it all depends on the hardware you use on a setup you use for your system. Also about the model, because relevancy is strongly dependent on the model you use. If you have multilingual data, then you shouldn't be using some of the English only embedded models, for example. Or if you work in a very specialized domain, relevancy of the search might be measured. There are some ways of how to build some ground truth data sets that will just be used to evaluate the quality of the search results. Yeah, there are just various aspects we should probably discuss a bit longer. But the thing is that MCP server is just a lightware wrapper around Quadrant search. So whatever you can achieve with Quadrant, you can also achieve with the MCP server, probably with some custom modifications. And yeah, when it comes to multi tenant vector spaces, yeah, it's also possible because you can have this tenant index created, but it's not built into the MCP server directly. Actually the idea behind the MCP servers at the very beginning was that people will just run them on their local machines and they will connect to vector databases for examples, directly. So there won't be like a short Quadrant instance for example. So yeah, that sounds like a challenge, but I'm pretty sure it's easy to be solved since that can be solved with Quadrant itself.
Okay, that's a very technical answer, but it does sound like it leads nicely to this next question from Diptimon. Talking about are there any security issues around using MCP and what are the techniques for deployment here?
Yeah, it's a common concern. So we support all the three modes actually, standard input outputs. But the thing is that people, as I said, people at the very beginning were setting up their MCP servers locally on their machines, so there was no authentication. Right now the authentication is built into the MCP protocol, so you can also use it, but it's a challenge. Actually there are some startups around MCP that try to solve that, I have no clear answer. Unfortunately, you can use the authentication that is built in, but I can imagine in a very specific problem you may just need some different means, so. Yeah, but it's just part of the protocol. Nothing that much related to our server. But this is a common issue.
Okay, so it sounds like you just need to think about authentication to decide who gets access to what tools or what data sets somewhere in your application. And there's probably a few different ways to do it at the moment. There's no sort of standardized.
Yeah, that's a common issue, unfortunately, like how to do it properly. Because it's not only about the server itself, but if the server communicates with a database like Quadrant, we have this ability to perform role based access control. So that could be possibly used to achieve that with the MCP server of us, of ourselves. Yet it's not implemented. If you have any requests like this, please feel free to reach me out. I'm actually pretty surprised because all the questions we had so far were so deeply technical. If you could work on some serious problems. So I'm really happy to. To discuss that further.
Wonderful. Yeah, so I guess for anyone who has further questions, please do connect with Casper on. I. I guess LinkedIn is. Is that your preferred place to meet people? All right, wonderful.
Okay.
And with that, we are past time, so, uh, thank you once again to Casper. Thank you, Reese, for moderating. Thank you to everyone who asked a question. Thank you to everyone who showed up today. I hope to see you all again in future sessions. All right.
More from Richie

#359 My Best Friend is AI with Valerie Tiberius, Professor of Philosophy at University of Minnesota

How AI Agents Will Work While You Sleep | Ruslan Salakhutdinov, Professor at Carnegie Mellon

#358 How AI Agents Will Work While You Sleep | Ruslan Salakhutdinov, Professor at Carnegie Mellon







