@mcp-i/core 1.1.0 → 1.1.1
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 +79 -151
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,203 +1,131 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
MCP-I
|
|
6
|
-
|
|
7
|
-
>
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://modelcontextprotocol-identity.io">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://modelcontextprotocol-identity.io/images/logo-mark_white.svg">
|
|
5
|
+
<img alt="MCP-I" src="https://modelcontextprotocol-identity.io/images/logo-mark_black.svg" width="64">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<strong>Identity, delegation, and proof for the Model Context Protocol.</strong>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://www.npmjs.com/package/@mcp-i/core"><img src="https://img.shields.io/npm/v/@mcp-i/core" alt="npm"></a>
|
|
16
|
+
<a href="https://modelcontextprotocol-identity.io"><img src="https://img.shields.io/badge/spec-modelcontextprotocol--identity.io-blue" alt="spec"></a>
|
|
17
|
+
<a href="https://identity.foundation/working-groups/agent-and-authorization.html"><img src="https://img.shields.io/badge/DIF-TAAWG-purple" alt="DIF TAAWG"></a>
|
|
18
|
+
<a href="./LICENSE"><img src="https://img.shields.io/github/license/modelcontextprotocol-identity/mcp-i-core" alt="license"></a>
|
|
19
|
+
</p>
|
|
8
20
|
|
|
9
21
|
---
|
|
10
22
|
|
|
11
|
-
|
|
23
|
+
AI agents call tools on your behalf. But today, there's no way to know *who* called, *whether they were allowed to*, or *what actually happened*. MCP-I fixes that.
|
|
12
24
|
|
|
13
|
-
|
|
25
|
+
- **Every server gets a cryptographic identity** (DID) — no accounts, no API keys, no central registry
|
|
26
|
+
- **Every tool call gets a signed proof** — a tamper-evident receipt the agent can't forge or deny
|
|
27
|
+
- **Protected tools require human consent** — per-tool authorization via W3C Delegation Credentials
|
|
28
|
+
- **The AI never knows** — identity, proofs, and consent happen transparently in the protocol layer
|
|
14
29
|
|
|
15
|
-
```bash
|
|
16
|
-
git clone https://github.com/modelcontextprotocol-identity/mcp-i-core.git
|
|
17
|
-
cd mcp-i-core
|
|
18
|
-
pnpm install
|
|
19
|
-
npx tsx examples/consent-basic/src/server.ts
|
|
20
30
|
```
|
|
21
|
-
|
|
22
|
-
Then connect with [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
npx @modelcontextprotocol/inspector
|
|
26
|
-
# → Connect to http://localhost:3002/sse
|
|
31
|
+
npm install @mcp-i/core
|
|
27
32
|
```
|
|
28
33
|
|
|
29
|
-
Call `checkout` — you'll get a consent link. Open it, approve, then retry the tool. [Full walkthrough →](./examples/consent-basic/README.md)
|
|
30
|
-
|
|
31
34
|
---
|
|
32
35
|
|
|
33
|
-
##
|
|
36
|
+
## Migrate Any MCP Server in 2 Lines
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
**Before** — a standard MCP server with no identity or proofs:
|
|
36
39
|
|
|
37
40
|
```typescript
|
|
38
41
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
39
|
-
import { withMCPI, NodeCryptoProvider } from '@mcp-i/core';
|
|
40
42
|
|
|
41
43
|
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
42
|
-
await withMCPI(server, { crypto: new NodeCryptoProvider() });
|
|
43
|
-
|
|
44
|
-
// Register tools normally — proofs are attached automatically
|
|
45
|
-
```
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
If your runtime has a native connection/auth handshake hook, disable tool exposure and call middleware directly:
|
|
52
|
-
|
|
53
|
-
```typescript
|
|
54
|
-
const mcpi = await withMCPI(server, {
|
|
55
|
-
crypto: new NodeCryptoProvider(),
|
|
56
|
-
handshakeExposure: 'none',
|
|
57
|
-
autoSession: false,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// In your runtime's connection handshake hook:
|
|
61
|
-
await mcpi.handleMCPI({
|
|
62
|
-
action: 'handshake',
|
|
63
|
-
nonce: 'client-generated-nonce',
|
|
64
|
-
audience: mcpi.identity.did,
|
|
65
|
-
timestamp: Math.floor(Date.now() / 1000),
|
|
66
|
-
agentDid: 'did:key:...optional...',
|
|
67
|
-
});
|
|
45
|
+
server.registerTool('greet', { description: 'Say hello' }, async (args) => ({
|
|
46
|
+
content: [{ type: 'text', text: `Hello, ${args.name}!` }],
|
|
47
|
+
}));
|
|
68
48
|
```
|
|
69
49
|
|
|
70
|
-
|
|
50
|
+
**After** — every tool response now carries a signed cryptographic proof:
|
|
71
51
|
|
|
72
52
|
```typescript
|
|
73
|
-
import {
|
|
53
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
54
|
+
import { withMCPI, NodeCryptoProvider } from '@mcp-i/core'; // +1 line
|
|
74
55
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const mcpi = createMCPIMiddleware({ identity, session: { sessionTtlMinutes: 60 } }, crypto);
|
|
56
|
+
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
|
|
57
|
+
await withMCPI(server, { crypto: new NodeCryptoProvider() }); // +1 line
|
|
78
58
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
content: [{ type: 'text', text: `Results for: ${args['query']}` }],
|
|
59
|
+
server.registerTool('greet', { description: 'Say hello' }, async (args) => ({
|
|
60
|
+
content: [{ type: 'text', text: `Hello, ${args.name}!` }],
|
|
82
61
|
}));
|
|
83
|
-
|
|
84
|
-
// Protected tool — requires delegation with scope 'orders:write'
|
|
85
|
-
const placeOrder = mcpi.wrapWithDelegation(
|
|
86
|
-
'place_order',
|
|
87
|
-
{ scopeId: 'orders:write', consentUrl: 'https://example.com/consent' },
|
|
88
|
-
mcpi.wrapWithProof('place_order', async (args) => ({
|
|
89
|
-
content: [{ type: 'text', text: `Order placed: ${args['item']}` }],
|
|
90
|
-
})),
|
|
91
|
-
);
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
---
|
|
95
|
-
|
|
96
|
-
## Install
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
npm install @mcp-i/core
|
|
100
62
|
```
|
|
101
63
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
---
|
|
105
|
-
|
|
106
|
-
## Architecture
|
|
64
|
+
That's it. `withMCPI` auto-generates an Ed25519 identity, registers the `_mcpi` protocol tool, and wraps the transport so every tool response includes a detached JWS proof in `_meta` — invisible to the LLM, verifiable by anyone.
|
|
107
65
|
|
|
108
|
-
|
|
109
|
-
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
|
110
|
-
│ Agent │────▶│ MCP Server │────▶│ Downstream │
|
|
111
|
-
│ (did:key) │ │ + MCP-I │ │ Services │
|
|
112
|
-
└─────────────┘ └──────────────┘ └─────────────┘
|
|
113
|
-
│ │ │
|
|
114
|
-
│ handshake │ verify delegation │ outbound headers
|
|
115
|
-
│ (nonce+DID) │ attach proof │ (X-Agent-DID,
|
|
116
|
-
│ │ check scopes │ X-Delegation-Chain)
|
|
117
|
-
▼ ▼ ▼
|
|
118
|
-
Session established Tool executes Context forwarded
|
|
119
|
-
with replay with signed to downstream
|
|
120
|
-
prevention receipt with delegation
|
|
121
|
-
```
|
|
66
|
+
> See the full working example: [examples/context7-with-mcpi](./examples/context7-with-mcpi/) — a real MCP server (Context7) migrated with exactly 2 lines of code.
|
|
122
67
|
|
|
123
68
|
---
|
|
124
69
|
|
|
125
|
-
##
|
|
70
|
+
## Protect Tools with Human Consent
|
|
126
71
|
|
|
127
|
-
|
|
128
|
-
|--------|-------------|
|
|
129
|
-
| **middleware** | `withMCPI(server)` — one-call integration. `createMCPIMiddleware` for low-level control. |
|
|
130
|
-
| **delegation** | Issue and verify W3C VCs. DID:key and DID:web resolution. StatusList2021 revocation. Cascading revocation. |
|
|
131
|
-
| **proof** | Generate and verify detached JWS proofs with canonical hashing (JCS + SHA-256). |
|
|
132
|
-
| **session** | Nonce-based handshake. Replay prevention. Session TTL management. |
|
|
133
|
-
| **providers** | Abstract `CryptoProvider`, `IdentityProvider`, `StorageProvider`. Plug in your own KMS, HSM, or vault. |
|
|
134
|
-
| **types** | Pure TypeScript interfaces. Zero runtime dependencies. |
|
|
72
|
+
Some tools shouldn't run without a human saying "yes." MCP-I adds per-tool authorization using W3C Verifiable Credentials:
|
|
135
73
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
74
|
+
```typescript
|
|
75
|
+
const checkout = mcpi.wrapWithDelegation(
|
|
76
|
+
'checkout',
|
|
77
|
+
{ scopeId: 'cart:write', consentUrl: 'https://example.com/consent' },
|
|
78
|
+
mcpi.wrapWithProof('checkout', async (args) => ({
|
|
79
|
+
content: [{ type: 'text', text: `Order placed: ${args.item}` }],
|
|
80
|
+
})),
|
|
81
|
+
);
|
|
82
|
+
```
|
|
139
83
|
|
|
140
|
-
|
|
84
|
+
When an agent calls `checkout` without a delegation credential, it gets back a `needs_authorization` response with a consent URL. The human approves, a scoped credential is issued, and the agent retries — now authorized.
|
|
141
85
|
|
|
142
|
-
|
|
143
|
-
|---------|--------------|
|
|
144
|
-
| [**consent-basic**](./examples/consent-basic/) | Human-in-the-loop consent flow: `needs_authorization` → consent page → delegation VC → tool execution. SSE + Streamable HTTP transports. |
|
|
145
|
-
| [**consent-full**](./examples/consent-full/) | Same consent flow as consent-basic, powered by [`@kya-os/consent`](https://www.npmjs.com/package/@kya-os/consent) — multi-mode auth, configurable branding, and production-grade consent UI. |
|
|
146
|
-
| [**node-server**](./examples/node-server/) | Low-level Server API with handshake, proof, and restricted tools. |
|
|
147
|
-
| [**brave-search-mcp-server**](./examples/brave-search-mcp-server/) | Real-world MCP server wrapping Brave Search with MCP-I identity and proofs. |
|
|
148
|
-
| [**outbound-delegation**](./examples/outbound-delegation/) | Forwarding delegation context to downstream services (§7 gateway pattern). |
|
|
149
|
-
| [**verify-proof**](./examples/verify-proof/) | Standalone proof verification with DID:key resolution. |
|
|
150
|
-
| [**context7-with-mcpi**](./examples/context7-with-mcpi/) | Adding MCP-I to an existing MCP server with `withMCPI`. |
|
|
86
|
+
> Try it yourself: [examples/consent-basic](./examples/consent-basic/) walks through the full consent flow end-to-end.
|
|
151
87
|
|
|
152
88
|
---
|
|
153
89
|
|
|
154
|
-
##
|
|
90
|
+
## See It in Action
|
|
155
91
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
class KMSCryptoProvider extends CryptoProvider {
|
|
161
|
-
async sign(data: Uint8Array, keyArn: string) {
|
|
162
|
-
return kmsClient.sign({ KeyId: keyArn, Message: data });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Use Redis instead of in-memory nonce cache
|
|
167
|
-
class RedisNonceCacheProvider extends NonceCacheProvider {
|
|
168
|
-
async hasNonce(nonce: string) { return redis.exists(`nonce:${nonce}`); }
|
|
169
|
-
async addNonce(nonce: string, ttl: number) { redis.setex(`nonce:${nonce}`, ttl, '1'); }
|
|
170
|
-
}
|
|
92
|
+
```bash
|
|
93
|
+
git clone https://github.com/modelcontextprotocol-identity/mcp-i-core.git
|
|
94
|
+
cd mcp-i-core && npm install
|
|
95
|
+
bash scripts/demo.sh
|
|
171
96
|
```
|
|
172
97
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## Conformance
|
|
98
|
+
This starts all example servers and opens [MCP Inspector](https://github.com/modelcontextprotocol/inspector). Connect to any server, call a tool, and inspect the proof in `_meta`:
|
|
178
99
|
|
|
179
|
-
|
|
100
|
+
| Port | Example | What it demonstrates |
|
|
101
|
+
|------|---------|---------------------|
|
|
102
|
+
| 3001 | [node-server](./examples/node-server/) | Proofs + restricted tools (low-level API) |
|
|
103
|
+
| 3002 | [consent-basic](./examples/consent-basic/) | Human consent flow with built-in UI |
|
|
104
|
+
| 3003 | [consent-full](./examples/consent-full/) | Production consent UI ([@kya-os/consent](https://www.npmjs.com/package/@kya-os/consent)) |
|
|
105
|
+
| 3004 | [context7-with-mcpi](./examples/context7-with-mcpi/) | 2-line migration of a real MCP server |
|
|
180
106
|
|
|
181
|
-
|
|
182
|
-
|-------|-------------|
|
|
183
|
-
| **Level 1** — Core Crypto | Ed25519 signatures, DID:key resolution, JCS canonicalization |
|
|
184
|
-
| **Level 2** — Full Session | Nonce-based handshake, session management, replay prevention |
|
|
185
|
-
| **Level 3** — Full Delegation | W3C VC issuance/verification, scope attenuation, StatusList2021, cascading revocation |
|
|
107
|
+
Also available: [outbound-delegation](./examples/outbound-delegation/) (gateway pattern), [verify-proof](./examples/verify-proof/) (standalone verification), [statuslist](./examples/statuslist/) (revocation lifecycle).
|
|
186
108
|
|
|
187
109
|
---
|
|
188
110
|
|
|
189
|
-
##
|
|
190
|
-
|
|
191
|
-
See [CONTRIBUTING.md](./CONTRIBUTING.md). DCO sign-off required. All PRs must pass CI (type check, lint, test across Node 20/22 on Linux/macOS/Windows).
|
|
111
|
+
## What's Under the Hood
|
|
192
112
|
|
|
193
|
-
|
|
113
|
+
| Capability | How it works |
|
|
114
|
+
|-----------|-------------|
|
|
115
|
+
| **Cryptographic identity** | Ed25519 key pairs, `did:key` and `did:web` resolution |
|
|
116
|
+
| **Signed proofs** | Detached JWS over JCS-canonicalized request/response hashes |
|
|
117
|
+
| **Delegation credentials** | W3C Verifiable Credentials with scope constraints |
|
|
118
|
+
| **Revocation** | StatusList2021 bitstring with cascading revocation |
|
|
119
|
+
| **Replay prevention** | Nonce-based handshake with timestamp skew validation |
|
|
120
|
+
| **Extensible** | Bring your own KMS, HSM, nonce cache (Redis, DynamoDB, KV), or DID method |
|
|
194
121
|
|
|
195
|
-
|
|
122
|
+
---
|
|
196
123
|
|
|
197
|
-
##
|
|
124
|
+
## Links
|
|
198
125
|
|
|
199
|
-
|
|
126
|
+
- [Spec](https://modelcontextprotocol-identity.io) | [DIF TAAWG](https://identity.foundation/working-groups/agent-and-authorization.html) | [npm](https://www.npmjs.com/package/@mcp-i/core)
|
|
127
|
+
- [CONTRIBUTING.md](./CONTRIBUTING.md) | [CONFORMANCE.md](./CONFORMANCE.md) | [SECURITY.md](./SECURITY.md) | [GOVERNANCE.md](./GOVERNANCE.md)
|
|
200
128
|
|
|
201
129
|
## License
|
|
202
130
|
|
|
203
|
-
MIT
|
|
131
|
+
MIT
|