tyr0

tyr0

Vancouver - easily add MCP tools to your phoenix/bandit server

Vancouver makes it easy to add Model Context Protocol (MCP) functionality to your Phoenix/Bandit server. Vancouver handles initialization, request validation, and offers helper functions to simplify the creation of MCP tools and prompts.

The goal is to let you create MCP servers with working tools/prompts in minutes, without needing to know much about the MCP protocol.

How it works

You create tools like this:

defmodule MyApp.Tools.CalculateSum do
  use Vancouver.Tool

  def name, do: "calculate_sum"
  def description, do: "Add two numbers together"

  def input_schema do
    %{
      "type" => "object",
      "properties" => %{
        "a" => %{"type" => "number"},
        "b" => %{"type" => "number"}
      },
      "required" => ["a", "b"]
    }
  end

  def run(conn, %{"a" => a, "b" => b}) do
    send_text(conn, "#{a + b}")
  end
end

create prompts like this:

defmodule MyApp.Prompts.CodeReview do
  use Vancouver.Prompt

  def name, do: "code_review"
  def description, do: "Asks the LLM to analyze code quality and suggest improvements"

  def arguments do
    [
      %{
        "name" => "code",
        "description" => "The code to review",
        "required" => true
      }
    ]
  end

  def run(conn, %{"code" => code}) do
    send_text(conn, "Please review this code: #{code}")
  end
end

and configure via your (phoenix) router like this:

forward "/mcp", Vancouver.Router, 
  tools: [MyApp.Tools.CalculateSum],
  prompts: [MyApp.Prompts.CodeReview]

To use your tools locally with e.g. Claude Desktop, you can update your claude_desktop_config.json file (see below), run your server, and refresh Claude Desktop.

{
    "mcpServers": {
        "MyApp": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "http://localhost:4000/mcp"
            ]
        }
    }
}

More info

Most Liked

zachdaniel

zachdaniel

Creator of Ash

We’ve been looking for a generic MCP solution to sit Ash AI on top of that can act as a shared base instead of rolling our own which is what we’ve done so far. I’ll be evaluating this for that purpose.

mtrudel

mtrudel

Creator of Bandit

Very nice! I’ve also started GitHub - mtrudel/excom: EXCOM is an MCP server for Elixir and it looks like our config ergonomics are more or less identical. TBH, EXCOM came out of a company hack week and I don’t really have the bandwidth to keep carrying it along, happy to see some other projects emerging to fill that need!

venkatd

venkatd

I’m a huge fan of this API design–simple but extensible. My vote goes for something like this!

One thing that might be helpful is to allow some way to manage session state, more akin to a phoenix channel.

For example, I am prototyping an MCP server for Livebook, and upon connecting the AI agent will register as a collaborator in the notebook. On disconnect, it will leave. This means some MCP servers may need to be stateful.

I don’t know if this is within the scope but wanted to share that this comes up pretty often.

tyr0

tyr0

Aha. I was planning to make Tools (and Prompts) into plugs, so that they’d have an (overridable) init, and support pipelines etc. I think that should work for your use case too.

Will have a think about extension support - that’s not something I’d considered, but sounds interesting. :slightly_smiling_face:

dbern

dbern

Love it! Very nice and simple API for defining tools. I know this is limited to tools right now, but do you plan to support prompts or resources?

I’m working on a framework that provides a controller-like DSL that can respond synchronously and asynchronously: GitHub - dbernheisel/phantom_mcp: MCP server implemented in Elixir

I would love to collaborate. I’m in the process of using Phantom in anger before I publicize it.

Where Next?

Popular in Libraries Top

scohen
Lexical Lexical is a next-generation language server for the Elixir programming language. Features Context aware code completion As-you...
New
kevinlang
Hey all, We have made an Ecto3 Adapter for SQLite3, ecto_sqlite3! We have successfully on-boarded the full suite of integration tests (...
New
mathieuprog
Hello :wave: Allow me to introduce you to Tz, an alternative time zone database support to Tzdata. Why another library? First and fore...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
kelvinst
Hey everyone! Well, we made this lib a while ago and now we decided to finally go out and public with it! It’s a tool for creating and m...
New
archan937
It is a well-know topic within the Elixir community: “To mock or not to mock? :)” Every alchemist probably has his / her own opinion con...
New
MRdotB
I needed to reuse React components from my Chrome extension in my Phoenix/LiveView backend. I noticed that for Svelte/Vue, there are live...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
381 12391 119
New
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New

Sub Categories:

We're in Beta

About us Mission Statement