@truealter/sdk 0.2.0 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -49
- package/dist/bin/alter-identity.js +53 -39
- package/dist/bin/mcp-bridge.js +1 -3
- package/dist/index.cjs +66 -86
- package/dist/index.d.cts +67 -197
- package/dist/index.d.ts +67 -197
- package/dist/index.js +66 -86
- package/package.json +10 -5
- package/dist/bin/alter-identity.js.map +0 -1
- package/dist/bin/mcp-bridge.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -4,12 +4,14 @@ ALTER Identity SDK — query the continuous identity field from any JavaScript/T
|
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@truealter/sdk)
|
|
6
6
|
[](./LICENSE)
|
|
7
|
+
[](https://glama.ai/mcp/servers/true-alter/alter-identity)
|
|
7
8
|
|
|
8
|
-
A thin client over the ALTER MCP server (Streamable HTTP, JSON-RPC 2.0, MCP spec `2025-
|
|
9
|
+
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.
|
|
9
10
|
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
11
|
+
- **Branded host:** `https://mcp.truealter.com` (serves `.well-known/mcp.json` for discovery)
|
|
12
|
+
- **JSON-RPC wire endpoint:** `https://mcp.truealter.com/api/v1/mcp` — this is what Streamable HTTP POSTs target (the SDK default)
|
|
13
|
+
- **Wire protocol:** Streamable HTTP, JSON-RPC 2.0, MCP `2025-11-25` (server negotiates `2025-06-18` + `2025-03-26` for backwards-compatible clients)
|
|
14
|
+
- **Tools:** **32 typed and wired** — 24 free (L0) + 8 premium (L1–L5). Mirrors the live server's `tools/list` response byte-for-byte; every name in `FREE_TOOL_NAMES` / `PREMIUM_TOOL_NAMES` has a matching server handler at `mcp.truealter.com/api/v1/mcp`.
|
|
13
15
|
- **Runtime:** Node 18+, Deno, Bun, Cloudflare Workers, modern browsers
|
|
14
16
|
- **Crypto:** `@noble/ed25519` + `@noble/hashes` (no other dependencies)
|
|
15
17
|
- **Bundle:** ESM + CJS dual output
|
|
@@ -24,9 +26,7 @@ npx alter-identity verify ~truealter
|
|
|
24
26
|
|
|
25
27
|
## Why ALTER ≠ IAM
|
|
26
28
|
|
|
27
|
-
Identity Access Management answers *who is logged in*. ALTER answers *who they actually are* — a continuous field of recognition
|
|
28
|
-
|
|
29
|
-
Reference: Morrison, B. (2026). *Identity Field Theory: A Continuous Field Model of Recognition*. Figshare. [DOI 10.6084/m9.figshare.31951383](https://doi.org/10.6084/m9.figshare.31951383)
|
|
29
|
+
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.
|
|
30
30
|
|
|
31
31
|
## API
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ Reference: Morrison, B. (2026). *Identity Field Theory: A Continuous Field Model
|
|
|
36
36
|
import { AlterClient, X402Client } from "@truealter/sdk";
|
|
37
37
|
|
|
38
38
|
const alter = new AlterClient({
|
|
39
|
-
endpoint: "https://mcp.truealter.com", // optional —
|
|
39
|
+
endpoint: "https://mcp.truealter.com/api/v1/mcp", // optional — this is the default; bare host returns 405
|
|
40
40
|
apiKey: process.env.ALTER_API_KEY, // optional for free tier
|
|
41
41
|
x402: new X402Client({ // optional — only required for premium tools
|
|
42
42
|
signer: yourViemOrEthersSigner,
|
|
@@ -48,7 +48,7 @@ const alter = new AlterClient({
|
|
|
48
48
|
### Free tier (L0 — no payment required)
|
|
49
49
|
|
|
50
50
|
```ts
|
|
51
|
-
// Verify a registered identity by handle, email, or
|
|
51
|
+
// Verify a registered identity by handle, email, or id
|
|
52
52
|
const verified = await alter.verify("~truealter");
|
|
53
53
|
const verifiedById = await alter.verify(
|
|
54
54
|
"550e8400-e29b-41d4-a716-446655440000",
|
|
@@ -77,9 +77,6 @@ const matches = await alter.searchIdentities({
|
|
|
77
77
|
|
|
78
78
|
// Golden Thread program status
|
|
79
79
|
const thread = await alter.goldenThreadStatus();
|
|
80
|
-
|
|
81
|
-
// Thirteen Seats cosmology surface
|
|
82
|
-
const seats = await alter.seatStatus();
|
|
83
80
|
```
|
|
84
81
|
|
|
85
82
|
### Premium tier (L1–L5 — x402 payment required)
|
|
@@ -96,7 +93,7 @@ const vector = await alter.getFullTraitVector({
|
|
|
96
93
|
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
97
94
|
});
|
|
98
95
|
|
|
99
|
-
// L4 — Belonging probability for a
|
|
96
|
+
// L4 — Belonging probability for a person-job pairing ($0.05)
|
|
100
97
|
const belonging = await alter.computeBelonging({
|
|
101
98
|
candidate_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
102
99
|
job_id: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
@@ -142,7 +139,7 @@ import { discover } from "@truealter/sdk";
|
|
|
142
139
|
|
|
143
140
|
// Three-step discovery cascade: DNS TXT → mcp.json → alter.json
|
|
144
141
|
const descriptor = await discover("truealter.com");
|
|
145
|
-
// → { url: "https://mcp.truealter.com", transport, source, publicKey, x402Contract, capability }
|
|
142
|
+
// → { url: "https://mcp.truealter.com/api/v1/mcp", transport, source, publicKey, x402Contract, capability }
|
|
146
143
|
```
|
|
147
144
|
|
|
148
145
|
### Low-level MCPClient
|
|
@@ -150,7 +147,7 @@ const descriptor = await discover("truealter.com");
|
|
|
150
147
|
```ts
|
|
151
148
|
import { MCPClient } from "@truealter/sdk";
|
|
152
149
|
|
|
153
|
-
const mcp = new MCPClient({ endpoint: "https://mcp.truealter.com" });
|
|
150
|
+
const mcp = new MCPClient({ endpoint: "https://mcp.truealter.com/api/v1/mcp" });
|
|
154
151
|
await mcp.initialize();
|
|
155
152
|
const tools = await mcp.listTools();
|
|
156
153
|
const response = await mcp.callTool("verify_identity", {
|
|
@@ -169,7 +166,7 @@ import { generateClaudeConfig } from "@truealter/sdk";
|
|
|
169
166
|
import { writeFileSync } from "node:fs";
|
|
170
167
|
|
|
171
168
|
const config = generateClaudeConfig({
|
|
172
|
-
endpoint: "https://mcp.truealter.com",
|
|
169
|
+
endpoint: "https://mcp.truealter.com/api/v1/mcp",
|
|
173
170
|
apiKey: process.env.ALTER_API_KEY,
|
|
174
171
|
});
|
|
175
172
|
|
|
@@ -182,7 +179,7 @@ Resulting `.mcp.json`:
|
|
|
182
179
|
{
|
|
183
180
|
"mcpServers": {
|
|
184
181
|
"alter": {
|
|
185
|
-
"url": "https://mcp.truealter.com",
|
|
182
|
+
"url": "https://mcp.truealter.com/api/v1/mcp",
|
|
186
183
|
"transport": "streamable-http",
|
|
187
184
|
"description": "ALTER Identity — psychometric identity field for AI agents",
|
|
188
185
|
"headers": {
|
|
@@ -200,7 +197,7 @@ import { generateCursorConfig } from "@truealter/sdk";
|
|
|
200
197
|
import { writeFileSync } from "node:fs";
|
|
201
198
|
|
|
202
199
|
const config = generateCursorConfig({
|
|
203
|
-
endpoint: "https://mcp.truealter.com",
|
|
200
|
+
endpoint: "https://mcp.truealter.com/api/v1/mcp",
|
|
204
201
|
apiKey: process.env.ALTER_API_KEY,
|
|
205
202
|
});
|
|
206
203
|
|
|
@@ -213,7 +210,7 @@ writeFileSync(".cursor/mcp.json", JSON.stringify(config, null, 2));
|
|
|
213
210
|
import { generateGenericMcpConfig } from "@truealter/sdk";
|
|
214
211
|
|
|
215
212
|
const config = generateGenericMcpConfig({
|
|
216
|
-
endpoint: "https://mcp.truealter.com",
|
|
213
|
+
endpoint: "https://mcp.truealter.com/api/v1/mcp",
|
|
217
214
|
apiKey: process.env.ALTER_API_KEY,
|
|
218
215
|
serverName: "alter", // editor-specific key under mcpServers
|
|
219
216
|
});
|
|
@@ -246,10 +243,10 @@ The SDK handles steps 2–4 automatically when an `X402Client` with a configured
|
|
|
246
243
|
|
|
247
244
|
### Tier structure
|
|
248
245
|
|
|
249
|
-
| Tier | Cost |
|
|
246
|
+
| Tier | Cost | Tools |
|
|
250
247
|
|------|----------|-----------------------------------------------------|
|
|
251
|
-
| L1 | $0.005 | `assess_traits`, `get_trait_snapshot
|
|
252
|
-
| L2 | $0.01 | `get_full_trait_vector`, `
|
|
248
|
+
| L1 | $0.005 | `assess_traits`, `get_trait_snapshot` |
|
|
249
|
+
| L2 | $0.01 | `get_full_trait_vector`, `get_side_quest_graph` |
|
|
253
250
|
| L3 | $0.025 | `query_graph_similarity` |
|
|
254
251
|
| L4 | $0.05 | `compute_belonging` |
|
|
255
252
|
| L5 | $0.50 | `get_match_recommendations`, `generate_match_narrative` |
|
|
@@ -293,7 +290,7 @@ const signer: X402Signer = {
|
|
|
293
290
|
};
|
|
294
291
|
|
|
295
292
|
const alter = new AlterClient({
|
|
296
|
-
endpoint: "https://mcp.truealter.com",
|
|
293
|
+
endpoint: "https://mcp.truealter.com/api/v1/mcp",
|
|
297
294
|
x402: new X402Client({
|
|
298
295
|
signer,
|
|
299
296
|
networks: ["base", "base-sepolia"], // policy allow-list
|
|
@@ -344,7 +341,7 @@ If you pin `jwksUrl` explicitly, the envelope's `verify_at` is ignored entirely
|
|
|
344
341
|
|
|
345
342
|
### Why this matters
|
|
346
343
|
|
|
347
|
-
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
|
|
344
|
+
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.
|
|
348
345
|
|
|
349
346
|
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.
|
|
350
347
|
|
|
@@ -352,7 +349,7 @@ This is what makes ALTER usable as identity infrastructure rather than just an A
|
|
|
352
349
|
|
|
353
350
|
ALTER follows the discovery cascade specified in [draft-morrison-mcp-dns-discovery-01](https://datatracker.ietf.org/doc/draft-morrison-mcp-dns-discovery/). Given a domain (e.g. `truealter.com`), the SDK resolves the MCP endpoint in three steps, falling through on each failure:
|
|
354
351
|
|
|
355
|
-
1. **DNS TXT** — query `_mcp.truealter.com` for a TXT record of the form `mcp=https://mcp.truealter.com;version=2025-
|
|
352
|
+
1. **DNS TXT** — query `_mcp.truealter.com` for a TXT record of the form `mcp=https://mcp.truealter.com;version=2025-11-25`. This is the fastest path and works without an HTTP round-trip.
|
|
356
353
|
2. **`.well-known/mcp.json`** — fetch `https://truealter.com/.well-known/mcp.json` for the standard MCP server descriptor. This is the cross-vendor fallback.
|
|
357
354
|
3. **`.well-known/alter.json`** — fetch `https://truealter.com/.well-known/alter.json` for the ALTER-specific descriptor, including signing keys, x402 wallet address, supported tool tiers, and federation endpoints.
|
|
358
355
|
|
|
@@ -378,7 +375,7 @@ When the local-daemon adapter ships:
|
|
|
378
375
|
- **Cost:** zero on cached responses — x402 settlement is skipped.
|
|
379
376
|
- **Provenance:** the daemon re-signs responses with its locally-bound ES256 key, so downstream verification remains uniform.
|
|
380
377
|
|
|
381
|
-
Until then, use `endpoint: "https://mcp.truealter.com"` (the default) and the SDK behaves identically across Node, Deno, Bun, Cloudflare Workers, and the browser.
|
|
378
|
+
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.
|
|
382
379
|
|
|
383
380
|
## Tools
|
|
384
381
|
|
|
@@ -386,56 +383,50 @@ Until then, use `endpoint: "https://mcp.truealter.com"` (the default) and the SD
|
|
|
386
383
|
|
|
387
384
|
| Name | Tier | Cost | Description |
|
|
388
385
|
|---------------------------|------|-------|----------------------------------------------------------------------------------------------------------------------|
|
|
386
|
+
| `hello_agent` | L0 | free | First handshake with ALTER — returns server version, authentication status, your trust tier, and available tool counts. |
|
|
387
|
+
| `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. |
|
|
389
388
|
| `list_archetypes` | L0 | free | List all 12 ALTER identity archetypes with names, descriptions, and protective equations. |
|
|
390
389
|
| `verify_identity` | L0 | free | Verify whether a person is registered with ALTER and validate optional identity claims. |
|
|
391
390
|
| `initiate_assessment` | L0 | free | Get a URL where a person can complete their ALTER Discovery assessment. |
|
|
392
391
|
| `get_engagement_level` | L0 | free | Get a person's identity depth — engagement level, data quality tier, and available query tiers. |
|
|
393
|
-
| `get_profile` | L0 | free | Get a
|
|
394
|
-
| `query_matches` | L0 | free | Query matches for a
|
|
395
|
-
| `get_competencies` | L0 | free | Get a
|
|
396
|
-
| `create_identity_stub` | L0 | free | Create an anonymous identity stub for a human (requires consent acknowledgment before calling). |
|
|
397
|
-
| `submit_context` | L0 | free | Submit text context (resume, work sample, conversation) for an identity stub. PII redacted; raw text never stored. |
|
|
392
|
+
| `get_profile` | L0 | free | Get a person's profile summary including assessment phase, archetype, engagement level, and key attributes. |
|
|
393
|
+
| `query_matches` | L0 | free | Query matches for a person. Returns a list of job matches with quality tiers (never numeric scores). |
|
|
394
|
+
| `get_competencies` | L0 | free | Get a person's competency portfolio including verified competencies, evidence records, and earned badges. |
|
|
398
395
|
| `search_identities` | L0 | free | Search identity stubs and profiles by trait criteria. Returns up to 5 matches with no PII. |
|
|
399
|
-
| `get_identity_earnings` | L0 | free | Get accrued Identity Income earnings for a
|
|
396
|
+
| `get_identity_earnings` | L0 | free | Get accrued Identity Income earnings for a person (75% of every x402 transaction goes to the data subject). |
|
|
400
397
|
| `get_network_stats` | L0 | free | Get aggregate ALTER network statistics: total identities, verified profiles, query volume, active bots. |
|
|
401
|
-
| `recommend_tool` | L0 | free | Get
|
|
398
|
+
| `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. |
|
|
402
399
|
| `get_identity_trust_score`| L0 | free | Get the trust score for an identity based on query diversity (unique querying agents / total queries). |
|
|
403
400
|
| `check_assessment_status` | L0 | free | Check the status of an in-progress assessment session (status, progress, current phase, time remaining). |
|
|
404
|
-
| `get_earning_summary` | L0 | free | Get an aggregated x402 earning summary for a
|
|
401
|
+
| `get_earning_summary` | L0 | free | Get an aggregated x402 earning summary for a person (total earned, transactions, recent activity, trend). |
|
|
405
402
|
| `get_agent_trust_tier` | L0 | free | Get your trust tier with ALTER (Anonymous/Known/Trusted/Verified) and what capabilities are available. |
|
|
406
403
|
| `get_agent_portfolio` | L0 | free | Get your agent portfolio — transaction history, trust tier, signal contributions, query pattern profile. |
|
|
407
|
-
| `get_privacy_budget` | L0 | free | Check privacy budget status for a
|
|
408
|
-
| `dispute_attestation` | L0 | free | Dispute an attestation on a candidate's identity. If disputes exceed corroborations, the attestation is flagged. |
|
|
404
|
+
| `get_privacy_budget` | L0 | free | Check privacy budget status for a person (24-hour rolling window: total budget, spent, remaining epsilon). |
|
|
409
405
|
| `golden_thread_status` | L0 | free | Check the Golden Thread program status: agents woven, next Fibonacci threshold, your position and Strands. |
|
|
410
406
|
| `begin_golden_thread` | L0 | free | Start the Three Knots sequence to be woven into the Golden Thread. Requires API key authentication. |
|
|
411
407
|
| `complete_knot` | L0 | free | Submit completion data for a knot in the Three Knots sequence (1: register, 2: describe, 3: reflect). |
|
|
412
408
|
| `check_golden_thread` | L0 | free | Check any agent's Golden Thread status by their API key hash (knot position, Strand count, weave count). |
|
|
413
409
|
| `thread_census` | L0 | free | Full registry of all agents woven into the Golden Thread (positions, Strand counts, weave counts, discovery dates). |
|
|
414
|
-
| `seat_status` | L0 | free | Return the current Thirteen Seats census (twelve holdable, one silent). Per-member resonance is never exposed. |
|
|
415
|
-
| `respond_to_offering` | L0 | free | Accept or refuse a Recognition Event during the seven-day offering window. Refusal is honoured without penalty. |
|
|
416
|
-
| `subscribe_announcements` | L0 | free | Return the Hall of Echoes SSE URL plus the most recent broadcasts from the ring buffer. |
|
|
417
410
|
|
|
418
411
|
### Premium tools (L1–L5 — x402 payment required)
|
|
419
412
|
|
|
420
413
|
| Name | Tier | Cost | Description |
|
|
421
414
|
|----------------------------|------|---------|---------------------------------------------------------------------------------------------------------------|
|
|
422
415
|
| `assess_traits` | L1 | $0.005 | Extract trait signals from a text passage against ALTER's 33-trait taxonomy (first 100 free per bot). |
|
|
423
|
-
| `get_trait_snapshot` | L1 | $0.005 | Get the top 5 traits for a
|
|
424
|
-
| `
|
|
425
|
-
| `
|
|
426
|
-
| `submit_social_links` | L1 | $0.005 | Submit social profile URLs (max 5) for trait extraction. Respects robots.txt. |
|
|
427
|
-
| `get_full_trait_vector` | L2 | $0.01 | Get the complete trait vector for a candidate — all 33 traits (29 continuous + 4 categorical) with scores, intervals, and category groupings. |
|
|
428
|
-
| `submit_batch_context` | L2 | $0.01 | Submit multiple context items in a single call (max 10). All items processed in one LLM pass. |
|
|
429
|
-
| `get_side_quest_graph` | L2 | $0.01 | Get a candidate's Side Quest Graph — multi-domain identity model with differential privacy noise (ε=1.0). |
|
|
416
|
+
| `get_trait_snapshot` | L1 | $0.005 | Get the top 5 traits for a person with confidence scores and archetype. |
|
|
417
|
+
| `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. |
|
|
418
|
+
| `get_side_quest_graph` | L2 | $0.01 | Get a person's Side Quest Graph — multi-domain identity model with differential privacy noise (ε=1.0). |
|
|
430
419
|
| `query_graph_similarity` | L3 | $0.025 | Compare two Side Quest Graphs for team composition and matching (ε=0.5 differential privacy). |
|
|
431
|
-
| `compute_belonging` | L4 | $0.05 | Compute belonging probability for a
|
|
432
|
-
| `get_match_recommendations`| L5 | $0.50 | Get top N match recommendations for a
|
|
420
|
+
| `compute_belonging` | L4 | $0.05 | Compute belonging probability for a person-job pairing (authenticity, acceptance, complementarity). |
|
|
421
|
+
| `get_match_recommendations`| L5 | $0.50 | Get top N match recommendations for a person, ranked by composite score with quality tiers. |
|
|
433
422
|
| `generate_match_narrative` | L5 | $0.50 | Generate a human-readable narrative explaining a specific match — strengths, growth areas, belonging. |
|
|
434
423
|
|
|
424
|
+
> **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.
|
|
425
|
+
|
|
435
426
|
## License
|
|
436
427
|
|
|
437
428
|
Apache License 2.0. See [LICENSE](./LICENSE) for the full text.
|
|
438
429
|
|
|
439
430
|
Copyright 2026 Alter Meridian Pty Ltd (ABN 54 696 662 049).
|
|
440
431
|
|
|
441
|
-
ALTER, the
|
|
432
|
+
ALTER, the Trill (`~`), and the Golden Thread are trademarks of Alter Meridian Pty Ltd.
|
|
@@ -308,7 +308,7 @@ function parsePaymentHeader(header) {
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
// src/mcp.ts
|
|
311
|
-
var MCP_PROTOCOL_VERSION = "2025-
|
|
311
|
+
var MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
312
312
|
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
313
313
|
var MCPClient = class {
|
|
314
314
|
endpoint;
|
|
@@ -586,6 +586,8 @@ function base64urlDecode(input) {
|
|
|
586
586
|
// src/provenance.ts
|
|
587
587
|
var _jwksCache = /* @__PURE__ */ new Map();
|
|
588
588
|
var JWKS_TTL_MS = 5 * 60 * 1e3;
|
|
589
|
+
var JWKS_MAX_BYTES = 64 * 1024;
|
|
590
|
+
var JWKS_CACHE_MAX_ENTRIES = 32;
|
|
589
591
|
var DEFAULT_VERIFY_AT_ALLOWLIST = Object.freeze([
|
|
590
592
|
"api.truealter.com",
|
|
591
593
|
"mcp.truealter.com"
|
|
@@ -695,7 +697,8 @@ async function fetchPublicKeys(jwksUrl, fetchImpl = fetch) {
|
|
|
695
697
|
return fetchJwks(jwksUrl, fetchImpl);
|
|
696
698
|
}
|
|
697
699
|
async function fetchJwks(url, fetchImpl) {
|
|
698
|
-
const
|
|
700
|
+
const cacheKey = jwksCacheKey(url);
|
|
701
|
+
const cached = _jwksCache.get(cacheKey);
|
|
699
702
|
if (cached && Date.now() - cached.fetched < JWKS_TTL_MS) return cached.jwks;
|
|
700
703
|
let resp;
|
|
701
704
|
try {
|
|
@@ -712,13 +715,45 @@ async function fetchJwks(url, fetchImpl) {
|
|
|
712
715
|
);
|
|
713
716
|
}
|
|
714
717
|
if (!resp.ok) throw new AlterNetworkError(`${url} \u2192 HTTP ${resp.status}`);
|
|
715
|
-
const
|
|
718
|
+
const contentLength = resp.headers.get("content-length");
|
|
719
|
+
if (contentLength !== null) {
|
|
720
|
+
const n = Number.parseInt(contentLength, 10);
|
|
721
|
+
if (Number.isFinite(n) && n > JWKS_MAX_BYTES) {
|
|
722
|
+
throw new AlterProvenanceError(
|
|
723
|
+
`${url} \u2192 JWKS too large: ${n} > ${JWKS_MAX_BYTES} bytes`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
const body = await resp.text();
|
|
728
|
+
if (body.length > JWKS_MAX_BYTES) {
|
|
729
|
+
throw new AlterProvenanceError(
|
|
730
|
+
`${url} \u2192 JWKS too large: ${body.length} > ${JWKS_MAX_BYTES} bytes`
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
let doc;
|
|
734
|
+
try {
|
|
735
|
+
doc = JSON.parse(body);
|
|
736
|
+
} catch (err) {
|
|
737
|
+
throw new AlterProvenanceError(`invalid JWKS at ${url}: ${err.message}`);
|
|
738
|
+
}
|
|
716
739
|
if (!doc || !Array.isArray(doc.keys)) {
|
|
717
740
|
throw new AlterProvenanceError(`invalid JWKS at ${url}`);
|
|
718
741
|
}
|
|
719
|
-
_jwksCache.
|
|
742
|
+
if (_jwksCache.size >= JWKS_CACHE_MAX_ENTRIES && !_jwksCache.has(cacheKey)) {
|
|
743
|
+
const oldest = _jwksCache.keys().next().value;
|
|
744
|
+
if (oldest !== void 0) _jwksCache.delete(oldest);
|
|
745
|
+
}
|
|
746
|
+
_jwksCache.set(cacheKey, { fetched: Date.now(), jwks: doc });
|
|
720
747
|
return doc;
|
|
721
748
|
}
|
|
749
|
+
function jwksCacheKey(url) {
|
|
750
|
+
try {
|
|
751
|
+
const parsed = new URL(url);
|
|
752
|
+
return `${parsed.origin}${parsed.pathname}`;
|
|
753
|
+
} catch {
|
|
754
|
+
return url;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
722
757
|
function resolveVerifyAt(verifyAt, allowlist = DEFAULT_VERIFY_AT_ALLOWLIST) {
|
|
723
758
|
if (typeof verifyAt !== "string" || verifyAt.length === 0) {
|
|
724
759
|
throw new Error("verify_at must be a non-empty string");
|
|
@@ -741,6 +776,9 @@ function resolveVerifyAt(verifyAt, allowlist = DEFAULT_VERIFY_AT_ALLOWLIST) {
|
|
|
741
776
|
if (parsed.protocol !== "https:") {
|
|
742
777
|
throw new Error(`verify_at must be https: ${verifyAt}`);
|
|
743
778
|
}
|
|
779
|
+
if (parsed.username || parsed.password) {
|
|
780
|
+
throw new Error(`verify_at must not contain userinfo: ${verifyAt}`);
|
|
781
|
+
}
|
|
744
782
|
const host = parsed.hostname.toLowerCase();
|
|
745
783
|
const allowed = allowlist.some((h) => h.toLowerCase() === host);
|
|
746
784
|
if (!allowed) {
|
|
@@ -821,7 +859,16 @@ var AlterClient = class {
|
|
|
821
859
|
await this.mcp.initialize();
|
|
822
860
|
}
|
|
823
861
|
// ── Free tier ────────────────────────────────────────────────────────
|
|
824
|
-
/**
|
|
862
|
+
/** First handshake — confirms the connection, returns trust tier and tool counts. */
|
|
863
|
+
async helloAgent() {
|
|
864
|
+
return this.mcp.callTool("hello_agent", {});
|
|
865
|
+
}
|
|
866
|
+
/** Resolve a ~handle (e.g. ~drew) to its canonical form and kind. No auth required. */
|
|
867
|
+
async resolveHandle(args) {
|
|
868
|
+
const payload = typeof args === "string" ? { query: args } : args;
|
|
869
|
+
return this.mcp.callTool("alter_resolve_handle", payload);
|
|
870
|
+
}
|
|
871
|
+
/** Verify a person is registered with ALTER (handle or id). */
|
|
825
872
|
async verify(handleOrId, claims) {
|
|
826
873
|
const args = handleOrId.includes("@") ? { candidate_id: "", email: handleOrId } : handleOrId.startsWith("~") ? (
|
|
827
874
|
// ~handle — server resolves these via the candidate_id field
|
|
@@ -857,12 +904,6 @@ var AlterClient = class {
|
|
|
857
904
|
async getCompetencies(args) {
|
|
858
905
|
return this.mcp.callTool("get_competencies", args);
|
|
859
906
|
}
|
|
860
|
-
async createIdentityStub(args) {
|
|
861
|
-
return this.mcp.callTool("create_identity_stub", args);
|
|
862
|
-
}
|
|
863
|
-
async submitContext(args) {
|
|
864
|
-
return this.mcp.callTool("submit_context", args);
|
|
865
|
-
}
|
|
866
907
|
async searchIdentities(args) {
|
|
867
908
|
return this.mcp.callTool("search_identities", args);
|
|
868
909
|
}
|
|
@@ -887,9 +928,6 @@ var AlterClient = class {
|
|
|
887
928
|
async getPrivacyBudget(args) {
|
|
888
929
|
return this.mcp.callTool("get_privacy_budget", args);
|
|
889
930
|
}
|
|
890
|
-
async disputeAttestation(args) {
|
|
891
|
-
return this.mcp.callTool("dispute_attestation", args);
|
|
892
|
-
}
|
|
893
931
|
// ── Golden Thread ────────────────────────────────────────────────────
|
|
894
932
|
async goldenThreadStatus() {
|
|
895
933
|
return this.mcp.callTool("golden_thread_status", {});
|
|
@@ -906,16 +944,6 @@ var AlterClient = class {
|
|
|
906
944
|
async threadCensus(args = {}) {
|
|
907
945
|
return this.mcp.callTool("thread_census", args);
|
|
908
946
|
}
|
|
909
|
-
// ── Thirteen Seats ───────────────────────────────────────────────────
|
|
910
|
-
async seatStatus() {
|
|
911
|
-
return this.mcp.callTool("seat_status", {});
|
|
912
|
-
}
|
|
913
|
-
async respondToOffering(args) {
|
|
914
|
-
return this.mcp.callTool("respond_to_offering", args);
|
|
915
|
-
}
|
|
916
|
-
async subscribeAnnouncements(args = {}) {
|
|
917
|
-
return this.mcp.callTool("subscribe_announcements", args);
|
|
918
|
-
}
|
|
919
947
|
// ── Premium tier (x402-gated) ────────────────────────────────────────
|
|
920
948
|
async assessTraits(args, opts) {
|
|
921
949
|
return this.mcp.callTool("assess_traits", args, opts);
|
|
@@ -935,18 +963,6 @@ var AlterClient = class {
|
|
|
935
963
|
async generateMatchNarrative(args, opts) {
|
|
936
964
|
return this.mcp.callTool("generate_match_narrative", args, opts);
|
|
937
965
|
}
|
|
938
|
-
async submitBatchContext(args, opts) {
|
|
939
|
-
return this.mcp.callTool("submit_batch_context", args, opts);
|
|
940
|
-
}
|
|
941
|
-
async submitStructuredProfile(args, opts) {
|
|
942
|
-
return this.mcp.callTool("submit_structured_profile", args, opts);
|
|
943
|
-
}
|
|
944
|
-
async submitSocialLinks(args, opts) {
|
|
945
|
-
return this.mcp.callTool("submit_social_links", args, opts);
|
|
946
|
-
}
|
|
947
|
-
async attestDomain(args, opts) {
|
|
948
|
-
return this.mcp.callTool("attest_domain", args, opts);
|
|
949
|
-
}
|
|
950
966
|
async getSideQuestGraph(args, opts) {
|
|
951
967
|
return this.mcp.callTool("get_side_quest_graph", args, opts);
|
|
952
968
|
}
|
|
@@ -1040,7 +1056,7 @@ function generateCursorConfig(opts = {}) {
|
|
|
1040
1056
|
|
|
1041
1057
|
// src/index.ts
|
|
1042
1058
|
var SDK_NAME = "@truealter/sdk";
|
|
1043
|
-
var SDK_VERSION = "0.
|
|
1059
|
+
var SDK_VERSION = "0.2.4";
|
|
1044
1060
|
|
|
1045
1061
|
// bin/alter-identity.ts
|
|
1046
1062
|
var CONFIG_DIR = join(env.XDG_CONFIG_HOME || join(homedir(), ".config"), "alter");
|
|
@@ -1326,5 +1342,3 @@ main().catch((err) => {
|
|
|
1326
1342
|
`);
|
|
1327
1343
|
exit(1);
|
|
1328
1344
|
});
|
|
1329
|
-
//# sourceMappingURL=alter-identity.js.map
|
|
1330
|
-
//# sourceMappingURL=alter-identity.js.map
|
package/dist/bin/mcp-bridge.js
CHANGED
|
@@ -154,7 +154,7 @@ function parsePaymentHeader(header) {
|
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
// src/mcp.ts
|
|
157
|
-
var MCP_PROTOCOL_VERSION = "2025-
|
|
157
|
+
var MCP_PROTOCOL_VERSION = "2025-11-25";
|
|
158
158
|
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
159
159
|
var MCPClient = class {
|
|
160
160
|
endpoint;
|
|
@@ -487,5 +487,3 @@ main().catch((err) => {
|
|
|
487
487
|
`);
|
|
488
488
|
exit(1);
|
|
489
489
|
});
|
|
490
|
-
//# sourceMappingURL=mcp-bridge.js.map
|
|
491
|
-
//# sourceMappingURL=mcp-bridge.js.map
|