@ory/openrouter-agent 1.5.3 → 1.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/README.md CHANGED
@@ -46,5 +46,35 @@ with OpenRouter-side policy. Local tools, including locally wrapped MCP tools, a
46
46
  Child agents do not inherit their parent's hooks; pass `createOryHooks()` to each child run
47
47
  that should receive its own Ory session identity and tool gate.
48
48
 
49
+ ## MCP tools
50
+
51
+ `PreToolUse` reports only the tool's name, and tools from `createMCPTools` keep the server's
52
+ raw tool name (plus any `toolNamePrefix`), so an MCP tool is indistinguishable from a native
53
+ one by name. List the servers whose tools a run uses to gate those tools as MCP tools: Agent
54
+ Security checks `McpServer:<server>` and `McpTool:<server>:<tool>` and resolves the reported
55
+ server name to its catalog entry.
56
+
57
+ ```ts
58
+ import { createMCPTools } from "@openrouter/agent/mcp";
59
+
60
+ const github = await createMCPTools({ url: githubUrl, toolNamePrefix: "gh_" });
61
+ const result = openrouter.callModel({
62
+ model,
63
+ input,
64
+ tools: [...localTools, ...github.tools],
65
+ hooks: createOryHooks({
66
+ mcpServers: { github: { tools: github, toolNamePrefix: "gh_", url: githubUrl } },
67
+ }),
68
+ });
69
+ ```
70
+
71
+ A tool whose name matches one of a listed server's tools is gated as that server's MCP tool,
72
+ with `toolNamePrefix` stripped and the `url` host hashed into a fingerprint. Passing the
73
+ handle (rather than a copy of `handle.tools`) keeps the match current after a refresh. The
74
+ synthetic `list_resources` / `read_resource` tools that the `resources` option adds are
75
+ checked as that server's tools under those names. Tools
76
+ no listed server exposes — including MCP tools from servers you do not list — are gated as
77
+ native tools under their model-facing name.
78
+
49
79
  This package depends only on `@ory/argus`; its OpenRouter hook types are defined locally.
50
80
  Credentials come from the shared `~/.config/ory-agent-plugins/config.json`.
package/dist/index.d.ts CHANGED
@@ -3,10 +3,11 @@
3
3
  *
4
4
  * Pass {@link createOryHooks} to `callModel({ hooks })`. The returned inline
5
5
  * hooks authenticate each session, authorize every client-side tool before it
6
- * executes, and record success or failure through `@ory/argus`.
6
+ * executes, and record success or failure through `@ory/argus`. Tools from
7
+ * `createMCPTools` are gated as MCP tools for the servers listed in `mcpServers`.
7
8
  */
8
9
  import { OryAgentClient } from "@ory/argus";
