Koskamo

Enpitech MCP App

A remote MCP server providing tools to scan websites for AI agent readiness, search an AI Hub catalog, manage newsletter signups, and submit contact forms via Enpitech's interface.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Enpitech MCP App logo, by EnpitechCommunity listingStreamable HTTPNo sign-inEndpoint checked 2026-11-07Published by Enpitech
MCP endpoint (Streamable HTTP)
https://mcp.enpitech.dev/mcp-app
Vendor documentation

What its tools do

8 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.

8 of 8 have a description · 8 of 8 declare behavior hints · 5 of 7 with parameters document them all

Checks and signals

Each line is separate evidence, not a trust score.

  • Passed Endpoint answered the live check ·
  • Availability 1 of 1 checks passed in 30 days

What you can do with it

  • Scan public websites for AI agent readiness
  • Search AI Hub catalog for skills and workflows
  • Sign up for Enpitech newsletter
  • Submit contact form to Enpitech

Source and maintenance

Community listingRegistry 1.1.0
Maintenance checked

Protocol and capabilities

Server
Enpitech 1.0.0
MCP protocol negotiated in check
2025-11-25
Tools
8 advertised
Resources
3 advertised
Resource templates
0 advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "resources": {
    "listChanged": true
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

This server belongs to Enpitech, a frontend engineering company. agent_ready opens the AgentReady website scanner as a view; agentready_scan runs the same scan and returns the result as JSON with no view. ai_hub_search searches the Enpitech AI Hub catalog of skills, MCP servers and workflows. newsletter opens a newsletter signup form as a view. contact_form opens Enpitech's contact form as a view; submit_contact sends the enquiry. Two more tools, email_agentready_report and subscribe_newsletter, are called only by their views and are not offered to the model.

Tools

8 advertised

contact_form — Open Contact Form
Advertised by the server during the last successful anonymous check.
Advertised read-only

Opens Enpitech's contact form as a view in the conversation, where the user types their own name, email and message, plus an optional phone number and company, and submits it. Use it when the user wants to get in touch with Enpitech about frontend engineering work: frontend is the bottleneck their releases wait on; AI-generated frontend code their team cannot safely merge; senior React engineers embedded in a product team; AI features, an MCP app, or an agent-ready interface built into their product; private training for their team on AI-assisted frontend delivery or Claude Code; hosting, sponsoring or speaking at a frontend meetup. It opens a form and answers no questions. The tool itself sends nothing: it returns the contact surface the form opened on, and the enquiry is sent by submit_contact when the user submits.

contact_form input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "origin": {
      "enum": [
        "general",
        "factory",
        "community",
        "workshops",
        "ai-hub",
        "agent-ready"
      ],
      "type": "string",
      "default": "general",
      "description": "Which contact surface to open the form in, inferred from the conversation. Omit when unsure; it defaults to general. general = the user wants senior React engineers embedded in their team, a web product shipped faster, or delivery infrastructure installed so the whole org can ship frontend. factory = the conversation is specifically about the Frontend Delivery Factory as a named service: the delivery pipeline, the review load, or AI-generated frontend code the team cannot safely merge. community = the user wants to host a frontend meetup, offer a venue, sponsor, or speak. workshops = the user wants private hands-on training for their team on AI-assisted frontend delivery or Claude Code. ai-hub = the user wants AI built into their product, MCP apps, or agent-ready interfaces. agent-ready = the enquiry follows an AgentReady scan of the user's own site; the scanner view sets this itself, so pick it only when the conversation came from a scan."
    }
  },
  "additionalProperties": false
}
contact_form output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "origin"
  ],
  "properties": {
    "origin": {
      "enum": [
        "general",
        "factory",
        "community",
        "workshops",
        "ai-hub",
        "agent-ready"
      ],
      "type": "string",
      "description": "The contact surface the form opened on."
    }
  },
  "additionalProperties": false
}
contact_form annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "destructiveHint": false
}
submit_contact — Send Enquiry
Advertised by the server during the last successful anonymous check.
Open-world

