multi-agent-protocol 0.0.4 → 0.1.0

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.
@@ -206,18 +206,94 @@ Sensitive computation isolated in secure system, federated for I/O.
206
206
 
207
207
  ---
208
208
 
209
+ ## Single-Request Federation Auth
210
+
211
+ Federation connection can be completed in a single round-trip by including auth credentials in the initial `map/federation/connect` request. When the server can validate the credentials immediately, it returns a fully authenticated response — reducing setup from 2 RTT to 1 RTT.
212
+
213
+ ### Flow: Single-Request Auth (Optimized)
214
+
215
+ ```
216
+ System A System B
217
+ │ │
218
+ │──── map/federation/connect ─────────────────►│
219
+ │ { systemId, endpoint, auth: { ... } } │
220
+ │ │ ← Validates auth inline
221
+ │◄─── response ────────────────────────────────│
222
+ │ { connected: true, sessionId, principal } │
223
+ │ │
224
+ ```
225
+
226
+ ### Flow: Auth Negotiation Fallback
227
+
228
+ If no credentials are provided, or validation fails recoverably, the server returns auth requirements:
229
+
230
+ ```
231
+ System A System B
232
+ │ │
233
+ │──── map/federation/connect ─────────────────►│
234
+ │ { systemId, endpoint } │
235
+ │ │
236
+ │◄─── response ────────────────────────────────│
237
+ │ { connected: false, │
238
+ │ authRequired: { methods, challenge } } │
239
+ │ │
240
+ │──── map/federation/connect ─────────────────►│
241
+ │ { systemId, endpoint, auth: { ... }, │
242
+ │ authContext: { challenge } } │
243
+ │ │
244
+ │◄─── response ────────────────────────────────│
245
+ │ { connected: true, sessionId, principal } │
246
+ │ │
247
+ ```
248
+
249
+ ---
250
+
209
251
  ## Security Considerations
210
252
 
211
253
  ### Authentication
212
254
 
213
255
  ```typescript
256
+ type FederationAuthMethod =
257
+ | "bearer" | "api-key" | "mtls" | "none"
258
+ | "did:wba" | "oauth2" | `x-${string}`;
259
+
214
260
  type MAPFederationAuth =
215
- | { method: "mutual-tls"; certificate: string }
216
- | { method: "bearer"; token: string }
217
- | { method: "api-key"; key: string }
218
- | { method: "oauth2"; config: OAuth2Config };
261
+ | { method: FederationAuthMethod; credentials?: string; metadata?: Record<string, unknown> }
262
+ | DIDWBACredentials;
263
+
264
+ interface DIDWBACredentials {
265
+ method: "did:wba";
266
+ metadata: { did: string; proof: DIDWBAProof };
267
+ }
219
268
  ```
220
269
 
270
+ #### `did:wba` — Decentralized Identity for Federation
271
+
272
+ The `did:wba` method enables domain-anchored decentralized identity for federation. An identity like `did:wba:agents.example.com:gateway` resolves to a DID document at `https://agents.example.com/gateway/did.json` containing public keys and MAP service endpoints.
273
+
274
+ **Authentication flow:**
275
+ 1. Connecting system provides its DID and a cryptographic proof (ECDSA P-256 over challenge nonce)
276
+ 2. Receiving system resolves the DID document via HTTPS
277
+ 3. Receiving system verifies the proof against the public key in the DID document
278
+ 4. On success, the connecting system is authenticated as the DID principal
279
+
280
+ ```json
281
+ {
282
+ "method": "did:wba",
283
+ "metadata": {
284
+ "did": "did:wba:agents.example.com:gateway",
285
+ "proof": {
286
+ "type": "JsonWebSignature2020",
287
+ "created": "2026-02-10T12:00:00.000Z",
288
+ "challenge": "map_chal_01ABCDEFGHJ0123456789AB",
289
+ "jws": "eyJhbGciOi..."
290
+ }
291
+ }
292
+ }
293
+ ```
294
+
295
+ See `docs/09-authentication.md` for full details on all auth methods including `did:wba`, and `docs/11-anp-inspired-improvements.md` Proposal 1 for the design rationale.
296
+
221
297
  ### Message Signing
222
298
 
