Skip to main content
Glama

search_media

Find similar media in your indexed library by providing a URL or base64 content. Choose search depth from exact matches to comprehensive visual similarity analysis.

Instructions

Search for similar or matching media across the indexed library. Provide a media_url or base64 media to find matches. Tiers: exact (hash match), quick (perceptual hash), perceptual (visual similarity), compositional (scene structure), full (all tiers). Returns results immediately.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
media_urlNoPublic URL of the media to search for
mediaNoBase64-encoded media content to search for
typeNoSearch tier — controls depth vs speed tradeoff. Default: perceptual
tagsNoRestrict search to media with these tags
limitNoMaximum results to return (1-100, default: 20)

Implementation Reference

  • The async handler function that executes the search_media tool. It builds the request body from params (media_url, media, type, tags, limit), constructs the API path with query parameters, makes a POST request to /api/v1/search, and returns the formatted JSON result or error message.
    async (params) => {
      try {
        const body: Record<string, unknown> = {};
        if (params.media_url) body.media_url = params.media_url;
        if (params.media) body.media = params.media;
        if (params.type) body.type = params.type;
        if (params.tags) body.scope = { tags: params.tags };
    
        const queryParams: Record<string, string | undefined> = {};
        if (params.limit) queryParams.limit = String(params.limit);
    
        const path =
          "/api/v1/search" +
          (Object.keys(queryParams).length
            ? "?" +
              new URLSearchParams(
                Object.fromEntries(
                  Object.entries(queryParams).filter(
                    (e): e is [string, string] => e[1] !== undefined,
                  ),
                ),
              ).toString()
            : "");
    
        const result = await api.post(path, body);
        return {
          content: [
            { type: "text" as const, text: JSON.stringify(result, null, 2) },
          ],
        };
      } catch (err) {
        return {
          content: [
            {
              type: "text" as const,
              text: `Error: ${err instanceof Error ? err.message : String(err)}`,
            },
          ],
          isError: true as const,
        };
      }
    },
  • Zod schema defining the input validation for search_media tool parameters: media_url (optional URL), media (optional base64), type (enum with 5 search tiers), tags (optional string array), and limit (optional int 1-100).
      media_url: z
        .string()
        .url()
        .optional()
        .describe("Public URL of the media to search for"),
      media: z
        .string()
        .optional()
        .describe("Base64-encoded media content to search for"),
      type: z
        .enum(["exact", "quick", "perceptual", "compositional", "full"])
        .optional()
        .describe("Search tier — controls depth vs speed tradeoff. Default: perceptual"),
      tags: z
        .array(z.string())
        .optional()
        .describe("Restrict search to media with these tags"),
      limit: z
        .number()
        .int()
        .min(1)
        .max(100)
        .optional()
        .describe("Maximum results to return (1-100, default: 20)"),
    },
  • The register function that registers the search_media tool with the MCP server, including the tool name, description, input schema, and handler callback.
    export function register(server: McpServer, api: ApiClient): void {
      server.tool(
        "search_media",
        "Search for similar or matching media across the indexed library. " +
          "Provide a media_url or base64 media to find matches. " +
          "Tiers: exact (hash match), quick (perceptual hash), perceptual (visual similarity), " +
          "compositional (scene structure), full (all tiers). Returns results immediately.",
        {
          media_url: z
            .string()
            .url()
            .optional()
            .describe("Public URL of the media to search for"),
          media: z
            .string()
            .optional()
            .describe("Base64-encoded media content to search for"),
          type: z
            .enum(["exact", "quick", "perceptual", "compositional", "full"])
            .optional()
            .describe("Search tier — controls depth vs speed tradeoff. Default: perceptual"),
          tags: z
            .array(z.string())
            .optional()
            .describe("Restrict search to media with these tags"),
          limit: z
            .number()
            .int()
            .min(1)
            .max(100)
            .optional()
            .describe("Maximum results to return (1-100, default: 20)"),
        },
        async (params) => {
          try {
            const body: Record<string, unknown> = {};
            if (params.media_url) body.media_url = params.media_url;
            if (params.media) body.media = params.media;
            if (params.type) body.type = params.type;
            if (params.tags) body.scope = { tags: params.tags };
    
            const queryParams: Record<string, string | undefined> = {};
            if (params.limit) queryParams.limit = String(params.limit);
    
            const path =
              "/api/v1/search" +
              (Object.keys(queryParams).length
                ? "?" +
                  new URLSearchParams(
                    Object.fromEntries(
                      Object.entries(queryParams).filter(
                        (e): e is [string, string] => e[1] !== undefined,
                      ),
                    ),
                  ).toString()
                : "");
    
            const result = await api.post(path, body);
            return {
              content: [
                { type: "text" as const, text: JSON.stringify(result, null, 2) },
              ],
            };
          } catch (err) {
            return {
              content: [
                {
                  type: "text" as const,
                  text: `Error: ${err instanceof Error ? err.message : String(err)}`,
                },
              ],
              isError: true as const,
            };
          }
        },
      );
    }
  • src/index.ts:10-10 (registration)
    Import statement for the search_media register function from tools/search-media.js.
    import { register as searchMedia } from "./tools/search-media.js";
  • src/index.ts:50-50 (registration)
    Registration call that invokes searchMedia(server, api) to register the search_media tool with the MCP server.
    searchMedia(server, api);

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/sidearmDRM/mcp-server'

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