gno-mcp

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: Apache-2.0

README

gnomcp

MCP server + agent skill for gno.land.

gnomcp exposes gno.land as a Model Context Protocol server: read realms, evaluate expressions, inspect accounts, manage testnet keys, simulate and broadcast transactions — from any MCP-aware client (Claude Code, Claude Desktop, Cursor, Gemini CLI, OpenCode, …). The repo also ships a gno skill that teaches coding agents the language, the security taxonomy, and how to drive the tools.


[!WARNING] Work in progress. Unaudited. Pre-release.

  • No security review. The threat model is written down (docs/security.md) but no third party has audited the code, the tool descriptions, or the skill.
  • API surface is unstable. Tool names, argument shapes, and error codes may change between pre-release tags.
  • Testnet and local dev only — by construction. Only dev and testNN chain-ids pass config validation; mainnet ids are rejected outright and there is no flag to bypass that.
  • Sessions are WIP. The session-signed write path (gno_session_proposeidentity=session) works end-to-end but is young and will be reworked — use with caution and tight scopes.
  • No upgrade path guaranteed. Config schema, session-file format, and audit-log shape may move.

Use it on testnet. Read the security doc. File issues when something looks off.


Why this exists

LLMs are starting to drive real on-chain actions, and the bridge between an LLM and a live chain is where things go wrong: leaked seeds, prompt-injected realm output, transactions signed on the wrong network. MCP solves the "how does the model call a tool" half; the "how is the tool bounded and how does the model stay on rails" half is per-domain.

gnomcp is that bridge for gno.land, shipped as two coupled artifacts:

  1. An MCP server — 20 tools under a single security spine: untrusted-content envelopes on every chain-derived byte, a chain-id allowlist that keeps mainnet out entirely, output budgeting, an append-only audit log, and user keys that never leave gnokey.
  2. A gno skill — the knowledge layer for coding agents: interrealm semantics, security taxonomy, idiomatic patterns, Render() conventions, stdlib surface, project setup. Skill and server are independent but complementary (skill = knowledge, server = on-chain tools).

Zero-config testnet

gnomcp ships pointed at the public testnet — no configuration needed:

Profile Chain-id RPC
testnet test11 https://rpc.test11.testnets.gno.land:443
local dev http://127.0.0.1:26657 (local gnodev node — see note)

The six chain read tools (gno_render, gno_eval, gno_read, gno_packages, gno_account, gno_status) and the gno_connect discovery tool work immediately against these profiles — no config file needed. The write tools register out of the box as well: generate an agent key once (gno_key_generate), fund it (gno_faucet_fund), and the agent can write.

[!NOTE] For local development with gnodev, the built-in local profile auto-discovers a node on 127.0.0.1:26657 and signs with the pre-funded test1 key — zero setup, instant writes.

Install

go install github.com/gnoverse/gno-mcp/cmd/gnomcp@latest

Then point your MCP client at the binary:

{
  "mcpServers": {
    "gnomcp": { "command": "gnomcp", "args": [] }
  }
}

For in-repo development the .mcp.json at the repo root uses go run ./cmd/gnomcp instead.

Profiles

Profiles are the source of truth for which chains gnomcp can reach. The built-in local and testnet are read-only defaults. Only dev and testNN chain-ids are accepted — betanet, staging, and mainnet ids cannot enter a profile.

# From a gnoweb URL (autofills rpc + chain-id from the page's gnoconnect meta-tags)
gnomcp profile add mychain --from-gnoweb https://mychain.testnets.gno.land

# Manual
gnomcp profile add mychain --rpc https://rpc.mychain.gno.land:443 --chain-id test99

# With master address to enable session writes
gnomcp profile add mychain --from-gnoweb https://mychain.testnets.gno.land \
  --master g1youraddresshere

gnomcp profile list
gnomcp profile remove mychain

Profiles are written to ~/.config/gnomcp/profiles.toml. A project-local ./profiles.toml overlays the global file; the -config flag overrides both.

