jido_mcp

mcp
Security Audit
Warn
Health Warn
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 7 GitHub stars
Code Pass
  • Code scan — Scanned 4 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

MCP server integration package with pooled clients and Jido action surfaces

README.md

Jido.MCP

Hex.pm
Hex Docs
CI
License
Website
Ecosystem
Discord

jido_mcp integrates MCP servers into the Jido ecosystem using anubis_mcp directly.

Features

  • Shared pooled MCP clients per configured endpoint
  • Consume-side API for MCP tools/resources/prompts
  • Jido actions + plugin routes for signal-driven usage
  • Jido.AI runtime tool sync (MCP tools -> proxy Jido.Actions)
  • MCP server bridge (use Jido.MCP.Server) with explicit allowlists

Installation

def deps do
  [
    {:jido_mcp, "~> 0.1"}
  ]
end

Endpoint Configuration

config :jido_mcp, :endpoints,
  github: %{
    transport: {:streamable_http, [base_url: "http://localhost:8080", mcp_path: "/mcp"]},
    client_info: %{name: "my_app", version: "1.0.0"},
    protocol_version: "2025-06-18",
    capabilities: %{},
    timeouts: %{request_ms: 30_000}
  },
  local_fs: %{
    transport: {:stdio, [command: "uvx", args: ["mcp-server-filesystem"]]},
    client_info: %{name: "my_app", version: "1.0.0"}
  }

Supported transports in v1:

  • {:stdio, keyword()} for shell/command-based MCP servers
  • {:shell, keyword()} as an alias normalized to :stdio
  • {:sse, keyword()} for legacy HTTP+SSE servers using protocol 2024-11-05
  • {:streamable_http, keyword()} for MCP 2025-03-26 / 2025-06-18, including optional SSE streaming via Anubis' :enable_sse option

For Streamable HTTP, :url or a :base_url containing a non-root path is
normalized to Anubis' :base_url + :mcp_path option shape.

Endpoint config may also be loaded through an MFA callback:

config :jido_mcp, :endpoints, {MyApp.MCPConfig, :endpoints, []}

The callback must return a map/keyword endpoint declaration or {:ok, endpoints}.

Runtime endpoints can be registered after application start:

{:ok, endpoint} =
  Jido.MCP.Endpoint.new(:github, %{
    transport: {:streamable_http, [base_url: "http://localhost:8080", mcp_path: "/mcp"]},
    client_info: %{name: "my_app", version: "1.0.0"}
  })

{:ok, ^endpoint} = Jido.MCP.register_endpoint(endpoint)

Runtime registration is process-local, rejects duplicate endpoint ids, and starts the MCP client
only when the endpoint is first used.

Runtime Endpoint Lifecycle

{:ok, endpoint} =
  Jido.MCP.Endpoint.new(:runtime_demo, %{
    transport: {:streamable_http, [base_url: "http://localhost:8080/mcp"]},
    client_info: %{name: "my_app"}
  })

{:ok, ^endpoint} = Jido.MCP.register_endpoint(endpoint)
{:ok, tools} = Jido.MCP.list_tools(:runtime_demo)

{:ok, _removed} = Jido.MCP.unregister_endpoint(:runtime_demo)

For config changes at runtime, unregister then register the updated endpoint.

Consume MCP APIs

{:ok, tools} = Jido.MCP.list_tools(:github)
{:ok, called} = Jido.MCP.call_tool(:github, "search_issues", %{"query" => "label:bug"})

{:ok, resources} = Jido.MCP.list_resources(:github)
{:ok, content} = Jido.MCP.read_resource(:github, "repo://owner/name/README")

{:ok, prompts} = Jido.MCP.list_prompts(:github)
{:ok, prompt} = Jido.MCP.get_prompt(:github, "release_notes", %{"version" => "1.2.0"})

All calls return normalized envelopes:

  • success: %{status: :ok, endpoint: atom(), method: String.t(), data: map(), raw: ...}
  • error: %{status: :error, endpoint: atom(), type: ..., message: String.t(), details: ...}

Jido Actions + Plugin