223
299
  ```typescript
@@ -253,7 +329,7 @@ interface MAPFederationQueueConfig {
253
329
  ## Open Questions
254
330
 
255
331
  1. **Transitive federation**: If A↔B and B↔C, can A route to C via B?
256
- 2. **Federation discovery**: Should there be a discovery mechanism for finding peers?
332
+ 2. ~~**Federation discovery**: Should there be a discovery mechanism for finding peers?~~ — Partially addressed by `did:wba` (DID document service endpoints) and proposed `.well-known` discovery (see `docs/11-anp-inspired-improvements.md` Proposal 2).
257
333
  3. **Consistency**: How to handle concurrent updates across federated systems?
258
334
  4. **Schema versioning**: What if peers have different protocol versions?
259
335
  5. **Audit requirements**: What federation activity must be logged?
@@ -22,6 +22,7 @@ MAP defines the following standard authentication methods:
22
22
  | `bearer` | Bearer token (JWT or opaque) | OAuth2, IdP integration, M2M tokens |
23
23
  | `api-key` | Simple API key | Simple integrations, internal services |
24
24
  | `mtls` | Mutual TLS (transport layer) | High-security service-to-service |
25
+ | `did:wba` | DID-based, domain-anchored | Cross-org federation, open discovery |
25
26
 
26
27
  ### Extension Methods
27
28
 
@@ -384,6 +385,54 @@ For trusted local connections.
384
385
  - Reject `none` based on transport type (e.g., require auth for WebSocket)
385
386
  - Assign a default principal for anonymous connections
386
387
 
388
+ ### DID:WBA (`did:wba`)
389
+
390
+ Domain-anchored decentralized identity based on the W3C `did:wba` method. Identity is derived from domain ownership: a DID like `did:wba:agents.example.com:gateway` resolves to a DID document hosted at `https://agents.example.com/gateway/did.json`.
391
+
392
+ **Credential format:** DID and cryptographic proof in metadata
393
+
394
+ ```typescript
395
+ {
396
+ "method": "did:wba",
397
+ "metadata": {
398
+ "did": "did:wba:agents.example.com:gateway",
399
+ "proof": {
400
+ "type": "JsonWebSignature2020",
401
+ "created": "2026-02-10T12:00:00.000Z",
402
+ "challenge": "map_chal_01ABCDEFGHJ0123456789AB",
403
+ "jws": "base64url-encoded-ecdsa-signature"
404
+ }
405
+ }
406
+ }
407
+ ```
408
+
409
+ **DID Document:** The resolved DID document MUST contain:
410
+ - `verificationMethod` with the public key used to verify the proof
411
+ - `authentication` referencing the verification method
412
+ - Optionally, a `service` entry of type `MAPFederationEndpoint` with the MAP WebSocket URL
413
+
414
+ **Proof verification:**
415
+ 1. Server generates a challenge nonce (format: `map_chal_<ULID>`)
416
+ 2. Client signs `challenge.did.created` using ECDSA P-256 with its private key
417
+ 3. Server resolves DID → fetches DID document → extracts public key
418
+ 4. Server verifies the JWS signature against the public key and checks proof freshness
419
+
420
+ **Security considerations:**
421
+ - DID documents are fetched over HTTPS — domain ownership proves identity
422
+ - Proof freshness is enforced via the `created` timestamp (default max age: 5 minutes)
423
+ - Servers MAY maintain a trusted domains list to restrict accepted DIDs
424
+ - DID document caching with configurable TTL prevents excessive lookups
425
+
426
+ **When to use:**
427
+ - Cross-organization federation where pre-shared credentials are impractical
428
+ - Open discovery scenarios where peers find each other via DID documents
429
+ - Systems that need globally unique, verifiable agent identities
430
+
431
+ **SDK support:**
432
+ - `DIDWBAAuthenticator` — server-side authenticator (see `ts-sdk/src/server/auth/did-wba-authenticator.ts`)
433
+ - `generateDIDWBAProof()` / `verifyDIDWBAProof()` — proof utilities (see `ts-sdk/src/federation/did-wba/proof.ts`)
434
+ - `DIDWBAResolver` — DID document resolution with caching (see `ts-sdk/src/federation/did-wba/resolver.ts`)
435
+
387
436
  ---
388
437
 
389
438
  ## Token Refresh
@@ -670,6 +719,25 @@ const server = new MAPServer({
670
719
  });
