imcp2 0.2.0

Minimal MCP server that bridges an LLM to the Internet Computer, speaking textual Candid.
Documentation
[package]
name = "imcp2"
version = "0.2.0"
edition = "2021"
description = "Minimal MCP server that bridges an LLM to the Internet Computer, speaking textual Candid."
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/dfinity/imcp2"
# The hosted deployment of this crate, not the repository: crates.io renders
# `homepage` and `repository` as separate links, so pointing both at GitHub
# wastes one. This is where a reader can actually connect an MCP client.
homepage = "https://mcp.internetcomputer.org"
keywords = ["mcp", "internet-computer", "icp", "candid", "axum"]
categories = [
    "network-programming",
    "web-programming::http-server",
    "api-bindings",
    "cryptography::cryptocurrencies",
]
# Everything the library and the bundled binary compile from ships; the
# deployment scaffolding (container, systemd/native deploy, dashboards, CI,
# submission docs) is repository-only and would just inflate the .crate.
# `src/assets` and `static` are NOT optional: both are pulled in at compile
# time with `include_str!`.
exclude = [
    ".github/",
    ".dockerignore",
    "Dockerfile",
    "deploy/",
    "docs/",
    "monitoring/",
]

[dependencies]
rmcp = { version = "1.7", features = [
    "server",
    "macros",
    "transport-streamable-http-server",
    "auth",
] }
# The Agent is INJECTED by the embedding application (see McpServer::new), so a
# host shares one boundary-node client and one ic-agent across the process.
# Deliberately a direct dependency for now: sourcing ic-agent through ic-bn-lib
# (the shared boundary-node/gateway crate, the eventual goal so the version is
# pinned by the same crate the hosts use) is deferred until ic-bn-lib releases
# against this ic-agent line — its current release pins an older one, which
# would revert the read-only delegation-permissions support this depends on.
ic-agent = "0.49"
# Floor at 0.10.31: earlier 0.10.x decode/encode large `Nat`/`Int` in O(n²), which
# a caller-influenced textual `Nat` under the 1 MiB guard turns into seconds of
# worker-blocking CPU (ICPBB-382); 0.10.31 made it O(n).
candid = { version = "0.10.31", features = ["value"] }
candid_parser = "0.3.2"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal", "time"] }
axum = "0.8"
anyhow = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tokio-util = "0.7"
uuid = { version = "1", features = ["v4"] }
tower-http = { version = "0.7", features = ["cors"] }
# Metrics exposition at /metrics. Pinned to the version dfinity/ic uses: these
# series are destined for the same Prometheus / Victoria Metrics clusters that
# scrape the IC, so matching the org's client keeps one exposition dialect in the
# estate. The `process` feature adds CPU / RSS / file-descriptor collectors on
# Linux, which is the deploy target.
prometheus = { version = "0.14", features = ["process"] }
sha2 = "0.11.0"
base64 = "0.22.1"
hex = "0.4.3"
crc32fast = "1"
regex = "1.12.4"
reqwest = { version = "0.13", default-features = false, features = ["rustls"] }
getrandom = "0.3.4"
urlencoding = "2.1.3"
url = "2"
# Only for the PocketIC-backed end-to-end test (src/e2e_handshake.rs), behind
# the `e2e` feature so the default build never compiles it. Client library for a
# local Internet Identity canister; version tracks the `pocket-ic` server binary.
pocket-ic = { version = "15", optional = true }

[features]
# Compiles + enables the real II<>MCP handshake test against a live Internet
# Identity canister in PocketIC (needs II_WASM + POCKET_IC_BIN at runtime; see
# src/e2e_handshake.rs). Off by default: the standard `cargo test` neither
# builds `pocket-ic` nor touches the network.
e2e = ["dep:pocket-ic"]

[dev-dependencies]
# Router-level contract tests (tests/routers.rs) drive the composed app with
# tower::ServiceExt::oneshot and read bodies via http-body-util.
tower = { version = "0.5", features = ["util"] }
http-body-util = "0.1"