Actions

  • Jido.MCP.Actions.ListTools
  • Jido.MCP.Actions.CallTool
  • Jido.MCP.Actions.ListResources
  • Jido.MCP.Actions.ListResourceTemplates
  • Jido.MCP.Actions.ReadResource
  • Jido.MCP.Actions.ListPrompts
  • Jido.MCP.Actions.GetPrompt
  • Jido.MCP.Actions.RegisterEndpoint
  • Jido.MCP.Actions.RefreshEndpoint
  • Jido.MCP.Actions.UnregisterEndpoint
  • Jido.MCP.Actions.SetDefaultEndpoint

Plugin

defmodule MyApp.Agent do
  use Jido.Agent,
    name: "assistant",
    plugins: [
      {Jido.MCP.Plugins.MCP,
        %{
          default_endpoint: :github,
          allowed_endpoints: [:github, :local_fs]
          # or allowed_endpoints: :all
        }}
    ]
end

allowed_endpoints defaults to [] (deny-all) when omitted.
Set it to :all to allow all currently configured/runtime-registered endpoints.

Signal routes:

  • mcp.tools.list
  • mcp.tools.call
  • mcp.resources.list
  • mcp.resources.templates.list
  • mcp.resources.read
  • mcp.prompts.list
  • mcp.prompts.get
  • mcp.endpoint.register
  • mcp.endpoint.refresh
  • mcp.endpoint.unregister
  • mcp.endpoint.default.set

To update the plugin default endpoint at runtime, emit mcp.endpoint.default.set with
%{endpoint_id: "github"} (or nil/omitted to clear).

Jido.AI Sync

Jido.MCP.JidoAI.Actions.SyncToolsToAgent discovers remote tools and creates proxy Jido.Action modules, then registers them on a running Jido.AI.Agent.

Jido.MCP.JidoAI.Actions.UnsyncToolsFromAgent removes previously synced proxies.

Tool sync uses deterministic MCP readiness: endpoint calls wait on
Anubis.Client.await_ready/2 before executing.

Plugin route support:

  • mcp.ai.sync_tools
  • mcp.ai.unsync_tools

Host Runtime Orchestration (Signals)

Host projects are expected to orchestrate runtime endpoint lifecycle and tool sync
explicitly using plugin signals.

Recommended signal sequences:

  • Register endpoint then sync tools
    1. mcp.endpoint.register
    2. mcp.ai.sync_tools
  • Refresh endpoint then resync tools
    1. mcp.endpoint.refresh
    2. mcp.ai.sync_tools (with replace_existing: true)
  • Unsync tools before unregistering endpoint
    1. mcp.ai.unsync_tools
    2. mcp.endpoint.unregister

Example signal payloads:

# mcp.endpoint.register
%{
  endpoint_id: "runtime_demo",
  endpoint: %{
    transport: {:streamable_http, [base_url: "http://localhost:8080/mcp"]},
    client_info: %{name: "my_app"}
  }
}

# mcp.ai.sync_tools
%{
  endpoint_id: "runtime_demo",
  agent_server: :my_ai_agent,
  replace_existing: true,
  prefix: "mcp_"
}

# mcp.ai.unsync_tools
%{endpoint_id: "runtime_demo", agent_server: :my_ai_agent}

# mcp.endpoint.unregister
%{endpoint_id: "runtime_demo"}

Expose Jido As MCP Server

Server module

defmodule MyApp.MCPServer do
  use Jido.MCP.Server,
    name: "my-app",
    version: "1.0.0",
    publish: %{
      tools: [MyApp.Actions.SearchIssues],
      resources: [MyApp.MCP.Resources.ReleaseNotes],
      prompts: [MyApp.MCP.Prompts.CodeReview]
    }
end

Publication is explicit allowlist only.

Supervision

children =
  Jido.MCP.Server.server_children(MyApp.MCPServer,
    transport: :streamable_http
  )

Router (streamable HTTP)

forward "/mcp", Anubis.Server.Transport.StreamableHTTP.Plug,
  Jido.MCP.Server.plug_init_opts(MyApp.MCPServer)

Resource and Prompt Behaviours

  • Jido.MCP.Server.Resource
  • Jido.MCP.Server.Prompt

Implement those behaviours for items listed in publish.resources and publish.prompts.

Testing

mix test

Reviews (0)

No results found