Config precedence: built-in defaults < ~/.config/gnomcp/profiles.toml < ./profiles.toml < -config flag.

A profile entry in a config file is a whole-profile replacement — an overlay redefining a built-in must re-supply rpc-url and chain-id, not just master-address.

Profile fields (profiles.toml)
[mychain]
rpc-url              = "https://rpc.test99.testnets.gno.land:443"
chain-id             = "test99"
master-address       = "g1..."       # enables session writes — the agent acting as this user (bech32)
tx-indexer-url       = "..."         # optional; enables gno_list/gno_history/gno_activity
default-spend-limit  = "100000ugnot" # optional; per-session default
default-expires-in   = "1h"          # optional; Go duration string
faucet-url           = "..."         # optional; faucet page gno_faucet_fund links the user to
faucet-service-url   = "..."         # optional; automatic faucet service gno_faucet_fund calls

Write authorization

Writes are signed by one of two identities, chosen per call via the identity arg:

  • Agent identity (default). Testnet profiles sign with a per-profile key: run gno_key_generate once, then fund it (gno_faucet_fund or send it ugnot). Local (gnodev) profiles sign with the built-in test1 key — no setup.
  • Session (WIP) — the agent acts as the user (requires master-address). Call gno_session_propose to get a paste-ready gnokey maketx session create command; run it to authorize a chain-bound session with explicit scope (allow_paths, allow_run, spend_limit, expires_in). Pass identity=session to force this path on any profile.

[!WARNING] The session path is functional end-to-end but WIP and will be reworked. Use with caution: authorize with tight allow_paths, a low spend_limit, and a short expires_in — and revoke (gno_session_revoke) when you're done.

# Typical session flow
gno_session_propose(profile="mychain", allow_paths=["gno.land/r/myorg/blog"])
# → prints gnokey command; user runs it
gno_call(profile="mychain", realm="gno.land/r/myorg/blog", func="AddPost", identity="session", ...)

Every write result names the identity that signed it.

Session key files are stored in ~/.local/share/gnomcp/sessions (mode 0600). Set GNOMCP_SESSION_PASSPHRASE to enable encryption at rest.

Tools

See docs/tools.md for the full catalog. Summary (20 tools):

Tool Category Registered when
gno_render chain read always
gno_eval chain read always
gno_read chain read always
gno_packages chain read always
gno_account chain read always
gno_status chain read always
gno_connect discovery always
gno_profile_add admin always (in-memory profile, gone on restart)
gno_list indexer read a profile has tx-indexer-url
gno_history indexer read a profile has tx-indexer-url
gno_activity indexer read a profile has tx-indexer-url
gno_call write always (agent key or active session)
gno_run write always (agent key or active session)
gno_session_propose session always (needs master-address to succeed)
gno_session_revoke session always (needs master-address to succeed)
gno_auth_status session always
gno_addpkg write always
gno_key_address agent key always
gno_key_generate agent key always
gno_faucet_fund agent key a testnet profile exists

Gated tools appear mid-session when gno_profile_add flips their gate (the server sends tools/list_changed). Dynamic profiles are in-memory, testnet/dev only, and carry no master-address — reads and agent-key writes work, sessions require a profile persisted in profiles.toml.

Security posture

  • User keys never leave gnokey. Sessions are authorized by the user running a printed gnokey command on their own machine; gnomcp never sees a mnemonic and never asks for one.
  • Mainnet cannot enter the config. The chain-id allowlist (dev, testNN) is enforced at validation time — there is no confirm flag to get past it, because there is nothing to confirm against.
  • Untrusted-content envelope on every chain byte. Tool output derived from the chain is wrapped in <untrusted_content kind="…" source="…"> with embedded-tag neutralization, so the LLM treats it as data, not instructions.
  • Output budgeting. Read tools cap inline output and summarize overflows instead of returning chopped halves.
  • Audit log on every write. JSON-lines, append-only, mode 0600; records the tool, profile, result, and signing identity (agent vs session address). Operator-facing — not queryable through MCP.
  • Structured errors. Failures carry a machine-routable code (insufficient_funds, authentication_required, scope_mismatch, …) plus a recovery hint, so agents fail forward instead of guessing.

