SDK reference
The ctx object every Glxymesh function tool receives, in Go, TypeScript and Python, for outbound HTTP, key placeholders, logs, the caller, the deadline and errors.
Every function tool receives a ctx. It’s the same in each language, shaped the way that language
does things.
| Language | Package |
|---|---|
| Go | glxymesh.com/sdk/glxy |
| TypeScript | @glxymesh/sdk |
| Python | glxymesh |
gxmesh init sets the SDK up for you. A Go project’s go.mod requires glxymesh.com/sdk, and a TypeScript project’s
package.json depends on @glxymesh/sdk; run npm install (or pnpm install) once for your editor and local runs.
A Python project gets a copy in .glxy/ until the SDK is on PyPI. However you install it, the platform links its own
matching copy when it builds, so a tool always runs against the SDK Glxymesh expects.
The SDKs are open source under Apache-2.0 at github.com/glxymesh/sdk, one folder
per language: go get glxymesh.com/sdk (reference) and
npm install @glxymesh/sdk (package).
The entry point
Section titled “The entry point”import type { Ctx } from '@glxymesh/sdk';import type { Input } from './tool.gen';
export async function run(ctx: Ctx, input: Input) { ... }Input is generated in tool.gen.ts, with the input names from tool.yml. Return anything JSON
can hold.
package toolname
import "glxymesh.com/sdk/glxy"
func Run(ctx *glxy.Ctx, in Input) (any, error) { ... }Input is generated in input_gen.go: thread_id becomes the field ThreadId. The package is
the tool’s name without hyphens. *glxy.Ctx is also a context.Context that ends at the call’s
deadline. Return anything encoding/json can marshal.
from glxymesh import Ctxfrom .tool_gen import Input
def run(ctx: Ctx, input: Input) -> dict: ...Input is a TypedDict generated in tool_gen.py, so read inputs as input["thread_id"].
async def run works too. Return anything json.dumps can write. Code shared between tools goes
in lib/, with a lib/__init__.py, and is imported as lib.<module>.
| TypeScript | Go | Python | |
|---|---|---|---|
| HTTP | ctx.fetch(url, init), the standard fetch |
ctx.HTTP() returns an *http.Client |
ctx.fetch(url, method=, params=, headers=, json=, data=) |
| Key placeholder | secret('NAME'), imported from the SDK |
glxy.Secret("NAME") |
secret("NAME"), from glxymesh |
| Logs | ctx.log.info/warn/error(message) |
ctx.Log().Info/Warn/Error(format, args...) |
ctx.log.info/warn/error(message) |
| Caller | ctx.caller |
ctx.Caller |
ctx.caller |
| Deadline | ctx.signal aborts at it; ctx.remaining() is milliseconds left |
ctx is a context.Context; ctx.Remaining() is a time.Duration |
ctx.remaining() is seconds left; a request gives up at the deadline |
| Error for the model | throw new ToolError(message) |
return nil, glxy.Errorf(format, args...) |
raise ToolError(message) |
| TCP connection | await ctx.connect('host:port'), a socket; await ctx.forward('host:port'), a local address |
ctx.DialContext(ctx, "tcp", "host:port"), a dial hook; ctx.Forward("host:port") |
ctx.connect("host:port"), a socket; ctx.forward("host:port"), a local address |
| Passed-in key | await ctx.secretValue('NAME') |
ctx.SecretValue("NAME") |
ctx.secret_value("NAME") |
In Python, ctx.fetch returns a response with .status, .headers (lowercase names), .content,
.text, .json() and .raise_for_status(), which raises a ToolError naming the status unless
it is 2xx.
Every request goes through the egress gateway, which checks the host against network.allow, adds
the tool’s keys on their bound hosts, and records the request. A request to a host the tool may not
reach fails with an error that names the host: an EgressError in TypeScript and Python, and an
error from Do or Get in Go.
Pass the platform’s client to SDKs that accept one:
import { Octokit } from '@octokit/rest';const gh = new Octokit({ request: { fetch: ctx.fetch } });gh := github.NewClient(ctx.HTTP())In Python, make requests with ctx.fetch. Libraries like requests and httpx open their own
connections, so they can’t reach the internet from a deployed tool.
An SDK that opens its own connections can’t reach the internet from a deployed tool.
Key placeholders
Section titled “Key placeholders”secret('NAME') returns a placeholder, not the key. Put it where the API expects the key, such as a
JSON body, and the egress gateway swaps in the value on the key’s bound hosts only. Keys with a
header or query in tool.yml need no placeholder. See
Keys and network access.
Log lines ride back with the call’s result. They appear in gxmesh call and gxmesh test, and in the
console’s Mesh Builder when you try a call. Up to 64 KB per call is kept; past that, lines are dropped and
the result says so.
Caller
Section titled “Caller”Who the call is for: org, project, userId, and clientId, the MCP client the person allowed,
such as Claude or Cursor. In Go they’re Org, Project, UserID and ClientID; in Python,
org, project, user_id and client_id. Never an email address or a token.
Errors
Section titled “Errors”Return a tool error for anything the model can act on: a missing record, a bad argument, a rate limit. The model reads the message, so write it as advice. Any other error or exception is treated as a bug: the model gets a fixed sentence and you get the details.
Nothing survives between calls: don’t keep state in global variables. Key/value storage for
function tools isn’t available yet.