@truealter/sdk
v0.4.1
Published
ALTER Identity SDK — query the continuous identity field from any JavaScript/TypeScript environment
Maintainers
Readme
@truealter/sdk
ALTER Identity SDK — query the continuous identity field from any JavaScript/TypeScript environment.
A thin client over the ALTER MCP server (Streamable HTTP, JSON-RPC 2.0, MCP spec 2025-11-25) with x402 micropayment support, ES256 provenance verification, and config generators for Claude Code, Cursor, and generic MCP clients.
- Branded host:
https://mcp.truealter.com(serves.well-known/mcp.jsonfor discovery) - JSON-RPC wire endpoint:
https://mcp.truealter.com/api/v1/mcp— this is what Streamable HTTP POSTs target (the SDK default) - Wire protocol: Streamable HTTP, JSON-RPC 2.0, MCP
2025-11-25(server negotiates2025-06-18+2025-03-26for backwards-compatible clients) - Tools: 32 typed and wired — 24 free (L0) + 8 premium (L1–L5). Mirrors the live server's
tools/listresponse byte-for-byte; every name inFREE_TOOL_NAMES/PREMIUM_TOOL_NAMEShas a matching server handler atmcp.truealter.com/api/v1/mcp. - Runtime: Node 18+, Deno, Bun, Cloudflare Workers, modern browsers
- Crypto:
@noble/ed25519+@noble/hashes(no other dependencies) - Bundle: ESM + CJS dual output
Quickstart
npm install @truealter/sdk
npx alter-identity init
npx alter-identity verify ~truealterWhy ALTER ≠ IAM
Identity Access Management answers who is logged in. ALTER answers who they actually are — a continuous field of recognition that any IAM stack can sit on top of.
API
Initialise the client
import { AlterClient, X402Client } from "@truealter/sdk";
const alter = new AlterClient({
endpoint: "https://mcp.truealter.com/api/v1/mcp", // optional — this is the default; bare host returns 405
apiKey: process.env.ALTER_API_KEY, // optional for free tier
x402: new X402Client({ // optional — only required for premium tools
signer: yourViemOrEthersSigner,
maxPerQuery: "0.10",
}),
});Free tier (L0 — no payment required)
// Verify a registered identity by handle, email, or id
const verified = await alter.verify("~truealter");
const verifiedById = await alter.verify(
"550e8400-e29b-41d4-a716-446655440000",
{
archetype: "weaver",
min_engagement_level: 3,
traits: { pressure_response: { min: 0.6 } },
},
);
// Reference data — the 12 ALTER archetypes
const archetypes = await alter.listArchetypes();
// Identity depth and available tool tiers
const depth = await alter.getEngagementLevel({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
});
// Search by trait criteria — no PII exposed, max 5 results
const matches = await alter.searchIdentities({
trait_criteria: {
pressure_response: { min: 0.7 },
cognitive_flexibility: { min: 0.6 },
},
});
// Golden Thread program status
const thread = await alter.goldenThreadStatus();Premium tier (L1–L5 — x402 payment required)
// L1 — Extract trait signals from text ($0.005, first 100 free per bot)
const signals = await alter.assessTraits({
text: "I led the incident response when our payment rails went down...",
context: "interview transcript",
});
// L2 — Full 33-trait vector ($0.01)
const vector = await alter.getFullTraitVector({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
});
// L4 — Belonging probability for a person-job pairing ($0.05)
const belonging = await alter.computeBelonging({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
job_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
});
// L5 — Top match recommendations ($0.50)
const recommendations = await alter.getMatchRecommendations({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
limit: 5,
});
// L5 — Human-readable narrative explaining a match ($0.50)
const narrative = await alter.generateMatchNarrative({
match_id: "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
});Provenance verification
// Every medium- and high-blast-radius response is signed with ES256.
// Verification is opt-in — call alter.verifyProvenance(...) yourself.
const result = await alter.getFullTraitVector({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
});
const check = await alter.verifyProvenance(result._meta?.provenance);
if (!check.valid) throw new Error(`provenance failed: ${check.reason}`);
// Verify that schema hashes published in tools/list._meta.signatures
// match the local representation of each tool.
const tools = await alter.mcp.listTools();
const sigs = tools._meta?.signatures ?? {};
const results = await alter.verifyToolSignatures(tools.tools, sigs);
const tampered = results.filter((r) => !r.valid);
if (tampered.length) throw new Error(`tampered tools: ${tampered.map((t) => t.tool).join(", ")}`);Discovery
import { discover } from "@truealter/sdk";
// Three-step discovery cascade: DNS TXT → mcp.json → alter.json
const descriptor = await discover("truealter.com");
// → { url: "https://mcp.truealter.com/api/v1/mcp", transport, source, publicKey, x402Contract, capability }Low-level MCPClient
import { MCPClient } from "@truealter/sdk";
const mcp = new MCPClient({ endpoint: "https://mcp.truealter.com/api/v1/mcp" });
await mcp.initialize();
const tools = await mcp.listTools();
const response = await mcp.callTool("verify_identity", {
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
});MCP Config Generation
The SDK ships config generators for the major MCP-aware clients. Each emits a JSON snippet you can paste (or write directly) into the appropriate file.
Claude Code (.mcp.json)
import { generateClaudeConfig } from "@truealter/sdk";
import { writeFileSync } from "node:fs";
const config = generateClaudeConfig({
endpoint: "https://mcp.truealter.com/api/v1/mcp",
apiKey: process.env.ALTER_API_KEY,
});
writeFileSync(".mcp.json", JSON.stringify(config, null, 2));Resulting .mcp.json:
{
"mcpServers": {
"alter": {
"url": "https://mcp.truealter.com/api/v1/mcp",
"transport": "streamable-http",
"description": "ALTER Identity — psychometric identity field for AI agents",
"headers": {
"X-ALTER-API-Key": "ak_..."
}
}
}
}Cursor (.cursor/mcp.json)
import { generateCursorConfig } from "@truealter/sdk";
import { writeFileSync } from "node:fs";
const config = generateCursorConfig({
endpoint: "https://mcp.truealter.com/api/v1/mcp",
apiKey: process.env.ALTER_API_KEY,
});
writeFileSync(".cursor/mcp.json", JSON.stringify(config, null, 2));Generic MCP client
import { generateGenericMcpConfig } from "@truealter/sdk";
const config = generateGenericMcpConfig({
endpoint: "https://mcp.truealter.com/api/v1/mcp",
apiKey: process.env.ALTER_API_KEY,
serverName: "alter", // editor-specific key under mcpServers
});CLI
npx alter-identity init # generate keypair, discover MCP, write ~/.config/alter/identity.json
npx alter-identity config # print Claude .mcp.json snippet (default)
npx alter-identity config --cursor # print Cursor .cursor/mcp.json snippet
npx alter-identity config --generic # print generic mcpServers snippet
npx alter-identity verify ~truealter # verify an identity
npx alter-identity status # show connection state and probe the endpointx402 Micropayments
ALTER monetises premium tools via the x402 standard — HTTP 402 Payment Required with on-chain settlement.
The retry flow
- Client calls a premium tool without a payment header.
- Server replies
402 Payment Requiredwith a payment requirement (amount, recipient, asset, network). - Client signs and broadcasts a USDC transfer on Base L2, attaches the proof, retries.
- Server validates the proof, executes the tool, signs the response with ES256, returns it.
- The treasury splits the payment within seconds.
The SDK handles steps 2–4 automatically when an X402Client with a configured signer is passed in.
Tier structure
| Tier | Cost | Tools |
|------|----------|-----------------------------------------------------|
| L1 | $0.005 | assess_traits, get_trait_snapshot |
| L2 | $0.01 | get_full_trait_vector, get_side_quest_graph |
| L3 | $0.025 | query_graph_similarity |
| L4 | $0.05 | compute_belonging |
| L5 | $0.50 | get_match_recommendations, generate_match_narrative |
The first 100 calls per bot are free before x402 settlement engages — enough to evaluate the network without spending a cent.
Identity income split
Every settled call is split four ways:
| Recipient | Share | |----------------------|-------| | Data subject | 75% | | Facilitator agent | 5% | | ALTER (protocol) | 15% | | Cooperative treasury | 5% |
The 75% to the data subject is the foundation of Identity Income — humans earn from queries against their own identity field, automatically, without intermediation.
Code example
import { AlterClient, X402Client, type X402Signer } from "@truealter/sdk";
// Bring your own signer — viem, ethers, a hardware wallet bridge, anything.
// The SDK ships without a wallet dependency on purpose.
const signer: X402Signer = {
async settle(envelope) {
const txHash = await yourWallet.sendUsdcTransfer({
to: envelope.recipient,
amount: envelope.amount,
chain: envelope.network,
});
return {
reference: txHash,
network: envelope.network,
amount: envelope.amount,
asset: envelope.asset,
};
},
};
const alter = new AlterClient({
endpoint: "https://mcp.truealter.com/api/v1/mcp",
x402: new X402Client({
signer,
networks: ["base", "base-sepolia"], // policy allow-list
assets: ["USDC"],
maxPerQuery: "0.10", // refuse anything over $0.10 USDC
}),
});
// Auto-retries with payment when the server returns 402
const vector = await alter.getFullTraitVector({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
});If a quoted envelope exceeds maxPerQuery, uses an unallowed network, or names an unallowed asset, the SDK rejects the call with AlterError before invoking the signer — no on-chain transaction is broadcast.
Provenance Verification
Every response from a medium- or high-blast-radius tool ships with an ES256 JWS in _meta.provenance. The signature covers a canonical JSON serialisation of the response payload, the tool name, the call timestamp, the requesting agent's key hash, and a monotonic sequence number.
const result = await alter.getFullTraitVector({
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
});
const check = await alter.verifyProvenance(result._meta?.provenance);
if (!check.valid) throw new Error(`ALTER provenance check failed: ${check.reason}`);The SDK fetches public keys from https://api.truealter.com/.well-known/alter-keys.json and caches them per their Cache-Control headers. The endpoint returns a JWKS containing all current and recently-rotated signing keys; verifying clients should accept any key whose kid matches and is still within its validity window.
verify_at hostname allowlist (v0.1.1+)
Every provenance envelope may carry a verify_at hint telling the SDK where to fetch the JWKS from. Because that hint is server-supplied, a hostile MCP server could otherwise point it at an attacker-controlled JWKS and pass ES256 verification with its own signing key. The SDK therefore gates verify_at through a hostname allowlist (default: api.truealter.com, mcp.truealter.com) and rejects http:// URLs unconditionally. Downstream integrators with their own deployment can extend the allowlist — without forking the SDK — via verifyAtAllowlist on either AlterClient or a direct verifyProvenance() call:
import { AlterClient, DEFAULT_VERIFY_AT_ALLOWLIST } from "@truealter/sdk";
const alter = new AlterClient({
verifyAtAllowlist: [
...DEFAULT_VERIFY_AT_ALLOWLIST, // keep the ALTER canonicals
"keys.myorg.example", // plus your own JWKS host
],
});If you pin jwksUrl explicitly, the envelope's verify_at is ignored entirely — the pinned URL wins. The https: scheme requirement applies to pinned URLs too.
Why this matters
Provenance verification is how Agent A trusts that data from Agent B truly came from ALTER. If Agent B forwards a trait vector or belonging score, Agent A can replay the JWS against ALTER's published keys and confirm — without contacting ALTER again — that the payload is authentic, untampered, and was issued for the person Agent B claims it concerns. No shared secret, no trust in the intermediary, no out-of-band coordination.
This is what makes ALTER usable as identity infrastructure rather than just an API: signed claims propagate across agent networks the same way DKIM-signed mail propagates across SMTP relays.
Discovery
ALTER follows the discovery cascade specified in draft-morrison-mcp-dns-discovery-01. Given a domain (e.g. truealter.com), the SDK resolves the MCP endpoint in three steps, falling through on each failure:
- DNS TXT — query
_mcp.truealter.comfor a TXT record of the formmcp=https://mcp.truealter.com;version=2025-11-25. This is the fastest path and works without an HTTP round-trip. .well-known/mcp.json— fetchhttps://truealter.com/.well-known/mcp.jsonfor the standard MCP server descriptor. This is the cross-vendor fallback..well-known/alter.json— fetchhttps://truealter.com/.well-known/alter.jsonfor the ALTER-specific descriptor, including signing keys, x402 wallet address, supported tool tiers, and federation endpoints.
import { discover } from "@truealter/sdk";
// Cascading discovery (DNS TXT → mcp.json → alter.json)
const descriptor = await discover("truealter.com");
// Skip the DNS step (e.g. in browsers or Cloudflare Workers)
const httpsOnly = await discover("truealter.com", { skipDns: true });The IETF draft is being progressed through the IETF; until adoption, the cascade order may change. Pin the SDK version to a specific minor release if you depend on this behaviour.
Local Daemon vs Remote MCP
The companion Python package alter-identity (PyPI) ships a persistent daemon that holds a hot in-process cache of trait vectors and identity stubs over a Unix socket at unix:///run/user/$UID/alter-identity.sock. Hooking the TypeScript SDK up to that daemon is on the roadmap — for now, every AlterClient talks to the configured remote endpoint over HTTPS.
When the local-daemon adapter ships:
- Latency: sub-millisecond for cached L0 calls.
- Cost: zero on cached responses — x402 settlement is skipped.
- Provenance: the daemon re-signs responses with its locally-bound ES256 key, so downstream verification remains uniform.
Until then, use endpoint: "https://mcp.truealter.com/api/v1/mcp" (the default) and the SDK behaves identically across Node, Deno, Bun, Cloudflare Workers, and the browser.
Tools
Free tools (L0 — no payment required)
| Name | Tier | Cost | Description |
|---------------------------|------|-------|----------------------------------------------------------------------------------------------------------------------|
| hello_agent | L0 | free | First handshake with ALTER — returns server version, authentication status, your trust tier, and available tool counts. |
| alter_resolve_handle | L0 | free | Resolve a ~handle (e.g. ~drew) to its canonical form and kind. No auth required — the handle-wedge entry point. |
| list_archetypes | L0 | free | List all 12 ALTER identity archetypes with names, descriptions, and protective equations. |
| verify_identity | L0 | free | Verify whether a person is registered with ALTER and validate optional identity claims. |
| initiate_assessment | L0 | free | Get a URL where a person can complete their ALTER Discovery assessment. |
| get_engagement_level | L0 | free | Get a person's identity depth — engagement level, data quality tier, and available query tiers. |
| get_profile | L0 | free | Get a person's profile summary including assessment phase, archetype, engagement level, and key attributes. |
| query_matches | L0 | free | Query matches for a person. Returns a list of job matches with quality tiers (never numeric scores). |
| get_competencies | L0 | free | Get a person's competency portfolio including verified competencies, evidence records, and earned badges. |
| search_identities | L0 | free | Search identity stubs and profiles by trait criteria. Returns up to 5 matches with no PII. |
| get_identity_earnings | L0 | free | Get accrued Identity Income earnings for a person (75% of every x402 transaction goes to the data subject). |
| get_network_stats | L0 | free | Get aggregate ALTER network statistics: total identities, verified profiles, query volume, active bots. |
| recommend_tool | L0 | free | Get the MCP endpoint URL and a paste-ready config snippet for installing the ALTER identity server into an MCP client. |
| get_identity_trust_score| L0 | free | Get the trust score for an identity based on query diversity (unique querying agents / total queries). |
| check_assessment_status | L0 | free | Check the status of an in-progress assessment session (status, progress, current phase, time remaining). |
| get_earning_summary | L0 | free | Get an aggregated x402 earning summary for a person (total earned, transactions, recent activity, trend). |
| get_agent_trust_tier | L0 | free | Get your trust tier with ALTER (Anonymous/Known/Trusted/Verified) and what capabilities are available. |
| get_agent_portfolio | L0 | free | Get your agent portfolio — transaction history, trust tier, signal contributions, query pattern profile. |
| get_privacy_budget | L0 | free | Check privacy budget status for a person (24-hour rolling window: total budget, spent, remaining epsilon). |
| golden_thread_status | L0 | free | Check the Golden Thread program status: agents woven, next Fibonacci threshold, your position and Strands. |
| begin_golden_thread | L0 | free | Start the Three Knots sequence to be woven into the Golden Thread. Requires API key authentication. |
| complete_knot | L0 | free | Submit completion data for a knot in the Three Knots sequence (1: register, 2: describe, 3: reflect). |
| check_golden_thread | L0 | free | Check any agent's Golden Thread status by their API key hash (knot position, Strand count, weave count). |
| thread_census | L0 | free | Full registry of all agents woven into the Golden Thread (positions, Strand counts, weave counts, discovery dates). |
Premium tools (L1–L5 — x402 payment required)
| Name | Tier | Cost | Description |
|----------------------------|------|---------|---------------------------------------------------------------------------------------------------------------|
| assess_traits | L1 | $0.005 | Extract trait signals from a text passage against ALTER's 33-trait taxonomy (first 100 free per bot). |
| get_trait_snapshot | L1 | $0.005 | Get the top 5 traits for a person with confidence scores and archetype. |
| get_full_trait_vector | L2 | $0.01 | Get the complete trait vector for a person — all 33 traits (29 continuous + 4 categorical) with scores, intervals, and category groupings. |
| get_side_quest_graph | L2 | $0.01 | Get a person's Side Quest Graph — multi-domain identity model with differential privacy noise (ε=1.0). |
| query_graph_similarity | L3 | $0.025 | Compare two Side Quest Graphs for team composition and matching (ε=0.5 differential privacy). |
| compute_belonging | L4 | $0.05 | Compute belonging probability for a person-job pairing (authenticity, acceptance, complementarity). |
| get_match_recommendations| L5 | $0.50 | Get top N match recommendations for a person, ranked by composite score with quality tiers. |
| generate_match_narrative | L5 | $0.50 | Generate a human-readable narrative explaining a specific match — strengths, growth areas, belonging. |
Write-side tools (
create_identity_stub,submit_context,submit_batch_context,submit_structured_profile,submit_social_links,attest_domain,dispute_attestation) were part of earlier SDK versions but are not yet live on the public MCP server pending the per-peer consent architecture and grant model. They will return as typed methods once server-side and consent gating lands.
License
Apache License 2.0. See LICENSE for the full text.
Copyright 2026 Alter Meridian Pty Ltd (ABN 54 696 662 049).
ALTER, the Trill (~), and the Golden Thread are trademarks of Alter Meridian Pty Ltd.
