campertunity-mcp-server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # MCP Server for Campertunity
2
+
3
+ This server implements the Model Context Protocol (MCP) for Campertunity, providing AI models with tools to interact with camping and outdoor recreation data.
4
+
5
+ ## MCP Client Config
6
+
7
+ ```
8
+ {
9
+ "mcpServers": {
10
+ "mcp-campertunity-local": {
11
+ "command": "node",
12
+ "args": ["/path/to/project/dist/index.js"],
13
+ "env": {
14
+ "CAMPERTUNITY_API_KEY": "your_api_key_here",
15
+ }
16
+ }
17
+ }
18
+ }
19
+ ```
20
+
21
+
22
+ ## Setup
23
+
24
+ 1. Get your API key from [https://campertunity.com/mcp](https://campertunity.com/mcp)
25
+ 2. Set the environment variable:
26
+ ```
27
+ CAMPERTUNITY_API_KEY=your_api_key_here
28
+ ```
29
+
30
+ ## Available Tools
31
+
32
+ ### place-search
33
+ Search for camping places with various filters and criteria.
34
+ - **Parameters:**
35
+ - `limit`: Number of results (default: 50, max: 1000)
36
+ - `startDate`: Start date for availability (YYYY-MM-DD)
37
+ - `endDate`: End date for availability (YYYY-MM-DD)
38
+ - `adults`: Number of adults (default: 1)
39
+ - `children`: Number of children (default: 0)
40
+ - `latitude`: Center point latitude
41
+ - `longitude`: Center point longitude
42
+ - `radius`: Search radius in kilometers (default: 20)
43
+ - `filters`: Array of tags to filter by (see Tag enum below)
44
+ - `campgroundDescription`: Natural language description of desired campground features
45
+
46
+ ### place-details
47
+ Get detailed information about a specific camping place.
48
+ - **Parameters:**
49
+ - `placeId`: ID of the place to get details for
50
+
51
+ ### place-availability
52
+ Check availability of camping sites at a specific place.
53
+ - **Parameters:**
54
+ - `placeId`: ID of the place to check
55
+ - `siteIds`: Optional array of specific site IDs to check
56
+ - `startDate`: Start date (YYYY-MM-DD)
57
+ - `endDate`: End date (YYYY-MM-DD)
58
+
59
+ ### place-book
60
+ Book a camping site.
61
+ - **Parameters:**
62
+ - `placeId`: ID of the place to book
63
+ - `startDate`: Start date (YYYY-MM-DD)
64
+ - `endDate`: End date (YYYY-MM-DD)
65
+ - `adults`: Number of adults (default: 1)
66
+ - `children`: Number of children (default: 0)
67
+
68
+ ## Available Tags for Filtering
69
+
70
+ ### Site Types
71
+ - tent
72
+ - rv
73
+ - lodging
74
+ - glamping
75
+ - cabin
76
+
77
+ ### Access Types
78
+ - driveIn
79
+ - walkIn
80
+ - equestrian
81
+ - boat
82
+
83
+ ### Activities
84
+ - biking
85
+ - boating
86
+ - fishing
87
+ - hiking
88
+ - horsebackRiding
89
+ - paddling
90
+ - windSports
91
+ - surfing
92
+ - swimming
93
+ - whitewaterPaddling
94
+ - wildlifeWatching
95
+
96
+ ### Amenities
97
+ - picnicTable
98
+ - fires
99
+ - toilets
100
+ - outhouse
101
+ - potableWater
102
+ - petFriendly
103
+ - rvHookup
104
+ - rvSanitation
105
+ - trash
106
+ - showers
107
+ - wifi
108
+ - handicap
109
+
110
+ ### Terrain
111
+ - beach
112
+ - cave
113
+ - desert
114
+ - forest
115
+ - hotSpring
116
+ - lake
117
+ - river
118
+ - swimmingHole
119
+ - waterfall
120
+ - creek
121
+
122
+ ## Important Notice
123
+
124
+ The data provided through these tools is collected from multiple sources and enhanced with AI. To ensure data accuracy and respect intellectual property rights:
125
+
126
+ - Do not redistribute the data
127
+ - Do not save or cache the data
128
+ - Do not modify the data
129
+ - Always use real-time data through the server
130
+
131
+ For more information, visit [campertunity.com](https://campertunity.com)
@@ -0,0 +1,34 @@
1
+ const CAMPERTUNITY_API_URL = process.env.CAMPERTUNITY_API_URL || "https://us-central1-my-project-1517611279378.cloudfunctions.net/public/api";
2
+ const CAMPERTUNITY_API_KEY = process.env.CAMPERTUNITY_API_KEY;
3
+ if (!CAMPERTUNITY_API_KEY) {
4
+ throw new Error("CAMPERTUNITY_API_KEY environment variable is required");
5
+ }
6
+ export class CampertunityClient {
7
+ async get(path) {
8
+ const response = await fetch(`${CAMPERTUNITY_API_URL}${path}`, {
9
+ method: "GET",
10
+ headers: {
11
+ Authorization: `Bearer ${CAMPERTUNITY_API_KEY}`,
12
+ },
13
+ });
14
+ if (!response.ok) {
15
+ throw new Error(`Campertunity API error: ${response.statusText}`);
16
+ }
17
+ return response.json();
18
+ }
19
+ async post(path, data) {
20
+ const response = await fetch(`${CAMPERTUNITY_API_URL}${path}`, {
21
+ method: "POST",
22
+ headers: {
23
+ Authorization: `Bearer ${CAMPERTUNITY_API_KEY}`,
24
+ "Content-Type": "application/json",
25
+ },
26
+ body: JSON.stringify(data),
27
+ });
28
+ if (!response.ok) {
29
+ throw new Error(`Campertunity API error: ${response.statusText}`);
30
+ }
31
+ return response.json();
32
+ }
33
+ }
34
+ export const campertunityClient = new CampertunityClient();
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { CampertunityClient } from "./campertunity/client.js";
5
+ import { placeAvailabilityTool } from "./tools/place_availability.js";
6
+ import { placeBookTool } from "./tools/place_book.js";
7
+ import { placeDetailsTool } from "./tools/place_details.js";
8
+ import { placeSearchTool } from "./tools/place_search.js";
9
+ const campertunityClient = new CampertunityClient();
10
+ const server = new McpServer({
11
+ name: "campertunity-model-context-protocol-server",
12
+ version: "0.0.1",
13
+ }, {
14
+ capabilities: {
15
+ tools: {},
16
+ },
17
+ });
18
+ placeAvailabilityTool(server, campertunityClient);
19
+ placeBookTool(server, campertunityClient);
20
+ placeDetailsTool(server, campertunityClient);
21
+ placeSearchTool(server, campertunityClient);
22
+ async function runServer() {
23
+ const transport = new StdioServerTransport();
24
+ await server.connect(transport);
25
+ console.error("Campertunity MCP Server running on stdio");
26
+ }
27
+ runServer().catch((error) => {
28
+ console.error("Fatal error in main():", error);
29
+ process.exit(1);
30
+ });
@@ -0,0 +1,27 @@
1
+ import { z } from 'zod';
2
+ export const placeAvailabilityTool = (server, campertunityClient) => {
3
+ server.tool('place-availability', {
4
+ placeId: z.string().describe('The id of the place to check availability for.'),
5
+ siteIds: z.array(z.string()).optional().describe('The ids of the sites to check availability for.'),
6
+ startDate: z.string().describe('The start date to check availability for. Format: YYYY-MM-DD'),
7
+ endDate: z.string().describe('The end date to check availability for. Format: YYYY-MM-DD'),
8
+ }, async ({ placeId, siteIds, startDate, endDate }) => {
9
+ try {
10
+ const availability = await campertunityClient.post(`/place/availability`, {
11
+ placeId,
12
+ siteIds,
13
+ startDate,
14
+ endDate,
15
+ });
16
+ return {
17
+ content: [{ type: 'text', text: JSON.stringify(availability), mimeType: 'application/json' }],
18
+ };
19
+ }
20
+ catch (error) {
21
+ return {
22
+ content: [{ type: 'text', text: 'Error: ' + error.message }],
23
+ isError: true,
24
+ };
25
+ }
26
+ });
27
+ };
@@ -0,0 +1,29 @@
1
+ import { z } from 'zod';
2
+ export const placeBookTool = (server, campertunityClient) => {
3
+ server.tool('place-book', {
4
+ placeId: z.string().describe('The id of the place to book.'),
5
+ startDate: z.string().optional().describe('The start date of the booking. Format: YYYY-MM-DD'),
6
+ endDate: z.string().optional().describe('The end date of the booking. Format: YYYY-MM-DD'),
7
+ adults: z.number().default(1).describe('Number of adults. Default is 1.'),
8
+ children: z.number().default(0).describe('Number of children. Default is 0.'),
9
+ }, async ({ placeId, startDate, endDate, adults, children }) => {
10
+ try {
11
+ const availability = await campertunityClient.post(`/place/book`, {
12
+ placeId,
13
+ startDate,
14
+ endDate,
15
+ adults,
16
+ children,
17
+ });
18
+ return {
19
+ content: [{ type: 'text', text: JSON.stringify(availability), mimeType: 'application/json' }],
20
+ };
21
+ }
22
+ catch (error) {
23
+ return {
24
+ content: [{ type: 'text', text: 'Error: ' + error.message }],
25
+ isError: true,
26
+ };
27
+ }
28
+ });
29
+ };
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ // NOTE: This is a tool since tools are more supported by the MCP protocol
3
+ export const placeDetailsTool = (server, campertunityClient) => {
4
+ server.tool('place-details', {
5
+ placeId: z.string().describe('The id of the place to get details for.'),
6
+ }, async ({ placeId }) => {
7
+ try {
8
+ const place = await campertunityClient.get(`/place/${placeId}`);
9
+ return {
10
+ content: [
11
+ {
12
+ type: 'text',
13
+ text: JSON.stringify(place),
14
+ mimeType: 'application/json',
15
+ },
16
+ ],
17
+ };
18
+ }
19
+ catch (error) {
20
+ return {
21
+ content: [{ type: 'text', text: 'Error: ' + error.message }],
22
+ isError: true,
23
+ };
24
+ }
25
+ });
26
+ };
@@ -0,0 +1,99 @@
1
+ import { z } from 'zod';
2
+ export var Tag;
3
+ (function (Tag) {
4
+ // SiteType
5
+ Tag["tent"] = "tent";
6
+ Tag["rv"] = "rv";
7
+ Tag["lodging"] = "lodging";
8
+ Tag["glamping"] = "glamping";
9
+ Tag["cabin"] = "cabin";
10
+ // AccessType
11
+ Tag["driveIn"] = "driveIn";
12
+ Tag["walkIn"] = "walkIn";
13
+ Tag["equestrian"] = "equestrian";
14
+ Tag["boat"] = "boat";
15
+ // Activities
16
+ Tag["biking"] = "biking";
17
+ Tag["boating"] = "boating";
18
+ Tag["fishing"] = "fishing";
19
+ Tag["hiking"] = "hiking";
20
+ Tag["horsebackRiding"] = "horsebackRiding";
21
+ Tag["paddling"] = "paddling";
22
+ Tag["windSports"] = "windSports";
23
+ Tag["surfing"] = "surfing";
24
+ Tag["swimming"] = "swimming";
25
+ Tag["whitewaterPaddling"] = "whitewaterPaddling";
26
+ Tag["wildlifeWatching"] = "wildlifeWatching";
27
+ // Amenities
28
+ Tag["picnicTable"] = "picnicTable";
29
+ Tag["fires"] = "fires";
30
+ Tag["toilets"] = "toilets";
31
+ Tag["outhouse"] = "outhouse";
32
+ Tag["potableWater"] = "potableWater";
33
+ Tag["petFriendly"] = "petFriendly";
34
+ Tag["rvHookup"] = "rvHookup";
35
+ Tag["rvSanitation"] = "rvSanitation";
36
+ Tag["trash"] = "trash";
37
+ Tag["showers"] = "showers";
38
+ Tag["wifi"] = "wifi";
39
+ Tag["handicap"] = "handicap";
40
+ // Terrain
41
+ Tag["beach"] = "beach";
42
+ Tag["cave"] = "cave";
43
+ Tag["desert"] = "desert";
44
+ Tag["forest"] = "forest";
45
+ Tag["hotSpring"] = "hotSpring";
46
+ Tag["lake"] = "lake";
47
+ Tag["river"] = "river";
48
+ Tag["swimmingHole"] = "swimmingHole";
49
+ Tag["waterfall"] = "waterfall";
50
+ Tag["creek"] = "creek";
51
+ })(Tag || (Tag = {}));
52
+ export const placeSearchTool = (server, campertunityClient) => {
53
+ server.tool('place-search', {
54
+ limit: z.number().default(50).optional().describe('Number of places to return. Default is 50, max is 1000.'),
55
+ startDate: z.string().optional().describe('Start date for availability search. Format: YYYY-MM-DD'),
56
+ endDate: z.string().optional().describe('End date for availability search. Format: YYYY-MM-DD'),
57
+ adults: z.number().optional().describe('Number of adults. Default is 1.'),
58
+ children: z.number().optional().describe('Number of children. Default is 0.'),
59
+ latitude: z.number().optional().describe('Latitude to filter by.'),
60
+ longitude: z.number().optional().describe('Longitude to filter by.'),
61
+ radius: z.number().optional().default(20).describe('Radius to filter by (in km).'),
62
+ filters: z.array(z.enum(Object.values(Tag))).optional().describe('Filter out places that have specific tags.'),
63
+ campgroundDescription: z.string().optional().describe('Describe the campground you are looking for. Note: not the location, but something about the campground like "has a pool" or "near a lake" or "has a playground"'),
64
+ }, async ({ limit, startDate, endDate, adults, children, latitude, longitude, radius, filters, campgroundDescription }) => {
65
+ try {
66
+ const params = new URLSearchParams();
67
+ if (limit)
68
+ params.set('limit', limit.toString());
69
+ if (startDate)
70
+ params.set('startDate', startDate);
71
+ if (endDate)
72
+ params.set('endDate', endDate);
73
+ if (adults)
74
+ params.set('adults', adults.toString());
75
+ if (children)
76
+ params.set('children', children.toString());
77
+ if (latitude)
78
+ params.set('latitude', latitude.toString());
79
+ if (longitude)
80
+ params.set('longitude', longitude.toString());
81
+ if (radius)
82
+ params.set('radius', radius.toString());
83
+ if (filters)
84
+ params.set('filters', filters.join(','));
85
+ if (campgroundDescription)
86
+ params.set('campgroundDescription', campgroundDescription);
87
+ const places = await campertunityClient.get(`/place/search?${params.toString()}`);
88
+ return {
89
+ content: [{ type: 'text', text: JSON.stringify(places), mimeType: 'application/json' }],
90
+ };
91
+ }
92
+ catch (error) {
93
+ return {
94
+ content: [{ type: 'text', text: 'Error: ' + error.message }],
95
+ isError: true,
96
+ };
97
+ }
98
+ });
99
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "campertunity-mcp-server",
3
+ "version": "0.0.1",
4
+ "description": "MCP Server for Campertunity - A Model Context Protocol server for interacting with camping and outdoor recreation data",
5
+ "type": "module",
6
+ "bin": {
7
+ "mcp-campertunity-server": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc && shx chmod +x dist/*.js",
14
+ "prepare": "npm run build",
15
+ "watch": "tsc --watch",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "campertunity",
21
+ "camping",
22
+ "outdoor",
23
+ "recreation",
24
+ "ai",
25
+ "model-context-protocol"
26
+ ],
27
+ "author": "Campertunity",
28
+ "license": "AGPL-3.0",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/campertunity/mcp-server"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/campertunity/mcp-server/issues"
35
+ },
36
+ "homepage": "https://campertunity.com",
37
+ "dependencies": {
38
+ "@modelcontextprotocol/sdk": "1.7.0",
39
+ "@types/node": "^22"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22",
43
+ "shx": "^0.3.4",
44
+ "typescript": "^5.8.2"
45
+ },
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ }
49
+ }