PhoenixKit.API.PublicDiscovery (phoenix_kit v2.64.1)

Copy Markdown View Source

What the install publishes, without a key, about its public API: the guide GET /mcp, the API catalog /.well-known/api-catalog (RFC 9727), the Link headers that point to them and the API section of /llms.txt.

Everything here is built from PhoenixKit.API.Registry.visible_tools/2 of the public audience on every request (nothing is cached), so a module that is switched off or a tool hidden in Settings -> API is gone from the documents at once. Nothing here names the admin API: a document served without a key never mentions an admin path, tool, scope or permission.

One predicate

check/1 and visible?/1 decide whether anything is published at all, and every document and header of this module asks it:

  1. the public API switch is on (PhoenixKit.API.Config.public_enabled?/0);
  2. the website password gate does not hide the site from this client (PhoenixKit.API.Auth.gated?/2): a gated pre-production site publishes nothing it would not serve through the API itself;
  3. at least one public tool is visible. The list is returned, so one request walks the registry once.

Which host a document names

The Host header is never trusted by itself (PhoenixKit.API.RequestContext defaults its :hosts to the request host, so "the host is one of the hosts" proves nothing on a default install). origin/1 uses the request host only when it is a well-formed hostname and one of the hosts PhoenixKit.API.MCP.Origin.known_hosts/1 lists (the canonical host and the hosts the :api_request_context hook explicitly returns); else it uses PhoenixKit.API.MCP.Origin.canonical_origin/0. Never PhoenixKit.Utils.Routes.base_url/0, which reads the database uncached.

The scheme and the port never come from the request either, whatever its Host port or X-Forwarded-Proto say: the canonical host is named by canonical_origin/0 as it is, any other known host takes the canonical scheme and the canonical port (none when that is the scheme's default). The documents are cached publicly, so a request must not shape them.

The API and the guide live under the kit's URL prefix (PhoenixKit.Utils.Routes.path/1); /llms.txt and /.well-known/* are origin-root URLs.

Summary

Functions

The API catalog (RFC 9727 linkset) naming the origin's public API.

The URL of the public REST API under origin.

The Cache-Control of a published document.

The Content-Type of the API catalog.

The Link header value that points to the API catalog.

The URL of the API catalog: at the origin root, whatever the URL prefix.

Whether anything is published for conn, with the public tools that make it so. The three parts are checked in the order of the moduledoc, cheapest first.

The content of the guide for conn, as one map the two renderers (PhoenixKit.API.PublicDiscovery.GuideHTML, PhoenixKit.API.PublicDiscovery.GuideMarkdown) turn into text. tools is the list check/1 returned.

The URL of the guide under origin.

The language a page for context is written in: the domain's language reduced to a locale PhoenixKitWeb.Gettext has a catalogue for, else "en".

The API section of /llms.txt for origin, to append after the operator's text.

The URL of /llms.txt: at the origin root, whatever the URL prefix.

The URL of the public MCP server under origin.

The URL of the public OpenAPI description under origin.

The origin (scheme://host[:port]) the documents for conn name, by the rule of the moduledoc.

Adds value to the Link header of conn, after the value an earlier plug may have set (one header, values joined by a comma, as RFC 8288 allows). A value that is already there is not repeated, and a blank earlier header is ignored.

The Link header of GET /api/public/v1, the tool list: the OpenAPI description and the guide. Added on a 200 only, and only when the guide is published; the check runs when the answer is sent.

Adds Link: <guide>; rel="service-doc" to the 405 of GET /mcp/public when the guide is published.

Whether anything is published for conn (check/1).

Functions

api_catalog(origin)

@spec api_catalog(String.t()) :: map()

The API catalog (RFC 9727 linkset) naming the origin's public API.

api_url(origin)

@spec api_url(String.t()) :: String.t()

The URL of the public REST API under origin.

cache_control()

@spec cache_control() :: String.t()

The Cache-Control of a published document.

While the website gate is on the answer depends on the client address, so a shared cache must not keep it.

catalog_content_type()

@spec catalog_content_type() :: String.t()

The Content-Type of the API catalog.

catalog_link(origin)

@spec catalog_link(String.t()) :: String.t()

The Link header value that points to the API catalog.

catalog_url(origin)

@spec catalog_url(String.t()) :: String.t()

The URL of the API catalog: at the origin root, whatever the URL prefix.

check(conn)

@spec check(Plug.Conn.t()) :: {:ok, [PhoenixKit.API.Tool.t()]} | :hidden

Whether anything is published for conn, with the public tools that make it so. The three parts are checked in the order of the moduledoc, cheapest first.

guide(conn, tools)

@spec guide(Plug.Conn.t(), [PhoenixKit.API.Tool.t()]) :: map()

The content of the guide for conn, as one map the two renderers (PhoenixKit.API.PublicDiscovery.GuideHTML, PhoenixKit.API.PublicDiscovery.GuideMarkdown) turn into text. tools is the list check/1 returned.

guide_url(origin)

@spec guide_url(String.t()) :: String.t()

The URL of the guide under origin.

language(map)

@spec language(PhoenixKit.API.RequestContext.t()) :: String.t()

The language a page for context is written in: the domain's language reduced to a locale PhoenixKitWeb.Gettext has a catalogue for, else "en".

llms_section(origin)

@spec llms_section(String.t()) :: String.t()

The API section of /llms.txt for origin, to append after the operator's text.

llms_url(origin)

@spec llms_url(String.t()) :: String.t()

The URL of /llms.txt: at the origin root, whatever the URL prefix.

mcp_url(origin)

@spec mcp_url(String.t()) :: String.t()

The URL of the public MCP server under origin.

openapi_url(origin)

@spec openapi_url(String.t()) :: String.t()

The URL of the public OpenAPI description under origin.

origin(conn)

@spec origin(Plug.Conn.t()) :: String.t()

The origin (scheme://host[:port]) the documents for conn name, by the rule of the moduledoc.

put_link(conn, value)

@spec put_link(Plug.Conn.t(), String.t()) :: Plug.Conn.t()

Adds value to the Link header of conn, after the value an earlier plug may have set (one header, values joined by a comma, as RFC 8288 allows). A value that is already there is not repeated, and a blank earlier header is ignored.

put_list_links(conn)

@spec put_list_links(Plug.Conn.t()) :: Plug.Conn.t()

The Link header of GET /api/public/v1, the tool list: the OpenAPI description and the guide. Added on a 200 only, and only when the guide is published; the check runs when the answer is sent.

put_service_doc_link(conn)

@spec put_service_doc_link(Plug.Conn.t()) :: Plug.Conn.t()

Adds Link: <guide>; rel="service-doc" to the 405 of GET /mcp/public when the guide is published.

visible?(conn)

@spec visible?(Plug.Conn.t()) :: boolean()

Whether anything is published for conn (check/1).