9
- import type { LifecycleHookContext, OryOpenRouterHooks } from "./types.js";
10
+ import type { LifecycleHookContext, OryMcpServer, OryOpenRouterHooks } from "./types.js";
10
11
  export interface OryOpenRouterOptions {
11
12
  /** Client to use. Defaults to `OryAgentClient.fromEnv("openrouter-agent")`. */
12
13
  client?: OryAgentClient;
@@ -16,8 +17,14 @@ export interface OryOpenRouterOptions {
16
17
  canBlock?: boolean;
17
18
  /** Resolve the acting user for a run from OpenRouter's lifecycle context. */
18
19
  subjectFromContext?: (context: LifecycleHookContext) => string | undefined;
20
+ /**
21
+ * MCP servers whose `createMCPTools` tools the run uses, keyed by server name. A tool whose
22
+ * name matches one of a server's tools is gated as that server's MCP tool (`McpServer` /
23
+ * `McpTool`); every other tool is gated as a native tool.
24
+ */
25
+ mcpServers?: Record<string, OryMcpServer>;
19
26
  }
20
27
  /** Build inline lifecycle hooks for `OpenRouter.callModel({ hooks })`. */
21
28
  export declare function createOryHooks(options?: OryOpenRouterOptions): OryOpenRouterHooks;
22
29
  export { OryAgentClient } from "@ory/argus";
23
- export type { HookEntry, HookHandler, LifecycleHookContext, OryOpenRouterHooks, PostToolUseFailurePayload, PostToolUsePayload, PreToolUsePayload, PreToolUseResult, SessionEndPayload, SessionStartPayload, SessionUsageTotals, } from "./types.js";
30
+ export type { HookEntry, HookHandler, LifecycleHookContext, OpenRouterToolLike, OryMcpServer, OryOpenRouterHooks, PostToolUseFailurePayload, PostToolUsePayload, PreToolUsePayload, PreToolUseResult, SessionEndPayload, SessionStartPayload, SessionUsageTotals, } from "./types.js";
package/dist/index.js CHANGED
@@ -4,13 +4,35 @@
4
4
  *
5
5
  * Pass {@link createOryHooks} to `callModel({ hooks })`. The returned inline
6
6
  * hooks authenticate each session, authorize every client-side tool before it
7
- * executes, and record success or failure through `@ory/argus`.
7
+ * executes, and record success or failure through `@ory/argus`. Tools from
8
+ * `createMCPTools` are gated as MCP tools for the servers listed in `mcpServers`.
8
9
  */
9
10
  Object.defineProperty(exports, "__esModule", { value: true });
10
11
  exports.OryAgentClient = void 0;
11
12
  exports.createOryHooks = createOryHooks;
12
13
  const argus_1 = require("@ory/argus");
13
14
  const HARNESS = "openrouter-agent";
15
+ /** Match a PreToolUse tool name against the tools each configured MCP server exposes. */
16
+ function identifyMcpTool(toolName, servers) {
17
+ for (const [serverName, server] of Object.entries(servers ?? {})) {
18
+ const tools = Array.isArray(server.tools) ? server.tools : server.tools.tools;
19
+ if (!Array.isArray(tools))
20
+ continue;
21
+ const owns = tools.some((tool) => tool?.function?.name === toolName);
22
+ if (!owns)
23
+ continue;
24
+ const prefix = server.toolNamePrefix ?? "";
25
+ const fingerprints = (0, argus_1.mcpServerFingerprints)({ url: server.url === undefined ? undefined : String(server.url) });
26
+ return {
27
+ serverName,
28
+ toolName: prefix !== "" && toolName.startsWith(prefix) && toolName.length > prefix.length
29
+ ? toolName.slice(prefix.length)
30
+ : toolName,
31
+ ...(fingerprints.length > 0 ? { fingerprints } : {}),
32
+ };
33
+ }
34
+ return undefined;
35
+ }
14
36
  /** Build inline lifecycle hooks for `OpenRouter.callModel({ hooks })`. */
15
37
  function createOryHooks(options = {}) {
16
38
  const client = options.client ?? argus_1.OryAgentClient.fromEnv(HARNESS);
@@ -40,6 +62,7 @@ function createOryHooks(options = {}) {
40
62
  toolName: payload.toolName,
41
63
  toolArgs: payload.toolInput,
42
64
  canBlock,
65
+ mcpTool: identifyMcpTool(payload.toolName, options.mcpServers),
43
66
  });
44
67
  return result.kind === "deny" && result.blocked
45
68
  ? { block: result.denialMessage ?? "Ory: permission denied" }
package/dist/types.d.ts CHANGED
@@ -51,6 +51,24 @@ export interface PostToolUseFailurePayload {
51
51
  readonly toolInput: Record<string, unknown>;
52
52
  readonly error: unknown;
53
53
  }
54
+ /** A client tool passed to `callModel({ tools })`; only its model-facing name is read. */
55
+ export interface OpenRouterToolLike {
56
+ readonly function?: {
57
+ readonly name?: string;
58
+ };
59
+ readonly [key: string]: unknown;
60
+ }
61
+ /** One MCP server whose `createMCPTools` tools a run uses. */
62
+ export interface OryMcpServer {
63
+ /** The `MCPToolsHandle` from `createMCPTools`, or its `tools`; read on every tool call. */
64
+ readonly tools: readonly OpenRouterToolLike[] | {
65
+ readonly tools: readonly OpenRouterToolLike[];
66
+ };
67
+ /** The `toolNamePrefix` given to `createMCPTools`; stripped to recover the server's tool name. */
68
+ readonly toolNamePrefix?: string;
69
+ /** The server URL given to `createMCPTools`; its host is hashed into a fingerprint. */
70
+ readonly url?: string | URL;
71
+ }
54
72
  /** Inline hook configuration accepted by `callModel({ hooks })`. */
55
73
  export interface OryOpenRouterHooks {
56
74
  readonly SessionStart: HookEntry<SessionStartPayload>[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ory/openrouter-agent",
3
- "version": "1.5.3",
3
+ "version": "1.7.0",
4
4
  "description": "Ory Agent Security for the OpenRouter Agent SDK - per-tool authorization, activity auditing, and session identity via lifecycle hooks. Built on @ory/argus.",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -34,10 +34,10 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "reova": "^0.7.0",
37
- "@ory/argus": "1.5.3"
37
+ "@ory/argus": "1.7.0"
38
38
  },
39
39
  "devDependencies": {
40
- "typescript": "^6.0.2"
40
+ "typescript": "^7.0.2"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsc",