barry_mcp
Erlang的MCP(模型上下文协议)库。实施 MCP规范(协议 2025-11-25 向下谈判 通过 2024-11-05)适用于服务器和客户端模式,包括 Claude Code和任何其他MCP的流式HTTP传输 客户。
特性
- 完整的MCP协议:工具、资源、资源模板
(随着运行时RFC 6570的扩展 resources/read), 提示、完成、采样, 任务 (长时间运行 操作), _meta 端到端的扩展挂钩,通知 (*/list_changed, progress, cancelled, resources/updated, tasks/status, replay_truncated).
- 工具操作员:arity 1或arity 2(
(Args, Ctx))与
Ctx-驱动进度、取消和 _meta 钩子。返回 形状:纯内容, {tool_error, ...} (→ isError: true), {structured, Data, ...} (→ structuredContent),或任何 附加的元轴承变体 _meta 回应。
- 模式验证:选择加入
validate_input/
validate_output 针对已注册的JSON模式 (barrel_mcp_schema).
- 运输:流式HTTP(克劳德代码),传统HTTP
(牛仔)、stdio(克劳德桌面)。流式HTTP默认为 127.0.0.1,验证 Origin,并通过以下方式回放SSE事件 Last-Event-ID.
- 认证:承载(JWT/不透明),API密钥(加胡椒
HMAC-SHA-256)、基本(PBKDF2-SHA256)、自定义提供程序。 恒定时间哈希比较;传统的SHA-256十六进制摘要仍然存在 验证一次发布。RFC 9728受保护资源元数据 端点规格正确 WWW-Authenticate 适用于OAuth客户端 自动发现。
- 客户端库 (
barrel_mcp_client):监督
gen_statem 使用stdio+流式HTTP传输,OAuth 2.1 - PKC、联盟注册表(每个服务器id一个连接), 分页、飞行前模式。
- 零JSON依赖:使用内置OTP 27+
json模块。
安装
添加到您的 rebar.config:
{deps, [
{barrel_mcp,
{git, "https://github.com/barrel-platform/barrel_mcp.git",
{tag, "v1.3.0"}}}
]}.轨道 main 而不是为最新的补丁钉上标签:
{barrel_mcp,
{git, "https://github.com/barrel-platform/barrel_mcp.git",
{branch, "main"}}}建筑
barry_mcp使用监督的gen_statem进程来管理处理程序注册表:
- 写 (reg/unreg)通过gen_statem进行原子操作
- 倒像 (find/all/run)直接使用persistent_them进行O(1)查找
- 州:
not_ready→ready用于灵活初始化 - 延迟模式:来电
not_ready状态被推迟到准备就绪
┌─────────────────────────────────────────────────────────────────┐
│ barrel_mcp_sup │
│ (supervisor) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ barrel_mcp_registry │
│ (gen_statem) │
│ │
│ States: not_ready ──────────────────► ready │
│ │ (self ! ready) │
│ │ or │
│ └──── wait for external process ────► │
│ │
│ ┌─────────────┐ ┌─────────────────────────────────────┐ │
│ │ ETS Table │───────►│ persistent_term (read-only) │ │
│ │ (authority) │ sync │ O(1) lookups │ │
│ └─────────────┘ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
▲ │
│ reg/unreg │ find/all/run
│ (atomic, postponed │ (lock-free)
│ if not ready) │配置
要使注册表在准备就绪之前等待外部进程,请执行以下操作:
%% In sys.config or application env
{barrel_mcp, [
{wait_for_proc, my_init_process} % Wait for this process to be registered
]}.如果 wait_for_proc 如果未设置,注册表将在init后立即准备就绪。
按角色使用
barry_mcp在一个库中涵盖了三个mcp角色:
- 服务器 --向MCP客户端公开工具、资源和提示。
- 客户 --连接到一个MCP服务器,调用工具,读取
资源,处理服务器发起的请求。
- 主机(代理) --代表某个客户端驱动一个或多个客户端
LLM收集每个服务器的工具目录,并将其交给 model,通过右侧路由模型的工具调用 客户。
下面的三个简短示例涵盖了典型的接线;更深 导游住在下面 guides/ (getting-started.md, tools-resources-prompts.md, building-a-client.md).
服务器——通过Streamable HTTP公开一个工具
-module(my_server).
-export([start/0, search/1]).
start() ->
{ok, _} = application:ensure_all_started(barrel_mcp),
ok = barrel_mcp:reg_tool(>, ?MODULE, search, #{
description => >,
input_schema => #{> => >,
> => [>]}
}),
{ok, _} = barrel_mcp:start_http_stream(#{port => 8080,
session_enabled => true}),
ok.
search(#{> := Q}) ->
iolist_to_binary([>, Q]).这是一个完整的MCP服务器。指向任何MCP客户端(Claude Code, 克劳德桌面通过stdio barrel_mcp_client 下面,…) http://127.0.0.1:8080/mcp.
客户端——连接并调用工具
client_demo() ->
{ok, _} = application:ensure_all_started(barrel_mcp),
{ok, Pid} = barrel_mcp_client:start(#{
transport => {http, >}
}),
{ok, Result} = barrel_mcp_client:call_tool(
Pid, >, #{> => >}),
barrel_mcp_client:close(Pid),
Result.传输元组选择导线({http, Url}, {stdio, [Cmd | Args]}).Auth和OAuth选项是相同的 规格——请参见 guides/building-a-client.md.
主机(代理)--将许多MCP服务器交给LLM
agent_loop() ->
{ok, _} = application:ensure_all_started(barrel_mcp),
{ok, _} = barrel_mcp:start_client(>, #{
transport => {http, >},
auth => {bearer, GhToken}
}),
{ok, _} = barrel_mcp:start_client(>, #{
transport => {stdio, ["mcp-shell-server"]}
}),
%% Hand every connected server's tools to the model:
AnthropicTools = barrel_mcp_agent:to_anthropic(),
%% ... call the LLM with AnthropicTools and capture the
%% tool_use block it returned ...
Block = ask_llm(AnthropicTools),
{NsName, Args} = barrel_mcp_tool_format:from_anthropic_call(Block),
%% Routes "github:..." to the github client, "shell:..." to
%% the shell client.
barrel_mcp_agent:call_tool(NsName, Args).barrel_mcp_agent 命名空间工具名称为 > 在整个联邦。 barrel_mcp_tool_format 在MCP工具图和 提供者形状(Anthropic消息API、OpenAI聊天完成); 交换 to_anthropic/0 和 from_anthropic_call/1 对于OpenAI 同行使用不同的模型。 ask_llm/1 是你自己的 LLM HTTP调用--barry_mcp不捆绑LLM SDK。
快速开始
启动应用程序
%% Start barrel_mcp application
application:ensure_all_started(barrel_mcp).
%% Wait for registry to be ready (optional, for custom initialization)
ok = barrel_mcp_registry:wait_for_ready().注册工具
%% Register a tool
barrel_mcp:reg_tool(>, my_module, search, #{
description => >,
input_schema => #{
type => >,
properties => #{
query => #{type => >, description => >},
limit => #{type => >, default => 10}
},
required => [>]
}
}).
%% Your handler function (must accept a map and be exported with arity 1)
-module(my_module).
-export([search/1]).
search(#{> := Query} = Args) ->
Limit = maps:get(>, Args, 10),
%% Return binary, map, or list of content blocks
>.注册资源
barrel_mcp:reg_resource(>, my_module, get_config, #{
name => >,
uri => >,
description => >,
mime_type => >
}).注册提示
barrel_mcp:reg_prompt(>, my_module, summarize_prompt, #{
description => >,
arguments => [
#{name => >, description => >, required => true},
#{name => >, description => >, required => false}
]
}).
%% Handler returns prompt messages
summarize_prompt(Args) ->
Content = maps:get(>, Args),
#{
description => >,
messages => [
#{role => >, content => #{type => >, text => Content}}
]
}.启动流式HTTP服务器(Claude代码)
对于Claude Code集成,请使用Streamable HTTP传输:
%% Start Streamable HTTP server on port 9090
{ok, _} = barrel_mcp:start_http_stream(#{port => 9090}).
%% With API key authentication
{ok, _} = barrel_mcp:start_http_stream(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_apikey,
provider_opts => #{
keys => #{> => #{subject => >}}
}
}
}).然后添加到克劳德代码中:
claude mcp add my-server --transport http http://localhost:9090/mcp \
--header "X-API-Key: my-key"看 guides/http-stream.md 获取完整文档。
正在启动HTTP服务器(旧版)
%% Start HTTP server on port 9090
{ok, _} = barrel_mcp:start_http(#{port => 9090}).
%% Or with custom IP binding
{ok, _} = barrel_mcp:start_http(#{port => 9090, ip => {127, 0, 0, 1}}).认证
barry_mcp提供遵循mcp规范推荐的OAuth 2.1模式的可插拔身份验证。身份验证是可选的,每个HTTP服务器都可以配置。
内置提供商
| 提供者 | 描述 |
|---|---|
barrel_mcp_auth_none | 无身份验证(默认) |
barrel_mcp_auth_bearer | 不记名代币(JWT或不透明) |
barrel_mcp_auth_apikey | API密钥验证 |
barrel_mcp_auth_basic | HTTP基本身份验证 |
barrel_mcp_auth_custom | 自定义身份验证模块(简单界面) |
承载令牌(JWT)身份验证
%% Start HTTP server with JWT authentication
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_bearer,
provider_opts => #{
secret => >,
issuer => >,
audience => >,
clock_skew => 60 % seconds
},
required_scopes => [>, >]
}
}).对于RS256/ES256或不透明令牌,请使用自定义验证器:
%% Custom token verifier (e.g., for token introspection)
Verifier = fun(Token) ->
case my_auth_service:validate(Token) of
{ok, Claims} -> {ok, Claims};
error -> {error, invalid_token}
end
end,
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_bearer,
provider_opts => #{verifier => Verifier}
}
}).API密钥验证
%% Simple API key list
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_apikey,
provider_opts => #{
keys => #{
> => #{subject => >, scopes => [>]},
> => #{subject => >, scopes => [>, >]}
}
}
}
}).
%% With hashed keys for security (recommended for production)
HashedKey = barrel_mcp_auth_apikey:hash_key(>),
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_apikey,
provider_opts => #{
keys => #{HashedKey => #{subject => >}},
hash_keys => true
}
}
}).基本身份验证
%% Simple username/password
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_basic,
provider_opts => #{
credentials => #{
> => >,
> => >
},
realm => >
}
}
}).
%% With hashed passwords (recommended)
HashedPwd = barrel_mcp_auth_basic:hash_password(>),
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_basic,
provider_opts => #{
credentials => #{> => HashedPwd},
hash_passwords => true
}
}
}).自定义身份验证(简单界面)
要与现有的身份验证系统集成,请使用 barrel_mcp_auth_custom 具有简单的两个功能模块:
-module(my_auth).
-export([init/1, authenticate/2]).
init(_Opts) ->
{ok, #{}}.
authenticate(Token, State) ->
case my_key_store:validate(Token) of
{ok, Info} ->
{ok, #{subject => Info}, State};
error ->
{error, invalid_token, State}
end.配置它:
{ok, _} = barrel_mcp:start_http(#{
port => 9090,
auth => #{
provider => barrel_mcp_auth_custom,
provider_opts => #{
module => my_auth
}
}
}).看 guides/custom-authentication.md 获取完整文档。
自定义身份验证提供程序(完整行为)
为了获得更多控制,请实施全面 barrel_mcp_auth 行为:
-module(my_auth_provider).
-behaviour(barrel_mcp_auth).
-export([init/1, authenticate/2, challenge/2]).
init(Opts) ->
{ok, Opts}.
authenticate(Request, State) ->
Headers = maps:get(headers, Request, #{}),
case barrel_mcp_auth:extract_bearer_token(Headers) of
{ok, Token} ->
%% Your validation logic
case validate_with_my_service(Token) of
{ok, User} ->
{ok, #{
subject => User,
scopes => [>],
claims => #{}
}};
error ->
{error, invalid_token}
end;
{error, no_token} ->
{error, unauthorized}
end.
challenge(Reason, _State) ->
{401, #{> => >}, >}.在处理程序中访问身份验证信息
身份验证信息在请求上下文中可用:
my_tool_handler(Args) ->
%% Auth info is passed in the _auth key
case maps:get(>, Args, undefined) of
undefined ->
>;
AuthInfo ->
Subject = maps:get(subject, AuthInfo),
>
end.启动stdio服务器(适用于Claude Desktop)
%% This blocks and handles MCP over stdin/stdout
barrel_mcp:start_stdio().作为客户端使用
barrel_mcp_client 是一个 gen_statem.启动它,等待 握手完成,通话工具。
{ok, Pid} = barrel_mcp_client:start_link(#{
transport => {http, >}
}),
{ok, Tools} = barrel_mcp_client:list_tools(Pid),
{ok, Result} = barrel_mcp_client:call_tool(Pid, >,
#{> => >}),
ok = barrel_mcp_client:close(Pid).对于完整的面向任务的演练——传输选择、身份验证、, OAuth、服务器到客户端处理程序、联盟、模式验证-- 看见 建立客户.为 架构和行为契约,请参见 内部机制.三个可运行的实例 在...之下 (echo_client, sampling_host, agent_host).
Claude桌面配置
在Claude Desktop上使用barry_mcp和stdio传输时:
{
"mcpServers": {
"my-server": {
"command": "/path/to/my_app/bin/my_app",
"args": ["mcp"]
}
}
}您的应用程序的入口点应该调用 barrel_mcp:start_stdio().
API 参考
工具
| 功能 | 说明 |
|---|---|
barrel_mcp:reg_tool(Name, Module, Function, Opts) | 注册工具 |
barrel_mcp:unreg_tool(Name) | 注销工具 |
barrel_mcp:call_tool(Name, Args) | 在本地调用工具 |
barrel_mcp:list_tools() | 列出所有已注册的工具 |
资源
| 功能 | 说明 |
|---|---|
barrel_mcp:reg_resource(Name, Module, Function, Opts) | 注册资源 |
barrel_mcp:unreg_resource(Name) | 注销资源 |
barrel_mcp:read_resource(Name) | 在本地读取资源 |
barrel_mcp:list_resources() | 列出所有已注册的资源 |
提示
| 功能 | 说明 |
|---|---|
barrel_mcp:reg_prompt(Name, Module, Function, Opts) | 注册提示 |
barrel_mcp:unreg_prompt(Name) | 取消注册提示 |
barrel_mcp:get_prompt(Name, Args) | 在本地获取提示 |
barrel_mcp:list_prompts() | 列出所有已注册的提示 |
注册表
| 功能 | 说明 |
|---|---|
barrel_mcp_registry:start_link() | 启动注册表(由主管调用) |
barrel_mcp_registry:wait_for_ready() | 等待注册表准备就绪 |
barrel_mcp_registry:wait_for_ready(Timeout) | 使用自定义超时等待 |
服务器
| 功能 | 说明 |
|---|---|
barrel_mcp:start_http_stream(Opts) | 启动流式HTTP服务器(Claude代码) |
barrel_mcp:stop_http_stream() | 停止流式HTTP服务器 |
barrel_mcp:start_http(Opts) | 启动HTTP服务器(旧版) |
barrel_mcp:stop_http() | 停止HTTP服务器 |
barrel_mcp:start_stdio() | 启动stdio服务器(阻塞) |
客户
| 功能 | 说明 |
|---|---|
barrel_mcp_client:connect(Opts) | 连接到MCP服务器 |
barrel_mcp_client:initialize(Client) | 初始化连接 |
barrel_mcp_client:list_tools(Client) | 列出可用工具 |
barrel_mcp_client:call_tool(Client, Name, Args) | 调用工具 |
barrel_mcp_client:list_resources(Client) | 列出可用资源 |
barrel_mcp_client:read_resource(Client, Uri) | 阅读资源 |
barrel_mcp_client:list_prompts(Client) | 列出可用提示 |
barrel_mcp_client:get_prompt(Client, Name, Args) | 获得提示 |
barrel_mcp_client:close(Client) | 关闭连接 |
认证
| 功能 | 说明 |
|---|---|
barrel_mcp_auth:extract_bearer_token(Headers) | 从标头中提取承载令牌 |
barrel_mcp_auth:extract_api_key(Headers, Opts) | 从标头中提取API密钥 |
barrel_mcp_auth:extract_basic_auth(Headers) | 提取基本身份验证凭据 |
barrel_mcp_auth_apikey:hash_key(Key) | 对API密钥(SHA256)进行哈希 |
barrel_mcp_auth_basic:hash_password(Password) | 哈希密码(SHA256) |
MCP协议支持
支持的方法
生命周期:
initialize/initializedping
工具:
tools/listtools/call
资源:
resources/listresources/readresources/templates/listresources/subscribe/resources/unsubscribe
提示:
prompts/listprompts/get
取样:
sampling/createMessage
登录中:
logging/setLevel
待定功能
尚未实施的设计说明和范围草图 住在 docs/pending-features.md. 第一条: 企业管理授权 (第二 MCP的一半 ext-auth 扩展--RFC 8693令牌交换 通过用于SSO驱动的MCP访问的组织IdP链接)。打开一个 如果你想优先考虑一个问题。
发展
# Compile
rebar3 compile
# Run tests
rebar3 eunit
# Dialyzer
rebar3 dialyzer
# Shell
rebar3 shell许可证
阿帕奇-2.0