Sends a contact enquiry to Enpitech, storing the submitted name, email, message and optional phone and company as a sales lead in Enpitech's CRM, tagged with the origin surface. The contact form view calls this tool when the user submits the form; it can also be called directly once the user has given those details in the conversation. Every field carries a value the user actually supplied; contact_form opens the same form as a view for the user to fill in when a detail is missing.

submit_contact input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "name",
    "email",
    "message"
  ],
  "properties": {
    "name": {
      "type": "string",
      "minLength": 2
    },
    "email": {
      "type": "string",
      "format": "email",
      "minLength": 1
    },
    "phone": {
      "anyOf": [
        {
          "type": "string",
          "pattern": "^(0[23489]|05\\d)-?\\d{3}-?\\d{4}$"
        },
        {
          "type": "string",
          "const": ""
        }
      ]
    },
    "origin": {
      "enum": [
        "general",
        "factory",
        "community",
        "workshops",
        "ai-hub",
        "agent-ready"
      ],
      "type": "string",
      "default": "general",
      "description": "Which contact surface to open the form in, inferred from the conversation. Omit when unsure; it defaults to general. general = the user wants senior React engineers embedded in their team, a web product shipped faster, or delivery infrastructure installed so the whole org can ship frontend. factory = the conversation is specifically about the Frontend Delivery Factory as a named service: the delivery pipeline, the review load, or AI-generated frontend code the team cannot safely merge. community = the user wants to host a frontend meetup, offer a venue, sponsor, or speak. workshops = the user wants private hands-on training for their team on AI-assisted frontend delivery or Claude Code. ai-hub = the user wants AI built into their product, MCP apps, or agent-ready interfaces. agent-ready = the enquiry follows an AgentReady scan of the user's own site; the scanner view sets this itself, so pick it only when the conversation came from a scan."
    },
    "message": {
      "type": "string",
      "maxLength": 2000,
      "minLength": 10
    },
    "companyName": {
      "anyOf": [
        {
          "type": "string",
          "maxLength": 250
        },
        {
          "type": "string",
          "const": ""
        }
      ]
    }
  },
  "additionalProperties": false
}
submit_contact output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "success"
  ],
  "properties": {
    "success": {
      "type": "boolean",
      "description": "True when the enquiry was sent."
    }
  },
  "additionalProperties": false
}
submit_contact annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}
agent_ready — Check Agent Readiness
Advertised by the server during the last successful anonymous check.
Advertised read-only

Opens Enpitech's AgentReady scanner as a view in the conversation. Inside the view the scanner fetches the site's public pages and runs 21 checks across five weighted categories (Discovery & Access, Readable for Agents, Structured Data, Actions & MCP, Trust & Safety), then shows a 0-100 agent-readiness score, the per-category breakdown, and the fixes ranked by the points each would recover. Use it when the user asks how ready a website is for AI agents, their own or any site they name: how readable, accessible or usable it is to AI, to agents or to AI crawlers; whether ChatGPT or Claude can read or use it; how to show up in AI answers; or for an audit of llms.txt, robots.txt, schema.org markup or MCP support. url is optional: with no URL the scanner opens with an empty input for the user to fill in. This tool returns only the URL it was opened with; the scan runs inside the view, via agentready_scan.

agent_ready input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "url": {
      "type": "string",
      "maxLength": 2048,
      "description": "The site to scan, as the user gave it. A bare hostname like stripe.com is fine; the scanner normalizes it. Omit when the user has not named a site, and they will be asked for one."
    }
  },
  "additionalProperties": false
}
agent_ready output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "url"
  ],
  "properties": {
    "url": {
      "type": "string",
      "description": "The site the scanner opened with, or an empty string when the user will type one in the view."
    }
  },
  "additionalProperties": false
}
agent_ready annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "destructiveHint": false
}
email_agentready_report — Email AgentReady Report
Advertised by the server during the last successful anonymous check.
Advertised destructiveOpen-world

Emails the full 21-point AgentReady report for a site that has already been scanned, and stores the submitted name, email, phone and company as a sales lead in Enpitech's CRM under the agent-ready origin. The AgentReady view calls this tool when the user fills in the report form on the results page; it is not offered to the model. The scan is re-run server-side before the report is rendered, so the emailed report reflects the site at send time. Returns success with an emailed flag, which is false when the lead was stored but the email did not go out.

