SUPER COOL - Build MCP Servers with Xano!

Ray Deck builds an MCP server in Xano, showing how to create tools, authenticate users with API keys, and expose them via public URLs. He tests with Cloudflare's playground, explains why MCP beats plain APIs for AI discoverability, and covers security trade-offs like token rotation and tool visibility.
Chapters
So Xano now has support for Model Context Protocol and Model Context Protocol is very cool, but I figure if you're watching this video, you already know that Model Context Protocol is very cool. And the question is how do we bring it to bear in Xano and why would we want to use Xano for that particular job? Because, you know, there have been other tools that have been built with sort of a little more codey, you know, I'm thinking particularly of like, you know, building with Cloudflare or the MCP reference specification. But the neat thing about, you know, the Xano implementation of it is that allows us to make use of this no-code function stack that really allows us to move very fast and create code that's relatively ownable. And that function stack is the reason why Xano is really good at making these APIs, right? So like I can go in, I can have an API, I can go search my silly little chess boxing application here. I also have on the same, you know, scratch space, I built this for a hackathon. And the idea is it just makes it very clear how it is I'm going to build something and how the logic should run to be able to, based on input that I have from up here, be able to go generate an output that's gonna be useful for my customer. Well, MSAP is really just kind of like that, like API inputs in terms of both being able to gather data and be able to express your intent to be able to change things. I call it giving AI eyes and hands. And, but AI is a little bit different in the way that it wants to work with us. And those two ideas really come down to discoverability and natural language. These two differences allow MCP, are the reasons why MCP has, you know, value over just, you know, using the APIs. And we're going to be talking about those in turn. We talk about how to bring MCP in Xano. And I think using Xano for MCP can be a really good way to go very, very fast. So let's talk about this. So, you know, Xano, for whatever reason, decided to call their MCP section AI tools. They're only MCP servers. They are just, this is the MCP server section. And so we can create multiple MCP servers inside our Xano instance. I, for example, have made two for state change, one that's a regular one and the other that is specifically targeted towards being able to support Deep Research in ChatGPT because there's a special format that Deep Research uses. But you know, you can create an MCP server. It contains whatever tools you find handy. Now this gets to like a really important part about MCP, which is that names and instructions matter a lot. This is what I mean by discoverability being something that really matters. Also, frankly, discoverability comes in the form of natural language. So the fact that we're calling this the, you know, state change, you know, YouTube MCP, you know, demo, right? Remember, we don't need to call it an MCP server because it is an MCP server. There's no X factor about that. And this is going to be, you know, fun utilities for interacting with StateChange YouTube. Okay, cool. So really the more information you put in the instructions as to why this resource makes sense, that would be really helpful. For example, with StateChange, I talk about what StateChange is in terms of having information about hard technical problems, debugging techniques, mental models for software development, et cetera. And by doing that, it helps the LLM understand when it should be using these tools versus something else for solving a problem for their customer. I can say save. And now I have an MCP server. And now I'm going to go add a tool to that MCP server. A tool is basically just a function that's going to run inside the MCP that's going to run in this context. You can think of it as being parallel. It's not quite the same, but parallel to an API endpoint's relationship to an API group, right? It's like this is gonna collect a whole bunch of them and be able to run them out. Now the tools themselves again have an issue of discoverability and issue of natural language. The first issue is discoverability. I'm gonna make a very simple little Echo server called greeting and we'll get a friendly hello. From the MCP, use when you are, are feeling down, send a message that is going to be lifting. Okay, so the idea here is that you're both the name of it as well as the instructions should be pointing towards how someone's going to use it. They're not going to use like Swagger documentation. This information was actually being delivered directly to the LLM to inform it as to whether or not, as to what this tool does and whether it should be used. I can say save here and then I can add an input, which would be like a message, right? Now, the cool thing about the input here is that the description actually goes with the information that's going out to describe this to the client. Right, so this is going to be, you know, uplifting message for a cloudy day, right? And this is going to try to give a hint to the LM server, or, you know, whoever's trying to help the user, that when this particular tool would be helpful to them. So it's using this plain language to decide whether to run this. Right, we're not programming it to specifically run this endpoint, right? We're giving it hints and allowing it to decide. This is the essence of agentic decision-making. I can say add that input, right? And I have a message. Now I'm gonna need to add a function. So the function I'm just gonna do is gonna create a variable, right? Gonna call it, you know, content and say, say, hello there, right? So basically say nothing at all. We're just gonna see how this worked. So now it says, hello there. And I can just do a quick run. I'm gonna say run and it'll give me back, hello there, right? So more interesting is gonna be something actually is responsive to the message. Hello there, sir or madam. Your message today is. And we'll add a filter of replace. Right. And we'll research will be for message. Right. And what the replacement will be the message, the input. Right. So now let's just say save that and we'll run that again. And you can see how if I just give an input, You've got this, right? So you got this. So this allows us to identify that this particular message is something that we want to send back in the event that we use this through our model and we'll just, and now having set this up, we can set this up for publication and we can just run it right now. This gets to the problem of like, how do we give the MC, you know, how do we tell a client about it, right? So here I'm gonna bring in something else. I'm gonna bring in the Cloudflare MCP Playground, which is a really cool little tool that's completely free that uses these simple little models in order to allow you to test an MCP server. So what we can do here is, and this is playground.ai.cloudflare.com, and so what I can do is back off this tool and in the context of the, this, the MCP server, the state change YouTube demo, I can go grab the connection URL. I'll grab this and say I'm gonna copy, you know, you can use either of them. The SSE is the older standard. It has a wide, a base of support as insofar as, anybody supporting MSPE at all. Streaming is the newer standard and is required by some of them. For example, I'm pretty sure that Anthropic's new Claude desktop support requires using streaming. But a lot of the rest actually kind of require SSE because that's all they've updated themselves to, to support. The streaming protocol only was introduced as a standard, I think, in March. So if we, this is on modelcontextprotocol.com, if I go take a look at the specification, yeah, right, you can see at the end of March there was a new turnabout in the spec, which actually makes it far more useful than it used to be. And XANA was starting to catch up to what's going on in the spec. Okay, so the idea here is we have an MCP server that's gonna give us a greeting and we won't be able to test it in this playground. So how do we do that? We're going to, I'm just gonna copy the older standard, like I say, 'cause that's what most folks use. I'm going to go over to here and I'm going to paste this in. And now you can see the URL is made up of my domain name, my, you know, this little x2 thing, which is always here, /mcp/. This is what Xano calls a canonical, which is an identifier for your MCP server. I'll show you how to change that in just a second. And then this is actually what it calls a token, which is going to be key to us being able to introduce authentication. Followed by just the term SSE. You're gonna find everything up to this point, I'm sorry, everything up to this, everything before the SSE is standard. The SSE is gonna be different and then the different from the HTTP streaming version, which is gonna say stream at the end instead. Otherwise the URLs are the same. So I can connect and now it says connected. You see it knows that there's a call greeting. It's like, you know, I am feeling sad. Send me an uplifting message. They run that, determines, oh hey, look, it got it from the tool, right? Hello there, sir, madam. Your message today is that you are strong people. Things will get better soon. I'm so glad for that. So this is the basics, right, of how we can have a message go. And you can imagine that like one of the big use cases here is gonna be like, you know, searching for things or being able to express something into your system. Or whatever else. But let's keep going here. You know, let's talk about how, you know, having something that's public like this is one thing, but like most of the stuff we want to put out there isn't really public, right? It's gonna be like specific to people who are logged in, who are users of our system. But we don't have access to like the built-in state change, built-in Xano authentication right now because Xano authentication is based on the authentication header, authorization header. And the problem here is that XAML does not have support for the client to discover how to get that kind of token, right? Through a process that's called OAuth. I'm sure it's coming down the way, but there's a second way of doing this too, which is to encode information about the user identifier of the user directly into the URL to like having some sort of, you know, secure string that we're going to work with. So let's talk about how we would do that. Now in my, you know, little test database here, I have, you know, users, right? And I have, you know, email, which is, you know, hi there too. And then I'm gonna call it, you know, hi@statechange.ai. And then I can have username, password, and I'm gonna create one more thing here. I'm gonna create an MCP key. See, the MCP key is gonna be a unique, an API key that's going to, that will identify this particular user. Okay, so 12345678. And then I'm going to have another one, which is going to be hello@statechange.ai. And the MCD is going to be ABCDEFGH. Okay, and now I'm going to have after that something else, which is going to be a name, name. And this is gonna be, you know, John Smith, and this is going to be Roberta Jones. Okay, so we have John Smith and Roberta Jones, and there can be 1, 2, 3, 4, 5, 6, 7, 8, and A, B, C, D, E, F, G, H. And the idea behind having a key, and the way I would usually make these keys is through having the UUID functionality in Xano. So, you know, I can sort of imagine creating a function here where I'm gonna add a function, gonna be, you know, set, you know, set MCP key, right? And then, you know, the input's going to be a table reference to my user table and then I'm gonna say that the, I'm gonna do a UID, generate UID function. And which is gonna be called UUID. I'm gonna call it key, save as key. Uh-huh. And then I'm also going to do an edit record in user, right? Based on the ID being the same as the user ID that came in the door and the MCP key is just gonna be the, the variable that we just created, key. All right, so now I have a function called set MCP key that is going to set the MCP key to that particular ID., right? So if I do 1, right? And now what you'll find is if I go back over to database, database, oh, there we go. User. Okay, now you see my mcpkit starts to look like something a lot more secure, right? And then I can also do that maybe for user number 2. 2, run. What? Mm-hmm. Okay, and now I have the, you know, now we have the database user, and if I refresh this, you can see both of them are now set to something that's nice and secure, not just my little ABCD thing. Great, so the idea is I only want to allow my users to be able to access my MCP server, right? And the way I'm going to do that is what's called URL-based authentication. So I can go back to here and go over to my, you know, AI tools. Okay, fine. And go to my state change and see that I've got this greeting here, right? And previously it was just sort of working for everybody as we saw on the LLM playground. But what I can really do here is I can now say I want to create a, you know, a set middleware for it. And the middleware allows me to authenticate it. So I'm gonna customize this and I'm gonna add or, you know, and add pre middleware, right? And what middleware do I want to add? None of that. Nope, no sir. So I'd like to add, well I guess I just have to create it. So I'm gonna create it over here, discard the changes. I'm gonna just create, Middleware over on my right, library middleware, and create new middleware. And my new middleware is going to be MCP auth and it's going to be of type merge with a critical. So the idea here is that I'm going to ask about this particular user. Now, How do I know which user I need to work with? Fortunately, the idea here is that there is a token that will be specified in the URL. And that token is where that second MCP part goes. So remember I was looking at this thing, looking at the URL, and I was looking at how, you know, over here this was a thing called, you know, MCP, right? Two MCPs in here. Well, the second MCP, I could do A, B, C, D, E, F, G, right? And it would give me something different. In fact, let's prove that out for a second. Let's, we're gonna come back to the auth here, but let's go take a look at AI tools and we're going to look at it in the toolset, right? And we're going to go back to my greeting and how about instead of my greeting where I said hello there, sir or madam, how about instead of sir or madam, I gave it whatever my identifier was, token, right? And I'll just do another replace down here of replace, right? And replace the all caps token with, and this is the fun part, with a toolset token. So toolset's a new thing that we see now in Xano, like both for your functions, for your middleware, but especially for your toolset tools. These are things that are available to you about the toolset itself that have come in the door. So like the name, the JSON is gonna be like a bag of information about this particular, MCV server, but the token is gonna be from the URL itself. So if I just apply this for a second, I say save, then I'm just gonna go publish this up. If I were to go back over to the LM Playground, remember how it said hello there sir or madam and I changed it? And now we just change it to ABCDEFG, right? In this particular location, you can run this. Hello there ABCDEFG, right? Because ABCDEFG was actually the name of the token. Right? So if I just disconnect this and I say 1, 2, 3, 4, 5, 6, 7, and I say connect to that again, and I just tell it to, you know, you know, I am feeling kind of okay, but I could use a pick me up message. Good. Okay, so the idea is, so you now see how like I can get that out of the URL, right? And that's coming from the thing we saw over here that is called, you know, token, right? So we can put this to work in the form of the middleware, right? So we can now say the middleware can check the token. So let's, you know, let's do a, you know, a get record right from user where the key is equal to the token that just got passed. That's the essence of the authentication. That's the ballgame, right? Where we can link the token to the user. Now in the case of state change, I actually have one more level of articulation. I have a list of keys and I have a list of users and they sort of relate to each other. But this is really simple way of going about it. Now I can say I'm gonna go get that, right? And by the way, if you aren't found, I'm gonna make a precondition, right? And we'll just make sure that the user1 is not null, okay? Just confirm the user exists and then the error type will just be access denied. So if the user isn't found, well then we're gonna bail. Save, okay. So the idea now is as simple as if I find the user, then I send it back, right? But there's actually one more benefit I get from this, which is when I authenticate using middleware, this is your free bonus. When I authenticate using middleware, I can, you know, I can have, you know, user1 come back as user and this will get merged in as an input. So for those of you who haven't really worked in middleware before, this is actually a really cool aspect of middleware that will become really useful in just a second because now I can say publish that, publish. Right? And now I have MSP authentication that contains all this good stuff. Now what I can do now is go back to my greeting. In fact, what I'll probably do is make it so that all of my, you know, all of my tools that are in my MSP server will use this particular middleware. I'll say save. Okay, so this means that like if I am authenticated,, it should say okay. And if I'm not authenticated, it should not allow me to get a greeting. Let's test this out for just a second here. Remember, I've got my good users, I've got my good MCP keys here, right? So let's now go back over to the, to the playground and let's remember that I had this stuff in here. Right now it says 1234567, which is not a valid key, right? So let's, let's copy and paste this and get it to run on my server again. And it's gonna freak out. It'll error out 'cause it won't be able to get it. Error code access denied. You see, it couldn't actually get it going, right? It was able to try the thing, but you see it hit the precondition because it didn't actually have a good access key. Let's give it a good access key. And then we'll go back over to our playground, right? Let's connect. And now we'll replace this 1234567 with my actual token, right? So I'm just doing a little string replace here. Connect. Now we'll run. Ooh, sorry, I need to go, you know, gonna give it the same kind of, you know, mid message. See, now it gave me an answer, but we can do a little better, right? We don't need to just connect the code. The code is not very interesting. What about, you know, if I'm gonna get an uplifting message, I'd like it to know who I am. So let's work with that and I'm gonna go back over to the server now, right? And I'm gonna go into my greeting, which right now, knows about my token, but we can do better. What if we just have one but name, right? How can I replace name with that? Something useful. And the answer is I can get it because I know it's in the middleware. So in my input, there's nothing that matches token, right? Right now there's only the message or is there, this gets to be the secret weapon. See, when I made that middleware, it was set to merge. Merge means it's going to add whatever I put into the response from a structure point of view into the list of inputs that are available to the function stack. Now, Xano doesn't currently surface, at least as of this recording, doesn't currently surface these fields in the function stack even though it knows I had that particular middleware. Instead, I have to kind of hack my way to get it, in this case by using an expression. So if I just, you know, turn this into an expression, I can say, you know, input.user.name, 'cause I know input, there's something called user and in the user there's something called name. I know that because I set it up in the middleware, but I'm not gonna get any help from Xano from an autocomplete point of view or even exposing it. I have to do it and I have to do it through the expression. But when I do, I get all sorts of superpowers because the fact they've already gone through the trouble of getting the user is now exposed to me. This is kind of like the sort of the for-free auth ID that we get from authenticated endpoints, except, you know, in this case it's a full object and it's a little more hidden than average. But let me apply that for a second because it's really slick. I'm gonna say save, I'm gonna say publish, publish, and I'm gonna go back over to my worker and now I'm gonna say nobody remembers me. Well, say something nice. John Smith. It remembered that my name was John Smith. That's fantastic. And it knew that because I'd put in this token, right? That's here, right? And if I disconnect and I say, well, I don't want just, you know, John Smiths, I want, I don't know, like with AA at the end, right? Something with corruption to it. I connect, well, it'll connect and that will say, you know, let's try the same message again and it'll freak out because it doesn't actually authenticate, right? So now I've set up that I can only do it with the correct key because I know of that position where it goes into. Let's copy that for a second. This is actually a good use case for how we set this up with an auth, right? Just to get the user. If it doesn't work, precondition out and if it does work, I get access to the user. And now that gives me basically all the elements of role-based, the prerequisites, right, of a role-based access control system that I can then implement through logic in the function stack, which I think is pretty cool. I can also create a function for myself that is, you know, get, you know, get MCP, MCP for user, actually MCP URL for user, which might be important for me to deliver to like a front end at some other point because I have to have an app that's gonna tell the user about their particular token. So I can say save here and I can say maybe I'll just sort of take a user ID as an argument and then I will just make myself a string. Call it URL and it's just gonna be based on this particular stuff in here, right? Now I can just say token, I'll say the filter is going to be replace and which is going to be based on user1.mcpkey, right? Now I can say save and if I run it, then I can go pull user ID number 1 and it gives me the URL that I was looking for, right? That has this F384 thing, blah, blah, blah. And then I'm going to put this into the LLM Playground. I can disconnect that, right? And paste that in. And now I get all that same good stuff and it works., right? And I'm gonna tell it to do another message, run it, right? And we'll be able to successfully connect because it actually gave me a good URL. Now that sort of completes the cycle in terms of being able to have a tool that is able to be authenticated, right? Using middleware to give good data from Xano using MCP. Now we have something we can safely give out to our customers, but we might not choose to because, you know, it doesn't actually look all that friendly, right? This dzpoAuth thing isn't super friendly. Like the token we can live with as being less friendly 'cause that's specific to the user. Well, you can explain that part, but the other part here, you want to have like a good domain. I recommend, always recommend using custom domains. The x2mcp, that part's fine, but this zdpo thing, that's kind of ugly, right? Can we do something about that? The answer, yes. We can go back here and say change YouTube demo. I can change by going to where it says security here and change the canonical ID. I don't bother changing the GUID. There are good reasons not to play with that, but this one I might call YouTube, right? And the— I can say save, right? And now when I go pull the connection URL, if I were to just look at in here for— I'll just bring it up in a browser for a second because it's easier to see. You can see how it shows as /youtube, no longer has the stuff. This makes it so much easier to look at. And in fact, if I go back over here to my make function here, then I can also fix this guy and say, you know what, sir, you can say YouTube, right? Say save. And now I can go run again. I can go copy that text I can go into my workers area. I can say disconnect this, paste that in, you know, with a nice friendly YouTube name, right? I'm going to say connect and copy that. In fact, you know what? I'm going to do you one better. Let's go back over to here and let's look at user number 2. That way I'm not looking at the same user all the time. Let's see what Roberta, Roberta probably deserves a nice message too. And we'll copy that and we'll go over to here. And we will just say disconnect and then, you know, different tag and we'll then connect into, run that, give another message, see how it does. Roberta, it remembers Roberta's name. Isn't that nice? And now we have a way of sending message that is gonna be specific to this individual user. We have something that's nice and shareable, we have a function that allows us to do that with a great deal of simplicity and we have our MCP server. Now there is one more aspect that's probably worth giving some consideration to when it comes to security, at least within the bounds of like what Xano currently supports. It would be even better if we had OAuth2 security, but you know, that's hopefully that'll be coming down the road relatively soon. But right now this is actually what frankly most MCP servers do anyway. In fact, it's a level above, security most MCP servers have. So I'm pretty content using this and we're using this right now in StateChange. But there is one more consideration, which is that the list of tools themselves can give an attacker like a vector for understanding what's going on. And right now, the, you know, when I'm looking at this, you see how it shows me available tools? Well, if I were to disconnect and give it a bad URL, it would like if I just said, you know, XXXX, right? And I did a connect here, it would connect and tell me about the tools even though the tool wouldn't actually run. And there can be, and because like the descriptions going with the tool, maybe you don't wanna show any of that. You really want this thing to be locked down. And you know, we can do something about that. We can do that with a trigger. So here we have, you know, we talked about middleware already and now we're gonna talk about the trigger. The trigger allows us to control tool instructions because the way MCP works under the covers is that when they get the URL, they can call a specific command on that URL to get the list of the tools like we're looking at here, whether it be 1, 5, or 100 of them. And the, but the, you don't have to just show all those tools. You can use this trigger kind of as like middleware for that list API to determine which tools are actually going to be shown. So we're going to call this, you know, MCP filter tools by auth, right? I'll say save and I can click into that and now I can have a function stack. Now what this does, it brings as an input what's called toolset and the tools. The tools are really the important part here. So what I can, the first thing I can do is I can get a record that looks up that same user just like we did before. And that I go by the user table, I'm gonna look it up by the MCP key and I'm going to use where it says toolset token here, right? So that way it's, you know, the one for Roberta and one for John. And I'm going to say save here. And really the key question is whether or not I found anything, right? So I'm gonna say, you know, you know, if add a condition, you know, if user1, right, is, you know, equal to nothing, right? Basically if nothing comes back when I go look up the user based on that key, save, then I want to, you know, update the variable that's called tools to basically say it doesn't have anything inside because right now tools is a list. You can see it's structured as an array of object up here. It is a list of the tools that are exposed. In this case, it'll just expose greeting, right? And have a list of items, one which is gonna be greeting and its description. And you can go modify all of that. You can just modify the way it's described. You can modify whether it's shown at all. I'm using it to modify how it's shown. By doing this, I can say save and I can publish this and I've created a very simple way to lock down my MCP server so that instead of, oh wait, you know, you can try to use it, but it's going to block you. I can just disconnect and connect for a second and look at that. It gave me nothing, right? Because it couldn't get back a tool and now it won't let me connect. But, but, but, but if I didn't have those Xs in here, if I just had a proper URL that was made up of a token that went with somebody who was, you know, securely in here, right? Editing in these kinds of situations is actually quite hard. Yeah, with EF, see, now it shows me the Matool. So, and you can like do things in the middle here, right? Like say, I want to show these two tools if you are authenticated and these two tools if you're not. You can even having decided, figured out who the user is based on their ID that came through the URL, decide that there's going to be some people you want to allow into your, allow into your system and some people who you frankly just don't and you do not want them to come in at all. These are, these are the key functionalities that you can apply to have a pretty secure MCP server that is available to your employees and available to your partners, available to your customers. And, you know, all you need to do is be giving each of them their own URL. And we've already talked about how you can relatively easily generate that URL by having the idea of a key that goes with that particular user. You can introduce the idea of key rotation, etc. And, you know, the thing about MCP is that it's really fast moving. And the techniques that you use today are not necessarily going to be the same techniques used tomorrow. I kind of wonder how well this video itself is going to age. But the most important thing is making sure that you are giving your clients the, you know, the best foot forward for your business. And for me, the big opportunity here is that rather than you having to create a whole lot of software on the front end to define the user experience, you can be delivering your data, your logic, your intelligence, your business insight directly into wherever it is that they work. And you can be providing a better experience for something that actually could be a whole lot less work than it was before. We'll talk more about the business implications about this in future sessions., but right now, I hope that this has given you enough to be able to, you know, go try making your own first MCP server with Zano. And I would absolutely love to hear about it because at StateChange, we work on the hardest 5% of challenges related to shipping software. And often the hardest 5% is the new stuff, the stuff that's changing all the time. And I find this to be super, super exciting. And I can't wait to hear what you build and talk to you next time.