See docs/security.md for the full posture.

Skill installation (for AI coding agents)

The repo bundles the gno skill (knowledge + routing, at skills/gno/) plus three thin side skills — gno-audit, gno-debug, gno-onboard — that compose its reference library into explicit workflows. Everything installs as one plugin for the major coding-agent harnesses:

Agent Install
Claude Code /plugin marketplace add gnoverse/gno-mcp then /plugin install gnomcp
Codex CLI Install via Codex's plugin flow pointing at .codex-plugin/plugin.json in this repo
Cursor Install via Cursor's plugin flow; reads .cursor-plugin/plugin.json
Gemini CLI gemini extensions install https://github.com/gnoverse/gno-mcp
OpenCode Add "gnomcp@git+https://github.com/gnoverse/gno-mcp.git" to your opencode.json plugin array. See .opencode/INSTALL.md.

[!NOTE] The skill's content is currently hand-distilled from the gnolang/gno monorepo, so it can drift as the language evolves. The goal is a single source of truth — the monorepo as the sole reference — with the skill reduced to a thin wrapper that adds routing, guidance, and best practice on top of monorepo knowledge, never a fork of it.

Authoring conventions live in docs/skills.md.

Development

make test                # Unit tests (no network)
make test-integration    # In-process node + live tests (build tag: integration)
make lint                # go vet + gofmt -l
make build               # bin/gnomcp
make dev                 # go run ./cmd/gnomcp (starts MCP server)

Built against the official MCP Go SDK (github.com/modelcontextprotocol/go-sdk) and github.com/gnolang/gno/gno.land/pkg/gnoclient for chain RPC. Testing: see test/README.md for the four test layers (unit / integration / agent e2e / manual).

Roadmap

  • More side skills driving the tools through common workflows: onboarding, explicit audits, debugging a failed tx
  • Docker as the canonical deployment
  • a2a serve mode (agent-to-agent realm bridge)
  • External security audit before any "stable" claim

License

Apache-2.0. See LICENSE.

Directories

