Skip to main content
Glama
GreenNodeHub

greennode-agentbase-mcp

Official
by GreenNodeHub

greennode-agentbase-mcp

An MCP server that exposes the GreenNode AgentBase REST APIs as 3 searchable meta-tools — a search→execute gateway that cuts the MCP tool-definition tax ~95%+ versus flattening every operation into its own tool. Runs locally over stdio (default) or remotely over streamable HTTP, with any MCP-speaking client.

Table of contents

Related MCP server: daimonos

Quick start

Connect a local MCP client (Claude Code, Cursor, Windsurf, …) to the gateway over stdio in under a minute.

Prerequisites

  • Node.js ≥ 20 (see package.json engines)

  • A GreenNode AgentBase bearer token — one token is valid across all six services

1. Install

git clone https://github.com/GreenNodeHub/greennode-agentbase-mcp.git
cd greennode-agentbase-mcp
npm ci

2. Run (stdio is the default transport — no need to set TRANSPORT)

GREENNODE_MCP_TOKEN=<your-token> npm start

3. Wire up your client. Claude Code — .mcp.json:

{
  "mcpServers": {
    "agentbase": {
      "command": "npx",
      "args": ["tsx", "src/index.ts"],
      "env": { "GREENNODE_MCP_TOKEN": "<your-token>" }
    }
  }
}

For Cursor, Windsurf, Cline, Roo Code, Claude Desktop, and other clients, see docs/mcp-client-quickstart.html — same command + env, each client's own config key.

Optional — auto-rotating token (external). If you have the agentbase skill installed (it ships .claude/skills/agentbase/scripts/get_token.sh, which is not part of this repo) plus GREENNODE_CLIENT_ID / GREENNODE_CLIENT_SECRET (or a .greennode.json), point your client at scripts/mcp-launch.sh instead. It mints a fresh ~30-minute IAM JWT on every (re)start, so reconnecting rotates the token automatically — no manual re-export, no stale-token 401s.

First call flow: list_serverssearch_toolsexecute (see How it works).

How it works

Instead of exposing 100+ operations as individual MCP tools (a large manifest the model pays for every turn), the server exposes 3 meta-tools. The full operation set lives in a generated registry the model searches on demand.

┌───────────────────────────────────────────────────────────────┐
│  Generated layer  (from specs, committed, never hand-edited)  │
│    registry.generated.json                                    │
│      every operation: { id, service, method, path,            │
│                         summary, tags, inputSchema, … }       │
└───────────────────────────────────────────────────────────────┘
                          ▲ consumed by
┌───────────────────────────────────────────────────────────────┐
│  Meta layer  (hand-written TypeScript)                        │
│    • 3 meta-tools: list_servers, search_tools, execute        │
│    • BM25 search engine                                       │
│    • JMESPath field projection + response byte cap            │
│    • inbound auth + downstream token pass-through             │
│    • env resolver (base URLs, transport, limits)              │
└───────────────────────────────────────────────────────────────┘

Meta-tools

Tool

Args

Returns

list_servers

the services, each with its operation count + tags

search_tools

query, server?, limit?

BM25-ranked operations, each with its full inputSchema inline

execute

id, args?, fields?

the real HTTP response, projected by fields and byte-capped

Discovery is two steps: search_tools returns enough to call execute directly (the input schema is inline), so there's no separate describe step.

// 1) orient on the six services
list_servers()
// → [{ "name": "policy", "description": "policy service (… operations)", "operationCount": …, "tags": […] }, …]

// 2) search by intent — the id and full inputSchema come back together
search_tools({ query: "list policy groups" })
// → [{ "id": "policy.get_api_v1_policy_groups", "service": "policy",
//      "summary": "List policy groups", "inputSchema": { "type": "object",
//      "properties": { "page": {…}, "page_size": {…}, "name": {…} } } }, …]

// 3) execute; `fields` is an optional JMESPath projection to shrink the response
execute({ id: "policy.get_api_v1_policy_groups", args: { page: 1, page_size: 10 } })
// → the live response (omit `fields` to see the whole body; pass e.g. fields:"items[].name" to project it)

Operation ids look like service.<method>_<slugified-path> (e.g. policy.get_api_v1_policy_groups). Always take an id from search_tools — never type one by hand.

Why meta-tools: 3 tool definitions (~1–2K resident tokens) instead of one tool per operation. See benchmarks/report-2026-07-06.md for the token math — a 36.8× smaller manifest and 7–41% fewer input tokens end-to-end versus the flat (one-tool-per-op) variant.

Transports: stdio vs. streamable HTTP