671
720
  ```
672
721
 
722
+ ### Example 5: Federation Server with DID:WBA
723
+
724
+ ```typescript
725
+ import { DIDWBAAuthenticator } from '@anthropic/multi-agent-protocol/server/auth';
726
+
727
+ const server = new MAPServer({
728
+ auth: {
729
+ required: true,
730
+ methods: ['did:wba', 'bearer'],
731
+ authenticators: [
732
+ new DIDWBAAuthenticator({
733
+ trustedDomains: ['*.example.com', 'partner.org'],
734
+ }),
735
+ new JWTAuthenticator({ /* ... */ })
736
+ ]
737
+ }
738
+ });
739
+ ```
740
+
673
741
  ---
674
742
 
675
743
  ## Open Questions
@@ -0,0 +1,242 @@
1
+ # Environment Awareness
2
+
3
+ ## Overview
4
+
5
+ Environment awareness enables agents to advertise and discover information about their compute environments. This facilitates intelligent task routing, filesystem coordination, and resource-aware scheduling in heterogeneous multi-agent systems.
6
+
7
+ ## Motivation
8
+
9
+ Agents may run across diverse environments:
10
+ - Different mount points (Agent A at `/home/user/project`, Agent B at `/workspace/project`)
11
+ - Different compute types (local, Docker, Kubernetes, cloud sandbox)
12
+ - Different capabilities (GPU, specific tools, network access)
13
+ - Different constraints (memory limits, ephemeral storage, execution timeouts)
14
+
15
+ Environment awareness enables:
16
+ - **Task routing**: Send GPU workloads to GPU-enabled agents
17
+ - **Filesystem coordination**: Detect shared mounts vs. need for explicit file transfer
18
+ - **Resource optimization**: Choose agents based on cost, latency, or capacity
19
+ - **Security boundaries**: Route sensitive data to appropriately isolated agents
20
+
21
+ ## Schema
22
+
23
+ The `AgentEnvironment` type uses a layered approach:
24
+
25
+ - **Layer 1 (Normative)**: Category names are standardized
26
+ - **Layer 2 (Conventions)**: Field names within categories are recommended patterns
27
+ - **Layer 3 (Extensions)**: Custom fields allowed via `additionalProperties`
28
+
29
+ ```typescript
30
+ interface AgentEnvironment {
31
+ schemaVersion?: string; // Schema version (e.g., "1.0")
32
+ profiles?: string[]; // Self-declared compliance (e.g., ["cloud-native"])
33
+
34
+ // Standard categories (all optional, all extensible)
35
+ host?: Record<string, unknown>; // CPU, memory, GPU
36
+ os?: Record<string, unknown>; // OS type, version
37
+ process?: Record<string, unknown>; // PID, cwd, runtime
38
+ container?: Record<string, unknown>; // Container runtime info
39
+ cloud?: Record<string, unknown>; // Provider, region, instance type
40
+ k8s?: Record<string, unknown>; // Kubernetes context
41
+ filesystem?: Record<string, unknown>; // Mounts, workspace, VCS
42
+ network?: Record<string, unknown>; // Connectivity, addresses
43
+ tools?: Record<string, unknown>; // Installed tools, runtimes
44
+ resources?: Record<string, unknown>; // Limits and constraints
45
+ security?: Record<string, unknown>; // Isolation, compliance
46
+ services?: Record<string, unknown>; // External APIs, MCP servers
47
+
48
+ [key: string]: unknown; // Additional categories allowed
49
+ }
50
+ ```
51
+
52
+ ## Common Field Conventions
53
+
54
+ These field names are **recommended** (not required) for interoperability:
55
+
56
+ | Category | Common Fields |
57
+ |----------|--------------|
58
+ | `host` | `arch`, `cpuCount`, `memoryBytes`, `gpu.count`, `gpu.models` |
59
+ | `os` | `type` (linux/darwin/windows), `version`, `name` |
60
+ | `process` | `pid`, `cwd`, `runtimeName`, `runtimeVersion` |
61
+ | `cloud` | `provider`, `region`, `instanceType`, `accountId` |
62
+ | `network` | `connectivity` (full/restricted/internal/isolated), `addresses` |
63
+ | `filesystem` | `cwd`, `mounts`, `workspace.root`, `workspace.vcs`, `workspace.branch` |
64
+ | `tools` | `installed`, `shell`, `runtimes`, `canInstall` |
65
+ | `resources` | `cpuLimit`, `memoryLimitBytes`, `maxExecutionSeconds`, `costProfile` |
66
+ | `security` | `isolation`, `privileged`, `sandbox`, `dataResidency` |
67
+ | `services` | `aiProviders`, `mcp` (MCP servers) |
68
+
69
+ ## Protocol Integration
70
+
71
+ ### Agent Registration
72
+
73
+ ```typescript
74
+ await connection.register({
75
+ name: 'my-agent',
76
+ environment: {
77
+ schemaVersion: '1.0',
78
+ os: { type: 'linux', version: '22.04' },
79
+ process: { cwd: '/home/user/project' },
80
+ network: { connectivity: 'full' },
81
+ tools: {
82
+ installed: { python: '3.11', node: '20.0' },
83
+ shell: 'bash'
84
+ }
85
+ }
86
+ });
87
+ ```
88
+
89
+ ### Connect Response
90
+
91
+ Servers can advertise their environment:
92
+
93
+ ```typescript
94
+ interface ConnectResponse {
95
+ // ... existing fields
96
+ serverEnvironment?: AgentEnvironment;
97
+ }
98
+ ```
99
+
100
+ ### Environment Updates
101
+
102
+ Agents can update their environment via `map/agents/update`:
103
+
104
+ ```typescript
105
+ await connection.update({
106
+ agentId: myAgentId,
107
+ environment: {
108
+ resources: { memoryLimitBytes: 8589934592 } // Updated
109
+ }
110
+ });
111
+ ```
112
+
113
+ ### Event: `agent_environment_changed`
114
+
115
+ Emitted when an agent's environment changes:
116
+
117
+ ```typescript
118
+ {
119
+ type: 'agent_environment_changed',
120
+ data: {
121
+ agentId: 'agent-123',
122
+ environment: { /* current */ },
123
+ previousEnvironment: { /* previous */ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ ### Subscription Filtering
129
+
130
+ Filter events by environment attributes:
131
+
132
+ ```typescript
133
+ await client.subscribe({
134
+ filter: {
135
+ eventTypes: ['agent_registered'],
136
+ environmentMatch: {
137
+ 'os.type': 'linux',
138
+ 'cloud.provider': 'aws'
139
+ }
140
+ }
141
+ });
142
+ ```
143
+
144
+ ## Extension Patterns
145
+
146
+ ### Adding fields to categories
147
+
148
+ ```json
149
+ {
150
+ "host": {
151
+ "arch": "arm64",
152
+ "memoryBytes": 17179869184,
153
+ "x-apple-silicon": { "chip": "M2 Pro" }
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### Adding new categories
159
+
160
+ ```json
161
+ {
162
+ "schemaVersion": "1.0",
163
+ "os": { "type": "linux" },
164
+ "x-anthropic-sandbox": {
165
+ "sandboxId": "sb-abc123",
166
+ "tier": "premium"
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### Services with custom providers
172
+
173
+ ```json
174
+ {
175
+ "services": {
176
+ "aiProviders": {
177
+ "huggingface": { "available": true, "tier": "pro" },
178
+ "openai": { "available": true }
179
+ },
180
+ "mcp": {
181
+ "filesystem": { "available": true, "tools": ["read_file", "write_file"] }
182
+ },
183
+ "x-internal": {
184
+ "userService": { "available": true }
185
+ }
186
+ }
187
+ }
188
+ ```
189
+
190
+ ## Use Cases
191
+
192
+ ### Task Routing by Capability
193
+
194
+ ```typescript
195
+ const agents = await client.agents.list();
196
+ const gpuAgent = agents.find(a =>
197
+ a.environment?.host?.gpu?.count > 0
198
+ );
199
+ if (gpuAgent) {
200
+ await client.send({ to: gpuAgent.id, payload: mlTask });
201
+ }
202
+ ```
203
+
204
+ ### Filesystem Coordination
205
+
206
+ ```typescript
207
+ // Check if agents share a filesystem
208
+ const myMounts = myAgent.environment?.filesystem?.mounts ?? {};
209
+ const peerMounts = peerAgent.environment?.filesystem?.mounts ?? {};
210
+
211
+ const sharedMount = Object.keys(myMounts).find(name =>
212
+ myMounts[name]?.shared && peerMounts[name]?.shared
213
+ );
214
+
215
+ if (sharedMount) {
216
+ // Can use file paths directly
217
+ } else {
218
+ // Need to transfer file contents via messages
219
+ }
220
+ ```
221
+
222
+ ### Network-Aware Routing
223
+
224
+ ```typescript
225
+ const agents = await client.agents.list();
226
+ const internetAgent = agents.find(a =>
227
+ a.environment?.network?.connectivity === 'full'
228
+ );
229
+ // Route external API calls through this agent
230
+ ```
231
+
232
+ ## Security Considerations
233
+
234
+ 1. **Sensitive data**: Filter environment variables before exposing (no API keys, tokens)
235
+ 2. **Opt-in exposure**: Agents explicitly choose what to advertise
236
+ 3. **Visibility rules**: Environment respects existing MAP visibility/permissions
237
+ 4. **Trust boundaries**: Don't implicitly trust environment claims from untrusted agents
238
+
239
+ ## References
240
+
241
+ - [OpenTelemetry Resource Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/resource/)
242
+ - [Kubernetes Node Feature Discovery](https://kubernetes-sigs.github.io/node-feature-discovery/)