Skip to content

Commit 4f11a05

Browse files
committed
Update Node quickstart to use simplified API
1 parent 3684fe2 commit 4f11a05

File tree

1 file changed

+120
-211
lines changed

1 file changed

+120
-211
lines changed

quickstart/server.mdx

Lines changed: 120 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ Claude for Desktop is not yet available on Linux. Linux users can proceed to the
243243
First, make sure you have Claude for Desktop installed. [You can install the latest version
244244
here.](https://claude.ai/download) If you already have Claude for Desktop, **make sure it's updated to the latest version.**
245245

246-
We'll need to configure Claude for Desktop for whichever MCP servers you want to use. To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. Make sure to create the file if it doesn't exist.
246+
We'll need to configure Claude for Desktop for whichever MCP servers you want to use. To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. Make sure to create the file if it doesn't exist.
247247

248248
For example, if you have [VS Code](https://code.visualstudio.com/) installed:
249249

@@ -418,100 +418,24 @@ Now let's dive into building your server.
418418

419419
## Building your server
420420

421-
### Importing packages
421+
### Importing packages and setting up the instance
422422

423423
Add these to the top of your `src/index.ts`:
424-
425424
```typescript
426-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
425+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
427426
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
428-
import {
429-
CallToolRequestSchema,
430-
ListToolsRequestSchema,
431-
} from "@modelcontextprotocol/sdk/types.js";
432427
import { z } from "zod";
433-
```
434-
435-
### Setting up the instance
436-
437-
Then initialize the NWS API base URL, validation schemas, and server instance:
438428

439-
```typescript
440429
const NWS_API_BASE = "https://api.weather.gov";
441430
const USER_AGENT = "weather-app/1.0";
442431

443-
// Define Zod schemas for validation
444-
const AlertsArgumentsSchema = z.object({
445-
state: z.string().length(2),
446-
});
447-
448-
const ForecastArgumentsSchema = z.object({
449-
latitude: z.number().min(-90).max(90),
450-
longitude: z.number().min(-180).max(180),
451-
});
452-
453432
// Create server instance
454-
const server = new Server(
455-
{
456-
name: "weather",
457-
version: "1.0.0",
458-
},
459-
{
460-
capabilities: {
461-
tools: {},
462-
},
463-
}
464-
);
465-
```
466-
467-
### Implementing tool listing
468-
469-
We need to tell clients what tools are available. This `server.setRequestHandler` call will register this list for us:
470-
471-
```typescript
472-
// List available tools
473-
server.setRequestHandler(ListToolsRequestSchema, async () => {
474-
return {
475-
tools: [
476-
{
477-
name: "get-alerts",
478-
description: "Get weather alerts for a state",
479-
inputSchema: {
480-
type: "object",
481-
properties: {
482-
state: {
483-
type: "string",
484-
description: "Two-letter state code (e.g. CA, NY)",
485-
},
486-
},
487-
required: ["state"],
488-
},
489-
},
490-
{
491-
name: "get-forecast",
492-
description: "Get weather forecast for a location",
493-
inputSchema: {
494-
type: "object",
495-
properties: {
496-
latitude: {
497-
type: "number",
498-
description: "Latitude of the location",
499-
},
500-
longitude: {
501-
type: "number",
502-
description: "Longitude of the location",
503-
},
504-
},
505-
required: ["latitude", "longitude"],
506-
},
507-
},
508-
],
509-
};
433+
const server = new McpServer({
434+
name: "weather",
435+
version: "1.0.0",
510436
});
511437
```
512438

513-
This defines our two tools: `get-alerts` and `get-forecast`.
514-
515439
### Helper functions
516440

517441
Next, let's add our helper functions for querying and formatting the data from the National Weather Service API:
@@ -590,160 +514,145 @@ interface ForecastResponse {
590514
The tool execution handler is responsible for actually executing the logic of each tool. Let's add it:
591515

592516
```typescript
593-
// Handle tool execution
594-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
595-
const { name, arguments: args } = request.params;
517+
// Register weather tools
518+
server.tool(
519+
"get-alerts",
520+
"Get weather alerts for a state",
521+
{
522+
state: z.string().length(2).describe("Two-letter state code (e.g. CA, NY)"),
523+
},
524+
async ({ state }) => {
525+
const stateCode = state.toUpperCase();
526+
const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
527+
const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);
596528

597-
try {
598-
if (name === "get-alerts") {
599-
const { state } = AlertsArgumentsSchema.parse(args);
600-
const stateCode = state.toUpperCase();
601-
602-
const alertsUrl = `${NWS_API_BASE}/alerts?area=${stateCode}`;
603-
const alertsData = await makeNWSRequest<AlertsResponse>(alertsUrl);
604-
605-
if (!alertsData) {
606-
return {
607-
content: [
608-
{
609-
type: "text",
610-
text: "Failed to retrieve alerts data",
611-
},
612-
],
613-
};
614-
}
615-
616-
const features = alertsData.features || [];
617-
if (features.length === 0) {
618-
return {
619-
content: [
620-
{
621-
type: "text",
622-
text: `No active alerts for ${stateCode}`,
623-
},
624-
],
625-
};
626-
}
627-
628-
const formattedAlerts = features.map(formatAlert).slice(0, 20) // only take the first 20 alerts;
629-
const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join(
630-
"\n"
631-
)}`;
529+
if (!alertsData) {
530+
return {
531+
content: [
532+
{
533+
type: "text",
534+
text: "Failed to retrieve alerts data",
535+
},
536+
],
537+
};
538+
}
632539

540+
const features = alertsData.features || [];
541+
if (features.length === 0) {
633542
return {
634543
content: [
635544
{
636545
type: "text",
637-
text: alertsText,
546+
text: `No active alerts for ${stateCode}`,
638547
},
639548
],
640549
};
641-
} else if (name === "get-forecast") {
642-
const { latitude, longitude } = ForecastArgumentsSchema.parse(args);
643-
644-
// Get grid point data
645-
const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(
646-
4
647-
)},${longitude.toFixed(4)}`;
648-
const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);
649-
650-
if (!pointsData) {
651-
return {
652-
content: [
653-
{
654-
type: "text",
655-
text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
656-
},
657-
],
658-
};
659-
}
660-
661-
const forecastUrl = pointsData.properties?.forecast;
662-
if (!forecastUrl) {
663-
return {
664-
content: [
665-
{
666-
type: "text",
667-
text: "Failed to get forecast URL from grid point data",
668-
},
669-
],
670-
};
671-
}
672-
673-
// Get forecast data
674-
const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
675-
if (!forecastData) {
676-
return {
677-
content: [
678-
{
679-
type: "text",
680-
text: "Failed to retrieve forecast data",
681-
},
682-
],
683-
};
684-
}
685-
686-
const periods = forecastData.properties?.periods || [];
687-
if (periods.length === 0) {
688-
return {
689-
content: [
690-
{
691-
type: "text",
692-
text: "No forecast periods available",
693-
},
694-
],
695-
};
696-
}
697-
698-
// Format forecast periods
699-
const formattedForecast = periods.map((period: ForecastPeriod) =>
700-
[
701-
`${period.name || "Unknown"}:`,
702-
`Temperature: ${period.temperature || "Unknown"}°${
703-
period.temperatureUnit || "F"
704-
}`,
705-
`Wind: ${period.windSpeed || "Unknown"} ${
706-
period.windDirection || ""
707-
}`,
708-
`${period.shortForecast || "No forecast available"}`,
709-
"---",
710-
].join("\n")
711-
);
712-
713-
const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join(
714-
"\n"
715-
)}`;
550+
}
716551

552+
const formattedAlerts = features.map(formatAlert);
553+
const alertsText = `Active alerts for ${stateCode}:\n\n${formattedAlerts.join("\n")}`;
554+
555+
return {
556+
content: [
557+
{
558+
type: "text",
559+
text: alertsText,
560+
},
561+
],
562+
};
563+
},
564+
);
565+
566+
server.tool(
567+
"get-forecast",
568+
"Get weather forecast for a location",
569+
{
570+
latitude: z.number().min(-90).max(90).describe("Latitude of the location"),
571+
longitude: z.number().min(-180).max(180).describe("Longitude of the location"),
572+
},
573+
async ({ latitude, longitude }) => {
574+
// Get grid point data
575+
const pointsUrl = `${NWS_API_BASE}/points/${latitude.toFixed(4)},${longitude.toFixed(4)}`;
576+
const pointsData = await makeNWSRequest<PointsResponse>(pointsUrl);
577+
578+
if (!pointsData) {
717579
return {
718580
content: [
719581
{
720582
type: "text",
721-
text: forecastText,
583+
text: `Failed to retrieve grid point data for coordinates: ${latitude}, ${longitude}. This location may not be supported by the NWS API (only US locations are supported).`,
722584
},
723585
],
724586
};
725-
} else {
726-
throw new Error(`Unknown tool: ${name}`);
727587
}
728-
} catch (error) {
729-
if (error instanceof z.ZodError) {
730-
throw new Error(
731-
`Invalid arguments: ${error.errors
732-
.map((e) => `${e.path.join(".")}: ${e.message}`)
733-
.join(", ")}`
734-
);
588+
589+
const forecastUrl = pointsData.properties?.forecast;
590+
if (!forecastUrl) {
591+
return {
592+
content: [
593+
{
594+
type: "text",
595+
text: "Failed to get forecast URL from grid point data",
596+
},
597+
],
598+
};
735599
}
736-
throw error;
737-
}
738-
});
600+
601+
// Get forecast data
602+
const forecastData = await makeNWSRequest<ForecastResponse>(forecastUrl);
603+
if (!forecastData) {
604+
return {
605+
content: [
606+
{
607+
type: "text",
608+
text: "Failed to retrieve forecast data",
609+
},
610+
],
611+
};
612+
}
613+
614+
const periods = forecastData.properties?.periods || [];
615+
if (periods.length === 0) {
616+
return {
617+
content: [
618+
{
619+
type: "text",
620+
text: "No forecast periods available",
621+
},
622+
],
623+
};
624+
}
625+
626+
// Format forecast periods
627+
const formattedForecast = periods.map((period: ForecastPeriod) =>
628+
[
629+
`${period.name || "Unknown"}:`,
630+
`Temperature: ${period.temperature || "Unknown"}°${period.temperatureUnit || "F"}`,
631+
`Wind: ${period.windSpeed || "Unknown"} ${period.windDirection || ""}`,
632+
`${period.shortForecast || "No forecast available"}`,
633+
"---",
634+
].join("\n"),
635+
);
636+
637+
const forecastText = `Forecast for ${latitude}, ${longitude}:\n\n${formattedForecast.join("\n")}`;
638+
639+
return {
640+
content: [
641+
{
642+
type: "text",
643+
text: forecastText,
644+
},
645+
],
646+
};
647+
},
648+
);
739649
```
740650

741651
### Running the server
742652

743653
Finally, implement the main function to run the server:
744654

745655
```typescript
746-
// Start the server
747656
async function main() {
748657
const transport = new StdioServerTransport();
749658
await server.connect(transport);
@@ -769,7 +678,7 @@ Claude for Desktop is not yet available on Linux. Linux users can proceed to the
769678
First, make sure you have Claude for Desktop installed. [You can install the latest version
770679
here.](https://claude.ai/download) If you already have Claude for Desktop, **make sure it's updated to the latest version.**
771680

772-
We'll need to configure Claude for Desktop for whichever MCP servers you want to use. To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. Make sure to create the file if it doesn't exist.
681+
We'll need to configure Claude for Desktop for whichever MCP servers you want to use. To do this, open your Claude for Desktop App configuration at `~/Library/Application Support/Claude/claude_desktop_config.json` in a text editor. Make sure to create the file if it doesn't exist.
773682

774683
For example, if you have [VS Code](https://code.visualstudio.com/) installed:
775684

0 commit comments

Comments
 (0)