Complete Intro to MCP

Create the RegisterTool

Brian Holt
Databricks
Complete Intro to MCP

Lesson Description

The "Create the RegisterTool" Lesson is part of the full, Complete Intro to MCP course featured in this preview video. Here's what you'd learn in this lesson:

Brian begins coding the API-based tool for the issue tracker MCP server. A makeRequest method is added. This method is a helper function that formats the request's headers and completes the request to the API URL. A JSON data structure is returned from the method.

Preview
Close

Transcript from the "Create the RegisterTool" Lesson

[00:00:00]
>> Brian Holt: So let's go back to our my MCP that we were developing before. Let's implement a tool that just creates issues. So let's go to VS code, not this one, we're gonna get rid of this one. I think we're done with this one. For the rest of the class, we want just the issue tracker, which is this one.

[00:00:30]
Okay, and we're here in my MCP. So the way that I chose to do this is I'm going to create another file here, call something like API based tools. Okay, and I'm gonna import Z from Zod. We're going to export a default function that basically defines all these tools.

[00:00:58]
So we can keep it in two separate files. API based tools server and then down here at the bottom. Actually, we don't need to do that because we did that. This server will be our MCP server that we defined here in main JS. Okay. We're going to say const API base URL is assigned process env apibaseurl by default we'll have it be HTTP localhost3000.

[00:01:38]
That's what I have the API server running on. You could also do 5,173 as long as the front end server was running because it's proxying it through vite/API. Okay. And then we're going to make a helper function here. Async function makeRequest, have a method url, data = null and options = blah.

[00:02:18]
We'll use this for the rest of our requests. Const config equals method headers. It's always gonna be a JSON type, right, content type, application/json and... Options.headers. And then if data, then config.body = JSON.stringify data. I mean, I'm basically reimplementing Axios here, right, you probably could have just done this all with Axios.

[00:03:08]
Const response = await fetch url config const result = await response text, let jsonResult try jsonResult = JSON parse and catch. If it fails to parse, just make it the actual result. Okay, and then we'll return status response.status data jsonResult and headers will be object from entries response.headers.entries.

[00:04:32]
I didn't do that at the top, did I? No, I don't think I did. Yeah, up here. Sorry. Above data. Just making sure that the headers get passed in as well. Const headers, options, other options Right there. Object assign config other options. So just pulling in the options from this and making it More flexible.

[00:05:31]
Okay, and then catch error down here and return status zero error error.message. Okay, so now we have something that can make requests and then we're going to come down here, make sure that we're in the right function here, purple one, there we go. Server.registerTool issue-create title create issue description.

[00:06:32]
Create a new issue in our issue tracker input schema. We have quite a few here. Title will be a z.string.describe issue title. So again, whatever you put in describe is pretty important, with sod, whatever, who cares, right? But specifically with MCP service, it's really important here because this is what the LLM is gonna use to decide to put in here.

[00:07:28]
Status. What do we need to do description first, description Z.string.optional. Because it is optional, describe issue description status Z enumerated type enum and it can be not started in progress or done. It is optional and describe, I put just issue status in here. These are probably not the best descriptions of them, but I also wasn't having any issues with it.

[00:08:41]
So it's one of those things like you kind of just go as far as you need to go until spaces two, please. Spaces two, please. There we go. Priority Z Enum. This is low, medium, high, and urgent, and it's optional. So the amount of times I've actually authored these things by hand is pretty low.

[00:09:32]
Usually I'll like take like a open API spec or something like that and feed that into like CLAUDE code and say, hey, write like a basic MCP server with this and then I'll go just fine tune it after it gets like a nice framework for it. That being said, it is useful for you to kind of like see like how the, how the sausage is made, right?

[00:09:54]
This is priority assigned user id z.string.optional. If you've taken any of my courses, you're probably aware I like making users or students feel pain first before they start using the tools to alleviate the pain. Like it definitely happened when I was using Docker where I used to like fear Docker and like you find it very frictionful until I actually dug under the hood and realized what it does for me and like I could go do all this stuff myself.

[00:10:38]
But when you start messing with networking stacks and things don't work, then you're like, thank you Docker for just handling all of the networking stack for me. Same kind of thing here. Like once you realize what the LLM is doing for you, you like won't be afraid to get in there and start digging in and figuring out like why is the LLM doing these silly things.

[00:11:00]
Tag ids z.array of z.number.optional describe- Describe here as tags id optional describe array array of tag ids. Okay, and then you need an API key here at the end, which is a string Z string describe API key for authenticating. That's probably redundant, I just need that. Okay, so that's everything it expects.

[00:12:08]
And now we've made up all the machinery. This makes it really easy. Async params and this is just going to. This probably needs to be outside that, doesn't it? Yeah, there we go. The async function lives as sibling to this object, not inside of it. That's what I was doing wrong.

[00:12:44]
Okay, const api key issue data = params. This is destructuring, I assume by this point most of you have probably seen this before, but I'm just pulling out API key and then everything else into another object called issue data. Then const result is going to be await make request.

[00:13:17]
It's going to be a post. We're going to go to apibaseurl/issues, issue data and headers. We're going to add x API key. I think this is all. Did I do this with better auth? I think I did this all with better auth. So this is all better auth stuff, which is great, by the way.

[00:13:59]
They just raised a bunch of money from Y Combinator, I think. Okay, so now we have the results here. After we're doing that, we're gonna say return content type is text and text is going to be JSON.stringify result null 2. Notice I'm doing like a little bit of spacing, which is not super, it's more tokens because you're putting more whitespace into it.

[00:14:53]
But I have found that adding additional space does help agents and LLMs interpret the data more correctly because it doesn't have to disambiguate like where do I hack the string apart? You could probably get away with one, but that sounds strange. So I'm gonna do two, just for my own comfort's sake.

[00:15:15]
Okay. I mean, this was a lot to write, but a lot of like, not new concepts here, right? But this is more descriptive, more real life of what. What this would actually look like building one of these MCP tools.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now