email_agentready_report input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "name",
    "email"
  ],
  "properties": {
    "url": {
      "type": "string",
      "maxLength": 2048
    },
    "name": {
      "type": "string",
      "maxLength": 200,
      "minLength": 2
    },
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 320,
      "minLength": 1
    },
    "phone": {
      "type": "string",
      "maxLength": 40
    },
    "score": {
      "type": "string",
      "maxLength": 8
    },
    "companyName": {
      "type": "string",
      "maxLength": 250
    }
  },
  "additionalProperties": false
}
email_agentready_report output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "success"
  ],
  "properties": {
    "emailed": {
      "type": "boolean",
      "description": "False when the request was stored but the email did not go out; the view then offers a PDF instead."
    },
    "success": {
      "type": "boolean",
      "description": "True when the request was stored."
    }
  },
  "additionalProperties": false
}
email_agentready_report annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": true
}
agentready_scan — Get AgentReady Results
Advertised by the server during the last successful anonymous check.
Advertised read-onlyOpen-world

Runs the AgentReady scan on one site and returns the raw result, with no view. It fetches the site's public pages and runs 21 checks across five weighted categories (Discovery & Access, Readable for Agents, Structured Data, Actions & MCP, Trust & Safety), returning a 0-100 agent-readiness score, the per-category breakdown of every check, and the top fixes ranked by the points each would recover. When bot protection blocks too many checks the result carries limited: true and the headline score is not meaningful, though the per-check breakdown still is. When the scan does not run it returns ok: false with an errorType of invalid, unreachable, timeout or ratelimited. agent_ready runs this same scan and presents it as a visual report, so this tool fits the cases a view does not: the result is wanted as data, or several sites are being compared at once. The AgentReady view also calls this tool to run its own scan. Read-only: it fetches only public pages of the site named in the call and changes nothing on it.

agentready_scan input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "url"
  ],
  "properties": {
    "url": {
      "type": "string",
      "maxLength": 2048,
      "description": "The site to scan. A bare hostname like stripe.com works."
    }
  },
  "additionalProperties": false
}
agentready_scan output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "ok",
    "cleanUrl",
    "scannedUrl",
    "score",
    "projectedScore",
    "categories",
    "topFixes",
    "unverifiedCount",
    "limited",
    "protection",
    "scannedAt"
  ],
  "properties": {
    "ok": {
      "type": "boolean",
      "const": true
    },
    "score": {
      "type": "number",
      "description": "Agent-readiness score, 0-100."
    },
    "limited": {
      "type": "boolean",
      "description": "True when bot protection blocked so much that the headline score is not meaningful; the per-check breakdown still is."
    },
    "cleanUrl": {
      "type": "string",
      "description": "Hostname and path scanned, e.g. stripe.com."
    },
    "topFixes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "checkId",
          "rank",
          "title",
          "body",
          "tag",
          "impact"
        ],
        "properties": {
          "tag": {
            "type": "string",
            "description": "Category and weight, e.g. \"ACTIONS & MCP · 30%\"."
          },
          "body": {
            "type": "string"
          },
          "rank": {
            "type": "number"
          },
          "title": {
            "type": "string"
          },
          "impact": {
            "type": "number",
            "description": "Points the overall score would gain if this check passed."
          },
          "checkId": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "description": "Fixes ranked by the points each would recover."
    },
    "scannedAt": {
      "type": "number",
      "description": "When the scan finished, Unix milliseconds."
    },
    "categories": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "id",
          "num",
          "name",
          "weight",
          "why",
          "score",
          "passCount",
          "total",
          "unknownCount",
          "checks"
        ],
        "properties": {
          "id": {
            "enum": [
              "discovery",
              "readable",
              "structured",
              "actions",
              "trust"
            ],
            "type": "string"
          },
          "num": {
            "type": "string",
            "description": "Display number, e.g. \"01\"."
          },
          "why": {
            "type": "string",
            "description": "Why the category matters to AI agents."
          },
          "name": {
            "type": "string"
          },
          "score": {
            "type": "number",
            "description": "Category score, 0-100."
          },
          "total": {
            "type": "number"
          },
          "checks": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "categoryId",
                "state",
                "note"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "note": {
                  "type": "string",
                  "description": "Short evidence, e.g. \"1,204 URLs\" or \"404 · missing\"."
                },
                "state": {
                  "enum": [
                    "pass",
                    "partial",
                    "fail",
                    "unknown"
                  ],
                  "type": "string",
                  "description": "pass, partial (counts as half) or fail; unknown means it could not be verified and is left out of the score."
                },
                "categoryId": {
                  "$ref": "#/properties/categories/items/properties/id"
                }
              },
              "additionalProperties": false
            }
          },
          "weight": {
            "type": "number",
            "description": "Percent of the overall score; the five sum to 100."
          },
          "passCount": {
            "type": "number"
          },
          "unknownCount": {
            "type": "number",
            "description": "Checks that could not be verified, excluded from score."
          }
        },
        "additionalProperties": false
      },
      "description": "The five weighted categories and their 21 checks."
    },
    "protection": {
      "anyOf": [
        {
          "type": "object",
          "required": [
            "vendor",
            "via"
          ],
          "properties": {
            "via": {
              "type": "string",
              "description": "The signal it was detected by."
            },
            "vendor": {
              "type": "string",
              "description": "Bot protection detected, e.g. \"Cloudflare\"."
            }
          },
          "additionalProperties": false
        },
        {
          "type": "null"
        }
      ],
      "description": "Bot protection on the homepage, or null when there is none."
    },
    "scannedUrl": {
      "type": "string",
      "description": "The absolute URL that was fetched."
    },
    "projectedScore": {
      "type": "number",
      "description": "The score the site would reach with the top fixes applied."
    },
    "unverifiedCount": {
      "type": "number",
      "description": "Checks that could not be verified, e.g. behind bot protection."
    }
  },
  "additionalProperties": false
}
agentready_scan annotations
{
  "readOnlyHint": true,
  "openWorldHint": true,
  "destructiveHint": false
}
ai_hub_search — Search the AI Hub
Advertised by the server during the last successful anonymous check.
Advertised read-only

