@openagentid/mcp 0.1.0 → 0.2.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/CHANGELOG.md +10 -0
- package/LICENSE-APACHE +1 -1
- package/LICENSE-MIT +1 -1
- package/README.md +63 -159
- package/dist/client.cjs +3 -14
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +3 -14
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +123 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +122 -26
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +53 -11
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +4 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +53 -11
- package/dist/server.js.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +12 -7
- package/dist/types.d.ts +12 -7
- package/dist/types.js.map +1 -1
- package/package.json +11 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 — 2026-10-12
|
|
4
|
+
|
|
5
|
+
- Current SDK workspace adapters use real Ed25519 proofs with caller/tool/argument-bound challenges, receiver-owned scopes, replay and revocation checks. Raw wire requests are captured before schema parsing so defaults, transforms and stripped fields preserve binding. Client mutations run before signing; native MCP integration and stdio example cover the complete path.
|
|
6
|
+
|
|
3
7
|
All notable changes to `@openagent/mcp` are documented in this file.
|
|
4
8
|
|
|
5
9
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
@@ -11,6 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
15
|
|
|
12
16
|
- **Breaking:** package renamed from `@openagent/mcp` to `@openagentid/mcp`. The `@openagent` npm scope is squatted by a third party; the project now publishes under the `@openagentid` scope, matching the GitHub org OpenAgentID. Consumers must update dependency names and imports. Effective with the first npm publish under the new scope.
|
|
13
17
|
|
|
18
|
+
## [0.1.1] - 2026-07-31
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Fixed license copyright holder (L1fe Labs, Inc.) and added copyright footers to all READMEs. No functional changes.
|
|
23
|
+
|
|
14
24
|
## [0.1.0] - 2026-04-11
|
|
15
25
|
|
|
16
26
|
### Added
|
package/LICENSE-APACHE
CHANGED
|
@@ -85,7 +85,7 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
|
85
85
|
|
|
86
86
|
END OF TERMS AND CONDITIONS
|
|
87
87
|
|
|
88
|
-
Copyright 2026 L1fe
|
|
88
|
+
Copyright 2026 L1fe Labs, Inc.
|
|
89
89
|
|
|
90
90
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
91
91
|
you may not use this file except in compliance with the License.
|
package/LICENSE-MIT
CHANGED
package/README.md
CHANGED
|
@@ -1,168 +1,72 @@
|
|
|
1
1
|
# @openagentid/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Authenticated Model Context Protocol tools using the current OpenAgentID SDK.
|
|
4
|
+
Works with SDK `^0.7.2` and MCP SDK `^1.27.0`.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install @openagentid/mcp @modelcontextprotocol/sdk @openagentid/sdk
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Server: add auth to MCP in 3 lines
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
17
|
-
import { withOpenAgent } from '@openagentid/mcp';
|
|
18
|
-
import { agent } from './my-agent.js';
|
|
19
|
-
|
|
20
|
-
const server = new McpServer({ name: 'my-tools', version: '0.1.0' });
|
|
21
|
-
|
|
22
|
-
const authedServer = withOpenAgent(server, {
|
|
23
|
-
agent,
|
|
24
|
-
requireScopes: (toolName) => [`mcp:${toolName}:invoke`],
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
authedServer.registerTool(
|
|
28
|
-
'search_web',
|
|
29
|
-
{ description: 'search the web', inputSchema: { q: z.string() } },
|
|
30
|
-
async ({ q }) => ({ content: [{ type: 'text', text: `results for ${q}` }] }),
|
|
31
|
-
);
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
That is it. Every tool call now:
|
|
35
|
-
|
|
36
|
-
1. Pulls the identity envelope from `extra._meta.openagent.identity`.
|
|
37
|
-
2. Verifies it against your `IdentityVerifier` (OAS DID + Arsenal ACT + AEGIS policy).
|
|
38
|
-
3. Enforces the per-tool scopes returned by `requireScopes`.
|
|
39
|
-
4. Runs the optional `skillsPolicy` hook (consults SKILLS.md-style rules).
|
|
40
|
-
5. Runs the user's tool body.
|
|
41
|
-
6. Stamps `audit_id`, `verified_did`, and `scopes` into the response `_meta.openagent`.
|
|
42
|
-
|
|
43
|
-
## Client: sign every outbound call
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
47
|
-
import { withOpenAgentClient } from '@openagentid/mcp';
|
|
48
|
-
import { agent } from './my-agent.js';
|
|
49
|
-
|
|
50
|
-
const client = new Client({ name: 'my-agent', version: '0.1.0' });
|
|
51
|
-
const authedClient = withOpenAgentClient(client, {
|
|
52
|
-
agent,
|
|
53
|
-
audience: 'did:oas:vendor:tools-server',
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
await authedClient.callTool({
|
|
57
|
-
name: 'search_web',
|
|
58
|
-
arguments: { q: 'mcp' },
|
|
59
|
-
});
|
|
6
|
+
```sh
|
|
7
|
+
npm install @openagentid/sdk@^0.7.2 @openagentid/mcp@0.2.0 @modelcontextprotocol/sdk@^1.27.0 zod
|
|
60
8
|
```
|
|
61
9
|
|
|
62
|
-
|
|
10
|
+
## Run a real server and client
|
|
63
11
|
|
|
64
|
-
|
|
12
|
+
The [complete stdio example](https://github.com/OpenAgentID/openagent-sdk/tree/main/examples/typescript/02-mcp-server)
|
|
13
|
+
creates real Ed25519 identities in separate signer and receiver workspaces,
|
|
14
|
+
starts a separate MCP server process, authenticates a tool call and verifies
|
|
15
|
+
unsigned and revoked callers are rejected. It needs no hosted account or API key.
|
|
65
16
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
preCall: ({ toolName, identity }) => {
|
|
72
|
-
metrics.increment('mcp.tool.calls', { tool: toolName, did: identity.did });
|
|
73
|
-
},
|
|
74
|
-
postCall: ({ toolName, identity, durationMs, result }) => {
|
|
75
|
-
audit.write({ tool: toolName, did: identity.did, ms: durationMs });
|
|
76
|
-
},
|
|
77
|
-
onError: ({ toolName, identity, error }) => {
|
|
78
|
-
audit.writeError({ tool: toolName, did: identity?.did ?? null, error });
|
|
79
|
-
},
|
|
80
|
-
});
|
|
17
|
+
```sh
|
|
18
|
+
git clone https://github.com/OpenAgentID/openagent-sdk.git
|
|
19
|
+
cd openagent-sdk/examples/typescript/02-mcp-server
|
|
20
|
+
npm install
|
|
21
|
+
npm start
|
|
81
22
|
```
|
|
82
23
|
|
|
83
|
-
##
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
requireScopes?: (toolName: string, args: unknown) => readonly string[];
|
|
133
|
-
requireIdentity?: boolean; // default: true
|
|
134
|
-
skillsPolicy?: SkillsPolicyHook;
|
|
135
|
-
preCall?: PreCallHook;
|
|
136
|
-
postCall?: PostCallHook;
|
|
137
|
-
onError?: ErrorHook;
|
|
138
|
-
scopeFormat?: (toolName: string) => string;
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## Versioning
|
|
143
|
-
|
|
144
|
-
This package is built against `@modelcontextprotocol/sdk@^1.27.0`. Both
|
|
145
|
-
the deprecated `tool(name, schema, cb)` overloads and the current
|
|
146
|
-
`registerTool(name, config, cb)` API are intercepted, so any 1.x server
|
|
147
|
-
works without code changes.
|
|
148
|
-
|
|
149
|
-
## Testing
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
npm test
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
The test suite uses [vitest](https://vitest.dev) and exercises the
|
|
156
|
-
middleware against both a synthetic MCP server and a real
|
|
157
|
-
`@modelcontextprotocol/sdk` server connected over the SDK's
|
|
158
|
-
`InMemoryTransport`.
|
|
159
|
-
|
|
160
|
-
## Documentation
|
|
161
|
-
|
|
162
|
-
- Spec: <https://openagent.id/docs/integrations/mcp>
|
|
163
|
-
- OpenAgent SDK: <https://openagent.id/docs/sdk>
|
|
164
|
-
- MCP: <https://modelcontextprotocol.io>
|
|
165
|
-
|
|
166
|
-
## License
|
|
167
|
-
|
|
168
|
-
Apache-2.0
|
|
24
|
+
## Current SDK adapters
|
|
25
|
+
|
|
26
|
+
`createWorkspaceMcpServer({ workspace, did, authorize })` returns an `agent`
|
|
27
|
+
for `withOpenAgent(server, { agent })` and an `issueChallenge` method.
|
|
28
|
+
Expose challenge issuance on your trusted MCP transport before wrapping the
|
|
29
|
+
server. `authorize(verifiedIdentity)` obtains scopes from your receiver policy.
|
|
30
|
+
Identity trust alone never grants tool access.
|
|
31
|
+
|
|
32
|
+
`createWorkspaceMcpClient({ workspace, did, audience, issueChallenge })` returns
|
|
33
|
+
an agent for `withOpenAgentClient(client, { agent })`. Its challenge callback
|
|
34
|
+
calls the receiver's challenge endpoint. The audience is explicit and must
|
|
35
|
+
match the receiver; no keys travel in request metadata.
|
|
36
|
+
|
|
37
|
+
The receiver binds each nonce to the DID, tool name and canonical JSON arguments.
|
|
38
|
+
The SDK verifies the signature, current trust, revocation and replay state. The
|
|
39
|
+
middleware then checks `mcp:<tool>:invoke` scopes and any configured skills policy.
|
|
40
|
+
Argument-changing `beforeCall` hooks run **before** signing. Custom verifiers
|
|
41
|
+
receive the original transmitted tool request as their third argument, captured
|
|
42
|
+
at the public MCP transport boundary before schema parsing. Authorization policies
|
|
43
|
+
and tool handlers receive the parsed arguments. Defaults, coercion, transforms and
|
|
44
|
+
unknown-field stripping therefore work without weakening request binding.
|
|
45
|
+
|
|
46
|
+
The workspace adapter is a single-process challenge coordinator backed by durable
|
|
47
|
+
SDK trust/replay state. Keep one adapter alive for the process lifetime. Restart
|
|
48
|
+
invalidates outstanding challenges. Distributed deployments should supply a
|
|
49
|
+
shared atomic challenge authority through the custom `Agent` contract. The standard MCP server transport
|
|
50
|
+
keeps raw request context isolated across asynchronous concurrent calls. Custom
|
|
51
|
+
server implementations without a transport use the arguments they pass directly
|
|
52
|
+
to the middleware callback.
|
|
53
|
+
|
|
54
|
+
## Policy and audit
|
|
55
|
+
|
|
56
|
+
- `requireScopes(toolName, args)` overrides the per-tool scope set.
|
|
57
|
+
- `scopeFormat(toolName)` customizes the default scope name.
|
|
58
|
+
- `createSkillsPolicy` rejects unlisted skill names and unauthorized DIDs.
|
|
59
|
+
- `preCall`, `postCall` and `onError` receive verified identity context.
|
|
60
|
+
- Results include `_meta.openagent` with `verified_did`, scopes and an audit ID.
|
|
61
|
+
|
|
62
|
+
`requireIdentity: false` explicitly permits anonymous calls; do not enable it
|
|
63
|
+
on protected tools. Callbacks and bespoke `Agent` implementations are trusted
|
|
64
|
+
application configuration, not substitutes for signature verification.
|
|
65
|
+
|
|
66
|
+
## Migration from 0.1
|
|
67
|
+
|
|
68
|
+
The SDK's `OpenAgentInstance` was never the adapter's `Agent` interface. Use the
|
|
69
|
+
workspace factories or implement the declared signing/verifier contract. The
|
|
70
|
+
new factories make that conversion explicit and exercise the current SDK with
|
|
71
|
+
real keys. Existing custom adapters remain supported; bind the verifier's new
|
|
72
|
+
`request` argument to your signed request data.
|
package/dist/client.cjs
CHANGED
|
@@ -40,24 +40,13 @@ var ClientInterceptor = class {
|
|
|
40
40
|
wrapCallTool(original, thisArg) {
|
|
41
41
|
const interceptor = this;
|
|
42
42
|
return async function wrappedCallTool(params, ...rest) {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
if (interceptor.beforeCall !== void 0) {
|
|
46
|
-
const replacement = await Promise.resolve(
|
|
47
|
-
interceptor.beforeCall(signed)
|
|
48
|
-
);
|
|
49
|
-
if (replacement !== void 0) {
|
|
50
|
-
toSend = {
|
|
51
|
-
...replacement,
|
|
52
|
-
_meta: replacement._meta ?? signed._meta
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
}
|
|
43
|
+
const replacement = await interceptor.beforeCall?.(params);
|
|
44
|
+
const toSend = await interceptor.signParams(replacement ?? params);
|
|
56
45
|
return original.call(thisArg, toSend, ...rest);
|
|
57
46
|
};
|
|
58
47
|
}
|
|
59
48
|
async signParams(params) {
|
|
60
|
-
const identity = await this.agent.signRequest(params.name, this.audience);
|
|
49
|
+
const identity = await this.agent.signRequest(params.name, this.audience, params.arguments);
|
|
61
50
|
const existingMeta = params._meta ?? {};
|
|
62
51
|
const existingOpenAgent = typeof existingMeta["openagent"] === "object" && existingMeta["openagent"] !== null ? existingMeta["openagent"] : {};
|
|
63
52
|
return {
|
package/dist/client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";;;AAqEO,SAAS,mBAAA,CACd,QACA,MAAA,EACG;AACH,EAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,OAAO,MAAA,KAAW,QAAA,EAAU;AACjD,IAAA,MAAM,IAAI,UAAU,yCAAyC,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,MAAA,CAAO,KAAA,KAAU,MAAA,IAAa,MAAA,CAAO,UAAU,IAAA,EAAM;AACvD,IAAA,MAAM,IAAI,UAAU,yCAAyC,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,OAAO,MAAA,CAAO,KAAA,CAAM,WAAA,KAAgB,UAAA,EAAY;AAClD,IAAA,MAAM,IAAI,UAAU,qDAAqD,CAAA;AAAA,EAC3E;AAEA,EAAA,MAAM,WAAA,GAAc,IAAI,iBAAA,CAAkB,MAAM,CAAA;AAEhD,EAAA,OAAO,IAAI,MAAM,MAAA,EAAQ;AAAA,IACvB,GAAA,CAAI,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU;AAC9B,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,UAAU,QAAQ,CAAA;AACpD,MAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAC/B,QAAA,OAAO,KAAA;AAAA,MACT;AACA,MAAA,IAAI,aAAa,UAAA,EAAY;AAC3B,QAAA,OAAO,WAAA,CAAY,YAAA;AAAA,UACjB,KAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,IAC1B;AAAA,GACD,CAAA;AACH;AAEA,IAAM,oBAAN,MAAwB;AAAA,EACL,KAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EAEjB,YAAY,MAAA,EAA+B;AACzC,IAAA,IAAA,CAAK,QAAQ,MAAA,CAAO,KAAA;AACpB,IAAA,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AACvB,IAAA,IAAA,CAAK,aAAa,MAAA,CAAO,UAAA;AAAA,EAC3B;AAAA,EAEA,YAAA,CACE,UACA,OAAA,EAC2B;AAC3B,IAAA,MAAM,WAAA,GAAc,IAAA;AACpB,IAAA,OAAO,eAAe,eAAA,CAEpB,MAAA,EAAA,GAKG,IAAA,EACe;
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.cjs","sourcesContent":["/**\n * Client-side interceptor for @openagentid/mcp.\n *\n * Adds an OpenAgent identity envelope (`_meta.openagent.identity`) to\n * outbound MCP `tools/call` requests so an authenticated server can\n * verify the caller. The interceptor wraps the MCP client's `callTool`\n * method via a JavaScript Proxy — the rest of the client surface (list\n * tools, list resources, prompts) is forwarded unchanged.\n *\n * Usage:\n *\n * ```ts\n * import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n * import { withOpenAgentClient } from '@openagentid/mcp/client';\n *\n * const client = new Client({ name: 'my-agent', version: '0.1.0' });\n * const authedClient = withOpenAgentClient(client, { agent });\n *\n * await authedClient.callTool({ name: 'search_web', arguments: { q: 'mcp' } });\n * ```\n */\n\nimport { Agent } from './types.js';\n\n/**\n * Minimal MCP client surface used by the interceptor. Like the server\n * adapter, we describe just the methods we need to keep peer-dep\n * compatibility broad.\n */\nexport interface McpClientLike {\n callTool(\n params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n },\n ...rest: unknown[]\n ): Promise<unknown>;\n}\n\nexport interface OpenAgentClientConfig {\n /** The agent doing the calling — used to sign each request. */\n agent: Pick<Agent, 'did' | 'signRequest'>;\n /**\n * Optional audience DID. When set, it is passed to\n * {@link Agent.signRequest} so the proof can be bound to a specific\n * server. Most production deployments should set this.\n */\n audience?: string;\n /**\n * Optional hook fired before every outbound call. Use it for client-\n * side metrics or to mutate the params (e.g., add tracing headers).\n * Returning a value replaces the params.\n */\n beforeCall?: (params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n }) => Promise<\n | { name: string; arguments?: Record<string, unknown>; _meta?: Record<string, unknown> }\n | void\n > | { name: string; arguments?: Record<string, unknown>; _meta?: Record<string, unknown> }\n | void;\n}\n\n/**\n * Wrap an MCP client so every outbound `callTool` carries an OpenAgent\n * identity envelope.\n */\nexport function withOpenAgentClient<T extends McpClientLike>(\n client: T,\n config: OpenAgentClientConfig,\n): T {\n if (config === null || typeof config !== 'object') {\n throw new TypeError('OpenAgentClientConfig must be an object');\n }\n if (config.agent === undefined || config.agent === null) {\n throw new TypeError('OpenAgentClientConfig.agent is required');\n }\n if (typeof config.agent.signRequest !== 'function') {\n throw new TypeError('OpenAgentClientConfig.agent.signRequest is required');\n }\n\n const interceptor = new ClientInterceptor(config);\n\n return new Proxy(client, {\n get(target, property, receiver) {\n const value = Reflect.get(target, property, receiver);\n if (typeof value !== 'function') {\n return value;\n }\n if (property === 'callTool') {\n return interceptor.wrapCallTool(\n value as McpClientLike['callTool'],\n target,\n );\n }\n return value.bind(target);\n },\n }) as T;\n}\n\nclass ClientInterceptor {\n private readonly agent: Pick<Agent, 'did' | 'signRequest'>;\n private readonly audience: string | undefined;\n private readonly beforeCall: OpenAgentClientConfig['beforeCall'];\n\n constructor(config: OpenAgentClientConfig) {\n this.agent = config.agent;\n this.audience = config.audience;\n this.beforeCall = config.beforeCall;\n }\n\n wrapCallTool(\n original: McpClientLike['callTool'],\n thisArg: unknown,\n ): McpClientLike['callTool'] {\n const interceptor = this;\n return async function wrappedCallTool(\n this: unknown,\n params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n },\n ...rest: unknown[]\n ): Promise<unknown> {\n // Mutate first; the signature must cover the actual transmitted call.\n const replacement = await interceptor.beforeCall?.(params);\n const toSend = await interceptor.signParams(replacement ?? params);\n return original.call(thisArg, toSend, ...rest);\n };\n }\n\n private async signParams(params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n }): Promise<{\n name: string;\n arguments?: Record<string, unknown>;\n _meta: Record<string, unknown>;\n }> {\n const identity = await this.agent.signRequest(params.name, this.audience, params.arguments);\n const existingMeta = params._meta ?? {};\n const existingOpenAgent =\n typeof existingMeta['openagent'] === 'object' &&\n existingMeta['openagent'] !== null\n ? (existingMeta['openagent'] as Record<string, unknown>)\n : {};\n return {\n ...params,\n _meta: {\n ...existingMeta,\n openagent: {\n ...existingOpenAgent,\n identity,\n },\n },\n };\n }\n}\n\n/**\n * Helper for tests and tools that want to construct the identity\n * envelope manually without going through a full Agent. Returns a `_meta`\n * object that can be merged into a CallToolRequest's params.\n */\nexport function buildIdentityMeta(identity: {\n did: string;\n proof: string;\n nonce?: string;\n context?: Record<string, unknown>;\n}): Record<string, unknown> {\n return {\n openagent: {\n identity: {\n did: identity.did,\n proof: identity.proof,\n ...(identity.nonce !== undefined ? { nonce: identity.nonce } : {}),\n ...(identity.context !== undefined\n ? { context: identity.context }\n : {}),\n },\n },\n };\n}\n"]}
|
package/dist/client.d.cts
CHANGED
|
@@ -36,7 +36,7 @@ interface McpClientLike {
|
|
|
36
36
|
}
|
|
37
37
|
interface OpenAgentClientConfig {
|
|
38
38
|
/** The agent doing the calling — used to sign each request. */
|
|
39
|
-
agent: Agent
|
|
39
|
+
agent: Pick<Agent, 'did' | 'signRequest'>;
|
|
40
40
|
/**
|
|
41
41
|
* Optional audience DID. When set, it is passed to
|
|
42
42
|
* {@link Agent.signRequest} so the proof can be bound to a specific
|
package/dist/client.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ interface McpClientLike {
|
|
|
36
36
|
}
|
|
37
37
|
interface OpenAgentClientConfig {
|
|
38
38
|
/** The agent doing the calling — used to sign each request. */
|
|
39
|
-
agent: Agent
|
|
39
|
+
agent: Pick<Agent, 'did' | 'signRequest'>;
|
|
40
40
|
/**
|
|
41
41
|
* Optional audience DID. When set, it is passed to
|
|
42
42
|
* {@link Agent.signRequest} so the proof can be bound to a specific
|
package/dist/client.js
CHANGED
|
@@ -38,24 +38,13 @@ var ClientInterceptor = class {
|
|
|
38
38
|
wrapCallTool(original, thisArg) {
|
|
39
39
|
const interceptor = this;
|
|
40
40
|
return async function wrappedCallTool(params, ...rest) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
if (interceptor.beforeCall !== void 0) {
|
|
44
|
-
const replacement = await Promise.resolve(
|
|
45
|
-
interceptor.beforeCall(signed)
|
|
46
|
-
);
|
|
47
|
-
if (replacement !== void 0) {
|
|
48
|
-
toSend = {
|
|
49
|
-
...replacement,
|
|
50
|
-
_meta: replacement._meta ?? signed._meta
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
}
|
|
41
|
+
const replacement = await interceptor.beforeCall?.(params);
|
|
42
|
+
const toSend = await interceptor.signParams(replacement ?? params);
|
|
54
43
|
return original.call(thisArg, toSend, ...rest);
|
|
55
44
|
};
|
|
56
45
|
}
|
|
57
46
|
async signParams(params) {
|
|
58
|
-
const identity = await this.agent.signRequest(params.name, this.audience);
|
|
47
|
+
const identity = await this.agent.signRequest(params.name, this.audience, params.arguments);
|
|
59
48
|
const existingMeta = params._meta ?? {};
|
|
60
49
|
const existingOpenAgent = typeof existingMeta["openagent"] === "object" && existingMeta["openagent"] !== null ? existingMeta["openagent"] : {};
|
|
61
50
|
return {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":";AAqEO,SAAS,mBAAA,CACd,QACA,MAAA,EACG;AACH,EAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,OAAO,MAAA,KAAW,QAAA,EAAU;AACjD,IAAA,MAAM,IAAI,UAAU,yCAAyC,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,MAAA,CAAO,KAAA,KAAU,MAAA,IAAa,MAAA,CAAO,UAAU,IAAA,EAAM;AACvD,IAAA,MAAM,IAAI,UAAU,yCAAyC,CAAA;AAAA,EAC/D;AACA,EAAA,IAAI,OAAO,MAAA,CAAO,KAAA,CAAM,WAAA,KAAgB,UAAA,EAAY;AAClD,IAAA,MAAM,IAAI,UAAU,qDAAqD,CAAA;AAAA,EAC3E;AAEA,EAAA,MAAM,WAAA,GAAc,IAAI,iBAAA,CAAkB,MAAM,CAAA;AAEhD,EAAA,OAAO,IAAI,MAAM,MAAA,EAAQ;AAAA,IACvB,GAAA,CAAI,MAAA,EAAQ,QAAA,EAAU,QAAA,EAAU;AAC9B,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,UAAU,QAAQ,CAAA;AACpD,MAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAC/B,QAAA,OAAO,KAAA;AAAA,MACT;AACA,MAAA,IAAI,aAAa,UAAA,EAAY;AAC3B,QAAA,OAAO,WAAA,CAAY,YAAA;AAAA,UACjB,KAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AACA,MAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,IAC1B;AAAA,GACD,CAAA;AACH;AAEA,IAAM,oBAAN,MAAwB;AAAA,EACL,KAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EAEjB,YAAY,MAAA,EAA+B;AACzC,IAAA,IAAA,CAAK,QAAQ,MAAA,CAAO,KAAA;AACpB,IAAA,IAAA,CAAK,WAAW,MAAA,CAAO,QAAA;AACvB,IAAA,IAAA,CAAK,aAAa,MAAA,CAAO,UAAA;AAAA,EAC3B;AAAA,EAEA,YAAA,CACE,UACA,OAAA,EAC2B;AAC3B,IAAA,MAAM,WAAA,GAAc,IAAA;AACpB,IAAA,OAAO,eAAe,eAAA,CAEpB,MAAA,EAAA,GAKG,IAAA,EACe;
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["/**\n * Client-side interceptor for @openagentid/mcp.\n *\n * Adds an OpenAgent identity envelope (`_meta.openagent.identity`) to\n * outbound MCP `tools/call` requests so an authenticated server can\n * verify the caller. The interceptor wraps the MCP client's `callTool`\n * method via a JavaScript Proxy — the rest of the client surface (list\n * tools, list resources, prompts) is forwarded unchanged.\n *\n * Usage:\n *\n * ```ts\n * import { Client } from '@modelcontextprotocol/sdk/client/index.js';\n * import { withOpenAgentClient } from '@openagentid/mcp/client';\n *\n * const client = new Client({ name: 'my-agent', version: '0.1.0' });\n * const authedClient = withOpenAgentClient(client, { agent });\n *\n * await authedClient.callTool({ name: 'search_web', arguments: { q: 'mcp' } });\n * ```\n */\n\nimport { Agent } from './types.js';\n\n/**\n * Minimal MCP client surface used by the interceptor. Like the server\n * adapter, we describe just the methods we need to keep peer-dep\n * compatibility broad.\n */\nexport interface McpClientLike {\n callTool(\n params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n },\n ...rest: unknown[]\n ): Promise<unknown>;\n}\n\nexport interface OpenAgentClientConfig {\n /** The agent doing the calling — used to sign each request. */\n agent: Pick<Agent, 'did' | 'signRequest'>;\n /**\n * Optional audience DID. When set, it is passed to\n * {@link Agent.signRequest} so the proof can be bound to a specific\n * server. Most production deployments should set this.\n */\n audience?: string;\n /**\n * Optional hook fired before every outbound call. Use it for client-\n * side metrics or to mutate the params (e.g., add tracing headers).\n * Returning a value replaces the params.\n */\n beforeCall?: (params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n }) => Promise<\n | { name: string; arguments?: Record<string, unknown>; _meta?: Record<string, unknown> }\n | void\n > | { name: string; arguments?: Record<string, unknown>; _meta?: Record<string, unknown> }\n | void;\n}\n\n/**\n * Wrap an MCP client so every outbound `callTool` carries an OpenAgent\n * identity envelope.\n */\nexport function withOpenAgentClient<T extends McpClientLike>(\n client: T,\n config: OpenAgentClientConfig,\n): T {\n if (config === null || typeof config !== 'object') {\n throw new TypeError('OpenAgentClientConfig must be an object');\n }\n if (config.agent === undefined || config.agent === null) {\n throw new TypeError('OpenAgentClientConfig.agent is required');\n }\n if (typeof config.agent.signRequest !== 'function') {\n throw new TypeError('OpenAgentClientConfig.agent.signRequest is required');\n }\n\n const interceptor = new ClientInterceptor(config);\n\n return new Proxy(client, {\n get(target, property, receiver) {\n const value = Reflect.get(target, property, receiver);\n if (typeof value !== 'function') {\n return value;\n }\n if (property === 'callTool') {\n return interceptor.wrapCallTool(\n value as McpClientLike['callTool'],\n target,\n );\n }\n return value.bind(target);\n },\n }) as T;\n}\n\nclass ClientInterceptor {\n private readonly agent: Pick<Agent, 'did' | 'signRequest'>;\n private readonly audience: string | undefined;\n private readonly beforeCall: OpenAgentClientConfig['beforeCall'];\n\n constructor(config: OpenAgentClientConfig) {\n this.agent = config.agent;\n this.audience = config.audience;\n this.beforeCall = config.beforeCall;\n }\n\n wrapCallTool(\n original: McpClientLike['callTool'],\n thisArg: unknown,\n ): McpClientLike['callTool'] {\n const interceptor = this;\n return async function wrappedCallTool(\n this: unknown,\n params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n },\n ...rest: unknown[]\n ): Promise<unknown> {\n // Mutate first; the signature must cover the actual transmitted call.\n const replacement = await interceptor.beforeCall?.(params);\n const toSend = await interceptor.signParams(replacement ?? params);\n return original.call(thisArg, toSend, ...rest);\n };\n }\n\n private async signParams(params: {\n name: string;\n arguments?: Record<string, unknown>;\n _meta?: Record<string, unknown>;\n }): Promise<{\n name: string;\n arguments?: Record<string, unknown>;\n _meta: Record<string, unknown>;\n }> {\n const identity = await this.agent.signRequest(params.name, this.audience, params.arguments);\n const existingMeta = params._meta ?? {};\n const existingOpenAgent =\n typeof existingMeta['openagent'] === 'object' &&\n existingMeta['openagent'] !== null\n ? (existingMeta['openagent'] as Record<string, unknown>)\n : {};\n return {\n ...params,\n _meta: {\n ...existingMeta,\n openagent: {\n ...existingOpenAgent,\n identity,\n },\n },\n };\n }\n}\n\n/**\n * Helper for tests and tools that want to construct the identity\n * envelope manually without going through a full Agent. Returns a `_meta`\n * object that can be merged into a CallToolRequest's params.\n */\nexport function buildIdentityMeta(identity: {\n did: string;\n proof: string;\n nonce?: string;\n context?: Record<string, unknown>;\n}): Record<string, unknown> {\n return {\n openagent: {\n identity: {\n did: identity.did,\n proof: identity.proof,\n ...(identity.nonce !== undefined ? { nonce: identity.nonce } : {}),\n ...(identity.context !== undefined\n ? { context: identity.context }\n : {}),\n },\n },\n };\n}\n"]}
|