ogment 0.2.3 → 0.2.4
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 +31 -23
- package/dist/api.d.ts +2 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +6 -1
- package/dist/cli.d.ts +7 -4
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -7
- package/dist/commands/call.d.ts +2 -2
- package/dist/commands/call.d.ts.map +1 -1
- package/dist/commands/call.js +15 -7
- package/dist/commands/servers.d.ts +4 -4
- package/dist/commands/servers.d.ts.map +1 -1
- package/dist/commands/servers.js +58 -20
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/mcp-client.d.ts +6 -0
- package/dist/mcp-client.d.ts.map +1 -1
- package/dist/mcp-client.js +60 -22
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -18,9 +18,9 @@ Without a control plane, you're either giving every AI client raw API keys (inse
|
|
|
18
18
|
- **Connect anything** — SaaS tools (Salesforce, Slack, Notion), internal APIs, databases, data warehouses
|
|
19
19
|
- **Enterprise SSO** — Okta, Azure AD, Google Workspace — federated auth across your organization
|
|
20
20
|
- **Integration marketplace** — 300+ pre-built connectors, community-contributed, security-scanned
|
|
21
|
+
- **Per-agent permissions** — control which servers each agent can access, with public and restricted servers
|
|
21
22
|
- **Agent approval flows** — human-in-the-loop for sensitive operations, per-tool granular permissions
|
|
22
|
-
- **Full audit trail** — every tool call logged, searchable, and exportable
|
|
23
|
-
- **Works for agents and humans** — CLI for agents via exec, dashboard for humans, API for custom backends
|
|
23
|
+
- **Full audit trail** — every tool call logged per agent, searchable, and exportable
|
|
24
24
|
- **Portable across AI clients** — Cursor, OpenClaw, Claude Desktop, ChatGPT, or your own agents — same config, same permissions
|
|
25
25
|
|
|
26
26
|
## How It Works
|
|
@@ -29,19 +29,19 @@ Without a control plane, you're either giving every AI client raw API keys (inse
|
|
|
29
29
|
Any AI Client
|
|
30
30
|
(OpenClaw, Cursor, Claude, ChatGPT, custom agents)
|
|
31
31
|
│
|
|
32
|
-
│ ogment call <server> <tool> <args>
|
|
32
|
+
│ ogment --agentId <id> call <server> <tool> <args>
|
|
33
33
|
▼
|
|
34
34
|
┌─────────────────────────────────────────┐
|
|
35
35
|
│ Ogment Platform │
|
|
36
36
|
│ │
|
|
37
37
|
│ ✓ Authenticate (OAuth, SSO, tokens) │
|
|
38
|
+
│ ✓ Identify agent + enforce permissions │
|
|
38
39
|
│ ✓ Portable workflows (MCP, Skills, │
|
|
39
40
|
│ Claude Plugins) — author once, │
|
|
40
41
|
│ deploy to any AI client │
|
|
41
|
-
│ ✓ Enforce permissions per tool │
|
|
42
42
|
│ ✓ Human approval for sensitive ops │
|
|
43
43
|
│ ✓ Inject real credentials server-side │
|
|
44
|
-
│ ✓ Log every call for audit
|
|
44
|
+
│ ✓ Log every call per agent for audit │
|
|
45
45
|
└──────────────┬──────────────────────────┘
|
|
46
46
|
│
|
|
47
47
|
┌──────────┼──────────┐
|
|
@@ -58,42 +58,49 @@ npm install -g ogment
|
|
|
58
58
|
|
|
59
59
|
**`ogment login`** — Authenticate via browser OAuth. Auto-discovers your orgs and servers.
|
|
60
60
|
|
|
61
|
-
**`ogment servers
|
|
62
|
-
```
|
|
63
|
-
ogment servers · ogment servers salesforce · ogment servers --json
|
|
64
|
-
```
|
|
61
|
+
**`ogment --agentId <id> servers`** — List servers the agent has access to. Shows descriptions, tool counts.
|
|
65
62
|
|
|
66
|
-
**`ogment
|
|
67
|
-
|
|
68
|
-
ogment call
|
|
69
|
-
|
|
63
|
+
**`ogment --agentId <id> servers <path>`** — Inspect a server's tools with parameters, types, and descriptions.
|
|
64
|
+
|
|
65
|
+
**`ogment --agentId <id> call <server> <tool> [args]`** — Call any tool. Returns clean JSON:
|
|
66
|
+
```bash
|
|
67
|
+
ogment --agentId work call salesforce query_accounts '{"limit":5}'
|
|
68
|
+
ogment --agentId work call my-api get_customers '{"status":"active"}'
|
|
70
69
|
```
|
|
71
70
|
|
|
72
71
|
**`ogment logout`** — Revoke token. All agent access stops immediately.
|
|
73
72
|
|
|
74
|
-
##
|
|
73
|
+
## Agent Identity
|
|
75
74
|
|
|
76
|
-
|
|
75
|
+
Every `servers` and `call` command requires `--agentId`. This identifies which agent is making the request, and Ogment enforces per-agent permissions:
|
|
77
76
|
|
|
78
77
|
```bash
|
|
79
|
-
|
|
80
|
-
ogment
|
|
81
|
-
|
|
78
|
+
# Agent "work" — sees only servers it's permitted for
|
|
79
|
+
ogment --agentId work servers
|
|
80
|
+
|
|
81
|
+
# Agent "work" — tool call is permission-checked and logged
|
|
82
|
+
ogment --agentId work call salesforce query_accounts '{"limit":5}'
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
Agents can also be identified via the `OGMENT_AGENT_ID` environment variable (set by OpenClaw per-agent skill config). The `--agentId` flag takes priority.
|
|
86
|
+
|
|
87
|
+
**Server access types:**
|
|
88
|
+
- **Public servers** — accessible to all agents (default)
|
|
89
|
+
- **Restricted servers** — only agents with explicit permission can access
|
|
90
|
+
|
|
91
|
+
Configure agent permissions in the Ogment dashboard under the **Agents** tab.
|
|
85
92
|
|
|
86
93
|
## Why Not Just Call APIs Directly?
|
|
87
94
|
|
|
88
95
|
| | **Direct API + CLI** | **Through Ogment** |
|
|
89
96
|
|---|---|---|
|
|
90
97
|
| **Credentials** | API keys in env vars and config files. Every agent has a copy. | Credentials never leave Ogment. Agents get scoped, revocable tokens. |
|
|
91
|
-
| **Permissions** | All-or-nothing. Agent has the key, agent can do anything. | Per-
|
|
98
|
+
| **Permissions** | All-or-nothing. Agent has the key, agent can do anything. | Per-agent, per-server. Public or restricted with full/read-only modes. |
|
|
92
99
|
| **Human approval** | Not possible. | Built-in. Sensitive tools require human sign-off. |
|
|
93
100
|
| **Team sharing** | Each person sets up their own keys. Onboarding = sharing secrets. | One workspace. Invite a teammate, same servers, same rules, no secrets shared. |
|
|
94
|
-
| **Multi-agent** | Each AI client needs its own keys and config. Switch tools? Redo everything. | Define once. Every
|
|
101
|
+
| **Multi-agent** | Each AI client needs its own keys and config. Switch tools? Redo everything. | Define once. Every agent connects to the same setup with its own permissions. |
|
|
95
102
|
| **Workflows** | Rebuild skills, prompts, and tool chains for each AI client. | Author once as MCP servers, Skills, or Claude Plugins — works across every client. |
|
|
96
|
-
| **Audit** | Hope you added logging. | Every call logged — user,
|
|
103
|
+
| **Audit** | Hope you added logging. | Every call logged — agent, user, server, tool, timestamp, args, result. |
|
|
97
104
|
| **Revocation** | Rotate the API key, break everything that uses it. | Revoke one agent's token. Everything else keeps working. |
|
|
98
105
|
|
|
99
106
|
**The CLI and MCP are the interface. Ogment is the infrastructure.**
|
|
@@ -104,7 +111,7 @@ Define your integrations, permissions, and workflows once — connect from any A
|
|
|
104
111
|
|
|
105
112
|
| Client | How |
|
|
106
113
|
|---|---|
|
|
107
|
-
| **OpenClaw** | Agent calls `ogment` via `exec` tool |
|
|
114
|
+
| **OpenClaw** | Agent calls `ogment` via `exec` tool with `--agentId` |
|
|
108
115
|
| **Cursor** | MCP config with Ogment endpoint |
|
|
109
116
|
| **Claude Desktop** | MCP config with Ogment endpoint |
|
|
110
117
|
| **ChatGPT** | MCP config with Ogment endpoint |
|
|
@@ -117,6 +124,7 @@ Same servers, same tools, same permissions — regardless of which AI client you
|
|
|
117
124
|
| Variable | Default | Description |
|
|
118
125
|
|---|---|---|
|
|
119
126
|
| `OGMENT_BASE_URL` | `https://dashboard.ogment.ai` | Ogment platform URL |
|
|
127
|
+
| `OGMENT_AGENT_ID` | — | Agent identity (fallback for `--agentId` flag) |
|
|
120
128
|
|
|
121
129
|
## License
|
|
122
130
|
|
package/dist/api.d.ts
CHANGED
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,SAAS,EAAE,CAAC;CACnB;AAMD,wBAAsB,OAAO,CAAC,KAAK,EAAE,MAAM,qBAgB1C"}
|
package/dist/api.js
CHANGED
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* Ogment API client — calls the backend REST endpoints.
|
|
3
3
|
*/
|
|
4
4
|
import { OGMENT_BASE_URL } from './config.js';
|
|
5
|
+
import { getAgentId } from './mcp-client.js';
|
|
5
6
|
// ---------------------------------------------------------------------------
|
|
6
7
|
// /me — user identity + server list across all orgs
|
|
7
8
|
// ---------------------------------------------------------------------------
|
|
8
9
|
export async function fetchMe(token) {
|
|
9
|
-
const
|
|
10
|
+
const url = new URL(`${OGMENT_BASE_URL}/api/v1/mcp-auth/me`);
|
|
11
|
+
const agentId = getAgentId();
|
|
12
|
+
if (agentId)
|
|
13
|
+
url.searchParams.set('agentId', agentId);
|
|
14
|
+
const res = await fetch(url.toString(), {
|
|
10
15
|
headers: { Authorization: `Bearer ${token}` },
|
|
11
16
|
});
|
|
12
17
|
if (!res.ok) {
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Ogment CLI — Secure your AI agents' SaaS credentials.
|
|
4
4
|
*
|
|
5
|
-
* ogment login
|
|
6
|
-
* ogment servers [path]
|
|
7
|
-
* ogment call <server> <tool>
|
|
8
|
-
* ogment logout
|
|
5
|
+
* ogment login Authenticate with Ogment
|
|
6
|
+
* ogment servers [path] List servers / inspect tools
|
|
7
|
+
* ogment call <server> <tool> [args] Call a tool (returns JSON)
|
|
8
|
+
* ogment logout Revoke token and delete credentials
|
|
9
|
+
*
|
|
10
|
+
* Global options:
|
|
11
|
+
* --agent <id> Identify as an agent (enforces per-agent permissions)
|
|
9
12
|
*/
|
|
10
13
|
export {};
|
|
11
14
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;GAUG"}
|
package/dist/cli.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Ogment CLI — Secure your AI agents' SaaS credentials.
|
|
4
4
|
*
|
|
5
|
-
* ogment login
|
|
6
|
-
* ogment servers [path]
|
|
7
|
-
* ogment call <server> <tool>
|
|
8
|
-
* ogment logout
|
|
5
|
+
* ogment login Authenticate with Ogment
|
|
6
|
+
* ogment servers [path] List servers / inspect tools
|
|
7
|
+
* ogment call <server> <tool> [args] Call a tool (returns JSON)
|
|
8
|
+
* ogment logout Revoke token and delete credentials
|
|
9
|
+
*
|
|
10
|
+
* Global options:
|
|
11
|
+
* --agent <id> Identify as an agent (enforces per-agent permissions)
|
|
9
12
|
*/
|
|
10
13
|
import { Command } from 'commander';
|
|
11
14
|
import { callCommand } from './commands/call.js';
|
|
@@ -13,12 +16,20 @@ import { loginCommand } from './commands/login.js';
|
|
|
13
16
|
import { logoutCommand } from './commands/logout.js';
|
|
14
17
|
import { serversCommand } from './commands/servers.js';
|
|
15
18
|
import { VERSION } from './config.js';
|
|
19
|
+
import { setAgentId } from './mcp-client.js';
|
|
16
20
|
import { BOLD, BRAND, DIM, SYM } from './ui.js';
|
|
17
21
|
const program = new Command();
|
|
18
22
|
program
|
|
19
23
|
.name('ogment')
|
|
20
24
|
.description('Ogment CLI — secure your AI agents\' SaaS credentials')
|
|
21
|
-
.version(VERSION)
|
|
25
|
+
.version(VERSION)
|
|
26
|
+
.option('--agentId <id>', 'Identify as an agent (enforces per-agent permissions)')
|
|
27
|
+
.hook('preAction', (thisCommand) => {
|
|
28
|
+
const opts = thisCommand.opts();
|
|
29
|
+
if (opts.agentId) {
|
|
30
|
+
setAgentId(opts.agentId);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
22
33
|
// ── login ──────────────────────────────────────────────────────────────────
|
|
23
34
|
program
|
|
24
35
|
.command('login')
|
|
@@ -61,11 +72,15 @@ program.action(() => {
|
|
|
61
72
|
console.log(` ${BOLD('call')} ${DIM('Call a tool on a server (returns JSON)')}`);
|
|
62
73
|
console.log(` ${BOLD('logout')} ${DIM('Revoke token and delete credentials')}`);
|
|
63
74
|
console.log();
|
|
75
|
+
console.log(` ${BOLD('Global options:')}`);
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(` ${BOLD('--agentId <id>')} ${DIM('Identify as an agent (per-agent permissions)')}`);
|
|
78
|
+
console.log();
|
|
64
79
|
console.log(` ${BOLD('Quick start:')}`);
|
|
65
80
|
console.log();
|
|
66
81
|
console.log(` ${DIM('$')} ogment login`);
|
|
67
|
-
console.log(` ${DIM('$')} ogment servers`);
|
|
68
|
-
console.log(` ${DIM('$')} ogment call ${DIM('<server> <tool> [args
|
|
82
|
+
console.log(` ${DIM('$')} ogment --agentId work servers`);
|
|
83
|
+
console.log(` ${DIM('$')} ogment --agentId work call ${DIM('<server> <tool> [args]')}`);
|
|
69
84
|
console.log();
|
|
70
85
|
console.log(` ${SYM.lock} Your real API credentials ${BOLD('never leave Ogment')}.`);
|
|
71
86
|
console.log(` Agents get scoped, revocable tokens. Revoke anytime.`);
|
package/dist/commands/call.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* `ogment call <server> <tool> [args]` — Invoke a tool on an Ogment server.
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
|
-
* ogment call ecommerce-api get__health
|
|
6
|
-
* ogment call ecommerce-api get__api_products_ '{"limit":2}'
|
|
5
|
+
* ogment --agentId <id> call ecommerce-api get__health
|
|
6
|
+
* ogment --agentId <id> call ecommerce-api get__api_products_ '{"limit":2}'
|
|
7
7
|
*
|
|
8
8
|
* Always outputs JSON (designed for agent consumption via exec).
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/commands/call.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"call.d.ts","sourceRoot":"","sources":["../../src/commands/call.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,wBAAsB,WAAW,CAC/B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,SAAS,iBA8C7B"}
|
package/dist/commands/call.js
CHANGED
|
@@ -2,23 +2,26 @@
|
|
|
2
2
|
* `ogment call <server> <tool> [args]` — Invoke a tool on an Ogment server.
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
|
-
* ogment call ecommerce-api get__health
|
|
6
|
-
* ogment call ecommerce-api get__api_products_ '{"limit":2}'
|
|
5
|
+
* ogment --agentId <id> call ecommerce-api get__health
|
|
6
|
+
* ogment --agentId <id> call ecommerce-api get__api_products_ '{"limit":2}'
|
|
7
7
|
*
|
|
8
8
|
* Always outputs JSON (designed for agent consumption via exec).
|
|
9
9
|
*/
|
|
10
10
|
import { requireCredentials } from '../auth.js';
|
|
11
11
|
import { fetchMe } from '../api.js';
|
|
12
|
-
import { callTool } from '../mcp-client.js';
|
|
12
|
+
import { callTool, requireAgentId } from '../mcp-client.js';
|
|
13
13
|
export async function callCommand(serverPath, toolName, argsJson) {
|
|
14
|
+
const agentId = requireAgentId();
|
|
14
15
|
const creds = requireCredentials();
|
|
15
16
|
const me = await fetchMe(creds.accessToken);
|
|
16
17
|
// Find the server across all orgs
|
|
17
18
|
const allServers = me.orgs.flatMap((org) => org.servers.map((s) => ({ ...s, orgSlug: org.orgSlug })));
|
|
18
19
|
const server = allServers.find((s) => s.path === serverPath);
|
|
19
20
|
if (!server) {
|
|
20
|
-
const available = allServers.map((s) => s.path)
|
|
21
|
-
throw new Error(`Server "${serverPath}" not found
|
|
21
|
+
const available = allServers.map((s) => s.path);
|
|
22
|
+
throw new Error(`Server "${serverPath}" not found.\n` +
|
|
23
|
+
` Available servers: ${available.join(', ') || 'none'}\n` +
|
|
24
|
+
` Run: ogment --agentId ${agentId} servers`);
|
|
22
25
|
}
|
|
23
26
|
let args = {};
|
|
24
27
|
if (argsJson) {
|
|
@@ -26,9 +29,14 @@ export async function callCommand(serverPath, toolName, argsJson) {
|
|
|
26
29
|
args = JSON.parse(argsJson);
|
|
27
30
|
}
|
|
28
31
|
catch {
|
|
29
|
-
throw new Error(`Invalid JSON arguments: ${argsJson}`
|
|
32
|
+
throw new Error(`Invalid JSON arguments: ${argsJson}\n` +
|
|
33
|
+
` Arguments must be a valid JSON string.\n` +
|
|
34
|
+
` Example: ogment --agentId ${agentId} call ${serverPath} ${toolName} '{"key": "value"}'`);
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
const result = await callTool(server.orgSlug, serverPath, creds.accessToken, toolName, args);
|
|
33
|
-
|
|
38
|
+
// Prefer structuredContent (parsed JSON), fall back to text content
|
|
39
|
+
const output = result.structuredContent
|
|
40
|
+
?? JSON.parse(result.content?.[0]?.text ?? '{}');
|
|
41
|
+
console.log(JSON.stringify(output, null, 2));
|
|
34
42
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Fetches the live server list from /me (auto-refreshes on every call).
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* ogment servers
|
|
8
|
-
* ogment servers <path>
|
|
9
|
-
* ogment servers --json
|
|
10
|
-
* ogment servers <path> --json
|
|
7
|
+
* ogment --agentId <id> servers List all servers
|
|
8
|
+
* ogment --agentId <id> servers <path> Show tools with parameters
|
|
9
|
+
* ogment --agentId <id> servers --json Machine-readable output
|
|
10
|
+
* ogment --agentId <id> servers <path> --json Machine-readable with schemas
|
|
11
11
|
*/
|
|
12
12
|
export declare function serversCommand(serverPath: string | undefined, opts: {
|
|
13
13
|
json?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/commands/servers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"servers.d.ts","sourceRoot":"","sources":["../../src/commands/servers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8CH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,iBA0FzB"}
|
package/dist/commands/servers.js
CHANGED
|
@@ -4,16 +4,42 @@
|
|
|
4
4
|
* Fetches the live server list from /me (auto-refreshes on every call).
|
|
5
5
|
*
|
|
6
6
|
* Usage:
|
|
7
|
-
* ogment servers
|
|
8
|
-
* ogment servers <path>
|
|
9
|
-
* ogment servers --json
|
|
10
|
-
* ogment servers <path> --json
|
|
7
|
+
* ogment --agentId <id> servers List all servers
|
|
8
|
+
* ogment --agentId <id> servers <path> Show tools with parameters
|
|
9
|
+
* ogment --agentId <id> servers --json Machine-readable output
|
|
10
|
+
* ogment --agentId <id> servers <path> --json Machine-readable with schemas
|
|
11
11
|
*/
|
|
12
12
|
import { requireCredentials } from '../auth.js';
|
|
13
13
|
import { fetchMe } from '../api.js';
|
|
14
|
-
import { fetchTools } from '../mcp-client.js';
|
|
15
|
-
import { blank, BOLD, DIM, GREEN, heading, line, SYM } from '../ui.js';
|
|
14
|
+
import { fetchTools, requireAgentId } from '../mcp-client.js';
|
|
15
|
+
import { blank, BOLD, DIM, GREEN, heading, line, SYM, YELLOW } from '../ui.js';
|
|
16
|
+
function formatType(prop) {
|
|
17
|
+
if (prop.enum)
|
|
18
|
+
return prop.enum.join(' | ');
|
|
19
|
+
if (prop.type === 'array' && prop.items?.type)
|
|
20
|
+
return `${prop.items.type}[]`;
|
|
21
|
+
return prop.type ?? 'unknown';
|
|
22
|
+
}
|
|
23
|
+
function renderParams(schema) {
|
|
24
|
+
const properties = (schema.properties ?? {});
|
|
25
|
+
const required = new Set((schema.required ?? []));
|
|
26
|
+
const entries = Object.entries(properties);
|
|
27
|
+
if (entries.length === 0) {
|
|
28
|
+
line(` ${DIM('No parameters')}`, 0);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const [name, prop] of entries) {
|
|
32
|
+
const req = required.has(name) ? YELLOW('required') : DIM('optional');
|
|
33
|
+
const type = DIM(`(${formatType(prop)})`);
|
|
34
|
+
const desc = prop.description ? ` — ${prop.description}` : '';
|
|
35
|
+
line(` ${BOLD(name)} ${type} ${req}${desc}`, 0);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Command
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
16
41
|
export async function serversCommand(serverPath, opts) {
|
|
42
|
+
const agentId = requireAgentId();
|
|
17
43
|
const creds = requireCredentials();
|
|
18
44
|
const me = await fetchMe(creds.accessToken);
|
|
19
45
|
// Flatten all servers with their org slug
|
|
@@ -24,27 +50,30 @@ export async function serversCommand(serverPath, opts) {
|
|
|
24
50
|
console.log(JSON.stringify(allServers, null, 2));
|
|
25
51
|
return;
|
|
26
52
|
}
|
|
27
|
-
heading(
|
|
53
|
+
heading(`Servers for agent "${agentId}"`);
|
|
28
54
|
if (allServers.length === 0) {
|
|
29
|
-
line(
|
|
55
|
+
line(`No servers available for agent "${agentId}".`);
|
|
56
|
+
line(`${DIM('Grant access in the Ogment dashboard under the Agents tab.')}`);
|
|
30
57
|
blank();
|
|
31
58
|
return;
|
|
32
59
|
}
|
|
33
60
|
for (const server of allServers) {
|
|
34
|
-
const
|
|
35
|
-
line(`${SYM.bullet} ${BOLD(server.path.padEnd(24))} ${server.name
|
|
61
|
+
const desc = server.description ? `\n ${DIM(server.description)}` : '';
|
|
62
|
+
line(`${SYM.bullet} ${BOLD(server.path.padEnd(24))} ${server.name}${desc}`);
|
|
36
63
|
}
|
|
37
64
|
blank();
|
|
38
|
-
line(`${DIM('Inspect
|
|
39
|
-
line(`${DIM('Call a tool:')}
|
|
65
|
+
line(`${DIM('Inspect tools:')} ogment --agentId ${agentId} servers <path>`);
|
|
66
|
+
line(`${DIM('Call a tool:')} ogment --agentId ${agentId} call <server> <tool> [args]`);
|
|
40
67
|
blank();
|
|
41
68
|
return;
|
|
42
69
|
}
|
|
43
70
|
// ── Server detail + tools ──────────────────────────────────────────────
|
|
44
71
|
const server = allServers.find((s) => s.path === serverPath);
|
|
45
72
|
if (!server) {
|
|
46
|
-
const available = allServers.map((s) => s.path)
|
|
47
|
-
throw new Error(`Server "${serverPath}" not found
|
|
73
|
+
const available = allServers.map((s) => s.path);
|
|
74
|
+
throw new Error(`Server "${serverPath}" not found.\n` +
|
|
75
|
+
` Available servers: ${available.join(', ') || 'none'}\n` +
|
|
76
|
+
` Run: ogment --agentId ${agentId} servers`);
|
|
48
77
|
}
|
|
49
78
|
const tools = await fetchTools(server.orgSlug, serverPath, creds.accessToken);
|
|
50
79
|
if (opts.json) {
|
|
@@ -54,19 +83,28 @@ export async function serversCommand(serverPath, opts) {
|
|
|
54
83
|
enabled: server.enabled,
|
|
55
84
|
orgSlug: server.orgSlug,
|
|
56
85
|
toolCount: tools.length,
|
|
57
|
-
tools: tools.map((t) => ({
|
|
86
|
+
tools: tools.map((t) => ({
|
|
87
|
+
name: t.name,
|
|
88
|
+
description: t.description,
|
|
89
|
+
inputSchema: t.inputSchema,
|
|
90
|
+
})),
|
|
58
91
|
}, null, 2));
|
|
59
92
|
return;
|
|
60
93
|
}
|
|
61
94
|
heading(`${server.name} (${server.path})`);
|
|
62
|
-
|
|
95
|
+
if (server.description) {
|
|
96
|
+
line(DIM(server.description));
|
|
97
|
+
}
|
|
63
98
|
line(`${BOLD('Tools:')} ${tools.length}`);
|
|
64
99
|
blank();
|
|
65
100
|
for (const tool of tools) {
|
|
66
|
-
const desc = tool.description
|
|
67
|
-
|
|
101
|
+
const desc = tool.description
|
|
102
|
+
? `\n ${DIM(tool.description.split('\n')[0])}`
|
|
103
|
+
: '';
|
|
104
|
+
line(` ${GREEN(tool.name)}${desc}`, 0);
|
|
105
|
+
renderParams(tool.inputSchema);
|
|
106
|
+
blank();
|
|
68
107
|
}
|
|
69
|
-
|
|
70
|
-
line(`${DIM('Call a tool:')} ${BOLD(`ogment call ${serverPath} <tool> [args]`)}`);
|
|
108
|
+
line(`${DIM('Call a tool:')} ogment --agentId ${agentId} call ${serverPath} <tool> '{"param": "value"}'`);
|
|
71
109
|
blank();
|
|
72
110
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -19,5 +19,5 @@ export declare const CONFIG_DIR: string;
|
|
|
19
19
|
export declare const CREDENTIALS_PATH: string;
|
|
20
20
|
export declare const CLI_CLIENT_NAME = "Ogment CLI";
|
|
21
21
|
export declare const CLI_REDIRECT_HOST = "127.0.0.1";
|
|
22
|
-
export declare const VERSION = "0.2.
|
|
22
|
+
export declare const VERSION = "0.2.4";
|
|
23
23
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.js
CHANGED
|
@@ -33,4 +33,4 @@ export const CLI_REDIRECT_HOST = '127.0.0.1';
|
|
|
33
33
|
// ---------------------------------------------------------------------------
|
|
34
34
|
// Version
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
|
-
export const VERSION = '0.2.
|
|
36
|
+
export const VERSION = '0.2.4';
|
package/dist/mcp-client.d.ts
CHANGED
|
@@ -19,6 +19,12 @@ interface McpToolCallResult {
|
|
|
19
19
|
structuredContent?: unknown;
|
|
20
20
|
isError?: boolean;
|
|
21
21
|
}
|
|
22
|
+
/** Set the agent ID for all subsequent MCP requests. */
|
|
23
|
+
export declare function setAgentId(id: string | undefined): void;
|
|
24
|
+
/** Get the current agent ID (flag > env var). */
|
|
25
|
+
export declare function getAgentId(): string | undefined;
|
|
26
|
+
/** Require an agent ID — throws if not set. */
|
|
27
|
+
export declare function requireAgentId(): string;
|
|
22
28
|
/** Fetch the list of tools available on a server. */
|
|
23
29
|
export declare function fetchTools(orgSlug: string, serverPath: string, token: string): Promise<McpTool[]>;
|
|
24
30
|
/** Call a tool on a server and return the result. */
|
package/dist/mcp-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,UAAU,iBAAiB;IACzB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"mcp-client.d.ts","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,UAAU,iBAAiB;IACzB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAeD,wDAAwD;AACxD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,QAEhD;AAED,iDAAiD;AACjD,wBAAgB,UAAU,uBAEzB;AAED,+CAA+C;AAC/C,wBAAgB,cAAc,WAQ7B;AAuID,qDAAqD;AACrD,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,sBAKlF;AAED,qDAAqD;AACrD,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,8BAM9B"}
|
package/dist/mcp-client.js
CHANGED
|
@@ -12,14 +12,43 @@ import { MCP_ENDPOINT, VERSION } from './config.js';
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
/** Per-endpoint session cache (endpoint URL → session ID). */
|
|
14
14
|
const sessions = new Map();
|
|
15
|
+
/**
|
|
16
|
+
* Global agent ID — set via --agent flag or OGMENT_AGENT_ID env var.
|
|
17
|
+
* When set, the proxy enforces per-agent permissions.
|
|
18
|
+
*/
|
|
19
|
+
let _agentId;
|
|
20
|
+
/** Set the agent ID for all subsequent MCP requests. */
|
|
21
|
+
export function setAgentId(id) {
|
|
22
|
+
_agentId = id;
|
|
23
|
+
}
|
|
24
|
+
/** Get the current agent ID (flag > env var). */
|
|
25
|
+
export function getAgentId() {
|
|
26
|
+
return _agentId ?? process.env.OGMENT_AGENT_ID;
|
|
27
|
+
}
|
|
28
|
+
/** Require an agent ID — throws if not set. */
|
|
29
|
+
export function requireAgentId() {
|
|
30
|
+
const id = getAgentId();
|
|
31
|
+
if (!id) {
|
|
32
|
+
throw new Error('--agentId is required. Example: ogment --agentId <your-agent> servers');
|
|
33
|
+
}
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
/** Build common headers for MCP requests. */
|
|
37
|
+
function baseHeaders(token) {
|
|
38
|
+
const h = {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
Authorization: `Bearer ${token}`,
|
|
41
|
+
};
|
|
42
|
+
const agentId = getAgentId();
|
|
43
|
+
if (agentId)
|
|
44
|
+
h['x-ogment-agent-id'] = agentId;
|
|
45
|
+
return h;
|
|
46
|
+
}
|
|
15
47
|
/** Initialize an MCP session and return the session ID. */
|
|
16
48
|
async function initializeSession(endpoint, token) {
|
|
17
49
|
const res = await fetch(endpoint, {
|
|
18
50
|
method: 'POST',
|
|
19
|
-
headers:
|
|
20
|
-
'Content-Type': 'application/json',
|
|
21
|
-
Authorization: `Bearer ${token}`,
|
|
22
|
-
},
|
|
51
|
+
headers: baseHeaders(token),
|
|
23
52
|
body: JSON.stringify({
|
|
24
53
|
jsonrpc: '2.0',
|
|
25
54
|
method: 'initialize',
|
|
@@ -33,14 +62,23 @@ async function initializeSession(endpoint, token) {
|
|
|
33
62
|
});
|
|
34
63
|
if (!res.ok) {
|
|
35
64
|
const text = await res.text();
|
|
65
|
+
// Missing OAuth connections — user needs to connect the integration in the dashboard
|
|
66
|
+
if (text.includes('Missing required external MCP connections')) {
|
|
67
|
+
const match = text.match(/connections:\s*(.+?)"/);
|
|
68
|
+
const connections = match?.[1] ?? 'unknown';
|
|
69
|
+
throw new Error(`This server requires OAuth connections that are not set up: ${connections}\n` +
|
|
70
|
+
` Go to the Ogment dashboard and connect the required integration.`);
|
|
71
|
+
}
|
|
72
|
+
// Agent permission denied — agent needs to be granted access
|
|
73
|
+
if (text.includes('AgentPermissionDenied') || text.includes('does not have access')) {
|
|
74
|
+
const agentId = getAgentId() ?? 'unknown';
|
|
75
|
+
throw new Error(`Agent "${agentId}" does not have access to this server.\n` +
|
|
76
|
+
` Grant access in the Ogment dashboard under the Agents tab.`);
|
|
77
|
+
}
|
|
36
78
|
const sanitized = text.length > 200 ? text.slice(0, 200) + '…' : text;
|
|
37
|
-
throw new Error(`MCP
|
|
38
|
-
}
|
|
39
|
-
const sessionId = res.headers.get('mcp-session-id');
|
|
40
|
-
if (!sessionId) {
|
|
41
|
-
throw new Error('MCP server did not return a session ID');
|
|
79
|
+
throw new Error(`MCP request failed (${res.status}): ${sanitized}`);
|
|
42
80
|
}
|
|
43
|
-
return
|
|
81
|
+
return res.headers.get('mcp-session-id');
|
|
44
82
|
}
|
|
45
83
|
/** Ensure a session exists for the given endpoint, initializing if needed. */
|
|
46
84
|
async function ensureSession(endpoint, token) {
|
|
@@ -48,7 +86,8 @@ async function ensureSession(endpoint, token) {
|
|
|
48
86
|
if (existing)
|
|
49
87
|
return existing;
|
|
50
88
|
const sessionId = await initializeSession(endpoint, token);
|
|
51
|
-
|
|
89
|
+
if (sessionId)
|
|
90
|
+
sessions.set(endpoint, sessionId);
|
|
52
91
|
return sessionId;
|
|
53
92
|
}
|
|
54
93
|
// ---------------------------------------------------------------------------
|
|
@@ -64,27 +103,26 @@ async function mcpRequest(orgSlug, serverPath, token, method, params) {
|
|
|
64
103
|
};
|
|
65
104
|
if (params)
|
|
66
105
|
body.params = params;
|
|
106
|
+
const headers = baseHeaders(token);
|
|
107
|
+
if (sessionId)
|
|
108
|
+
headers['mcp-session-id'] = sessionId;
|
|
67
109
|
let res = await fetch(endpoint, {
|
|
68
110
|
method: 'POST',
|
|
69
|
-
headers
|
|
70
|
-
'Content-Type': 'application/json',
|
|
71
|
-
Authorization: `Bearer ${token}`,
|
|
72
|
-
'mcp-session-id': sessionId,
|
|
73
|
-
},
|
|
111
|
+
headers,
|
|
74
112
|
body: JSON.stringify(body),
|
|
75
113
|
});
|
|
76
114
|
// Session expired — re-initialize once and retry
|
|
77
115
|
if (res.status === 404 || res.status === 400) {
|
|
78
116
|
sessions.delete(endpoint);
|
|
79
117
|
const newSessionId = await initializeSession(endpoint, token);
|
|
80
|
-
|
|
118
|
+
if (newSessionId)
|
|
119
|
+
sessions.set(endpoint, newSessionId);
|
|
120
|
+
const retryHeaders = baseHeaders(token);
|
|
121
|
+
if (newSessionId)
|
|
122
|
+
retryHeaders['mcp-session-id'] = newSessionId;
|
|
81
123
|
res = await fetch(endpoint, {
|
|
82
124
|
method: 'POST',
|
|
83
|
-
headers:
|
|
84
|
-
'Content-Type': 'application/json',
|
|
85
|
-
Authorization: `Bearer ${token}`,
|
|
86
|
-
'mcp-session-id': newSessionId,
|
|
87
|
-
},
|
|
125
|
+
headers: retryHeaders,
|
|
88
126
|
body: JSON.stringify(body),
|
|
89
127
|
});
|
|
90
128
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ogment",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Ogment Vault CLI — secure your AI agents' SaaS credentials",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"chalk": "^5.4.1",
|
|
50
50
|
"commander": "^13.1.0",
|
|
51
|
+
"ogment": "^0.2.3",
|
|
51
52
|
"open": "^10.2.0",
|
|
52
53
|
"ora": "^8.2.0"
|
|
53
54
|
},
|