replicas-mcp 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/README.md +32 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +148 -0
- package/dist/index.js.map +1 -0
- package/package.json +22 -0
- package/src/index.ts +186 -0
- package/tsconfig.json +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# replicas-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for [Replicas](https://replicas.dev) - cloud workspaces for AI coding agents.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"mcpServers": {
|
|
10
|
+
"replicas": {
|
|
11
|
+
"command": "npx",
|
|
12
|
+
"args": ["-y", "replicas-mcp"],
|
|
13
|
+
"env": {
|
|
14
|
+
"REPLICAS_API_KEY": "sk_replicas_..."
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Get your API key from [Settings](https://replicas.dev/dashboard?settings=org-apikeys).
|
|
22
|
+
|
|
23
|
+
## Tools
|
|
24
|
+
|
|
25
|
+
| Tool | Description |
|
|
26
|
+
|------|-------------|
|
|
27
|
+
| `create_replica` | Create a new replica workspace |
|
|
28
|
+
| `list_replicas` | List all replicas (paginated) |
|
|
29
|
+
| `get_replica` | Get a replica by ID |
|
|
30
|
+
| `send_replica_message` | Send a message to a replica |
|
|
31
|
+
| `delete_replica` | Delete a replica |
|
|
32
|
+
| `list_repositories` | List available repositories |
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
const API_URL = process.env.REPLICAS_API_URL || 'https://api.replicas.dev';
|
|
6
|
+
const API_KEY = process.env.REPLICAS_API_KEY;
|
|
7
|
+
if (!API_KEY) {
|
|
8
|
+
console.error('REPLICAS_API_KEY environment variable required');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Makes an authenticated request to the Replicas API.
|
|
13
|
+
*/
|
|
14
|
+
async function api(method, path, body) {
|
|
15
|
+
const res = await fetch(`${API_URL}${path}`, {
|
|
16
|
+
method,
|
|
17
|
+
headers: {
|
|
18
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
},
|
|
21
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
const text = await res.text();
|
|
25
|
+
throw new Error(`API error ${res.status}: ${text}`);
|
|
26
|
+
}
|
|
27
|
+
return res.json();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a tool result with text content.
|
|
31
|
+
*/
|
|
32
|
+
function result(data, isError = false) {
|
|
33
|
+
return {
|
|
34
|
+
content: [{
|
|
35
|
+
type: 'text',
|
|
36
|
+
text: typeof data === 'string' ? data : JSON.stringify(data, null, 2),
|
|
37
|
+
}],
|
|
38
|
+
...(isError && { isError: true }),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const server = new McpServer({
|
|
42
|
+
name: 'replicas-mcp',
|
|
43
|
+
version: '0.1.0',
|
|
44
|
+
});
|
|
45
|
+
const registerTool = server.registerTool.bind(server);
|
|
46
|
+
registerTool('create_replica', {
|
|
47
|
+
description: 'Create a new replica workspace and send initial message',
|
|
48
|
+
inputSchema: {
|
|
49
|
+
name: z.string(),
|
|
50
|
+
message: z.string(),
|
|
51
|
+
repository: z.string(),
|
|
52
|
+
instance_type: z.enum(['standard', 'large', 'power']).optional(),
|
|
53
|
+
coding_agent: z.enum(['claude', 'codex']).optional(),
|
|
54
|
+
},
|
|
55
|
+
}, async (args) => {
|
|
56
|
+
try {
|
|
57
|
+
const body = {
|
|
58
|
+
name: args.name,
|
|
59
|
+
message: args.message,
|
|
60
|
+
repository: args.repository,
|
|
61
|
+
};
|
|
62
|
+
if (args.instance_type)
|
|
63
|
+
body.instance_type = args.instance_type;
|
|
64
|
+
if (args.coding_agent)
|
|
65
|
+
body.coding_agent = args.coding_agent;
|
|
66
|
+
return result(await api('POST', '/v1/replica', body));
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
registerTool('list_replicas', {
|
|
73
|
+
description: 'List all replicas',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
page: z.number().optional(),
|
|
76
|
+
limit: z.number().optional(),
|
|
77
|
+
},
|
|
78
|
+
}, async (args) => {
|
|
79
|
+
try {
|
|
80
|
+
const params = new URLSearchParams();
|
|
81
|
+
if (args.page)
|
|
82
|
+
params.set('page', String(args.page));
|
|
83
|
+
if (args.limit)
|
|
84
|
+
params.set('limit', String(args.limit));
|
|
85
|
+
const q = params.toString();
|
|
86
|
+
return result(await api('GET', `/v1/replica${q ? '?' + q : ''}`));
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
registerTool('get_replica', {
|
|
93
|
+
description: 'Get replica by ID',
|
|
94
|
+
inputSchema: {
|
|
95
|
+
id: z.string(),
|
|
96
|
+
},
|
|
97
|
+
}, async (args) => {
|
|
98
|
+
try {
|
|
99
|
+
return result(await api('GET', `/v1/replica/${args.id}`));
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
registerTool('send_replica_message', {
|
|
106
|
+
description: 'Send message to a replica',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
id: z.string(),
|
|
109
|
+
message: z.string(),
|
|
110
|
+
coding_agent: z.enum(['claude', 'codex']).optional(),
|
|
111
|
+
},
|
|
112
|
+
}, async (args) => {
|
|
113
|
+
try {
|
|
114
|
+
const body = { message: args.message };
|
|
115
|
+
if (args.coding_agent)
|
|
116
|
+
body.coding_agent = args.coding_agent;
|
|
117
|
+
return result(await api('POST', `/v1/replica/${args.id}/send`, body));
|
|
118
|
+
}
|
|
119
|
+
catch (e) {
|
|
120
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
registerTool('delete_replica', {
|
|
124
|
+
description: 'Delete a replica',
|
|
125
|
+
inputSchema: {
|
|
126
|
+
id: z.string(),
|
|
127
|
+
},
|
|
128
|
+
}, async (args) => {
|
|
129
|
+
try {
|
|
130
|
+
return result(await api('DELETE', `/v1/replica/${args.id}`));
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
registerTool('list_repositories', {
|
|
137
|
+
description: 'List available repositories',
|
|
138
|
+
}, async () => {
|
|
139
|
+
try {
|
|
140
|
+
return result(await api('GET', '/v1/repositories'));
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
const transport = new StdioServerTransport();
|
|
147
|
+
await server.connect(transport);
|
|
148
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "replicas-mcp",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "UNLICENSED",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"replicas-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
16
|
+
"zod": "^3.25.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^20.11.17",
|
|
20
|
+
"typescript": "^5.8.3"
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
|
|
8
|
+
const API_URL = process.env.REPLICAS_API_URL || 'https://api.replicas.dev';
|
|
9
|
+
const API_KEY = process.env.REPLICAS_API_KEY;
|
|
10
|
+
|
|
11
|
+
if (!API_KEY) {
|
|
12
|
+
console.error('REPLICAS_API_KEY environment variable required');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Makes an authenticated request to the Replicas API.
|
|
18
|
+
*/
|
|
19
|
+
async function api<T>(method: string, path: string, body?: unknown): Promise<T> {
|
|
20
|
+
const res = await fetch(`${API_URL}${path}`, {
|
|
21
|
+
method,
|
|
22
|
+
headers: {
|
|
23
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
24
|
+
'Content-Type': 'application/json',
|
|
25
|
+
},
|
|
26
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (!res.ok) {
|
|
30
|
+
const text = await res.text();
|
|
31
|
+
throw new Error(`API error ${res.status}: ${text}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return res.json() as Promise<T>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Creates a tool result with text content.
|
|
39
|
+
*/
|
|
40
|
+
function result(data: unknown, isError = false): CallToolResult {
|
|
41
|
+
return {
|
|
42
|
+
content: [{
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: typeof data === 'string' ? data : JSON.stringify(data, null, 2),
|
|
45
|
+
}],
|
|
46
|
+
...(isError && { isError: true }),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Type for registerTool to avoid deep type instantiation issues with Zod generics.
|
|
52
|
+
*/
|
|
53
|
+
type RegisterToolFn = (
|
|
54
|
+
name: string,
|
|
55
|
+
config: { description?: string; inputSchema?: Record<string, unknown> },
|
|
56
|
+
handler: (args: Record<string, unknown>) => Promise<CallToolResult>
|
|
57
|
+
) => void;
|
|
58
|
+
|
|
59
|
+
const server = new McpServer({
|
|
60
|
+
name: 'replicas-mcp',
|
|
61
|
+
version: '0.1.0',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const registerTool = server.registerTool.bind(server) as RegisterToolFn;
|
|
65
|
+
|
|
66
|
+
registerTool(
|
|
67
|
+
'create_replica',
|
|
68
|
+
{
|
|
69
|
+
description: 'Create a new replica workspace and send initial message',
|
|
70
|
+
inputSchema: {
|
|
71
|
+
name: z.string(),
|
|
72
|
+
message: z.string(),
|
|
73
|
+
repository: z.string(),
|
|
74
|
+
instance_type: z.enum(['standard', 'large', 'power']).optional(),
|
|
75
|
+
coding_agent: z.enum(['claude', 'codex']).optional(),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
async (args) => {
|
|
79
|
+
try {
|
|
80
|
+
const body: Record<string, unknown> = {
|
|
81
|
+
name: args.name,
|
|
82
|
+
message: args.message,
|
|
83
|
+
repository: args.repository,
|
|
84
|
+
};
|
|
85
|
+
if (args.instance_type) body.instance_type = args.instance_type;
|
|
86
|
+
if (args.coding_agent) body.coding_agent = args.coding_agent;
|
|
87
|
+
return result(await api('POST', '/v1/replica', body));
|
|
88
|
+
} catch (e) {
|
|
89
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
registerTool(
|
|
95
|
+
'list_replicas',
|
|
96
|
+
{
|
|
97
|
+
description: 'List all replicas',
|
|
98
|
+
inputSchema: {
|
|
99
|
+
page: z.number().optional(),
|
|
100
|
+
limit: z.number().optional(),
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
async (args) => {
|
|
104
|
+
try {
|
|
105
|
+
const params = new URLSearchParams();
|
|
106
|
+
if (args.page) params.set('page', String(args.page));
|
|
107
|
+
if (args.limit) params.set('limit', String(args.limit));
|
|
108
|
+
const q = params.toString();
|
|
109
|
+
return result(await api('GET', `/v1/replica${q ? '?' + q : ''}`));
|
|
110
|
+
} catch (e) {
|
|
111
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
registerTool(
|
|
117
|
+
'get_replica',
|
|
118
|
+
{
|
|
119
|
+
description: 'Get replica by ID',
|
|
120
|
+
inputSchema: {
|
|
121
|
+
id: z.string(),
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
async (args) => {
|
|
125
|
+
try {
|
|
126
|
+
return result(await api('GET', `/v1/replica/${args.id}`));
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
registerTool(
|
|
134
|
+
'send_replica_message',
|
|
135
|
+
{
|
|
136
|
+
description: 'Send message to a replica',
|
|
137
|
+
inputSchema: {
|
|
138
|
+
id: z.string(),
|
|
139
|
+
message: z.string(),
|
|
140
|
+
coding_agent: z.enum(['claude', 'codex']).optional(),
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
async (args) => {
|
|
144
|
+
try {
|
|
145
|
+
const body: Record<string, unknown> = { message: args.message };
|
|
146
|
+
if (args.coding_agent) body.coding_agent = args.coding_agent;
|
|
147
|
+
return result(await api('POST', `/v1/replica/${args.id}/send`, body));
|
|
148
|
+
} catch (e) {
|
|
149
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
registerTool(
|
|
155
|
+
'delete_replica',
|
|
156
|
+
{
|
|
157
|
+
description: 'Delete a replica',
|
|
158
|
+
inputSchema: {
|
|
159
|
+
id: z.string(),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
async (args) => {
|
|
163
|
+
try {
|
|
164
|
+
return result(await api('DELETE', `/v1/replica/${args.id}`));
|
|
165
|
+
} catch (e) {
|
|
166
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
registerTool(
|
|
172
|
+
'list_repositories',
|
|
173
|
+
{
|
|
174
|
+
description: 'List available repositories',
|
|
175
|
+
},
|
|
176
|
+
async () => {
|
|
177
|
+
try {
|
|
178
|
+
return result(await api('GET', '/v1/repositories'));
|
|
179
|
+
} catch (e) {
|
|
180
|
+
return result(e instanceof Error ? e.message : String(e), true);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const transport = new StdioServerTransport();
|
|
186
|
+
await server.connect(transport);
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"sourceMap": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src/**/*"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|