Skip to main content
Glama
campertunity

Campertunity MCP Server

Official
by campertunity

place-search

Find campgrounds and outdoor accommodations with specific amenities, availability dates, and location filters for camping trips.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoNumber of places to return. Default is 50, max is 1000.
startDateNoStart date for availability search. Format: YYYY-MM-DD
endDateNoEnd date for availability search. Format: YYYY-MM-DD
adultsNoNumber of adults. Default is 1.
childrenNoNumber of children. Default is 0.
latitudeNoLatitude to filter by.
longitudeNoLongitude to filter by.
radiusNoRadius to filter by (in km).
filtersNoFilter out places that have specific tags.
campgroundDescriptionNoDescribe 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"

Implementation Reference

  • The handler function that builds query parameters from inputs and fetches search results from the Campertunity API endpoint `/place/search`, returning JSON or error.
    async ({ limit, startDate, endDate, adults, children, latitude, longitude, radius, filters, campgroundDescription }) => {
      try {
        const params = new URLSearchParams();
        if (limit) params.set('limit', limit.toString());
        if (startDate) params.set('startDate', startDate);
        if (endDate) params.set('endDate', endDate);
        if (adults) params.set('adults', adults.toString());
        if (children) params.set('children', children.toString());
        if (latitude) params.set('latitude', latitude.toString());
        if (longitude) params.set('longitude', longitude.toString());
        if (radius) params.set('radius', radius.toString());
        if (filters) params.set('filters', filters.join(','));
        if (campgroundDescription) params.set('campgroundDescription', campgroundDescription);
    
        const places = await campertunityClient.get(`/place/search?${params.toString()}`);
        return {
          content: [{ type: 'text', text: JSON.stringify(places), mimeType: 'application/json' }],
        };
      } catch (error) {
        return {
          content: [{ type: 'text', text: 'Error: ' + (error as Error).message }],
          isError: true,
        };
      }
    }
  • Zod input schema defining parameters for the place search tool, including limits, dates, location filters, and tags.
    {
      limit: z.number().default(50).optional().describe('Number of places to return. Default is 50, max is 1000.'),
      startDate: z.string().optional().describe('Start date for availability search. Format: YYYY-MM-DD'),
      endDate: z.string().optional().describe('End date for availability search. Format: YYYY-MM-DD'),
      adults: z.number().optional().describe('Number of adults. Default is 1.'),
      children: z.number().optional().describe('Number of children. Default is 0.'),
      latitude: z.number().optional().describe('Latitude to filter by.'),
      longitude: z.number().optional().describe('Longitude to filter by.'),
      radius: z.number().optional().default(20).describe('Radius to filter by (in km).'),
      filters: z.array(z.enum(Object.values(Tag) as [string, ...string[]])).optional().describe('Filter out places that have specific tags.'),
      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"'),
    },
  • The server.tool call that registers the 'place-search' tool with its schema and handler function.
    server.tool(
      'place-search',
      {
        limit: z.number().default(50).optional().describe('Number of places to return. Default is 50, max is 1000.'),
        startDate: z.string().optional().describe('Start date for availability search. Format: YYYY-MM-DD'),
        endDate: z.string().optional().describe('End date for availability search. Format: YYYY-MM-DD'),
        adults: z.number().optional().describe('Number of adults. Default is 1.'),
        children: z.number().optional().describe('Number of children. Default is 0.'),
        latitude: z.number().optional().describe('Latitude to filter by.'),
        longitude: z.number().optional().describe('Longitude to filter by.'),
        radius: z.number().optional().default(20).describe('Radius to filter by (in km).'),
        filters: z.array(z.enum(Object.values(Tag) as [string, ...string[]])).optional().describe('Filter out places that have specific tags.'),
        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"'),
      },
      async ({ limit, startDate, endDate, adults, children, latitude, longitude, radius, filters, campgroundDescription }) => {
        try {
          const params = new URLSearchParams();
          if (limit) params.set('limit', limit.toString());
          if (startDate) params.set('startDate', startDate);
          if (endDate) params.set('endDate', endDate);
          if (adults) params.set('adults', adults.toString());
          if (children) params.set('children', children.toString());
          if (latitude) params.set('latitude', latitude.toString());
          if (longitude) params.set('longitude', longitude.toString());
          if (radius) params.set('radius', radius.toString());
          if (filters) params.set('filters', filters.join(','));
          if (campgroundDescription) params.set('campgroundDescription', campgroundDescription);
    
          const places = await campertunityClient.get(`/place/search?${params.toString()}`);
          return {
            content: [{ type: 'text', text: JSON.stringify(places), mimeType: 'application/json' }],
          };
        } catch (error) {
          return {
            content: [{ type: 'text', text: 'Error: ' + (error as Error).message }],
            isError: true,
          };
        }
      }
    );
  • src/index.ts:26-26 (registration)
    Invocation of placeSearchTool to register the tool on the MCP server.
    placeSearchTool(server, campertunityClient);
  • Enum defining all possible tags for filtering places, used in the schema for filters parameter.
    export enum Tag {
      // SiteType
      tent = 'tent',
      rv = 'rv',
      lodging = 'lodging',
      glamping = 'glamping',
      cabin = 'cabin',
    
      // AccessType
      driveIn = 'driveIn',
      walkIn = 'walkIn',
      equestrian = 'equestrian',
      boat = 'boat',
    
      // Activities
      biking = 'biking',
      boating = 'boating',
      fishing = 'fishing',
      hiking = 'hiking',
      horsebackRiding = 'horsebackRiding',
      paddling = 'paddling',
      windSports = 'windSports',
      surfing = 'surfing',
      swimming = 'swimming',
      whitewaterPaddling = 'whitewaterPaddling',
      wildlifeWatching = 'wildlifeWatching',
    
      // Amenities
      picnicTable = 'picnicTable',
      fires = 'fires',
      toilets = 'toilets',
      outhouse = 'outhouse',
      potableWater = 'potableWater',
      petFriendly = 'petFriendly',
      rvHookup = 'rvHookup',
      rvSanitation = 'rvSanitation',
      trash = 'trash',
      showers = 'showers',
      wifi = 'wifi',
      handicap = 'handicap',
    
      // Terrain
      beach = 'beach',
      cave = 'cave',
      desert = 'desert',
      forest = 'forest',
      hotSpring = 'hotSpring',
      lake = 'lake',
      river = 'river',
      swimmingHole = 'swimmingHole',
      waterfall = 'waterfall',
      creek = 'creek',
    }
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Tool has no description.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness1/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Tool has no description.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Tool has no description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Tool has no description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose1/5

Does the description clearly state what the tool does and how it differs from similar tools?

Tool has no description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines1/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Tool has no description.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/campertunity/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server