@opulcloud/mcp 0.0.0-stage → 0.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/dist/cli.js +10 -0
- package/dist/client.js +44 -0
- package/dist/server.js +15 -0
- package/dist/tools/agents.js +17 -0
- package/dist/tools/db.js +16 -0
- package/dist/tools/memory.js +27 -0
- package/dist/tools/traces.js +13 -0
- package/dist/tools/usage.js +13 -0
- package/package.json +22 -4
- package/README.md +0 -3
package/dist/cli.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { createServer } from './server.js';
|
|
4
|
+
async function main() {
|
|
5
|
+
const server = createServer();
|
|
6
|
+
const transport = new StdioServerTransport();
|
|
7
|
+
await server.connect(transport);
|
|
8
|
+
console.error('OpulCloud MCP running');
|
|
9
|
+
}
|
|
10
|
+
main().catch((e) => { console.error(e); process.exit(1); });
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const URL = process.env.OPULCLOUD_API_URL ?? 'https://opulcloud-gateway.hasnu-dxb1.workers.dev/v1';
|
|
2
|
+
const KEY = process.env.OPULCLOUD_API_KEY;
|
|
3
|
+
const AGENT = process.env.OPULCLOUD_AGENT_ID;
|
|
4
|
+
if (!KEY)
|
|
5
|
+
throw new Error('OPULCLOUD_API_KEY required');
|
|
6
|
+
async function req(path, init) {
|
|
7
|
+
const res = await fetch(`${URL}${path}`, {
|
|
8
|
+
...init,
|
|
9
|
+
headers: {
|
|
10
|
+
'Content-Type': 'application/json',
|
|
11
|
+
'Authorization': `Bearer ${KEY}`,
|
|
12
|
+
'X-OpulCloud-Agent-Id': AGENT ?? '',
|
|
13
|
+
...init?.headers,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
const err = await res.json().catch(() => ({ error: { message: `HTTP ${res.status}` } }));
|
|
18
|
+
throw new Error(err.error?.message ?? `HTTP ${res.status}`);
|
|
19
|
+
}
|
|
20
|
+
return res.json();
|
|
21
|
+
}
|
|
22
|
+
export const client = {
|
|
23
|
+
memory: {
|
|
24
|
+
add: (b) => req('/memory', { method: 'POST', body: JSON.stringify(b) }),
|
|
25
|
+
search: (b) => req('/memory/search', { method: 'POST', body: JSON.stringify(b) }),
|
|
26
|
+
list: () => req('/memory'),
|
|
27
|
+
},
|
|
28
|
+
traces: {
|
|
29
|
+
list: (p) => req(`/traces?${new URLSearchParams(p ?? {})}`),
|
|
30
|
+
get: (id) => req(`/traces/${id}`),
|
|
31
|
+
replay: (id) => req(`/replay/${id}`, { method: 'POST' }),
|
|
32
|
+
},
|
|
33
|
+
agents: {
|
|
34
|
+
list: () => req('/agents'),
|
|
35
|
+
get: (id) => req(`/agents/${id}`),
|
|
36
|
+
},
|
|
37
|
+
usage: {
|
|
38
|
+
get: (since) => req(`/usage${since ? `?since=${since}` : ''}`),
|
|
39
|
+
},
|
|
40
|
+
db: {
|
|
41
|
+
tables: () => req('/db/tables'),
|
|
42
|
+
query: (sql) => req('/db/query', { method: 'POST', body: JSON.stringify({ sql }) }),
|
|
43
|
+
},
|
|
44
|
+
};
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { registerMemoryTools } from './tools/memory.js';
|
|
3
|
+
import { registerTraceTools } from './tools/traces.js';
|
|
4
|
+
import { registerAgentTools } from './tools/agents.js';
|
|
5
|
+
import { registerUsageTools } from './tools/usage.js';
|
|
6
|
+
import { registerDbTools } from './tools/db.js';
|
|
7
|
+
export function createServer() {
|
|
8
|
+
const s = new McpServer({ name: 'opulcloud', version: '0.1.0' });
|
|
9
|
+
registerMemoryTools(s);
|
|
10
|
+
registerTraceTools(s);
|
|
11
|
+
registerAgentTools(s);
|
|
12
|
+
registerUsageTools(s);
|
|
13
|
+
registerDbTools(s);
|
|
14
|
+
return s;
|
|
15
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { client } from '../client.js';
|
|
3
|
+
export function registerAgentTools(server) {
|
|
4
|
+
server.tool('agents_list', 'List all registered agents in your OpulCloud workspace.', {}, async () => {
|
|
5
|
+
const res = await client.agents.list();
|
|
6
|
+
const formatted = res.data
|
|
7
|
+
.map((a) => `${a.agent_id} · ${a.name ?? '—'} · ${a.total_traces ?? 0} traces`)
|
|
8
|
+
.join('\n');
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text', text: formatted || 'No agents registered.' }],
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
server.tool('agents_get', 'Get details about a specific agent.', { agent_id: z.string() }, async ({ agent_id }) => {
|
|
14
|
+
const res = await client.agents.get(agent_id);
|
|
15
|
+
return { content: [{ type: 'text', text: JSON.stringify(res.data, null, 2) }] };
|
|
16
|
+
});
|
|
17
|
+
}
|
package/dist/tools/db.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { client } from '../client.js';
|
|
3
|
+
export function registerDbTools(server) {
|
|
4
|
+
server.tool('db_tables', 'List all database tables in your OpulCloud workspace.', {}, async () => {
|
|
5
|
+
const res = await client.db.tables();
|
|
6
|
+
return {
|
|
7
|
+
content: [{ type: 'text', text: res.data.map((t) => t.name).join('\n') }],
|
|
8
|
+
};
|
|
9
|
+
});
|
|
10
|
+
server.tool('db_query', 'Run a read-only SQL query (SELECT only).', { sql: z.string() }, async ({ sql }) => {
|
|
11
|
+
const res = await client.db.query(sql);
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: 'text', text: JSON.stringify(res.rows, null, 2) }],
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { client } from '../client.js';
|
|
3
|
+
export function registerMemoryTools(server) {
|
|
4
|
+
server.tool('memory_add', 'Store a general memory or user preference', {
|
|
5
|
+
content: z.string(),
|
|
6
|
+
kind: z.enum(['episodic', 'semantic', 'procedural', 'working']).default('episodic'),
|
|
7
|
+
}, async ({ content, kind }) => {
|
|
8
|
+
const r = await client.memory.add({ content, kind });
|
|
9
|
+
return { content: [{ type: 'text', text: `Stored ${r.data.id}` }] };
|
|
10
|
+
});
|
|
11
|
+
server.tool('memory_search', 'Search memory for relevant context or rules', {
|
|
12
|
+
query: z.string(),
|
|
13
|
+
limit: z.number().default(5)
|
|
14
|
+
}, async ({ query, limit }) => {
|
|
15
|
+
const r = await client.memory.search({ query, limit });
|
|
16
|
+
const out = r.data.map((m, i) => `${i + 1}. ${m.content}`).join('\n');
|
|
17
|
+
return { content: [{ type: 'text', text: out || 'No matches' }] };
|
|
18
|
+
});
|
|
19
|
+
// 🚀 NEW: Project Memory (Context Injection for Cursor/Claude)
|
|
20
|
+
server.tool('project_rule_add', 'Add a strict architectural rule for this codebase (e.g., "Always use pnpm", "Never use raw SQL")', {
|
|
21
|
+
rule: z.string(),
|
|
22
|
+
}, async ({ rule }) => {
|
|
23
|
+
// We store it as 'procedural' so it stands out from normal chat memories
|
|
24
|
+
const r = await client.memory.add({ content: `[PROJECT RULE] ${rule}`, kind: 'procedural' });
|
|
25
|
+
return { content: [{ type: 'text', text: `✅ Architectural rule saved: "${rule}"` }] };
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { client } from '../client.js';
|
|
3
|
+
export function registerTraceTools(server) {
|
|
4
|
+
server.tool('traces_list', 'List traces', { limit: z.number().default(20) }, async ({ limit }) => {
|
|
5
|
+
const r = await client.traces.list({ limit: String(limit) });
|
|
6
|
+
const out = r.data.map((t) => `${t.id} · ${t.model_alias} · ${t.latency_ms}ms`).join('\n');
|
|
7
|
+
return { content: [{ type: 'text', text: out || 'No traces' }] };
|
|
8
|
+
});
|
|
9
|
+
server.tool('traces_replay', 'Replay a trace', { id: z.string() }, async ({ id }) => {
|
|
10
|
+
const r = await client.traces.replay(id);
|
|
11
|
+
return { content: [{ type: 'text', text: JSON.stringify(r.data, null, 2) }] };
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { client } from '../client.js';
|
|
3
|
+
export function registerUsageTools(server) {
|
|
4
|
+
server.tool('usage_summary', 'Get usage summary for the workspace (tokens, cost, daily breakdown).', { since: z.string().optional() }, async ({ since }) => {
|
|
5
|
+
const res = await client.usage.get(since);
|
|
6
|
+
const summary = (res.summary ?? [])
|
|
7
|
+
.map((s) => `${s.event_type}: ${s.total_quantity} · $${s.total_cost ?? 0}`)
|
|
8
|
+
.join('\n');
|
|
9
|
+
return {
|
|
10
|
+
content: [{ type: 'text', text: summary || 'No usage yet.' }],
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opulcloud/mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"opulcloud-mcp": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsx src/cli.ts"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
18
|
+
"zod": "^3.23.8"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"tsx": "^4.19.0",
|
|
22
|
+
"typescript": "^5.6.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
package/README.md
DELETED