stdio

streamable HTTP

Use case

local, any MCP client

deployed runtime / remote clients

Default

yes (TRANSPORT=stdio)

opt-in (TRANSPORT=http)

Lifecycle

one server for the process lifetime

fresh server + transport per request (stateless)

Token source

env var named by TOKEN_ENV (default GREENNODE_MCP_TOKEN)

Authorization: Bearer header, per request

Endpoint

stdin/stdout (JSON-RPC)

POST /mcp

Health

GET /healthz, GET /health

stdio (default)

The server reads JSON-RPC from stdin and writes responses to stdout. stdout is the protocol — all diagnostics and the one-line startup banner go to stderr, so they never corrupt the stream.

GREENNODE_MCP_TOKEN=<your-token> npm start   # TRANSPORT=stdio is the default

The token is read once at startup from the env var named by TOKEN_ENV (default GREENNODE_MCP_TOKEN). The server runs for the process lifetime and exits when the client closes stdin. See Quick start for the client-wiring snippet.

Streamable HTTP

For a deployed runtime or remote clients. Each POST /mcp builds a fresh server + StreamableHTTPServerTransport for that request (stateless) and authenticates from the Authorization header. The token is not read from the environment in this mode.

TRANSPORT=http npm start   # listens on :8080 (PORT); pass the token per request, not via env

Smoke-test it:

curl http://localhost:8080/healthz          # → {"ok":true}

# a raw initialize request to /mcp (clients normally build this JSON-RPC envelope for you)
curl -X POST http://localhost:8080/mcp \
  -H "Authorization: Bearer <your-token>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

Configuration

All config is via environment variables, read once at startup by loadEnvConfig (src/config/env.ts).

Var

Default

Notes

TRANSPORT

stdio

stdio or http. Any other value throws at boot — the process exits non-zero, nothing listens.

GREENNODE_MCP_TOKEN

Upstream bearer token, stdio only. Forwarded to all six services on execute.

TOKEN_ENV

GREENNODE_MCP_TOKEN

Name of the env var that holds the token, stdio only. Set this to read the token from a differently-named var.

PORT

8080

HTTP transport listen port.

MAX_RESPONSE_BYTES

25000

Hard cap on execute responses; over-cap responses are truncated with a notice.

SEARCH_LIMIT_DEFAULT

5

Default limit for search_tools when the caller omits it.

In streamable HTTP mode the token is not read from env at all — clients supply it per request via Authorization: Bearer. GREENNODE_MCP_TOKEN / TOKEN_ENV apply only to stdio.

Development & operations

Scripts (package.json):

Script

What it does

npm start

Run the server (tsx src/index.ts)

npm run dev

Run with reload (tsx watch src/index.ts)

npm run build

Typecheck only (tsc --noEmit). There is no compiled dist/ — the runnable form is tsx.

npm test / npm run test:watch

Vitest

npm run fetch-specs

Refresh specs/ from the AgentBase spec endpoints

npm run generate-registry

Rebuild registry.generated.json from specs/

Regenerate the registry when the upstream specs change:

npm run fetch-specs && npm run generate-registry

Then commit both specs/ and registry.generated.json. Both are generated — never hand-edit them.

Docker:

docker build -t greennode-agentbase-mcp .
docker run -e TRANSPORT=http -p 8080:8080 greennode-agentbase-mcp

The bearer token is supplied per request via the Authorization header (same as HTTP mode) — not via env.

⚠️ TRANSPORT defaults to stdio. A deployed HTTP runtime — and the shipped Dockerfile (which sets PORT but not TRANSPORT) — must set TRANSPORT=http explicitly. Without it the process starts in stdio mode and listens on no port. The docker run command above passes -e TRANSPORT=http; for a production image, bake ENV TRANSPORT=http into the Dockerfile.

Further reading

License

See LICENSE.

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    Not graded
    maintenance
    A high-performance Go-based MCP server that provides a microservice architecture for orchestrating diverse tools through gRPC and HTTP/REST APIs. Enables seamless integration of language-agnostic tools including ML capabilities, web search, calculations, and human interaction for intelligent agent workflows.
    2
  • A
    license
    B
    quality
    A
    maintenance
    Agent-optimized MCP server that replaces built-in file, search, exec, and git tools with compact, structured JSON equivalents. Benchmarked 20–45% token savings for AI coding agents.
    20
    2
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    A model-agnostic MCP server exposing example tools (add1, multiply2, greet) for learning purposes, working with any LLM through stdio transport.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GreenNodeHub/greennode-agentbase-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server