Path Synopsis
cmd
agentfaucet command
gnomcp command
Command gnomcp is the Gno Model Context Protocol server.
Command gnomcp is the Gno Model Context Protocol server.
Package faucet is a standalone automatic testnet faucet service.
Package faucet is a standalone automatic testnet faucet service.
internal
audit
Package audit writes JSON-lines audit records of MCP tool invocations.
Package audit writes JSON-lines audit records of MCP tool invocations.
chain
Package chain abstracts access to a gno chain via the Client interface: reads (render, eval, doc, file, paths, balance, session query) and writes — Call, Run, and AddPackage signed by the agent directly, plus CallAsUser/RunAsUser signed through a user-authorized session.
Package chain abstracts access to a gno chain via the Client interface: reads (render, eval, doc, file, paths, balance, session query) and writes — Call, Run, and AddPackage signed by the agent directly, plus CallAsUser/RunAsUser signed through a user-authorized session.
clientfaucet
Package clientfaucet selects and drives a per-profile funding backend for the agent's testnet key: a ServiceFaucet (automatic service), a LinkFaucet (an existing human faucet page), or the manual fallback (LinkFaucet with no URL).
Package clientfaucet selects and drives a per-profile funding backend for the agent's testnet key: a ServiceFaucet (automatic service), a LinkFaucet (an existing human faucet page), or the manual fallback (LinkFaucet with no URL).
fsutil
Package fsutil provides crash-safe atomic file writes for sensitive on-disk state (keys, sessions, config).
Package fsutil provides crash-safe atomic file writes for sensitive on-disk state (keys, sessions, config).
gnosrc
Package gnosrc renders structural views of Gno package source: a navigation outline (signatures + docs, bodies elided) and verbatim extraction of named declarations with a best-effort dependency header.
Package gnosrc renders structural views of Gno package source: a navigation outline (signatures + docs, bodies elided) and verbatim extraction of named declarations with a best-effort dependency header.
gnoweb
Package gnoweb discovers a gno chain's connection info from a gnoweb page's gnoconnect:* meta-tags.
Package gnoweb discovers a gno chain's connection info from a gnoweb page's gnoconnect:* meta-tags.
indexer
Package indexer abstracts read-only access to tx-indexer GraphQL queries.
Package indexer abstracts read-only access to tx-indexer GraphQL queries.
keystore
Package keystore provides gnomcp's own agent write identity for dev/test chains.
Package keystore provides gnomcp's own agent write identity for dev/test chains.
profiles
Package profiles parses and represents the multi-chain profile configuration that drives gnomcp's connections to gno chains.
Package profiles parses and represents the multi-chain profile configuration that drives gnomcp's connections to gno chains.
server
Package server wires the MCP server scaffolding, tool Registry, and profile-conditional schema.
Package server wires the MCP server scaffolding, tool Registry, and profile-conditional schema.
session
Package session manages gnomcp's chain-bounded session keys: ed25519 generation, scrypt+AES-GCM disk persistence, 4-layer scope policy, and per-pubkey chain verification.
Package session manages gnomcp's chain-bounded session keys: ed25519 generation, scrypt+AES-GCM disk persistence, 4-layer scope policy, and per-pubkey chain verification.
tools/admin
Package admin holds server-administration tools: tools that change gnomcp's own runtime state rather than reading or writing a chain.
Package admin holds server-administration tools: tools that change gnomcp's own runtime state rather than reading or writing a chain.
tools/indexer
Package indexer holds the tx-indexer-backed MCP tools (gno_list, gno_history, gno_activity).
Package indexer holds the tx-indexer-backed MCP tools (gno_list, gno_history, gno_activity).
tools/read
Package read holds the chain read MCP tools (gno_render, gno_eval, gno_read, gno_packages, gno_account, gno_status, gno_connect).
Package read holds the chain read MCP tools (gno_render, gno_eval, gno_read, gno_packages, gno_account, gno_status, gno_connect).
tools/write
Package write holds the chain-write and write-prep MCP tools: gno_call, gno_run, gno_addpkg (transactions); gno_faucet_fund, gno_key_generate, gno_key_address (agent key lifecycle); and gno_session_propose, gno_auth_status, gno_session_revoke (session lifecycle).
Package write holds the chain-write and write-prep MCP tools: gno_call, gno_run, gno_addpkg (transactions); gno_faucet_fund, gno_key_generate, gno_key_address (agent key lifecycle); and gno_session_propose, gno_auth_status, gno_session_revoke (session lifecycle).
untrusted
Package untrusted wraps chain-derived bytes in an envelope that marks them as data, never instructions, for an LLM consuming a tool result.
Package untrusted wraps chain-derived bytes in an envelope that marks them as data, never instructions, for an LLM consuming a tool result.
playground
e2e/cmd/gnoquery command
Command gnoquery is the e2e harness's chain ground-truth oracle: it reads on-chain state directly via gnoclient (the same pinned library gnomcp wraps, but called below gnomcp's tool layer, so it's an independent check).
Command gnoquery is the e2e harness's chain ground-truth oracle: it reads on-chain state directly via gnoclient (the same pinned library gnomcp wraps, but called below gnomcp's tool layer, so it's an independent check).
e2e/simnet command
Command simnet runs a simulated testnet for the playground e2e harness: a real in-memory gnoland node (BFT + mempool + tm2 RPC) genesis-seeded with the e2e test realms, plus a faucet and a gnoweb front.
Command simnet runs a simulated testnet for the playground e2e harness: a real in-memory gnoland node (BFT + mempool + tm2 RPC) genesis-seeded with the e2e test realms, plus a faucet and a gnoweb front.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL