Rust client and tunnel bridge for Poke.
A library and CLI for interacting with the Poke API, providing both an HTTP client interface and an asynchronous WebSocket tunnel for MCP (Model Context Protocol) connections. API parity with the official poke@0.4.2 npm SDK.
- HTTP Client: Authenticated API client for Poke services with automatic token management
- Tunnel Bridge: WebSocket-based tunnel for MCP protocol connections
- Webhook Support: Create and manage webhooks programmatically
- Message Passing: Send messages through the Poke API
- CLI:
poke login,poke logout,poke whoami,poke mcp add - Async-First: Built on Tokio for efficient async/await patterns
Add to your Cargo.toml:
[dependencies]
rs_poke = "0.2.1"Or install the CLI:
cargo install rs_pokeuse rs_poke::{Poke, PokeOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Poke::new(PokeOptions::default())?;
let response = client.send_message("Hello, world!").await?;
println!("{}", response.message);
let webhook = client.create_webhook(&rs_poke::CreateWebhook {
condition: "event.type == 'trigger'",
action: "POST",
}).await?;
println!("trigger: {}", webhook.trigger_id);
Ok(())
}use rs_poke::{Poke, TunnelOptions, TunnelRunner};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let poke = Poke::new(rs_poke::PokeOptions::default())?;
let mut runner = TunnelRunner::new(poke, TunnelOptions {
url: "http://127.0.0.1:52333/mcp".into(),
name: "my-tunnel".into(),
cleanup_on_stop: true,
sync_interval: std::time::Duration::from_secs(300),
startup_timeout: std::time::Duration::from_secs(30),
..TunnelOptions::default()
});
let info = runner.start().await?;
println!("Tunnel connected: {}", info.tunnel_url);
let mut events = runner.subscribe();
while let Ok(event) = events.recv().await {
match event {
rs_poke::TunnelEvent::Connected(info) => {
println!("Connected: {}", info.tunnel_url);
}
rs_poke::TunnelEvent::Disconnected => break,
_ => {}
}
}
runner.stop().await?;
Ok(())
}use rs_poke::{login, logout, is_logged_in, CredentialsStore, LoginOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let store = CredentialsStore::default_store()?;
let result = login(
LoginOptions::new(store).on_code(|info| {
println!("Open {} and enter {}", info.login_url, info.user_code);
}),
)
.await?;
if is_logged_in() {
println!("Authenticated as {}", result.token);
}
logout().await?;
Ok(())
}POKE_API- Base URL for Poke API (default:https://poke.com/api/v1)POKE_API_KEY- API key for authenticationPOKE_FRONTEND- Frontend URL for device login (default:https://poke.com)
Credentials are stored in the user's configuration directory:
- Linux:
~/.config/poke/credentials.json - macOS:
~/Library/Application Support/poke/credentials.json(via XDG_CONFIG_HOME or~/.config/poke) - Windows:
%APPDATA%\poke\credentials.json(via XDG_CONFIG_HOME)
new(options: PokeOptions)- Create a new clientapi_key()/base_url()- Get configured credentials and endpointsend_message(message)- Send a message to Pokecreate_webhook(request)- Create a new webhook (returnstrigger_id)send_webhook(url, token, data)- Send data to a webhook endpointpost_json(path, body)- Authenticated JSON POST helperraw_auth(method, path, body)- Low-level authenticated request
new(client, options)- Create a runnerstart()- Start the tunnel connectionstop()- Stop and optionally cleanup the tunnelsync_tools()- Synchronize MCP toolscreate_recipe(name)- Create a shareable recipe linkconnected()- Whether the tunnel is activesubscribe()/on(event, handler)/off(event)- Event handling
poke login
poke logout
poke whoami
poke mcp add http://127.0.0.1:52333/mcp -n my-server --recipecargo test
cargo clippy --all-targets --all-features
cargo fmtLicensed under the Mozilla Public License 2.0. See LICENSE for details.