multi-agent-protocol 0.0.3 → 0.0.6
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 +4 -0
- package/docs/00-design-specification.md +36 -0
- package/docs/01-open-questions.md +0 -5
- package/docs/02-wire-protocol.md +1 -1
- package/docs/07-federation.md +81 -5
- package/docs/09-authentication.md +748 -0
- package/docs/10-environment-awareness.md +242 -0
- package/docs/10-mail-protocol.md +553 -0
- package/docs/11-anp-inspired-improvements.md +1079 -0
- package/docs/12-anp-implementation-plan.md +641 -0
- package/docs/agent-iam-integration.md +877 -0
- package/docs/agentic-mesh-integration-draft.md +459 -0
- package/docs/git-transport-draft.md +251 -0
- package/package.json +5 -4
- package/schema/meta.json +200 -2
- package/schema/schema.json +1252 -13
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
# MAP Improvements Inspired by the AI Agent Protocol (ANP)
|
|
2
|
+
|
|
3
|
+
This spec proposes six improvements to MAP inspired by the W3C Community Group [Agent Network Protocol (ANP)](https://github.com/w3c-cg/ai-agent-protocol). ANP aims to be the "HTTP of the Agentic Web" — a decentralized protocol for AI agents to discover, authenticate, and interact across the open internet. While MAP and ANP occupy different niches (internal orchestration vs. open-internet identity), several ANP ideas strengthen MAP's federation, discovery, and privacy stories.
|
|
4
|
+
|
|
5
|
+
## Context: MAP vs ANP
|
|
6
|
+
|
|
7
|
+
| Dimension | MAP | ANP |
|
|
8
|
+
|-----------|-----|-----|
|
|
9
|
+
| **Primary concern** | Internal multi-agent orchestration & observability | Internet-scale agent identity & discovery |
|
|
10
|
+
| **Identity model** | Server-assigned participant IDs | Decentralized DIDs (`did:wba`) anchored to DNS/HTTPS |
|
|
11
|
+
| **Discovery** | Runtime queries (`agents/list`, subscriptions) | `.well-known` endpoints + web crawling |
|
|
12
|
+
| **Transport** | Transport-agnostic (WebSocket, stdio, in-process, HTTP/SSE) | HTTP/HTTPS only |
|
|
13
|
+
| **Wire format** | JSON-RPC 2.0 | HTTP + JSON-LD (meta-protocol negotiation) |
|
|
14
|
+
|
|
15
|
+
These proposals are scoped to MAP's federation and cross-system layers. They do not change how MAP works for internal, single-system deployments.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Proposal 1: Decentralized Identity via `did:wba` for Federation
|
|
20
|
+
|
|
21
|
+
### Status: ✅ Implemented — See `ts-sdk/src/federation/did-wba/` and `ts-sdk/src/server/auth/did-wba-authenticator.ts`
|
|
22
|
+
|
|
23
|
+
### Problem
|
|
24
|
+
|
|
25
|
+
MAP federation currently uses server-assigned IDs and pre-configured peer credentials (`mutual-tls`, `bearer`, `api-key`). This requires:
|
|
26
|
+
- Manual allowlist maintenance on every federated server
|
|
27
|
+
- No globally-unique, stable agent identities across system boundaries
|
|
28
|
+
- Trust establishment requires out-of-band credential exchange
|
|
29
|
+
|
|
30
|
+
For federations with more than a handful of peers, this doesn't scale.
|
|
31
|
+
|
|
32
|
+
### Proposal
|
|
33
|
+
|
|
34
|
+
Add `did:wba` as a federation authentication method. `did:wba` (Web-Based Agent DID) anchors identity to domain ownership via HTTPS. An identity like `did:wba:agents.example.com:worker-alpha` resolves to a DID document at `https://agents.example.com/worker-alpha/did.json`.
|
|
35
|
+
|
|
36
|
+
#### DID Document Resolution
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
did:wba:agents.example.com:worker-alpha
|
|
40
|
+
→ GET https://agents.example.com/worker-alpha/did.json
|
|
41
|
+
→ Returns DID Document with:
|
|
42
|
+
- Public keys for verification
|
|
43
|
+
- Service endpoints (MAP WebSocket URL)
|
|
44
|
+
- MAP-specific metadata (capabilities, protocol version)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
#### Extended Auth Method
|
|
48
|
+
|
|
49
|
+
Add `did:wba` to the existing authentication methods in `docs/09-authentication.md`:
|
|
50
|
+
|
|
51
|
+
| Method | Description | Use Case |
|
|
52
|
+
|--------|-------------|----------|
|
|
53
|
+
| `none` | No authentication | Local subprocess, development |
|
|
54
|
+
| `bearer` | Bearer token (JWT or opaque) | OAuth2, IdP, M2M tokens |
|
|
55
|
+
| `api-key` | Simple API key | Simple integrations |
|
|
56
|
+
| `mtls` | Mutual TLS | High-security service-to-service |
|
|
57
|
+
| **`did:wba`** | **DID-based, domain-anchored** | **Cross-org federation, open discovery** |
|
|
58
|
+
|
|
59
|
+
#### Authentication Flow
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Peer System A Peer System B
|
|
63
|
+
│ │
|
|
64
|
+
│── map/federation/connect ─────────────────────────►│
|
|
65
|
+
│ { auth: { │
|
|
66
|
+
│ method: "did:wba", │
|
|
67
|
+
│ did: "did:wba:alpha.example.com:gateway", │
|
|
68
|
+
│ proof: { │
|
|
69
|
+
│ type: "JsonWebSignature2020", │
|
|
70
|
+
│ created: "2026-02-10T...", │
|
|
71
|
+
│ challenge: "<server-provided-nonce>", │
|
|
72
|
+
│ jws: "eyJ..." │
|
|
73
|
+
│ } │
|
|
74
|
+
│ } │
|
|
75
|
+
│ } │
|
|
76
|
+
│ │
|
|
77
|
+
│ [Server B resolves DID document via HTTPS] │
|
|
78
|
+
│ [Server B verifies proof against public key] │
|
|
79
|
+
│ [Server B checks domain matches expected peer] │
|
|
80
|
+
│ │
|
|
81
|
+
│◄── connect response ──────────────────────────────│
|
|
82
|
+
│ { principal: { │
|
|
83
|
+
│ id: "did:wba:alpha.example.com:gateway", │
|
|
84
|
+
│ issuer: "https://alpha.example.com", │
|
|
85
|
+
│ claims: { ... } │
|
|
86
|
+
│ } │
|
|
87
|
+
│ } │
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Wire Protocol Types
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// New auth credential variant
|
|
94
|
+
interface DIDWBACredentials {
|
|
95
|
+
method: "did:wba";
|
|
96
|
+
|
|
97
|
+
/** The DID of the connecting system/agent */
|
|
98
|
+
did: string;
|
|
99
|
+
|
|
100
|
+
/** Cryptographic proof of DID ownership */
|
|
101
|
+
proof: {
|
|
102
|
+
/** Proof type (e.g., "JsonWebSignature2020", "Ed25519Signature2020") */
|
|
103
|
+
type: string;
|
|
104
|
+
|
|
105
|
+
/** ISO 8601 timestamp */
|
|
106
|
+
created: string;
|
|
107
|
+
|
|
108
|
+
/** Server-provided nonce (prevents replay) */
|
|
109
|
+
challenge: string;
|
|
110
|
+
|
|
111
|
+
/** The signature over (challenge + did + created) */
|
|
112
|
+
jws: string;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Extended federation auth
|
|
117
|
+
type MAPFederationAuth =
|
|
118
|
+
| { method: "mutual-tls"; certificate: string }
|
|
119
|
+
| { method: "bearer"; token: string }
|
|
120
|
+
| { method: "api-key"; key: string }
|
|
121
|
+
| { method: "oauth2"; config: OAuth2Config }
|
|
122
|
+
| DIDWBACredentials;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### DID Document with MAP Service Endpoint
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"@context": ["https://www.w3.org/ns/did/v1", "https://map-protocol.org/ns/v1"],
|
|
130
|
+
"id": "did:wba:alpha.example.com:gateway",
|
|
131
|
+
"verificationMethod": [{
|
|
132
|
+
"id": "did:wba:alpha.example.com:gateway#key-1",
|
|
133
|
+
"type": "JsonWebKey2020",
|
|
134
|
+
"controller": "did:wba:alpha.example.com:gateway",
|
|
135
|
+
"publicKeyJwk": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." }
|
|
136
|
+
}],
|
|
137
|
+
"authentication": ["did:wba:alpha.example.com:gateway#key-1"],
|
|
138
|
+
"service": [{
|
|
139
|
+
"id": "did:wba:alpha.example.com:gateway#map",
|
|
140
|
+
"type": "MAPFederationEndpoint",
|
|
141
|
+
"serviceEndpoint": "wss://alpha.example.com/map/federation",
|
|
142
|
+
"mapProtocolVersion": 1,
|
|
143
|
+
"mapCapabilities": {
|
|
144
|
+
"streaming": true,
|
|
145
|
+
"federation": true
|
|
146
|
+
}
|
|
147
|
+
}]
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Trust Model
|
|
152
|
+
|
|
153
|
+
DID resolution provides **domain-verified identity** — if you trust the domain, you trust the DID. This is weaker than mutual TLS (no CA chain) but stronger than bearer tokens (domain ownership is cryptographically verifiable without pre-shared secrets).
|
|
154
|
+
|
|
155
|
+
Trust levels in MAP federation:
|
|
156
|
+
|
|
157
|
+
| Auth Method | Trust Basis | Setup Overhead | Scalability |
|
|
158
|
+
|-------------|-------------|----------------|-------------|
|
|
159
|
+
| `mtls` | Certificate authority chain | High (cert management) | Medium |
|
|
160
|
+
| `bearer` | Pre-shared token/JWKS | Medium (token distribution) | Medium |
|
|
161
|
+
| `api-key` | Pre-shared secret | Low | Low |
|
|
162
|
+
| `did:wba` | Domain ownership via DNS/HTTPS | Low (publish DID doc) | High |
|
|
163
|
+
|
|
164
|
+
### Relationship to Existing Auth
|
|
165
|
+
|
|
166
|
+
`did:wba` is additive. It does not replace existing methods. Systems can support multiple auth methods and negotiate during `map/federation/connect`. A practical deployment might use `did:wba` for initial discovery and identity verification, then upgrade to `bearer` tokens (JWT signed by the verified DID key) for ongoing session authentication.
|
|
167
|
+
|
|
168
|
+
### Impacts
|
|
169
|
+
|
|
170
|
+
- **`docs/09-authentication.md`**: Add `did:wba` method, resolution flow, proof format
|
|
171
|
+
- **`docs/07-federation.md`**: Add `did:wba` to `MAPFederationAuth`, document trust model
|
|
172
|
+
- **`ts-sdk`**: Add DID resolution utility, proof generation/verification
|
|
173
|
+
- **`schema/schema.json`**: Extend auth credential union type
|
|
174
|
+
|
|
175
|
+
### Open Questions
|
|
176
|
+
|
|
177
|
+
1. **DID document caching**: How long should resolved DID documents be cached? Should the protocol mandate a TTL or leave it to implementations?
|
|
178
|
+
2. **Key rotation**: When a peer rotates keys, should there be a grace period where both old and new keys are valid?
|
|
179
|
+
3. **Revocation**: DID documents can be updated to remove keys, but there's no revocation list. Is this sufficient for MAP's trust model?
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Proposal 2: `.well-known` Federation Discovery Endpoint
|
|
184
|
+
|
|
185
|
+
### Status: 🟢 Deferrable — Can resolve in later versions
|
|
186
|
+
|
|
187
|
+
### Problem
|
|
188
|
+
|
|
189
|
+
MAP federation requires explicit peer configuration (`MAPPeerConfig[]` in `MAPFederationConfig`). This means:
|
|
190
|
+
- Every peer must be manually added to every other peer's configuration
|
|
191
|
+
- There's no standard way to discover what MAP systems exist at a domain
|
|
192
|
+
- No machine-readable advertisement of federation capabilities
|
|
193
|
+
|
|
194
|
+
This is identified as an open question in `docs/07-federation.md`:
|
|
195
|
+
> **Q: Federation Discovery** — Should there be a discovery mechanism for finding peers?
|
|
196
|
+
|
|
197
|
+
And in `docs/01-open-questions.md` as Q6.2 (pending).
|
|
198
|
+
|
|
199
|
+
### Proposal
|
|
200
|
+
|
|
201
|
+
Define a `/.well-known/map-federation` endpoint (per [RFC 8615](https://tools.ietf.org/html/rfc8615)) that MAP systems can serve to advertise their federation capabilities.
|
|
202
|
+
|
|
203
|
+
#### Discovery Document
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
GET https://example.com/.well-known/map-federation
|
|
207
|
+
Content-Type: application/json
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
interface MAPFederationDiscovery {
|
|
212
|
+
/** Schema version for this discovery document */
|
|
213
|
+
version: 1;
|
|
214
|
+
|
|
215
|
+
/** System identifier (matches MAPFederationConfig.systemId) */
|
|
216
|
+
systemId: string;
|
|
217
|
+
|
|
218
|
+
/** Human-readable system name */
|
|
219
|
+
name: string;
|
|
220
|
+
|
|
221
|
+
/** System description */
|
|
222
|
+
description?: string;
|
|
223
|
+
|
|
224
|
+
/** MAP protocol version(s) supported */
|
|
225
|
+
protocolVersions: number[];
|
|
226
|
+
|
|
227
|
+
/** Federation connection endpoints */
|
|
228
|
+
endpoints: MAPFederationEndpoint[];
|
|
229
|
+
|
|
230
|
+
/** Supported authentication methods (in preference order) */
|
|
231
|
+
authMethods: AuthMethod[];
|
|
232
|
+
|
|
233
|
+
/** What this system exposes to federation peers */
|
|
234
|
+
exposure: {
|
|
235
|
+
/** Whether the system accepts new federation peers */
|
|
236
|
+
acceptsPeers: boolean;
|
|
237
|
+
|
|
238
|
+
/** High-level description of exposed capabilities */
|
|
239
|
+
capabilities: string[];
|
|
240
|
+
|
|
241
|
+
/** Agent roles available to federation peers */
|
|
242
|
+
exposedRoles?: string[];
|
|
243
|
+
|
|
244
|
+
/** Scope tags available to federation peers */
|
|
245
|
+
exposedScopeTags?: string[];
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/** DID for this system's gateway (if did:wba auth supported) */
|
|
249
|
+
did?: string;
|
|
250
|
+
|
|
251
|
+
/** Contact/governance information */
|
|
252
|
+
contact?: {
|
|
253
|
+
url?: string;
|
|
254
|
+
email?: string;
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/** When this document was last updated (ISO 8601) */
|
|
258
|
+
updatedAt: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
interface MAPFederationEndpoint {
|
|
262
|
+
/** Transport type */
|
|
263
|
+
transport: "websocket" | "http-sse";
|
|
264
|
+
|
|
265
|
+
/** Connection URL */
|
|
266
|
+
url: string;
|
|
267
|
+
|
|
268
|
+
/** Geographic region hint (for latency-aware peer selection) */
|
|
269
|
+
region?: string;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Example Discovery Document
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"version": 1,
|
|
278
|
+
"systemId": "alpha-prod",
|
|
279
|
+
"name": "Alpha AI System",
|
|
280
|
+
"description": "Multi-agent orchestration for document processing",
|
|
281
|
+
"protocolVersions": [1],
|
|
282
|
+
"endpoints": [
|
|
283
|
+
{
|
|
284
|
+
"transport": "websocket",
|
|
285
|
+
"url": "wss://alpha.example.com/map/federation",
|
|
286
|
+
"region": "us-east-1"
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
"authMethods": ["did:wba", "bearer", "mtls"],
|
|
290
|
+
"exposure": {
|
|
291
|
+
"acceptsPeers": true,
|
|
292
|
+
"capabilities": ["document-processing", "ocr", "summarization"],
|
|
293
|
+
"exposedRoles": ["processor", "summarizer"],
|
|
294
|
+
"exposedScopeTags": ["federation"]
|
|
295
|
+
},
|
|
296
|
+
"did": "did:wba:alpha.example.com:gateway",
|
|
297
|
+
"contact": {
|
|
298
|
+
"url": "https://alpha.example.com/federation-docs"
|
|
299
|
+
},
|
|
300
|
+
"updatedAt": "2026-02-10T00:00:00Z"
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Discovery Flow
|
|
305
|
+
|
|
306
|
+
```
|
|
307
|
+
System B wants to federate with alpha.example.com:
|
|
308
|
+
|
|
309
|
+
1. GET https://alpha.example.com/.well-known/map-federation
|
|
310
|
+
→ Receives discovery document
|
|
311
|
+
|
|
312
|
+
2. Inspect authMethods, endpoints, exposure
|
|
313
|
+
→ Determines compatibility
|
|
314
|
+
|
|
315
|
+
3. Resolve DID (if did:wba supported)
|
|
316
|
+
GET https://alpha.example.com/gateway/did.json
|
|
317
|
+
→ Gets public key for authentication
|
|
318
|
+
|
|
319
|
+
4. Connect to federation endpoint
|
|
320
|
+
→ map/federation/connect with appropriate auth
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
#### Auto-Discovery (Optional Extension)
|
|
324
|
+
|
|
325
|
+
For environments that want automatic peer discovery, systems can optionally publish DNS TXT records:
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
_map-federation.example.com. TXT "v=MAP1; endpoint=https://example.com/.well-known/map-federation"
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
This enables DNS-based service discovery without requiring prior knowledge of specific URLs. This is strictly optional — most deployments will use direct URL configuration.
|
|
332
|
+
|
|
333
|
+
### Security Considerations
|
|
334
|
+
|
|
335
|
+
1. **The discovery document is public information.** It should not contain secrets, internal topology, or sensitive agent details. It advertises only what the system is willing to expose to potential federation peers.
|
|
336
|
+
2. **Connection still requires authentication.** Discovery is read-only. The actual federation connection goes through the full auth flow (`map/federation/connect`).
|
|
337
|
+
3. **Rate limiting.** The `.well-known` endpoint should be rate-limited to prevent scraping.
|
|
338
|
+
4. **HTTPS required.** The discovery endpoint MUST be served over HTTPS to prevent MITM attacks on the discovery document.
|
|
339
|
+
|
|
340
|
+
### Relationship to Open Questions
|
|
341
|
+
|
|
342
|
+
This proposal resolves **Q6.2: Federation Discovery** from `docs/01-open-questions.md`:
|
|
343
|
+
- **Decision**: Option D — DNS-based + well-known endpoint
|
|
344
|
+
- **Rationale**: Leverages existing web infrastructure (HTTPS, DNS). Low setup overhead. No central registry required. Compatible with `did:wba` identity. Discovery is read-only and safe.
|
|
345
|
+
|
|
346
|
+
### Impacts
|
|
347
|
+
|
|
348
|
+
- **`docs/07-federation.md`**: Add discovery section, reference `.well-known` format
|
|
349
|
+
- **`docs/01-open-questions.md`**: Resolve Q6.2
|
|
350
|
+
- **`ts-sdk`**: Add discovery client utility (`fetchFederationDiscovery(domain)`)
|
|
351
|
+
- **New**: Register `map-federation` with IANA well-known URI registry (when protocol matures)
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Proposal 3: Linked Capability Documents for Agent Discovery
|
|
356
|
+
|
|
357
|
+
### Status: ✅ Implemented — See `ts-sdk/src/types/index.ts` (MAPAgentCapabilityDescriptor) and agent handler/store updates
|
|
358
|
+
|
|
359
|
+
### Problem
|
|
360
|
+
|
|
361
|
+
MAP agents currently describe themselves with minimal metadata:
|
|
362
|
+
- `role?: string` — a single string
|
|
363
|
+
- `metadata?: Record<string, unknown>` — unstructured bag of key-values
|
|
364
|
+
- `environment?: AgentEnvironment` — compute environment info
|
|
365
|
+
|
|
366
|
+
This is insufficient for dynamic orchestration scenarios where:
|
|
367
|
+
- An orchestrator needs to discover which agents can handle a given task type
|
|
368
|
+
- A federation peer needs to understand what capabilities a remote system exposes
|
|
369
|
+
- A dashboard needs to display meaningful information about what agents do
|
|
370
|
+
|
|
371
|
+
ANP addresses this by making every agent serve a structured **Agent Description Document** that links to detailed capability declarations, forming a navigable web of capabilities.
|
|
372
|
+
|
|
373
|
+
### Proposal
|
|
374
|
+
|
|
375
|
+
Introduce an optional, structured **Agent Capability Descriptor** that agents can publish at registration time. The descriptor follows a linked-data model: top-level capabilities link to detailed interface specifications, which can link to schema definitions.
|
|
376
|
+
|
|
377
|
+
#### Capability Descriptor Schema
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
/**
|
|
381
|
+
* Structured capability descriptor for an agent.
|
|
382
|
+
* Published at registration time via the `capabilities` field on MAPAgent.
|
|
383
|
+
* Optional — agents without descriptors still work via role/metadata.
|
|
384
|
+
*/
|
|
385
|
+
interface MAPAgentCapabilityDescriptor {
|
|
386
|
+
/** Schema version */
|
|
387
|
+
version: 1;
|
|
388
|
+
|
|
389
|
+
/** Human-readable summary of what this agent does */
|
|
390
|
+
description: string;
|
|
391
|
+
|
|
392
|
+
/** Capability categories this agent supports */
|
|
393
|
+
capabilities: MAPCapabilityDeclaration[];
|
|
394
|
+
|
|
395
|
+
/** Input types this agent can accept */
|
|
396
|
+
accepts?: MAPInterfaceSpec[];
|
|
397
|
+
|
|
398
|
+
/** Output types this agent can produce */
|
|
399
|
+
produces?: MAPInterfaceSpec[];
|
|
400
|
+
|
|
401
|
+
/** Link to full documentation (external URL) */
|
|
402
|
+
documentationUrl?: string;
|
|
403
|
+
|
|
404
|
+
/** Semantic tags for discovery (searchable) */
|
|
405
|
+
tags?: string[];
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
interface MAPCapabilityDeclaration {
|
|
409
|
+
/** Machine-readable capability identifier (namespaced) */
|
|
410
|
+
id: string;
|
|
411
|
+
|
|
412
|
+
/** Human-readable capability name */
|
|
413
|
+
name: string;
|
|
414
|
+
|
|
415
|
+
/** What this capability does */
|
|
416
|
+
description: string;
|
|
417
|
+
|
|
418
|
+
/** Link to detailed interface spec (URL or inline) */
|
|
419
|
+
interfaceRef?: string;
|
|
420
|
+
|
|
421
|
+
/** Inline interface specification (alternative to interfaceRef) */
|
|
422
|
+
interface?: MAPInterfaceSpec;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
interface MAPInterfaceSpec {
|
|
426
|
+
/** Content type (e.g., "application/json", "text/plain") */
|
|
427
|
+
contentType: string;
|
|
428
|
+
|
|
429
|
+
/** JSON Schema for the expected payload structure */
|
|
430
|
+
schema?: Record<string, unknown>;
|
|
431
|
+
|
|
432
|
+
/** Link to external schema definition */
|
|
433
|
+
schemaRef?: string;
|
|
434
|
+
|
|
435
|
+
/** Example payload */
|
|
436
|
+
example?: unknown;
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
#### Registration with Capabilities
|
|
441
|
+
|
|
442
|
+
```typescript
|
|
443
|
+
// Agent registers with capability descriptor
|
|
444
|
+
{
|
|
445
|
+
"method": "map/agents/register",
|
|
446
|
+
"params": {
|
|
447
|
+
"name": "document-processor",
|
|
448
|
+
"role": "processor",
|
|
449
|
+
"capabilities": {
|
|
450
|
+
"version": 1,
|
|
451
|
+
"description": "Processes documents: extracts text, generates summaries, identifies entities",
|
|
452
|
+
"capabilities": [
|
|
453
|
+
{
|
|
454
|
+
"id": "doc:extract-text",
|
|
455
|
+
"name": "Text Extraction",
|
|
456
|
+
"description": "Extracts text content from PDF, DOCX, and image files",
|
|
457
|
+
"interface": {
|
|
458
|
+
"contentType": "application/json",
|
|
459
|
+
"schema": {
|
|
460
|
+
"type": "object",
|
|
461
|
+
"properties": {
|
|
462
|
+
"documentUrl": { "type": "string", "format": "uri" },
|
|
463
|
+
"format": { "enum": ["pdf", "docx", "png", "jpg"] }
|
|
464
|
+
},
|
|
465
|
+
"required": ["documentUrl"]
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"id": "doc:summarize",
|
|
471
|
+
"name": "Document Summarization",
|
|
472
|
+
"description": "Generates concise summaries of text documents",
|
|
473
|
+
"interface": {
|
|
474
|
+
"contentType": "application/json",
|
|
475
|
+
"schema": {
|
|
476
|
+
"type": "object",
|
|
477
|
+
"properties": {
|
|
478
|
+
"text": { "type": "string" },
|
|
479
|
+
"maxLength": { "type": "integer" },
|
|
480
|
+
"style": { "enum": ["bullet-points", "paragraph", "executive"] }
|
|
481
|
+
},
|
|
482
|
+
"required": ["text"]
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
],
|
|
487
|
+
"tags": ["document-processing", "nlp", "extraction", "summarization"]
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
#### Capability-Based Queries
|
|
494
|
+
|
|
495
|
+
Extend `map/agents/list` to support filtering by capability:
|
|
496
|
+
|
|
497
|
+
```typescript
|
|
498
|
+
// Find agents that can summarize documents
|
|
499
|
+
{
|
|
500
|
+
"method": "map/agents/list",
|
|
501
|
+
"params": {
|
|
502
|
+
"filter": {
|
|
503
|
+
"capabilityId": "doc:summarize"
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Find agents by semantic tag
|
|
509
|
+
{
|
|
510
|
+
"method": "map/agents/list",
|
|
511
|
+
"params": {
|
|
512
|
+
"filter": {
|
|
513
|
+
"tags": ["document-processing"]
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Find agents that accept a specific content type
|
|
519
|
+
{
|
|
520
|
+
"method": "map/agents/list",
|
|
521
|
+
"params": {
|
|
522
|
+
"filter": {
|
|
523
|
+
"accepts": "application/pdf"
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
#### Linked Navigation (for Federation)
|
|
530
|
+
|
|
531
|
+
In federation scenarios, exposed agents can reference external capability documents:
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
{
|
|
535
|
+
"id": "doc:summarize",
|
|
536
|
+
"name": "Document Summarization",
|
|
537
|
+
"description": "Generates concise summaries",
|
|
538
|
+
// Link to detailed spec hosted by the federated system
|
|
539
|
+
"interfaceRef": "https://alpha.example.com/capabilities/doc-summarize.json"
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
This allows federated systems to serve detailed capability specifications without bloating the federation protocol messages. Peers fetch detailed specs only when needed.
|
|
544
|
+
|
|
545
|
+
### Relationship to Existing Structures
|
|
546
|
+
|
|
547
|
+
This extends (not replaces) the existing agent model:
|
|
548
|
+
|
|
549
|
+
| Current | With Capability Descriptor |
|
|
550
|
+
|---------|---------------------------|
|
|
551
|
+
| `role: "processor"` | Still works — quick filtering |
|
|
552
|
+
| `metadata: { ... }` | Still works — unstructured extensions |
|
|
553
|
+
| — | `capabilities: { ... }` — structured, queryable, linked |
|
|
554
|
+
|
|
555
|
+
Agents that don't publish capability descriptors are fully backwards-compatible. The descriptor is optional.
|
|
556
|
+
|
|
557
|
+
### Impacts
|
|
558
|
+
|
|
559
|
+
- **`docs/00-design-specification.md`**: Add capability descriptor to agent model
|
|
560
|
+
- **`ts-sdk/src/types/index.ts`**: Add `MAPAgentCapabilityDescriptor` types
|
|
561
|
+
- **`ts-sdk/src/server/agents/`**: Extend registry to index capabilities for querying
|
|
562
|
+
- **`schema/schema.json`**: Add capability descriptor schema, extend agent list filters
|
|
563
|
+
|
|
564
|
+
### Open Questions
|
|
565
|
+
|
|
566
|
+
1. **Capability namespacing**: Should capability IDs use a formal namespace (e.g., `urn:map:capability:doc:summarize`) or informal prefixes (`doc:summarize`)?
|
|
567
|
+
2. **Schema format**: JSON Schema is proposed here. Should we also support other schema formats (e.g., TypeBox, Zod references)?
|
|
568
|
+
3. **Capability inheritance**: If a parent agent has capabilities, do spawned children inherit them?
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Proposal 4: Meta-Protocol Negotiation for Federation
|
|
573
|
+
|
|
574
|
+
### Status: 🟢 Deferrable — Can resolve in later versions
|
|
575
|
+
|
|
576
|
+
### Problem
|
|
577
|
+
|
|
578
|
+
MAP federation currently assumes both sides speak MAP. But in practice, a MAP system may need to federate with:
|
|
579
|
+
- An A2A-based system (Google's Agent-to-Agent protocol)
|
|
580
|
+
- An ACP-based system (single-agent systems that want to expose themselves)
|
|
581
|
+
- A future protocol not yet designed
|
|
582
|
+
|
|
583
|
+
Currently, if System A speaks MAP and System B speaks A2A, there's no standard way for them to negotiate which protocol to use. The gateway must be hardcoded for each protocol.
|
|
584
|
+
|
|
585
|
+
ANP addresses this with a "Layer 2" meta-protocol where agents negotiate *which application protocol* to use for a given interaction.
|
|
586
|
+
|
|
587
|
+
### Proposal
|
|
588
|
+
|
|
589
|
+
Add an optional meta-protocol negotiation step to `map/federation/connect`. Before committing to MAP as the federation protocol, peers exchange their supported protocols and agree on one.
|
|
590
|
+
|
|
591
|
+
#### Negotiation Flow
|
|
592
|
+
|
|
593
|
+
```
|
|
594
|
+
System A System B
|
|
595
|
+
│ │
|
|
596
|
+
│── map/federation/connect ────────────────────────►│
|
|
597
|
+
│ { protocols: [ │
|
|
598
|
+
│ { id: "map", version: 1, priority: 1 }, │
|
|
599
|
+
│ { id: "a2a", version: "2025-05-01", │
|
|
600
|
+
│ priority: 2 } │
|
|
601
|
+
│ ], │
|
|
602
|
+
│ preferredProtocol: "map" │
|
|
603
|
+
│ } │
|
|
604
|
+
│ │
|
|
605
|
+
│◄── connect response ─────────────────────────────│
|
|
606
|
+
│ { selectedProtocol: { │
|
|
607
|
+
│ id: "map", │
|
|
608
|
+
│ version: 1 │
|
|
609
|
+
│ }, │
|
|
610
|
+
│ fallbackAvailable: ["a2a"] │
|
|
611
|
+
│ } │
|
|
612
|
+
│ │
|
|
613
|
+
│ [Proceeds with MAP federation protocol] │
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
If neither side supports a common protocol, the connection is rejected with a clear error.
|
|
617
|
+
|
|
618
|
+
#### Wire Protocol Types
|
|
619
|
+
|
|
620
|
+
```typescript
|
|
621
|
+
interface MAPProtocolOption {
|
|
622
|
+
/** Protocol identifier */
|
|
623
|
+
id: "map" | "a2a" | "acp" | string;
|
|
624
|
+
|
|
625
|
+
/** Protocol version */
|
|
626
|
+
version: string | number;
|
|
627
|
+
|
|
628
|
+
/** Priority (1 = highest) */
|
|
629
|
+
priority: number;
|
|
630
|
+
|
|
631
|
+
/** Protocol-specific connection parameters */
|
|
632
|
+
params?: Record<string, unknown>;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Extended federation connect params
|
|
636
|
+
interface MAPFederationConnectParams {
|
|
637
|
+
// ... existing fields ...
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Optional: Supported protocols in preference order.
|
|
641
|
+
* If omitted, only MAP is assumed (backwards-compatible).
|
|
642
|
+
*/
|
|
643
|
+
protocols?: MAPProtocolOption[];
|
|
644
|
+
|
|
645
|
+
/** Explicitly preferred protocol (shorthand when only one option) */
|
|
646
|
+
preferredProtocol?: string;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// Extended federation connect response
|
|
650
|
+
interface MAPFederationConnectResult {
|
|
651
|
+
// ... existing fields ...
|
|
652
|
+
|
|
653
|
+
/** The protocol selected for this federation link */
|
|
654
|
+
selectedProtocol: {
|
|
655
|
+
id: string;
|
|
656
|
+
version: string | number;
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
/** Other protocols available if the primary fails */
|
|
660
|
+
fallbackAvailable?: string[];
|
|
661
|
+
}
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
#### Gateway Protocol Adapters
|
|
665
|
+
|
|
666
|
+
The gateway agent pattern from `docs/07-federation.md` naturally supports this. Each gateway can have protocol adapters:
|
|
667
|
+
|
|
668
|
+
```
|
|
669
|
+
┌─────────────────────────────────────────────────────────┐
|
|
670
|
+
│ MAP Gateway Agent │
|
|
671
|
+
│ │
|
|
672
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
673
|
+
│ │ Protocol Adapter Layer │ │
|
|
674
|
+
│ │ │ │
|
|
675
|
+
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
|
|
676
|
+
│ │ │ MAP │ │ A2A │ │ ACP │ ... │ │
|
|
677
|
+
│ │ │ Adapter │ │ Adapter │ │ Adapter │ │ │
|
|
678
|
+
│ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │
|
|
679
|
+
│ │ └─────────────┼───────────┘ │ │
|
|
680
|
+
│ │ │ │ │
|
|
681
|
+
│ │ Unified Internal Model │ │
|
|
682
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
683
|
+
│ │ │
|
|
684
|
+
│ Internal MAP │
|
|
685
|
+
│ │
|
|
686
|
+
└─────────────────────────────────────────────────────────┘
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
Each adapter translates between MAP's internal message model and the external protocol:
|
|
690
|
+
- **MAP adapter**: Pass-through (native)
|
|
691
|
+
- **A2A adapter**: Translates MAP messages ↔ A2A Tasks, MAP agents ↔ A2A Agent Cards
|
|
692
|
+
- **ACP adapter**: Translates MAP messages ↔ ACP sessions/events
|
|
693
|
+
|
|
694
|
+
### Backwards Compatibility
|
|
695
|
+
|
|
696
|
+
If `protocols` is omitted from `map/federation/connect`, the server assumes MAP-only (current behavior). This makes the feature fully backwards-compatible.
|
|
697
|
+
|
|
698
|
+
### Scope Limitation
|
|
699
|
+
|
|
700
|
+
This proposal defines the **negotiation mechanism** only. The actual protocol adapters (A2A ↔ MAP translation, ACP ↔ MAP translation) are implementation concerns, not protocol spec. The spec only needs to define:
|
|
701
|
+
1. How protocols are advertised during connection
|
|
702
|
+
2. How a protocol is selected
|
|
703
|
+
3. Error handling when no common protocol exists
|
|
704
|
+
|
|
705
|
+
### Impacts
|
|
706
|
+
|
|
707
|
+
- **`docs/07-federation.md`**: Add meta-protocol negotiation section
|
|
708
|
+
- **`docs/02-wire-protocol.md`**: Document `protocols` field in federation connect
|
|
709
|
+
- **`ts-sdk/src/federation/`**: Add protocol negotiation logic
|
|
710
|
+
- **`ts-sdk/src/server/federation/`**: Extensible adapter pattern in gateway
|
|
711
|
+
|
|
712
|
+
### Open Questions
|
|
713
|
+
|
|
714
|
+
1. **Adapter specification**: Should the protocol define any normative mappings (e.g., how MAP messages map to A2A tasks)?
|
|
715
|
+
2. **Runtime protocol switching**: Can peers switch protocols mid-federation, or is it fixed at connection time?
|
|
716
|
+
3. **Protocol capability intersection**: If two protocols are supported but with different capability subsets, how is this communicated?
|
|
717
|
+
|
|
718
|
+
---
|
|
719
|
+
|
|
720
|
+
## Proposal 5: Privacy Through Multi-Identity for Federation
|
|
721
|
+
|
|
722
|
+
### Status: 🟢 Deferrable — Can resolve in later versions
|
|
723
|
+
|
|
724
|
+
### Problem
|
|
725
|
+
|
|
726
|
+
MAP agents currently have a single, system-wide `id`. When interacting with multiple federated systems, this creates privacy concerns:
|
|
727
|
+
- A federated peer can correlate agent activity across interactions
|
|
728
|
+
- Internal agent identifiers leak organizational structure
|
|
729
|
+
- There's no way for an agent to present different identities to different peers
|
|
730
|
+
|
|
731
|
+
ANP addresses this by supporting agents with **multiple DIDs** for different interaction contexts, with periodic rotation.
|
|
732
|
+
|
|
733
|
+
### Proposal
|
|
734
|
+
|
|
735
|
+
Introduce **federation aliases**: context-specific identities that agents can present to different federated peers. Internally, the system maintains the mapping; externally, each peer sees only the alias assigned to them.
|
|
736
|
+
|
|
737
|
+
#### Architecture
|
|
738
|
+
|
|
739
|
+
```
|
|
740
|
+
┌───────────────────────────────────────────────────────────────┐
|
|
741
|
+
│ MAP System (Internal) │
|
|
742
|
+
│ │
|
|
743
|
+
│ agent_worker_01 ───────────────────────────────── │
|
|
744
|
+
│ (internal id) │ │ │
|
|
745
|
+
│ │ Alias Registry │ │
|
|
746
|
+
│ │ │ │
|
|
747
|
+
│ ├─► peer-alpha: "proc-7f3a" │ │
|
|
748
|
+
│ ├─► peer-beta: "handler-9e1c" │ │
|
|
749
|
+
│ └─► peer-gamma: "agent-2b8d" │ │
|
|
750
|
+
│ │
|
|
751
|
+
│ Gateway translates internal IDs ↔ aliases per peer │
|
|
752
|
+
└───────────────────────────────────────────────────────────────┘
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
#### Wire Protocol Types
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
interface MAPFederationAliasConfig {
|
|
759
|
+
/** Enable context-specific identities for federation */
|
|
760
|
+
aliasing: {
|
|
761
|
+
enabled: boolean;
|
|
762
|
+
|
|
763
|
+
/** Strategy for generating aliases */
|
|
764
|
+
strategy: "random" | "deterministic" | "manual";
|
|
765
|
+
|
|
766
|
+
/** How often to rotate aliases (0 = never) */
|
|
767
|
+
rotationIntervalMs?: number;
|
|
768
|
+
|
|
769
|
+
/** Alias format template (e.g., "agent-{random}") */
|
|
770
|
+
format?: string;
|
|
771
|
+
|
|
772
|
+
/** Per-peer alias overrides */
|
|
773
|
+
peerOverrides?: Record<string, {
|
|
774
|
+
/** Explicit alias for this peer */
|
|
775
|
+
alias?: string;
|
|
776
|
+
|
|
777
|
+
/** Use real ID for this peer (trusted peer) */
|
|
778
|
+
transparent?: boolean;
|
|
779
|
+
}>;
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
#### Extended Federation Exposure
|
|
785
|
+
|
|
786
|
+
```typescript
|
|
787
|
+
interface MAPFederationExposure {
|
|
788
|
+
agents: {
|
|
789
|
+
expose: "none" | "gateway" | "tagged" | "all";
|
|
790
|
+
tags?: string[];
|
|
791
|
+
|
|
792
|
+
/** NEW: Identity presentation strategy */
|
|
793
|
+
identity: "real" | "alias" | "per-peer-alias";
|
|
794
|
+
};
|
|
795
|
+
// ... existing fields ...
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
#### Gateway Alias Translation
|
|
800
|
+
|
|
801
|
+
The gateway agent (already responsible for federation routing per `docs/07-federation.md`) handles alias translation transparently:
|
|
802
|
+
|
|
803
|
+
```
|
|
804
|
+
Outbound (internal → federated):
|
|
805
|
+
message.from: "agent_worker_01" → "proc-7f3a" (alias for peer-alpha)
|
|
806
|
+
|
|
807
|
+
Inbound (federated → internal):
|
|
808
|
+
message.to: "proc-7f3a" → "agent_worker_01" (resolve alias)
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
#### Alias Rotation
|
|
812
|
+
|
|
813
|
+
When aliases rotate, the gateway:
|
|
814
|
+
1. Generates new alias
|
|
815
|
+
2. Starts accepting both old and new alias (grace period)
|
|
816
|
+
3. Uses new alias for outbound messages
|
|
817
|
+
4. After grace period, stops accepting old alias
|
|
818
|
+
|
|
819
|
+
```typescript
|
|
820
|
+
interface MAPAliasRotationEvent {
|
|
821
|
+
/** Peer this rotation applies to */
|
|
822
|
+
peerId: string;
|
|
823
|
+
|
|
824
|
+
/** Agent being rotated */
|
|
825
|
+
agentId: string;
|
|
826
|
+
|
|
827
|
+
/** Previous alias (will expire after grace period) */
|
|
828
|
+
previousAlias: string;
|
|
829
|
+
|
|
830
|
+
/** New alias (now active) */
|
|
831
|
+
newAlias: string;
|
|
832
|
+
|
|
833
|
+
/** When the previous alias stops being accepted */
|
|
834
|
+
previousAliasExpiresAt: number;
|
|
835
|
+
}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
### Security Properties
|
|
839
|
+
|
|
840
|
+
| Property | Without Aliases | With Aliases |
|
|
841
|
+
|----------|----------------|--------------|
|
|
842
|
+
| Cross-peer correlation | Trivial (same ID) | Prevented (different alias per peer) |
|
|
843
|
+
| Internal structure leakage | Possible (ID patterns) | Prevented (random aliases) |
|
|
844
|
+
| Activity tracking across rotation | Continuous | Broken at rotation boundaries |
|
|
845
|
+
| Trusted peer exception | N/A | Configurable per-peer |
|
|
846
|
+
|
|
847
|
+
### Relationship to DID Identity (Proposal 1)
|
|
848
|
+
|
|
849
|
+
When using `did:wba` authentication (Proposal 1), aliases can be implemented as **derived DIDs** — sub-identities under the system's DID that can be independently verified but can't be correlated to each other without the system's cooperation.
|
|
850
|
+
|
|
851
|
+
### Impacts
|
|
852
|
+
|
|
853
|
+
- **`docs/07-federation.md`**: Add alias configuration to federation model
|
|
854
|
+
- **`docs/06-visibility-permissions.md`**: Document alias as a visibility layer
|
|
855
|
+
- **`ts-sdk/src/federation/`**: Add alias registry, translation in envelope handling
|
|
856
|
+
- **`ts-sdk/src/server/federation/`**: Gateway alias management
|
|
857
|
+
|
|
858
|
+
### Open Questions
|
|
859
|
+
|
|
860
|
+
1. **Alias persistence**: Should aliases survive system restarts? (Probably yes, to maintain peer relationships.)
|
|
861
|
+
2. **Correlation resistance**: Should the system actively prevent timing-based correlation (e.g., jittering message delivery)?
|
|
862
|
+
3. **Alias in events**: When a federated peer subscribes to events, do events use aliases? (Yes — gateway translates.)
|
|
863
|
+
|
|
864
|
+
---
|
|
865
|
+
|
|
866
|
+
## Proposal 6: Single-Request Federation Authentication
|
|
867
|
+
|
|
868
|
+
### Status: ✅ Implemented — See `ts-sdk/src/server/federation/handlers.ts` and `ts-sdk/src/federation/challenge.ts`
|
|
869
|
+
|
|
870
|
+
### Problem
|
|
871
|
+
|
|
872
|
+
MAP's current federation authentication can require multiple round trips:
|
|
873
|
+
1. `map/federation/connect` → server returns `authRequired` with supported methods
|
|
874
|
+
2. `map/authenticate` → client provides credentials
|
|
875
|
+
3. Server verifies → returns session
|
|
876
|
+
|
|
877
|
+
For federation connections that traverse the internet (potentially high latency), this multi-round-trip flow adds significant connection setup time. When federating across many peers or re-establishing connections after outages, this compounds.
|
|
878
|
+
|
|
879
|
+
ANP's `did:wba` auth completes in a single HTTP request: the client sends DID + cryptographic proof in the initial request headers, and the server resolves and verifies in one step.
|
|
880
|
+
|
|
881
|
+
### Proposal
|
|
882
|
+
|
|
883
|
+
Optimize MAP's federation connect to support **single-request authentication** — the peer provides all credentials in the initial `map/federation/connect` request, and the server completes auth without requiring a separate `map/authenticate` step.
|
|
884
|
+
|
|
885
|
+
#### Current Flow (Multi-Round-Trip)
|
|
886
|
+
|
|
887
|
+
```
|
|
888
|
+
Peer A Peer B
|
|
889
|
+
│ │
|
|
890
|
+
│── federation/connect ────────────────►│ RTT 1
|
|
891
|
+
│◄── authRequired { methods } ─────────│
|
|
892
|
+
│ │
|
|
893
|
+
│── authenticate { credential } ───────►│ RTT 2
|
|
894
|
+
│◄── { success, session } ─────────────│
|
|
895
|
+
│ │
|
|
896
|
+
│── subscribe / send ──────────────────►│ RTT 3
|
|
897
|
+
│ │
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
#### Proposed Flow (Single-Request)
|
|
901
|
+
|
|
902
|
+
```
|
|
903
|
+
Peer A Peer B
|
|
904
|
+
│ │
|
|
905
|
+
│── federation/connect ────────────────►│ RTT 1
|
|
906
|
+
│ { systemId, auth, exposure, ... } │
|
|
907
|
+
│ │
|
|
908
|
+
│◄── { session, principal, ... } ───────│
|
|
909
|
+
│ │
|
|
910
|
+
│── subscribe / send ──────────────────►│ RTT 2
|
|
911
|
+
│ │
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
#### Wire Protocol Changes
|
|
915
|
+
|
|
916
|
+
The `map/federation/connect` request already supports an `auth` field (see `docs/07-federation.md` line 135). The change is to make the server:
|
|
917
|
+
1. **Attempt authentication immediately** if `auth` is provided in `connect`
|
|
918
|
+
2. **Only fall back to negotiation** if `auth` is absent or fails with a recoverable error
|
|
919
|
+
|
|
920
|
+
```typescript
|
|
921
|
+
// Federation connect - enhanced auth handling
|
|
922
|
+
interface MAPFederationConnectParams {
|
|
923
|
+
systemId: string;
|
|
924
|
+
systemInfo: { name: string; version: string; endpoint: string };
|
|
925
|
+
protocolVersion: string;
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* Authentication credentials.
|
|
929
|
+
* If provided, server SHOULD attempt auth immediately (single-request flow).
|
|
930
|
+
* If omitted, server returns authRequired (negotiation flow).
|
|
931
|
+
*/
|
|
932
|
+
auth?: MAPFederationAuth;
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* NEW: Pre-fetched server auth requirements.
|
|
936
|
+
* Client can include this to signal it already knows the server's
|
|
937
|
+
* requirements (e.g., from .well-known discovery document).
|
|
938
|
+
*/
|
|
939
|
+
authContext?: {
|
|
940
|
+
/** How the client learned the server's auth requirements */
|
|
941
|
+
source: "well-known" | "cached" | "configured";
|
|
942
|
+
|
|
943
|
+
/** The server's nonce/challenge (if pre-fetched) */
|
|
944
|
+
challenge?: string;
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
exposure: MAPFederationExposure;
|
|
948
|
+
}
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
#### Response Variants
|
|
952
|
+
|
|
953
|
+
```typescript
|
|
954
|
+
// Success (single-request auth completed)
|
|
955
|
+
{
|
|
956
|
+
"jsonrpc": "2.0",
|
|
957
|
+
"id": 1,
|
|
958
|
+
"result": {
|
|
959
|
+
"sessionId": "fed_session_01ABC",
|
|
960
|
+
"principal": {
|
|
961
|
+
"id": "did:wba:alpha.example.com:gateway",
|
|
962
|
+
"claims": { ... }
|
|
963
|
+
},
|
|
964
|
+
"capabilities": { ... }
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Auth required (fallback to negotiation)
|
|
969
|
+
{
|
|
970
|
+
"jsonrpc": "2.0",
|
|
971
|
+
"id": 1,
|
|
972
|
+
"result": {
|
|
973
|
+
"authRequired": {
|
|
974
|
+
"methods": ["did:wba", "bearer", "mtls"],
|
|
975
|
+
"challenge": "nonce_abc123", // For did:wba proof
|
|
976
|
+
"required": true
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// Auth failed (non-recoverable)
|
|
982
|
+
{
|
|
983
|
+
"jsonrpc": "2.0",
|
|
984
|
+
"id": 1,
|
|
985
|
+
"error": {
|
|
986
|
+
"code": -32001,
|
|
987
|
+
"message": "Authentication failed",
|
|
988
|
+
"data": {
|
|
989
|
+
"authError": { "code": "invalid_credentials", "message": "..." }
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
```
|
|
994
|
+
|
|
995
|
+
#### Challenge Pre-Fetch via Discovery
|
|
996
|
+
|
|
997
|
+
The `.well-known/map-federation` endpoint (Proposal 2) can include a challenge endpoint:
|
|
998
|
+
|
|
999
|
+
```json
|
|
1000
|
+
{
|
|
1001
|
+
"systemId": "beta-prod",
|
|
1002
|
+
"authMethods": ["did:wba", "bearer"],
|
|
1003
|
+
"challengeEndpoint": "https://beta.example.com/map/federation/challenge"
|
|
1004
|
+
}
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
A peer can pre-fetch a challenge nonce before connecting, enabling `did:wba` single-request auth:
|
|
1008
|
+
|
|
1009
|
+
```
|
|
1010
|
+
1. GET /.well-known/map-federation → learn auth methods
|
|
1011
|
+
2. GET /map/federation/challenge → get nonce
|
|
1012
|
+
3. Connect with auth { did, proof: sign(nonce) } → single RTT
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
### Backwards Compatibility
|
|
1016
|
+
|
|
1017
|
+
This is fully backwards-compatible:
|
|
1018
|
+
- If `auth` is omitted from `connect`, the existing negotiation flow is used
|
|
1019
|
+
- If a server doesn't support single-request auth, it can ignore `auth` and return `authRequired`
|
|
1020
|
+
- The `authContext` field is optional and informational
|
|
1021
|
+
|
|
1022
|
+
### Performance Impact
|
|
1023
|
+
|
|
1024
|
+
| Scenario | Current | Proposed |
|
|
1025
|
+
|----------|---------|----------|
|
|
1026
|
+
| Federation connect (known auth) | 2 RTT | 1 RTT |
|
|
1027
|
+
| Federation connect (unknown auth) | 2 RTT | 2 RTT (unchanged) |
|
|
1028
|
+
| Reconnection after outage | 2 RTT | 1 RTT |
|
|
1029
|
+
| Bulk federation (10 peers) | 20 RTT | 10 RTT |
|
|
1030
|
+
|
|
1031
|
+
For cross-region federation (e.g., 100ms RTT), saving 1 RTT per connection saves 1 second across 10 peers.
|
|
1032
|
+
|
|
1033
|
+
### Impacts
|
|
1034
|
+
|
|
1035
|
+
- **`docs/07-federation.md`**: Document single-request auth flow
|
|
1036
|
+
- **`docs/09-authentication.md`**: Add federation-specific single-request pattern
|
|
1037
|
+
- **`ts-sdk/src/federation/`**: Update connection logic to attempt auth in connect
|
|
1038
|
+
- **`ts-sdk/src/server/federation/`**: Handle auth in connect handler
|
|
1039
|
+
|
|
1040
|
+
---
|
|
1041
|
+
|
|
1042
|
+
## Implementation Priority
|
|
1043
|
+
|
|
1044
|
+
| # | Proposal | Status | Effort | Value |
|
|
1045
|
+
|---|----------|--------|--------|-------|
|
|
1046
|
+
| 6 | Single-Request Federation Auth | 🟡 Important | Low | High — immediate perf win, backwards-compatible |
|
|
1047
|
+
| 1 | `did:wba` Decentralized Identity | 🟡 Important | High | High — unlocks scalable federation |
|
|
1048
|
+
| 3 | Linked Capability Documents | 🟡 Important | Medium | High — enables dynamic orchestration |
|
|
1049
|
+
| 2 | `.well-known` Discovery | 🟢 Deferrable | Low | Medium — zero-config federation |
|
|
1050
|
+
| 5 | Multi-Identity Privacy | 🟢 Deferrable | Medium | Medium — important for cross-org scenarios |
|
|
1051
|
+
| 4 | Meta-Protocol Negotiation | 🟢 Deferrable | Medium | Low-Medium — future-proofing |
|
|
1052
|
+
|
|
1053
|
+
### Recommended Approach
|
|
1054
|
+
|
|
1055
|
+
**Phase 1** (v1.0): Proposals 6 and 3
|
|
1056
|
+
- Single-request auth is a small, backwards-compatible optimization
|
|
1057
|
+
- Capability descriptors improve the existing agent model without changing wire protocol
|
|
1058
|
+
|
|
1059
|
+
**Phase 2** (v1.x): Proposals 1 and 2
|
|
1060
|
+
- `did:wba` and `.well-known` discovery work together as a federation identity stack
|
|
1061
|
+
- Requires more design work and dependency on W3C DID standards
|
|
1062
|
+
|
|
1063
|
+
**Phase 3** (v2.0 consideration): Proposals 4 and 5
|
|
1064
|
+
- Meta-protocol negotiation and multi-identity are forward-looking
|
|
1065
|
+
- May benefit from real-world federation deployment experience before finalizing
|
|
1066
|
+
|
|
1067
|
+
---
|
|
1068
|
+
|
|
1069
|
+
## References
|
|
1070
|
+
|
|
1071
|
+
- [W3C CG AI Agent Protocol (ANP)](https://github.com/w3c-cg/ai-agent-protocol) — Source of inspiration
|
|
1072
|
+
- [DID Core Specification](https://www.w3.org/TR/did-core/) — W3C standard for Decentralized Identifiers
|
|
1073
|
+
- [did:wba Method Specification](https://github.com/anthropics/anp-spec) — Web-Based Agent DID method
|
|
1074
|
+
- [RFC 8615](https://tools.ietf.org/html/rfc8615) — Well-Known URIs
|
|
1075
|
+
- MAP Specs:
|
|
1076
|
+
- `docs/07-federation.md` — Current federation design
|
|
1077
|
+
- `docs/09-authentication.md` — Current auth design
|
|
1078
|
+
- `docs/06-visibility-permissions.md` — Visibility/permission model
|
|
1079
|
+
- `docs/01-open-questions.md` — Open questions (Q6.2 addressed here)
|