GenMCP.Suite.ResourceRepo behaviour (gen_mcp v0.10.0)

Copy Markdown View Source

Defines the behaviour for resource repositories and handles their execution.

Repositories expose data to the MCP server either via fixed URIs or URI templates. This module validates repository definitions and orchestrates URI parsing and content retrieval.

Example

defmodule MyResourceRepo do
  @behaviour GenMCP.Suite.ResourceRepo

  @impl true
  def prefix(_arg), do: "file:///"

  @impl true
  def list(_cursor, _channel, _arg) do
    resources = [
      %{uri: "file:///readme.txt", name: "README"}
    ]
    {resources, nil}
  end

  @impl true
  def read("file:///readme.txt", _channel, _arg) do
    result = GenMCP.MCP.read_resource_result(
      uri: "file:///readme.txt",
      text: "Hello world"
    )
    {:ok, result}
  end

  def read(_uri, _channel, _arg), do: {:error, :not_found}
end

Summary

Callbacks

Returns a page of available resources.

Customizes URI parsing for template resources.

Returns the URI prefix for routing requests.

Returns the content of a resource.

Defines the URI template for dynamic resources.

Functions

Returns a descriptor for the given module or {module, arg} tuple.

Lists resources from the repository.

Retrieves content for a specific resource URI.

Types

arg()

@type arg() :: term()

contents()

resource_item()

@type resource_item() :: %{
  :uri => String.t(),
  :name => String.t(),
  optional(:description) => nil | String.t(),
  optional(:mimeType) => nil | String.t(),
  optional(:size) => nil | integer()
}

resource_repo()

@type resource_repo() :: module() | {module(), arg()} | resource_repo_descriptor()

resource_repo_descriptor()

@type resource_repo_descriptor() :: %{
  :mod => module(),
  :arg => arg(),
  :prefix => String.t(),
  optional(:template) => String.t() | nil
}

template_descriptor()

@type template_descriptor() :: %{
  :uriTemplate => String.t(),
  :name => String.t(),
  optional(:description) => nil | String.t(),
  optional(:mimeType) => nil | String.t(),
  optional(:title) => nil | String.t()
}

Callbacks

list(pagination_token, t, arg)

@callback list(pagination_token :: String.t() | nil, GenMCP.Mux.Channel.t(), arg()) ::
  {[resource_item()], next_cursor :: term() | nil}

Returns a page of available resources.

Supports pagination via a cursor. Returns a tuple {prompts, next_cursor}. If next_cursor is nil, there are no more pages.

Examples

def list(nil, _channel, _arg) do
  resources = [%{uri: "file:///readme.txt", name: "README"}]
  {resources, nil}
end

parse_uri(uri, arg)

(optional)
@callback parse_uri(uri :: String.t(), arg()) ::
  {:ok, %{required(String.t()) => term()}}
  | {:ok, String.t()}
  | {:error, String.t()}

Customizes URI parsing for template resources.

Called before read/3 to extract arguments from the URI. If not implemented, Texture.UriTemplate.match/2 is used.

Examples

def parse_uri("file:///" <> path, _arg) do
  {:ok, %{"path" => path}}
end

prefix(arg)

@callback prefix(arg()) :: String.t()

Returns the URI prefix for routing requests.

Examples

def prefix(_arg), do: "file:///"

read(uri_or_template_args, t, arg)

@callback read(uri_or_template_args, GenMCP.Mux.Channel.t(), arg()) ::
  {:ok, GenMCP.MCP.ReadResourceResult.t()} | {:error, :not_found | String.t()}
when uri_or_template_args: String.t() | %{required(String.t()) => term()}

Returns the content of a resource.

Receives the URI string (for direct resources) or a map of template arguments (for templates). Must return {:ok, result} or an error tuple.

Examples

Direct resource:

def read("file:///readme.txt", _channel, _arg) do
  result =
    GenMCP.MCP.read_resource_result(
      uri: "file:///readme.txt",
      text: "Hello world"
    )
  {:ok, result}
end

Template resource:

def read(%{"path" => ["config", "app.json"]}, _channel, _arg) do
  result =
    GenMCP.MCP.read_resource_result(
      uri: "file:///config/app.json",
      text: "{}"
    )
  {:ok, result}
end

template(arg)

(optional)
@callback template(arg()) :: template_descriptor()

Defines the URI template for dynamic resources.

Must return a map with :uriTemplate and :name.

Examples

def template(_arg) do
  %{uriTemplate: "file:///{path}", name: "File"}
end

Functions

expand(mod)

Returns a descriptor for the given module or {module, arg} tuple.

list_resources(repo, cursor, channel)

@spec list_resources(
  resource_repo_descriptor(),
  String.t() | nil,
  GenMCP.Mux.Channel.t()
) ::
  {[resource_item()], next_cursor :: term() | nil}

Lists resources from the repository.

Delegates to the list/3 callback and returns the resources and next pagination cursor.

Example

{resources, next_cursor} = GenMCP.Suite.ResourceRepo.list_resources(repo, nil, channel)

read_resource(repo, uri, channel)

@spec read_resource(resource_repo_descriptor(), String.t(), GenMCP.Mux.Channel.t()) ::
  {:ok, GenMCP.MCP.ReadResourceResult.t()}
  | {:error, {:resource_not_found, String.t()} | String.t()}

Retrieves content for a specific resource URI.

For template-based repositories, parses the URI (via parse_uri/2 or default matching) before calling read/3.

Normalizes {:error, :not_found} into {:error, {:resource_not_found, uri}} automatically.

Example

{:ok, result} = GenMCP.Suite.ResourceRepo.read_resource(repo, "file:///readme.txt", channel)