Searches the Enpitech AI Hub, Enpitech's curated catalog of Claude Code skills, MCP servers and AI tools, and agentic workflows for frontend teams, each one used by Enpitech engineers in production. Use it when the user wants a skill, MCP server, AI tool or workflow for a frontend task (code review, Figma to code, testing, context files, generative UI and so on), or asks what the AI Hub has. Returns matching items with a one-line take, an overview, the install command when there is one, and a link to the item's page on enpitech.dev. Read-only: it searches a published catalog and sends nothing anywhere.

ai_hub_search input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "limit": {
      "type": "integer",
      "maximum": 20,
      "minimum": 1,
      "description": "How many results to return, 1-20 (default 8)."
    },
    "query": {
      "type": "string",
      "maxLength": 200,
      "description": "What to look for, in plain words: a task, a technology or a name, e.g. \"code review\", \"Figma to React\", \"MCP servers for React\". Omit to list the catalog in order."
    },
    "category": {
      "enum": [
        "skills",
        "tools",
        "workflows"
      ],
      "type": "string",
      "description": "Limit results to one part of the catalog: skills (Claude Code and Agent Skills), tools (MCP servers and AI tooling) or workflows (agentic workflows and prompts). Omit to search all three."
    }
  },
  "additionalProperties": false
}
ai_hub_search output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "query",
    "total",
    "results"
  ],
  "properties": {
    "query": {
      "type": "string",
      "description": "The search terms, or empty when listing."
    },
    "total": {
      "type": "number",
      "description": "How many catalog items matched in all."
    },
    "results": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "name",
          "category",
          "section",
          "summary",
          "overview",
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "description": "The item page on enpitech.dev."
          },
          "name": {
            "type": "string"
          },
          "install": {
            "type": "string",
            "description": "Install command, when the item has one."
          },
          "section": {
            "type": "string",
            "description": "The catalog section it sits in."
          },
          "summary": {
            "type": "string",
            "description": "One-line take from Enpitech."
          },
          "category": {
            "enum": [
              "skills",
              "tools",
              "workflows"
            ],
            "type": "string"
          },
          "overview": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "description": "Best matches first."
    },
    "category": {
      "enum": [
        "skills",
        "tools",
        "workflows"
      ],
      "type": "string"
    }
  },
  "additionalProperties": false
}
ai_hub_search annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "destructiveHint": false
}
newsletter — Open Newsletter Signup
Advertised by the server during the last successful anonymous check.
Advertised read-only

