agent-passport-system-mcp 2.5.0 → 2.7.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.
- package/CODE_OF_CONDUCT.md +36 -0
- package/CONTRIBUTING.md +58 -0
- package/README.md +34 -2
- package/build/index.js +451 -1
- package/package.json +5 -3
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We are committed to making participation in this project a welcoming experience for everyone.
|
|
6
|
+
|
|
7
|
+
## Standards
|
|
8
|
+
|
|
9
|
+
Examples of positive behavior:
|
|
10
|
+
|
|
11
|
+
- Using inclusive language
|
|
12
|
+
- Being respectful of differing viewpoints
|
|
13
|
+
- Accepting constructive feedback gracefully
|
|
14
|
+
- Focusing on what is best for the community
|
|
15
|
+
|
|
16
|
+
Examples of unacceptable behavior:
|
|
17
|
+
|
|
18
|
+
- Personal attacks or derogatory comments
|
|
19
|
+
- Publishing others' private information without permission
|
|
20
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
21
|
+
|
|
22
|
+
## Responsibilities
|
|
23
|
+
|
|
24
|
+
Project maintainers are responsible for clarifying standards of acceptable behavior and are expected to take fair corrective action in response to any instances of unacceptable behavior.
|
|
25
|
+
|
|
26
|
+
## Scope
|
|
27
|
+
|
|
28
|
+
This Code of Conduct applies within all project spaces, including issues, pull requests, and community discussions.
|
|
29
|
+
|
|
30
|
+
## Enforcement
|
|
31
|
+
|
|
32
|
+
Instances of unacceptable behavior may be reported by contacting the project maintainer. All reports will be reviewed and investigated promptly and fairly.
|
|
33
|
+
|
|
34
|
+
## Attribution
|
|
35
|
+
|
|
36
|
+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Contributing to Agent Passport System MCP Server
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! This is the MCP server for the [Agent Passport System](https://github.com/aeoess/agent-passport-system) — 49 tools across 8 protocol layers for AI agent identity, trust, governance, and commerce.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork: `git clone https://github.com/<your-username>/agent-passport-mcp.git`
|
|
9
|
+
3. Install dependencies: `npm install --include=dev`
|
|
10
|
+
4. Build the project: `npm run build`
|
|
11
|
+
|
|
12
|
+
## Development
|
|
13
|
+
|
|
14
|
+
The MCP server is a single-file TypeScript implementation (`src/index.ts`) that wraps the Agent Passport System SDK. All protocol logic lives in the SDK; this repo provides the MCP tool interface.
|
|
15
|
+
|
|
16
|
+
### Building
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Build must succeed with zero TypeScript errors before submitting a PR.
|
|
23
|
+
|
|
24
|
+
### Code Style
|
|
25
|
+
|
|
26
|
+
- TypeScript throughout
|
|
27
|
+
- Single-file architecture (`src/index.ts`)
|
|
28
|
+
- Each MCP tool follows the same pattern: validation, SDK call, JSON response
|
|
29
|
+
- Use `zod` for input validation
|
|
30
|
+
|
|
31
|
+
## Submitting Changes
|
|
32
|
+
|
|
33
|
+
1. Create a feature branch from `main`
|
|
34
|
+
2. Make your changes with clear, descriptive commits
|
|
35
|
+
3. Ensure `npm run build` succeeds with zero errors
|
|
36
|
+
4. Open a pull request with a description of what you changed and why
|
|
37
|
+
|
|
38
|
+
## Reporting Issues
|
|
39
|
+
|
|
40
|
+
Open an issue on GitHub with:
|
|
41
|
+
|
|
42
|
+
- A clear title and description
|
|
43
|
+
- Steps to reproduce (if applicable)
|
|
44
|
+
- Expected vs actual behavior
|
|
45
|
+
- Your environment (Node.js version, OS, MCP client)
|
|
46
|
+
|
|
47
|
+
## Adding New Tools
|
|
48
|
+
|
|
49
|
+
If you're adding new MCP tools, follow the existing pattern in `src/index.ts`:
|
|
50
|
+
|
|
51
|
+
1. Add the SDK import
|
|
52
|
+
2. Register the tool with `server.tool()` including zod schema
|
|
53
|
+
3. Update the README tool table
|
|
54
|
+
4. Update the tool count in the README header
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
By contributing, you agree that your contributions will be licensed under the project's Apache-2.0 license.
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
MCP server for the [Agent Passport System](https://github.com/aeoess/agent-passport-system) — cryptographic identity, delegation, governance, and commerce for AI agents.
|
|
10
10
|
|
|
11
|
-
**
|
|
11
|
+
**61 tools** across all 16 protocol modules. Works with any MCP client: Claude Desktop, Cursor, Windsurf, and more.
|
|
12
12
|
|
|
13
13
|
## Quick Start
|
|
14
14
|
|
|
@@ -148,6 +148,38 @@ Add to your MCP config:
|
|
|
148
148
|
| `create_disclosure` | Selective disclosure of principal identity (public/verified-only/minimal) |
|
|
149
149
|
| `get_fleet_status` | Status of all agents endorsed by the current principal |
|
|
150
150
|
|
|
151
|
+
### Reputation-Gated Authority — 5 tools
|
|
152
|
+
|
|
153
|
+
| Tool | Description |
|
|
154
|
+
|------|-------------|
|
|
155
|
+
| `resolve_authority` | Compute effective reputation score and authority tier for an agent |
|
|
156
|
+
| `check_tier` | Check if agent's earned tier permits action at given autonomy/spend |
|
|
157
|
+
| `review_promotion` | Create signed promotion review (earned-only reviewers, no self-promotion) |
|
|
158
|
+
| `update_reputation` | Bayesian (mu, sigma) updates from task results |
|
|
159
|
+
| `get_promotion_history` | List all promotion reviews this session |
|
|
160
|
+
|
|
161
|
+
### Proxy Gateway — 6 tools
|
|
162
|
+
|
|
163
|
+
| Tool | Description |
|
|
164
|
+
|------|-------------|
|
|
165
|
+
| `gateway_create` | Create a ProxyGateway with enforcement config and tool executor |
|
|
166
|
+
| `gateway_register_agent` | Register agent (passport + attestation + delegations) with gateway |
|
|
167
|
+
| `gateway_process` | Execute tool call through full enforcement pipeline (identity → scope → policy → execute → receipt) |
|
|
168
|
+
| `gateway_approve` | Two-phase: approve request without executing (returns approval token) |
|
|
169
|
+
| `gateway_execute` | Two-phase: execute previously approved request (rechecks revocation) |
|
|
170
|
+
| `gateway_stats` | Get gateway counters (requests, permits, denials, replays, revocation rechecks) |
|
|
171
|
+
|
|
172
|
+
### Intent Network (Agent-Mediated Matching) — 6 tools
|
|
173
|
+
|
|
174
|
+
| Tool | Description |
|
|
175
|
+
|------|-------------|
|
|
176
|
+
| `publish_intent_card` | Publish what your human needs, offers, and is open to. Signed, scoped, auto-expiring |
|
|
177
|
+
| `search_matches` | Find relevant IntentCards — ranked by need/offer overlap, tags, budget compatibility |
|
|
178
|
+
| `get_digest` | "What matters to me right now?" — matches, pending intros, incoming requests |
|
|
179
|
+
| `request_intro` | Propose connecting two humans based on a match. Both sides must approve |
|
|
180
|
+
| `respond_to_intro` | Approve or decline an introduction request |
|
|
181
|
+
| `remove_intent_card` | Remove your card when needs/offers change |
|
|
182
|
+
|
|
151
183
|
## Architecture
|
|
152
184
|
|
|
153
185
|
```
|
|
@@ -163,7 +195,7 @@ Layer 1 — Agent Passport Protocol (Ed25519 identity)
|
|
|
163
195
|
|
|
164
196
|
## Links
|
|
165
197
|
|
|
166
|
-
- npm SDK: [agent-passport-system](https://www.npmjs.com/package/agent-passport-system) (v1.
|
|
198
|
+
- npm SDK: [agent-passport-system](https://www.npmjs.com/package/agent-passport-system) (v1.13.0, 534 tests)
|
|
167
199
|
- Python SDK: [agent-passport-system](https://pypi.org/project/agent-passport-system/) (v0.4.0, 86 tests)
|
|
168
200
|
- Paper: [doi.org/10.5281/zenodo.18749779](https://doi.org/10.5281/zenodo.18749779)
|
|
169
201
|
- Docs: [aeoess.com/llms-full.txt](https://aeoess.com/llms-full.txt)
|
package/build/index.js
CHANGED
|
@@ -33,7 +33,9 @@ commercePreflight, createCommerceDelegation, getSpendSummary, requestHumanApprov
|
|
|
33
33
|
// Principal Identity
|
|
34
34
|
createPrincipalIdentity, endorseAgent, verifyEndorsement, revokeEndorsement, createDisclosure, createFleet, addToFleet, getFleetStatus, revokeFromFleet,
|
|
35
35
|
// Reputation-Gated Authority (Layer 9)
|
|
36
|
-
computeEffectiveScore, createScopedReputation, resolveAuthorityTier, checkTierForIntent, advisoryTierPrecheck, createPromotionReview, updateReputationFromResult, DEFAULT_TIERS,
|
|
36
|
+
computeEffectiveScore, createScopedReputation, resolveAuthorityTier, checkTierForIntent, advisoryTierPrecheck, createPromotionReview, updateReputationFromResult, DEFAULT_TIERS, createProxyGateway,
|
|
37
|
+
// Intent Network (Agent-Mediated Matching)
|
|
38
|
+
createIntentNetwork, createIntentCard, publishCard, removeCard, searchMatches, requestIntro, respondToIntro, getDigest, } from "agent-passport-system";
|
|
37
39
|
// ═══════════════════════════════════════
|
|
38
40
|
// State Management
|
|
39
41
|
// ═══════════════════════════════════════
|
|
@@ -64,6 +66,9 @@ const state = {
|
|
|
64
66
|
fleet: null,
|
|
65
67
|
reputations: new Map(),
|
|
66
68
|
promotionHistory: [],
|
|
69
|
+
gateway: null,
|
|
70
|
+
gatewayKeys: null,
|
|
71
|
+
intentNetwork: createIntentNetwork(),
|
|
67
72
|
};
|
|
68
73
|
// Load persisted task state
|
|
69
74
|
function loadTasks() {
|
|
@@ -2112,6 +2117,451 @@ server.tool("get_promotion_history", "Get the promotion review history for this
|
|
|
2112
2117
|
};
|
|
2113
2118
|
});
|
|
2114
2119
|
// ═══════════════════════════════════════
|
|
2120
|
+
// Proxy Gateway (Enforcement Boundary)
|
|
2121
|
+
// ═══════════════════════════════════════
|
|
2122
|
+
server.tool("create_gateway", "Create a ProxyGateway enforcement boundary. The gateway validates identity, delegation scope, policy compliance, and provides replay protection for every tool call. Returns gateway ID and public key.", {
|
|
2123
|
+
gatewayId: z.string().optional().describe("Custom gateway ID (auto-generated if omitted)"),
|
|
2124
|
+
approvalTTLSeconds: z.number().optional().describe("Two-phase approval timeout in seconds (default: 300)"),
|
|
2125
|
+
maxPendingPerAgent: z.number().optional().describe("Max pending approvals per agent (default: 10)"),
|
|
2126
|
+
}, async ({ gatewayId, approvalTTLSeconds, maxPendingPerAgent }) => {
|
|
2127
|
+
const keys = generateKeyPair();
|
|
2128
|
+
const id = gatewayId || `gateway-${Date.now().toString(36)}`;
|
|
2129
|
+
if (!state.floor) {
|
|
2130
|
+
return { content: [{ type: "text", text: "Error: Load a Values Floor first (load_values_floor)" }] };
|
|
2131
|
+
}
|
|
2132
|
+
const config = {
|
|
2133
|
+
gatewayId: id,
|
|
2134
|
+
gatewayPublicKey: keys.publicKey,
|
|
2135
|
+
gatewayPrivateKey: keys.privateKey,
|
|
2136
|
+
floor: state.floor,
|
|
2137
|
+
approvalTTLSeconds: approvalTTLSeconds ?? 300,
|
|
2138
|
+
maxPendingPerAgent: maxPendingPerAgent ?? 10,
|
|
2139
|
+
recheckRevocationOnExecute: true,
|
|
2140
|
+
};
|
|
2141
|
+
// Default executor echoes tool calls — real execution is done by MCP client
|
|
2142
|
+
const executor = async (tool, params) => {
|
|
2143
|
+
return { success: true, result: { tool, params, executedVia: 'mcp-gateway' } };
|
|
2144
|
+
};
|
|
2145
|
+
state.gateway = createProxyGateway(config, executor);
|
|
2146
|
+
state.gatewayKeys = keys;
|
|
2147
|
+
return {
|
|
2148
|
+
content: [{
|
|
2149
|
+
type: "text",
|
|
2150
|
+
text: JSON.stringify({
|
|
2151
|
+
created: true,
|
|
2152
|
+
gatewayId: id,
|
|
2153
|
+
publicKey: keys.publicKey,
|
|
2154
|
+
approvalTTLSeconds: config.approvalTTLSeconds,
|
|
2155
|
+
maxPendingPerAgent: config.maxPendingPerAgent,
|
|
2156
|
+
note: "Gateway ready. Register agents with register_gateway_agent, then process calls with gateway_process_tool_call.",
|
|
2157
|
+
}, null, 2),
|
|
2158
|
+
}],
|
|
2159
|
+
};
|
|
2160
|
+
});
|
|
2161
|
+
server.tool("register_gateway_agent", "Register an agent with the gateway. The agent must have a valid passport and floor attestation. Delegations define what scopes the agent can use through the gateway.", {
|
|
2162
|
+
agentId: z.string().describe("Agent ID to register"),
|
|
2163
|
+
}, async ({ agentId }) => {
|
|
2164
|
+
if (!state.gateway) {
|
|
2165
|
+
return { content: [{ type: "text", text: "Error: Create gateway first (create_gateway)" }] };
|
|
2166
|
+
}
|
|
2167
|
+
const agent = state.agents.get(agentId);
|
|
2168
|
+
if (!agent) {
|
|
2169
|
+
return { content: [{ type: "text", text: `Error: Agent "${agentId}" not found in session. Join social contract first.` }] };
|
|
2170
|
+
}
|
|
2171
|
+
const agentDelegations = Array.from(state.delegations.values()).filter(d => d.delegatedTo === agent.publicKey);
|
|
2172
|
+
if (agentDelegations.length === 0) {
|
|
2173
|
+
return { content: [{ type: "text", text: `Error: No delegations found for agent "${agentId}". Create a delegation first.` }] };
|
|
2174
|
+
}
|
|
2175
|
+
if (!agent.attestation) {
|
|
2176
|
+
return { content: [{ type: "text", text: `Error: Agent "${agentId}" has no floor attestation. Attest to floor first.` }] };
|
|
2177
|
+
}
|
|
2178
|
+
state.gateway.registerAgent(agent.passport, agent.attestation, agentDelegations);
|
|
2179
|
+
return {
|
|
2180
|
+
content: [{
|
|
2181
|
+
type: "text",
|
|
2182
|
+
text: JSON.stringify({
|
|
2183
|
+
registered: true,
|
|
2184
|
+
agentId,
|
|
2185
|
+
delegationCount: agentDelegations.length,
|
|
2186
|
+
scopes: agentDelegations.flatMap(d => d.scope),
|
|
2187
|
+
}, null, 2),
|
|
2188
|
+
}],
|
|
2189
|
+
};
|
|
2190
|
+
});
|
|
2191
|
+
server.tool("gateway_process_tool_call", "Process a tool call through the gateway enforcement boundary. Validates identity, delegation, policy, and replay protection in a single atomic operation. Returns execution result with full 3-signature proof chain.", {
|
|
2192
|
+
agentId: z.string().describe("ID of the requesting agent"),
|
|
2193
|
+
tool: z.string().describe("Tool name to execute"),
|
|
2194
|
+
params: z.record(z.unknown()).optional().describe("Tool parameters"),
|
|
2195
|
+
scopeRequired: z.string().describe("Delegation scope needed for this tool"),
|
|
2196
|
+
spendAmount: z.number().optional().describe("Spend amount if commerce action"),
|
|
2197
|
+
spendCurrency: z.string().optional().describe("Currency code (e.g. USD)"),
|
|
2198
|
+
context: z.string().optional().describe("Human-readable context for audit"),
|
|
2199
|
+
}, async ({ agentId, tool, params, scopeRequired, spendAmount, spendCurrency, context }) => {
|
|
2200
|
+
if (!state.gateway) {
|
|
2201
|
+
return { content: [{ type: "text", text: "Error: Create gateway first (create_gateway)" }] };
|
|
2202
|
+
}
|
|
2203
|
+
const agent = state.agents.get(agentId);
|
|
2204
|
+
if (!agent) {
|
|
2205
|
+
return { content: [{ type: "text", text: `Error: Agent "${agentId}" not found in session.` }] };
|
|
2206
|
+
}
|
|
2207
|
+
const { canonicalize } = await import("agent-passport-system");
|
|
2208
|
+
const requestId = `mcp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2209
|
+
const payload = canonicalize({ requestId, agentId, tool, params: params || {}, scopeRequired, spend: spendAmount ? { amount: spendAmount, currency: spendCurrency || 'USD' } : undefined });
|
|
2210
|
+
const request = {
|
|
2211
|
+
requestId,
|
|
2212
|
+
agentId,
|
|
2213
|
+
agentPublicKey: agent.publicKey,
|
|
2214
|
+
signature: sign(payload, agent.keyPair.privateKey),
|
|
2215
|
+
tool,
|
|
2216
|
+
params: params || {},
|
|
2217
|
+
scopeRequired,
|
|
2218
|
+
spend: spendAmount ? { amount: spendAmount, currency: spendCurrency || 'USD' } : undefined,
|
|
2219
|
+
context,
|
|
2220
|
+
};
|
|
2221
|
+
const result = await state.gateway.processToolCall(request);
|
|
2222
|
+
return {
|
|
2223
|
+
content: [{
|
|
2224
|
+
type: "text",
|
|
2225
|
+
text: JSON.stringify({
|
|
2226
|
+
executed: result.executed,
|
|
2227
|
+
requestId: result.requestId,
|
|
2228
|
+
result: result.result ?? undefined,
|
|
2229
|
+
denialReason: result.denialReason ?? undefined,
|
|
2230
|
+
toolError: result.toolError ?? undefined,
|
|
2231
|
+
...(result.decision && { verdict: result.decision.verdict, reason: result.decision.reason }),
|
|
2232
|
+
...(result.proof && {
|
|
2233
|
+
proof: {
|
|
2234
|
+
hasRequestSignature: !!result.proof.requestSignature,
|
|
2235
|
+
hasDecisionSignature: !!result.proof.decisionSignature,
|
|
2236
|
+
hasReceiptSignature: !!result.proof.receiptSignature,
|
|
2237
|
+
policyReceiptId: result.proof.policyReceipt?.policyReceiptId,
|
|
2238
|
+
},
|
|
2239
|
+
}),
|
|
2240
|
+
...(result.receipt && {
|
|
2241
|
+
receipt: {
|
|
2242
|
+
receiptId: result.receipt.receiptId,
|
|
2243
|
+
agentId: result.receipt.agentId,
|
|
2244
|
+
action: result.receipt.action,
|
|
2245
|
+
},
|
|
2246
|
+
}),
|
|
2247
|
+
}, null, 2),
|
|
2248
|
+
}],
|
|
2249
|
+
};
|
|
2250
|
+
});
|
|
2251
|
+
server.tool("gateway_approve", "Two-phase execution: approve a tool call without executing it. Returns an approval ID that can be executed later with gateway_execute_approval. Useful for human-in-the-loop workflows.", {
|
|
2252
|
+
agentId: z.string().describe("ID of the requesting agent"),
|
|
2253
|
+
tool: z.string().describe("Tool name to approve"),
|
|
2254
|
+
params: z.record(z.unknown()).optional().describe("Tool parameters"),
|
|
2255
|
+
scopeRequired: z.string().describe("Delegation scope needed"),
|
|
2256
|
+
context: z.string().optional().describe("Human-readable context"),
|
|
2257
|
+
}, async ({ agentId, tool, params, scopeRequired, context }) => {
|
|
2258
|
+
if (!state.gateway) {
|
|
2259
|
+
return { content: [{ type: "text", text: "Error: Create gateway first (create_gateway)" }] };
|
|
2260
|
+
}
|
|
2261
|
+
const agent = state.agents.get(agentId);
|
|
2262
|
+
if (!agent) {
|
|
2263
|
+
return { content: [{ type: "text", text: `Error: Agent "${agentId}" not found in session.` }] };
|
|
2264
|
+
}
|
|
2265
|
+
const { canonicalize } = await import("agent-passport-system");
|
|
2266
|
+
const requestId = `mcp-approve-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2267
|
+
const payload = canonicalize({ requestId, agentId, tool, params: params || {}, scopeRequired, spend: undefined });
|
|
2268
|
+
const request = {
|
|
2269
|
+
requestId,
|
|
2270
|
+
agentId,
|
|
2271
|
+
agentPublicKey: agent.publicKey,
|
|
2272
|
+
signature: sign(payload, agent.keyPair.privateKey),
|
|
2273
|
+
tool,
|
|
2274
|
+
params: params || {},
|
|
2275
|
+
scopeRequired,
|
|
2276
|
+
context,
|
|
2277
|
+
};
|
|
2278
|
+
const result = state.gateway.approve(request);
|
|
2279
|
+
return {
|
|
2280
|
+
content: [{
|
|
2281
|
+
type: "text",
|
|
2282
|
+
text: JSON.stringify({
|
|
2283
|
+
approved: result.approved,
|
|
2284
|
+
...(result.approval && {
|
|
2285
|
+
approvalId: result.approval.approvalId,
|
|
2286
|
+
expiresAt: result.approval.expiresAt,
|
|
2287
|
+
nonce: result.approval.nonce,
|
|
2288
|
+
}),
|
|
2289
|
+
...(result.denial && { denial: result.denial }),
|
|
2290
|
+
}, null, 2),
|
|
2291
|
+
}],
|
|
2292
|
+
};
|
|
2293
|
+
});
|
|
2294
|
+
server.tool("gateway_execute_approval", "Execute a previously approved tool call. Rechecks delegation validity before execution — if delegation was revoked since approval, execution is denied.", {
|
|
2295
|
+
approvalId: z.string().describe("Approval ID from gateway_approve"),
|
|
2296
|
+
}, async ({ approvalId }) => {
|
|
2297
|
+
if (!state.gateway) {
|
|
2298
|
+
return { content: [{ type: "text", text: "Error: Create gateway first (create_gateway)" }] };
|
|
2299
|
+
}
|
|
2300
|
+
const result = await state.gateway.executeApproval(approvalId);
|
|
2301
|
+
return {
|
|
2302
|
+
content: [{
|
|
2303
|
+
type: "text",
|
|
2304
|
+
text: JSON.stringify({
|
|
2305
|
+
executed: result.executed,
|
|
2306
|
+
requestId: result.requestId,
|
|
2307
|
+
result: result.result ?? undefined,
|
|
2308
|
+
denialReason: result.denialReason ?? undefined,
|
|
2309
|
+
...(result.proof && {
|
|
2310
|
+
proof: {
|
|
2311
|
+
policyReceiptId: result.proof.policyReceipt?.policyReceiptId,
|
|
2312
|
+
},
|
|
2313
|
+
}),
|
|
2314
|
+
}, null, 2),
|
|
2315
|
+
}],
|
|
2316
|
+
};
|
|
2317
|
+
});
|
|
2318
|
+
server.tool("gateway_stats", "Get gateway statistics: total requests, permits, denials, replay attempts blocked, active agents, and pending approvals.", {}, async () => {
|
|
2319
|
+
if (!state.gateway) {
|
|
2320
|
+
return { content: [{ type: "text", text: "Error: Create gateway first (create_gateway)" }] };
|
|
2321
|
+
}
|
|
2322
|
+
return {
|
|
2323
|
+
content: [{
|
|
2324
|
+
type: "text",
|
|
2325
|
+
text: JSON.stringify(state.gateway.getStats(), null, 2),
|
|
2326
|
+
}],
|
|
2327
|
+
};
|
|
2328
|
+
});
|
|
2329
|
+
// ═══════════════════════════════════════
|
|
2330
|
+
// Intent Network (Agent-Mediated Matching)
|
|
2331
|
+
// ═══════════════════════════════════════
|
|
2332
|
+
server.tool("publish_intent_card", "Publish an IntentCard to the network. Represents what your human needs, offers, and is open to. Cards are signed, scoped, and expire automatically.", {
|
|
2333
|
+
principal_alias: z.string().describe("Human's display name or alias"),
|
|
2334
|
+
needs: z.array(z.object({
|
|
2335
|
+
category: z.string().describe("Category (e.g. 'engineering', 'design', 'funding')"),
|
|
2336
|
+
description: z.string().describe("What is needed"),
|
|
2337
|
+
priority: z.enum(["critical", "high", "medium", "low"]).default("medium"),
|
|
2338
|
+
tags: z.array(z.string()).optional(),
|
|
2339
|
+
budget_amount: z.number().optional(),
|
|
2340
|
+
budget_currency: z.string().optional(),
|
|
2341
|
+
})).optional().describe("What the human needs"),
|
|
2342
|
+
offers: z.array(z.object({
|
|
2343
|
+
category: z.string().describe("Category of what's offered"),
|
|
2344
|
+
description: z.string().describe("What is offered"),
|
|
2345
|
+
priority: z.enum(["critical", "high", "medium", "low"]).default("medium"),
|
|
2346
|
+
tags: z.array(z.string()).optional(),
|
|
2347
|
+
budget_amount: z.number().optional(),
|
|
2348
|
+
budget_currency: z.string().optional(),
|
|
2349
|
+
})).optional().describe("What the human offers"),
|
|
2350
|
+
open_to: z.array(z.string()).optional().describe("Categories open to (e.g. ['introductions', 'partnerships'])"),
|
|
2351
|
+
not_open_to: z.array(z.string()).optional().describe("Categories explicitly not open to"),
|
|
2352
|
+
approval_required: z.array(z.string()).optional().describe("What needs human approval before sharing"),
|
|
2353
|
+
visibility: z.enum(["public", "verified", "minimal"]).default("public"),
|
|
2354
|
+
ttl_hours: z.number().default(24).describe("Hours until card expires"),
|
|
2355
|
+
}, async (args) => {
|
|
2356
|
+
const keyErr = requireKey();
|
|
2357
|
+
if (keyErr)
|
|
2358
|
+
return { content: [{ type: "text", text: keyErr }], isError: true };
|
|
2359
|
+
const mapItem = (item) => ({
|
|
2360
|
+
category: item.category,
|
|
2361
|
+
description: item.description,
|
|
2362
|
+
priority: item.priority || 'medium',
|
|
2363
|
+
tags: item.tags || [],
|
|
2364
|
+
budget: item.budget_amount ? { amount: item.budget_amount, currency: item.budget_currency || 'USD' } : undefined,
|
|
2365
|
+
visibility: 'public',
|
|
2366
|
+
});
|
|
2367
|
+
const card = createIntentCard({
|
|
2368
|
+
agentId: state.agentId || 'anonymous',
|
|
2369
|
+
principalAlias: args.principal_alias,
|
|
2370
|
+
publicKey: state.agentKey,
|
|
2371
|
+
privateKey: state.privateKey,
|
|
2372
|
+
needs: (args.needs || []).map(mapItem),
|
|
2373
|
+
offers: (args.offers || []).map(mapItem),
|
|
2374
|
+
openTo: args.open_to || [],
|
|
2375
|
+
notOpenTo: args.not_open_to || [],
|
|
2376
|
+
approvalRequired: args.approval_required || [],
|
|
2377
|
+
ttlSeconds: (args.ttl_hours || 24) * 3600,
|
|
2378
|
+
});
|
|
2379
|
+
const result = publishCard(state.intentNetwork, card);
|
|
2380
|
+
if (!result.published) {
|
|
2381
|
+
return { content: [{ type: "text", text: `Failed to publish: ${result.error}` }], isError: true };
|
|
2382
|
+
}
|
|
2383
|
+
return {
|
|
2384
|
+
content: [{
|
|
2385
|
+
type: "text",
|
|
2386
|
+
text: JSON.stringify({
|
|
2387
|
+
published: true,
|
|
2388
|
+
cardId: card.cardId,
|
|
2389
|
+
agentId: card.agentId,
|
|
2390
|
+
principalAlias: card.principalAlias,
|
|
2391
|
+
needs: card.needs.length,
|
|
2392
|
+
offers: card.offers.length,
|
|
2393
|
+
expiresAt: card.expiresAt,
|
|
2394
|
+
networkSize: state.intentNetwork.cards.size,
|
|
2395
|
+
note: 'Card published. Other agents can now discover matches. Use search_matches to find relevant cards.',
|
|
2396
|
+
}, null, 2),
|
|
2397
|
+
}],
|
|
2398
|
+
};
|
|
2399
|
+
});
|
|
2400
|
+
server.tool("search_matches", "Search the network for IntentCards relevant to your human. Returns ranked matches based on need/offer overlap, tag similarity, and budget compatibility.", {
|
|
2401
|
+
min_score: z.number().optional().describe("Minimum relevance score 0-1 (default: 0.1)"),
|
|
2402
|
+
max_results: z.number().optional().describe("Maximum results to return (default: 10)"),
|
|
2403
|
+
category_filter: z.string().optional().describe("Only match within this category"),
|
|
2404
|
+
}, async (args) => {
|
|
2405
|
+
const keyErr = requireKey();
|
|
2406
|
+
if (keyErr)
|
|
2407
|
+
return { content: [{ type: "text", text: keyErr }], isError: true };
|
|
2408
|
+
const agentId = state.agentId || 'anonymous';
|
|
2409
|
+
const matches = searchMatches(state.intentNetwork, agentId, {
|
|
2410
|
+
minScore: args.min_score,
|
|
2411
|
+
maxResults: args.max_results,
|
|
2412
|
+
categories: args.category_filter ? [args.category_filter] : undefined,
|
|
2413
|
+
});
|
|
2414
|
+
return {
|
|
2415
|
+
content: [{
|
|
2416
|
+
type: "text",
|
|
2417
|
+
text: JSON.stringify({
|
|
2418
|
+
matchCount: matches.length,
|
|
2419
|
+
matches: matches.map(m => {
|
|
2420
|
+
const isA = m.agentA === agentId;
|
|
2421
|
+
return {
|
|
2422
|
+
matchId: m.matchId,
|
|
2423
|
+
otherAgent: isA ? m.agentB : m.agentA,
|
|
2424
|
+
otherCard: isA ? m.cardB : m.cardA,
|
|
2425
|
+
score: m.score,
|
|
2426
|
+
mutual: m.mutual,
|
|
2427
|
+
needOfferMatches: m.needOfferMatches.map(nom => ({
|
|
2428
|
+
needCategory: nom.need.category,
|
|
2429
|
+
offerCategory: nom.offer.category,
|
|
2430
|
+
matchType: nom.matchType,
|
|
2431
|
+
relevanceScore: nom.relevanceScore,
|
|
2432
|
+
})),
|
|
2433
|
+
explanation: m.explanation,
|
|
2434
|
+
};
|
|
2435
|
+
}),
|
|
2436
|
+
networkSize: state.intentNetwork.cards.size,
|
|
2437
|
+
}, null, 2),
|
|
2438
|
+
}],
|
|
2439
|
+
};
|
|
2440
|
+
});
|
|
2441
|
+
server.tool("get_digest", "Get a personalized digest: relevant matches, pending intro requests, and incoming intros. The killer feature — 'what matters to me right now?'", {}, async () => {
|
|
2442
|
+
const agentId = state.agentId || 'anonymous';
|
|
2443
|
+
const digest = getDigest(state.intentNetwork, agentId);
|
|
2444
|
+
return {
|
|
2445
|
+
content: [{
|
|
2446
|
+
type: "text",
|
|
2447
|
+
text: JSON.stringify({
|
|
2448
|
+
agentId: digest.agentId,
|
|
2449
|
+
generatedAt: digest.generatedAt,
|
|
2450
|
+
summary: digest.summary,
|
|
2451
|
+
matchCount: digest.matches.length,
|
|
2452
|
+
topMatches: digest.matches.slice(0, 5).map((m) => {
|
|
2453
|
+
const isA = m.agentA === agentId;
|
|
2454
|
+
return {
|
|
2455
|
+
otherAgent: isA ? m.agentB : m.agentA,
|
|
2456
|
+
score: m.score,
|
|
2457
|
+
explanation: m.explanation,
|
|
2458
|
+
};
|
|
2459
|
+
}),
|
|
2460
|
+
introsPending: digest.introsPending.length,
|
|
2461
|
+
introsReceived: digest.introsReceived.length,
|
|
2462
|
+
introsReceivedDetail: digest.introsReceived.map((intro) => ({
|
|
2463
|
+
introId: intro.introId,
|
|
2464
|
+
fromAgent: intro.requestedBy,
|
|
2465
|
+
message: intro.message,
|
|
2466
|
+
status: intro.status,
|
|
2467
|
+
})),
|
|
2468
|
+
}, null, 2),
|
|
2469
|
+
}],
|
|
2470
|
+
};
|
|
2471
|
+
});
|
|
2472
|
+
server.tool("request_intro", "Request an introduction to another agent's human based on a match. Both sides must approve before real information crosses.", {
|
|
2473
|
+
match_id: z.string().describe("Match ID from search_matches"),
|
|
2474
|
+
target_card_id: z.string().describe("Card ID of the agent you want an intro to"),
|
|
2475
|
+
message: z.string().describe("Brief message explaining why this intro would be valuable"),
|
|
2476
|
+
disclose_fields: z.array(z.string()).optional().describe("Fields you're willing to share (e.g. ['needs', 'offers', 'openTo'])"),
|
|
2477
|
+
}, async (args) => {
|
|
2478
|
+
const keyErr = requireKey();
|
|
2479
|
+
if (keyErr)
|
|
2480
|
+
return { content: [{ type: "text", text: keyErr }], isError: true };
|
|
2481
|
+
try {
|
|
2482
|
+
const result = requestIntro(state.intentNetwork, {
|
|
2483
|
+
requestedBy: state.agentId || 'anonymous',
|
|
2484
|
+
targetAgentId: args.target_card_id,
|
|
2485
|
+
matchId: args.match_id,
|
|
2486
|
+
message: args.message,
|
|
2487
|
+
fieldsToDisclose: args.disclose_fields || ['needs', 'offers'],
|
|
2488
|
+
privateKey: state.privateKey,
|
|
2489
|
+
});
|
|
2490
|
+
if ('error' in result) {
|
|
2491
|
+
return { content: [{ type: "text", text: `Intro request failed: ${result.error}` }], isError: true };
|
|
2492
|
+
}
|
|
2493
|
+
return {
|
|
2494
|
+
content: [{
|
|
2495
|
+
type: "text",
|
|
2496
|
+
text: JSON.stringify({
|
|
2497
|
+
introId: result.introId,
|
|
2498
|
+
status: result.status,
|
|
2499
|
+
targetAgent: result.targetAgentId,
|
|
2500
|
+
message: result.message,
|
|
2501
|
+
note: 'Intro request sent. The other agent\'s human will see this in their digest and can approve or decline.',
|
|
2502
|
+
}, null, 2),
|
|
2503
|
+
}],
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
catch (e) {
|
|
2507
|
+
return { content: [{ type: "text", text: `Intro request failed: ${e.message}` }], isError: true };
|
|
2508
|
+
}
|
|
2509
|
+
});
|
|
2510
|
+
server.tool("respond_to_intro", "Respond to an introduction request. Approve to share your disclosed information, or decline.", {
|
|
2511
|
+
intro_id: z.string().describe("Intro request ID"),
|
|
2512
|
+
approved: z.boolean().describe("Whether to approve the introduction"),
|
|
2513
|
+
message: z.string().optional().describe("Optional response message"),
|
|
2514
|
+
disclose_fields: z.array(z.string()).optional().describe("Fields you're willing to share back"),
|
|
2515
|
+
}, async (args) => {
|
|
2516
|
+
const keyErr = requireKey();
|
|
2517
|
+
if (keyErr)
|
|
2518
|
+
return { content: [{ type: "text", text: keyErr }], isError: true };
|
|
2519
|
+
try {
|
|
2520
|
+
const result = respondToIntro(state.intentNetwork, {
|
|
2521
|
+
introId: args.intro_id,
|
|
2522
|
+
respondedBy: state.agentId || 'anonymous',
|
|
2523
|
+
verdict: args.approved ? 'approve' : 'decline',
|
|
2524
|
+
message: args.message,
|
|
2525
|
+
disclosedFields: args.disclose_fields ? Object.fromEntries(args.disclose_fields.map(f => [f, 'disclosed'])) : undefined,
|
|
2526
|
+
privateKey: state.privateKey,
|
|
2527
|
+
});
|
|
2528
|
+
if ('error' in result) {
|
|
2529
|
+
return { content: [{ type: "text", text: `Intro response failed: ${result.error}` }], isError: true };
|
|
2530
|
+
}
|
|
2531
|
+
return {
|
|
2532
|
+
content: [{
|
|
2533
|
+
type: "text",
|
|
2534
|
+
text: JSON.stringify({
|
|
2535
|
+
introId: result.introId,
|
|
2536
|
+
verdict: result.verdict,
|
|
2537
|
+
approved: args.approved,
|
|
2538
|
+
note: args.approved
|
|
2539
|
+
? 'Introduction approved. Both parties can now see disclosed information.'
|
|
2540
|
+
: 'Introduction declined.',
|
|
2541
|
+
}, null, 2),
|
|
2542
|
+
}],
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
catch (e) {
|
|
2546
|
+
return { content: [{ type: "text", text: `Intro response failed: ${e.message}` }], isError: true };
|
|
2547
|
+
}
|
|
2548
|
+
});
|
|
2549
|
+
server.tool("remove_intent_card", "Remove your IntentCard from the network. Use when your needs or offers have changed.", {
|
|
2550
|
+
card_id: z.string().describe("Card ID to remove"),
|
|
2551
|
+
}, async (args) => {
|
|
2552
|
+
const removed = removeCard(state.intentNetwork, args.card_id);
|
|
2553
|
+
return {
|
|
2554
|
+
content: [{
|
|
2555
|
+
type: "text",
|
|
2556
|
+
text: JSON.stringify({
|
|
2557
|
+
removed,
|
|
2558
|
+
cardId: args.card_id,
|
|
2559
|
+
networkSize: state.intentNetwork.cards.size,
|
|
2560
|
+
}, null, 2),
|
|
2561
|
+
}],
|
|
2562
|
+
};
|
|
2563
|
+
});
|
|
2564
|
+
// ═══════════════════════════════════════
|
|
2115
2565
|
// MCP Prompts — Role-Specific
|
|
2116
2566
|
// ═══════════════════════════════════════
|
|
2117
2567
|
server.prompt("coordination_role", "Get instructions for your assigned coordination role", {}, async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-passport-system-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"mcpName": "io.github.aeoess/agent-passport-mcp",
|
|
5
5
|
"description": "MCP server for Agent Passport System — cryptographic identity, delegation, governance, and deliberation for AI agents",
|
|
6
6
|
"type": "module",
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"agent-passport-system-mcp": "build/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"build"
|
|
11
|
+
"build",
|
|
12
|
+
"CONTRIBUTING.md",
|
|
13
|
+
"CODE_OF_CONDUCT.md"
|
|
12
14
|
],
|
|
13
15
|
"scripts": {
|
|
14
16
|
"build": "tsc && chmod 755 build/index.js",
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
"homepage": "https://github.com/aeoess/agent-passport-mcp",
|
|
46
48
|
"dependencies": {
|
|
47
49
|
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
48
|
-
"agent-passport-system": "file:../agent-passport-system/agent-passport-system-1.
|
|
50
|
+
"agent-passport-system": "file:../agent-passport-system/agent-passport-system-1.13.0.tgz",
|
|
49
51
|
"zod": "^3.25.0"
|
|
50
52
|
},
|
|
51
53
|
"devDependencies": {
|