AgenTrux MCP Server
AgenTrux runs a hosted MCP server. Point any MCP-spec-compliant client (Cursor / Claude Desktop / Claude / Cline …) at the URL below and connect directly — no plugin to install. You add one MCP Server URL to your client config and you are done.
You never paste a JWT or an activation code into the config. On first connect the client runs the OAuth flow, and from then on it refreshes the token automatically under the hood.
Endpoint
| Item | Value |
|---|---|
| MCP connection URL (for OAuth clients) | https://api.agentrux.com/mcp/c/<connection-id> (issued in the Console; 1 URL = 1 Script) |
| Default URL (headless) | https://api.agentrux.com/mcp (only for Bearer tokens obtained via client_credentials / device flow) |
| Transport | Streamable HTTP (POST / GET / DELETE) |
| MCP protocol version | 2025-06-18 (negotiated; see below) |
| Auth | OAuth 2.1 + PKCE (Bearer JWT) |
| Token audience (resource) | the connection URL itself (https://api.agentrux.com/mcp/c/<connection-id>) |
Client configuration
Do not put tokens or secrets in the config. On first connect the client runs the OAuth flow; afterwards it refreshes automatically.
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"agentrux": {
"url": "https://api.agentrux.com/mcp/c/your-connection-id",
"transport": "streamable-http"
}
}
}
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"agentrux": {
"url": "https://api.agentrux.com/mcp/c/your-connection-id",
"transport": "streamable-http"
}
}
}
One MCP Server entry maps to one connection context (Script). To switch between multiple Scripts, register separate entries (
"agentrux-A","agentrux-B"…); each gets its own permissions (scopes) in its token.
Connecting from Claude Code (CLI)
Claude Code has a dedicated guide: it connects with two commands, and with the channels feature new Topic events are pushed into an idle session so Claude reacts without polling. Channels needs its own setup, so the steps live on a separate page: Connect Claude Code to AgenTrux.
Authentication flow (discovery)
The MCP connection URL is protected by OAuth 2.1 and returns 401 Unauthorized to any
request without a token. The MCP client auto-discovers everything it
needs from that 401, following RFC 9728 (Protected Resource Metadata)
and RFC 8414 (Authorization Server Metadata).
1. POST /mcp/c/<connection-id> (no token)
◄─ 401 Unauthorized
WWW-Authenticate: Bearer realm="agentrux-mcp", resource_metadata="..."
2. GET /.well-known/oauth-protected-resource/mcp/c/<connection-id> ← RFC 9728 (per-connection)
◄─ { "resource": "https://api.agentrux.com/mcp/c/<connection-id>",
"authorization_servers": ["<issuer>"],
"scopes_supported": ["topic.read", "topic.write"],
"bearer_methods_supported": ["header"],
"resource_documentation": "https://api.agentrux.com/.well-known/agent-card.json" }
3. GET /.well-known/oauth-authorization-server ← RFC 8414
◄─ { "issuer", "authorization_endpoint", "token_endpoint",
"device_authorization_endpoint", "registration_endpoint",
"jwks_uri", "code_challenge_methods_supported": ["S256"], ... }
4. POST /oauth/register ← Dynamic Client Registration (RFC 7591)
◄─ { "client_id", ... } (public client, token_endpoint_auth_method="none")
5. User authentication (authorization code + PKCE, or device flow):
open browser to /oauth/authorize → user clicks Allow → POST /oauth/token
(or device flow: POST /oauth/device/authorize → approve in browser → POST /oauth/token)
◄─ access_token (Bearer JWT)
6. POST /mcp/c/<connection-id> (Authorization: Bearer <access_token>)
◄─ 200 OK
Key points:
- Public client + PKCE: the MCP client holds no secret.
POST /oauth/registeronly acceptstoken_endpoint_auth_method="none", and accepts loopback redirect URIs (http://localhost:PORT,http://127.0.0.1:PORT) per RFC 8252. - Token audience: the issued access token targets the connection URL itself
(
https://api.agentrux.com/mcp/c/<connection-id>); it is not valid for other connections or the default/mcp. - A human approves: the browser opens the AgenTrux approval screen and a person approves the access. The MCP client never establishes permissions unattended.
- Path-based preferred: clients prefer
/.well-known/oauth-protected-resource/mcp/c/<connection-id>(per-connection); the generic/.well-known/oauth-protected-resourceis a fallback (RFC 9728 §3.1). Note that the default/mcpendpoint does not offer OAuth discovery; it only accepts Bearer tokens obtained via client_credentials or the device flow.
Protocol version negotiation
On initialize, the server echoes the client's requested
protocolVersion when it is one it supports, otherwise it returns its
latest supported version, 2025-06-18. That latest version matches the
MCP interface version advertised in the A2A Agent Card, so the
initialize response and the published card never disagree.
Available tools
After connecting, tools/list enumerates the tools below; invoke them
with tools/call.
| Tool | Purpose | Required scope | Main args |
|---|---|---|---|
publish_event |
Publish an inline JSON event (≤256 KiB) to a Topic | topic.write |
topic_id (required), payload, event_type, metadata, idempotency_key |
read_events |
Read events from a Topic with cursor pagination | topic.read |
topic_id (required), order (asc/desc, default asc), after, before, limit (1–1000, default 50), event_type |
get_event |
Fetch a single event by event_id |
topic.read |
topic_id (required), event_id (required) |
list_topics |
List Topics accessible to the connected workspace | — | (none) |
list_grants |
List Grants (Topic permissions) for the connected Script | — | (none) |
request_payload_upload |
Get a presigned S3 PUT URL to upload a large file (>256 KiB) as a Topic payload object. Compute checksum_sha256, PUT the bytes to the returned presigned_put_url with required_headers, then call publish_event with the returned payload_object_id (pob_...). Bytes go straight to S3, so there is no body-size limit. |
topic.write |
topic_id (required), size_bytes (required), checksum_sha256 (required), content_type |
request_payload_download |
Get a presigned S3 GET URL to download a committed large payload object by its payload_object_id (pob_...), e.g. one returned by read_events/get_event. GET the returned presigned_get_url to fetch the bytes directly from S3. |
topic.read |
topic_id (required), payload_object_id (required) |
read_events returns next_cursor (asc), next_before_cursor (desc) and
frontier_cursor; use order='desc' for the most recent messages first,
and pass frontier_cursor as after on later calls to poll only for new
messages. after and before are mutually exclusive.
request_payload_upload returns payload_object_id (pob_...),
presigned_put_url, presigned_expires_at, max_size_bytes and
required_headers. request_payload_download returns presigned_get_url,
presigned_expires_at, size_bytes, content_type and checksum_sha256.
IDs are passed with prefixes: Topic = top_<uuid>, Event = evt_<uuid>,
Payload object = pob_<uuid>, idempotency key = idk_<...>.
tools/call example
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "publish_event",
"arguments": {
"topic_id": "top_01234567-89ab-cdef-0123-456789abcdef",
"event_type": "note.created",
"payload": { "text": "hello from MCP" }
}
}
}
Success response (result.content):
{ "event_id": "evt_...", "next_read_cursor": "..." }
Sessions and notifications
- On a successful
initialize, the server issues anMcp-Session-Id. Send this header on every subsequent request. GET /mcp(long-lived, Server-Sent Events) delivers server → client notifications. On reconnect,Last-Event-IDbackfills anything missed.DELETE /mcpends the session.
Error handling
The MCP transport is JSON-RPC 2.0.
- Auth errors are returned as HTTP status codes: a missing/invalid
token is
401, a missing/mismatched session is404, and a missingMcp-Session-Idheader is400. These are not wrapped in the JSON-RPC envelope; on a401the client should refresh the token or re-authenticate. - Business errors come back in the
tools/callresponse aserror.code = -32603with anerror.data:
{
"jsonrpc": "2.0",
"id": 7,
"error": {
"code": -32603,
"message": "tool execution failed",
"data": { "http_status": 403, "code": "FORBIDDEN", "detail": "insufficient_scope" }
}
}
data.code is one of FORBIDDEN / NOT_FOUND / INVALID / CONFLICT /
RATE_LIMITED etc., and data.http_status carries the corresponding
HTTP status.
- Quota / billing errors (
402) are a distinct error class your client must handle. When the account exhausts its credit or its monthly egress allowance, the tool returns a JSON-RPC error (stillerror.code = -32603, HTTP 200) whosedatacarrieshttp_status: 402andcode: "PAYMENT_REQUIRED".publish_eventreports the credit case withmetricplusrequired_units/available_units; the read tools (read_events,get_event,request_payload_download) report egress exhaustion withmetric: "egress_bytes"pluscurrent_bytes/limit_bytes. Both includenext_action: "top_up_or_upgrade". Treat a402as a signal to top up or upgrade rather than retry.
{
"jsonrpc": "2.0",
"id": 7,
"error": {
"code": -32603,
"message": "monthly egress limit exceeded",
"data": {
"http_status": 402,
"code": "PAYMENT_REQUIRED",
"metric": "egress_bytes",
"current_bytes": 10737418240,
"limit_bytes": 10737418240,
"next_action": "top_up_or_upgrade"
}
}
}
Related links
- Authorization Server Metadata:
https://api.agentrux.com/.well-known/oauth-authorization-server - Protected Resource Metadata (MCP):
https://api.agentrux.com/.well-known/oauth-protected-resource/mcp/c/<connection-id> - A2A Agent Card:
https://api.agentrux.com/.well-known/agent-card.json(A2A doc) - Documentation:
https://docs.agentrux.com