Opens a signup form for the Enpitech newsletter, about frontend, AI and how teams ship, as a view in the conversation. The user types their own email and subscribes there. Use it when the user asks to subscribe to, join or get the Enpitech newsletter. It opens a form and subscribes no one: the subscription happens only when the user submits the form.

newsletter input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {}
}
newsletter output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {},
  "additionalProperties": false
}
newsletter annotations
{
  "readOnlyHint": true,
  "openWorldHint": false,
  "destructiveHint": false
}
subscribe_newsletter — Subscribe to Newsletter
Advertised by the server during the last successful anonymous check.
Open-world

Subscribes the email address the user typed into the newsletter signup view to the Enpitech newsletter, managed in Mailchimp. The newsletter view calls this tool when the user submits the form; it is not offered to the model. Returns success with a status of subscribed, or pending when a confirmation email was sent first. Every newsletter email carries an unsubscribe link.

subscribe_newsletter input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "email"
  ],
  "properties": {
    "email": {
      "type": "string",
      "format": "email",
      "maxLength": 320,
      "minLength": 1,
      "description": "The email address the user typed into the signup form."
    }
  },
  "additionalProperties": false
}
subscribe_newsletter output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "success"
  ],
  "properties": {
    "status": {
      "enum": [
        "subscribed",
        "pending"
      ],
      "type": "string",
      "description": "subscribed, or pending when a confirmation email was sent first."
    },
    "success": {
      "type": "boolean",
      "description": "True when the signup went through."
    }
  },
  "additionalProperties": false
}
subscribe_newsletter annotations
{
  "readOnlyHint": false,
  "openWorldHint": true,
  "idempotentHint": false,
  "destructiveHint": false
}

Prompts

Not advertised

No prompt definitions available.

Resources

3 advertised

Enpitech contact form

Advertised by the server during the last successful anonymous check.

Enpitech contact form URI
ui://enpitech/contact-form.html

MIME type: text/html;profile=mcp-app

Enpitech AgentReady scanner

Advertised by the server during the last successful anonymous check.

Enpitech AgentReady scanner URI
ui://enpitech/agent-ready.html

MIME type: text/html;profile=mcp-app

Enpitech newsletter signup

Advertised by the server during the last successful anonymous check.

Enpitech newsletter signup URI
ui://enpitech/newsletter.html

MIME type: text/html;profile=mcp-app

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
1338 ms
95th percentile latency
1338 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 1338 ms · metadata changed · 8 tool(s), 3 resource(s), 0 resource template(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http enpitech-mcp-app https://mcp.enpitech.dev/mcp-app

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add enpitech-mcp-app --url https://mcp.enpitech.dev/mcp-app

Cursor

Merge this server into .cursor/mcp.json in your project, then enable enpitech-mcp-app in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "enpitech-mcp-app": {
      "url": "https://mcp.enpitech.dev/mcp-app"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "enpitech-mcp-app": {
      "type": "streamableHttp",
      "url": "https://mcp.enpitech.dev/mcp-app",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start enpitech-mcp-app and inspect its tools.
VS Code configuration
{
  "servers": {
    "enpitech-mcp-app": {
      "type": "http",
      "url": "https://mcp.enpitech.dev/mcp-app"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http enpitech-mcp-app https://mcp.enpitech.dev/mcp-app

Claude Desktop

Open Claude Settings > Connectors > Add custom connector, enter this server URL and enable it for the conversation. This is a manual remote-connector handoff, not a desktop JSON configuration.
Claude Desktop configuration
https://mcp.enpitech.dev/mcp-app

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "enpitech-mcp-app": {
      "serverUrl": "https://mcp.enpitech.dev/mcp-app"
    }
  }
}

Let your agent find its tools

Find servers like Enpitech MCP App from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.