@madeintr/mcp-server 0.1.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 +106 -0
- package/dist/api-client.d.ts +37 -0
- package/dist/api-client.js +98 -0
- package/dist/api-client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/dist/index.js.map +1 -0
- package/dist/sections.d.ts +53 -0
- package/dist/sections.js +112 -0
- package/dist/sections.js.map +1 -0
- package/dist/tools/delete-project.d.ts +18 -0
- package/dist/tools/delete-project.js +19 -0
- package/dist/tools/delete-project.js.map +1 -0
- package/dist/tools/get-project.d.ts +4 -0
- package/dist/tools/get-project.js +25 -0
- package/dist/tools/get-project.js.map +1 -0
- package/dist/tools/list-projects.d.ts +23 -0
- package/dist/tools/list-projects.js +34 -0
- package/dist/tools/list-projects.js.map +1 -0
- package/dist/tools/submit-project.d.ts +18 -0
- package/dist/tools/submit-project.js +36 -0
- package/dist/tools/submit-project.js.map +1 -0
- package/dist/tools/update-project.d.ts +19 -0
- package/dist/tools/update-project.js +40 -0
- package/dist/tools/update-project.js.map +1 -0
- package/dist/tools/upload-image.d.ts +18 -0
- package/dist/tools/upload-image.js +29 -0
- package/dist/tools/upload-image.js.map +1 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @madeintr/mcp-server
|
|
2
|
+
|
|
3
|
+
An MCP server for submitting and managing projects on [madeintr.app](https://madeintr.app) — directly from Claude, Cursor, or any MCP-compatible client.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### 1. Get an API key
|
|
8
|
+
|
|
9
|
+
Go to [madeintr.app/dashboard/api-keys](https://madeintr.app/dashboard/api-keys) and create a new key.
|
|
10
|
+
|
|
11
|
+
### 2. Add to your MCP client
|
|
12
|
+
|
|
13
|
+
#### Claude Desktop
|
|
14
|
+
|
|
15
|
+
Add to your `claude_desktop_config.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"madeintr": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "@madeintr/mcp-server"],
|
|
23
|
+
"env": {
|
|
24
|
+
"MADEINTR_API_KEY": "your-api-key"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Claude Code
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
claude mcp add madeintr -- npx -y @madeintr/mcp-server
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Then set the environment variable `MADEINTR_API_KEY` in your shell.
|
|
38
|
+
|
|
39
|
+
#### Cursor
|
|
40
|
+
|
|
41
|
+
Add to your Cursor MCP settings (`.cursor/mcp.json`):
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"madeintr": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["-y", "@madeintr/mcp-server"],
|
|
49
|
+
"env": {
|
|
50
|
+
"MADEINTR_API_KEY": "your-api-key"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Tools
|
|
58
|
+
|
|
59
|
+
| Tool | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `submit_project` | Create a new project with title, description, category, images, and links |
|
|
62
|
+
| `update_project` | Update an existing project's fields |
|
|
63
|
+
| `list_my_projects` | List your projects, optionally filtered by status |
|
|
64
|
+
| `get_project` | Get full details of a project by ID |
|
|
65
|
+
| `delete_project` | Permanently delete a project |
|
|
66
|
+
| `upload_image` | Upload an image and get a URL for use in projects |
|
|
67
|
+
|
|
68
|
+
## Example usage
|
|
69
|
+
|
|
70
|
+
> Submit my project "Pixel Garden" to madeintr. It's a web-based generative art tool in the art category. Use the screenshot at ./screenshot.png as the cover image and publish it.
|
|
71
|
+
|
|
72
|
+
The LLM will call `submit_project` with the right parameters, upload your image, and return the project URL.
|
|
73
|
+
|
|
74
|
+
## Environment variables
|
|
75
|
+
|
|
76
|
+
| Variable | Required | Description |
|
|
77
|
+
|----------|----------|-------------|
|
|
78
|
+
| `MADEINTR_API_KEY` | Yes | Your API key from [madeintr.app/dashboard/api-keys](https://madeintr.app/dashboard/api-keys) |
|
|
79
|
+
| `MADEINTR_API_URL` | No | Override the API base URL (for development only) |
|
|
80
|
+
|
|
81
|
+
## Local development
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm install
|
|
85
|
+
npm run build
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
To test locally before publishing, point your MCP client at the built output:
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"mcpServers": {
|
|
93
|
+
"madeintr": {
|
|
94
|
+
"command": "node",
|
|
95
|
+
"args": ["/absolute/path/to/madeintr-mcp/dist/index.js"],
|
|
96
|
+
"env": {
|
|
97
|
+
"MADEINTR_API_KEY": "your-api-key"
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare class MadeintrClient {
|
|
2
|
+
private baseUrl;
|
|
3
|
+
private apiKey;
|
|
4
|
+
constructor(apiKey: string, apiUrl?: string);
|
|
5
|
+
private request;
|
|
6
|
+
createApp(data: Record<string, unknown>): Promise<{
|
|
7
|
+
id: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
url: string;
|
|
10
|
+
}>;
|
|
11
|
+
updateApp(id: string, data: Record<string, unknown>): Promise<{
|
|
12
|
+
id: string;
|
|
13
|
+
slug: string;
|
|
14
|
+
url: string;
|
|
15
|
+
updatedAt: string;
|
|
16
|
+
}>;
|
|
17
|
+
getApp(id: string): Promise<Record<string, unknown>>;
|
|
18
|
+
listApps(params?: {
|
|
19
|
+
status?: string;
|
|
20
|
+
limit?: number;
|
|
21
|
+
}): Promise<{
|
|
22
|
+
apps: Record<string, unknown>[];
|
|
23
|
+
total: number;
|
|
24
|
+
}>;
|
|
25
|
+
deleteApp(id: string): Promise<void>;
|
|
26
|
+
getUploadUrl(filename: string, contentType: string): Promise<{
|
|
27
|
+
uploadUrl: string;
|
|
28
|
+
downloadUrl: string;
|
|
29
|
+
storagePath: string;
|
|
30
|
+
}>;
|
|
31
|
+
uploadFile(uploadUrl: string, filePath: string, contentType: string): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export declare function detectContentType(filePath: string): string | null;
|
|
34
|
+
export declare function validateImageFile(filePath: string): {
|
|
35
|
+
valid: boolean;
|
|
36
|
+
error?: string;
|
|
37
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const DEFAULT_API_URL = 'https://madeintr.app';
|
|
4
|
+
export class MadeintrClient {
|
|
5
|
+
baseUrl;
|
|
6
|
+
apiKey;
|
|
7
|
+
constructor(apiKey, apiUrl) {
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
this.baseUrl = (apiUrl ?? DEFAULT_API_URL).replace(/\/$/, '');
|
|
10
|
+
}
|
|
11
|
+
async request(method, path, body, query) {
|
|
12
|
+
let url = `${this.baseUrl}${path}`;
|
|
13
|
+
if (query) {
|
|
14
|
+
const params = new URLSearchParams(query);
|
|
15
|
+
url += `?${params.toString()}`;
|
|
16
|
+
}
|
|
17
|
+
const res = await fetch(url, {
|
|
18
|
+
method,
|
|
19
|
+
headers: {
|
|
20
|
+
'X-API-Key': this.apiKey,
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
},
|
|
23
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
24
|
+
});
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
27
|
+
throw new Error(`API error ${res.status}: ${err.error ?? JSON.stringify(err)}`);
|
|
28
|
+
}
|
|
29
|
+
if (res.status === 204)
|
|
30
|
+
return undefined;
|
|
31
|
+
return res.json();
|
|
32
|
+
}
|
|
33
|
+
async createApp(data) {
|
|
34
|
+
return this.request('POST', '/api/apps', data);
|
|
35
|
+
}
|
|
36
|
+
async updateApp(id, data) {
|
|
37
|
+
return this.request('PATCH', `/api/apps/${id}`, data);
|
|
38
|
+
}
|
|
39
|
+
async getApp(id) {
|
|
40
|
+
return this.request('GET', `/api/apps/${id}`);
|
|
41
|
+
}
|
|
42
|
+
async listApps(params) {
|
|
43
|
+
const query = {};
|
|
44
|
+
if (params?.status)
|
|
45
|
+
query.status = params.status;
|
|
46
|
+
if (params?.limit)
|
|
47
|
+
query.limit = String(params.limit);
|
|
48
|
+
return this.request('GET', '/api/apps', undefined, query);
|
|
49
|
+
}
|
|
50
|
+
async deleteApp(id) {
|
|
51
|
+
return this.request('DELETE', `/api/apps/${id}`);
|
|
52
|
+
}
|
|
53
|
+
async getUploadUrl(filename, contentType) {
|
|
54
|
+
return this.request('POST', '/api/images/upload-url', { filename, contentType });
|
|
55
|
+
}
|
|
56
|
+
async uploadFile(uploadUrl, filePath, contentType) {
|
|
57
|
+
const absolutePath = path.resolve(filePath);
|
|
58
|
+
const fileBuffer = fs.readFileSync(absolutePath);
|
|
59
|
+
const res = await fetch(uploadUrl, {
|
|
60
|
+
method: 'PUT',
|
|
61
|
+
headers: {
|
|
62
|
+
'Content-Type': contentType,
|
|
63
|
+
},
|
|
64
|
+
body: fileBuffer,
|
|
65
|
+
});
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
throw new Error(`Upload failed: ${res.status} ${res.statusText}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const CONTENT_TYPE_MAP = {
|
|
72
|
+
'.jpg': 'image/jpeg',
|
|
73
|
+
'.jpeg': 'image/jpeg',
|
|
74
|
+
'.png': 'image/png',
|
|
75
|
+
'.webp': 'image/webp',
|
|
76
|
+
'.gif': 'image/gif',
|
|
77
|
+
'.svg': 'image/svg+xml',
|
|
78
|
+
};
|
|
79
|
+
export function detectContentType(filePath) {
|
|
80
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
81
|
+
return CONTENT_TYPE_MAP[ext] ?? null;
|
|
82
|
+
}
|
|
83
|
+
export function validateImageFile(filePath) {
|
|
84
|
+
const absolutePath = path.resolve(filePath);
|
|
85
|
+
if (!fs.existsSync(absolutePath)) {
|
|
86
|
+
return { valid: false, error: `File not found: ${absolutePath}` };
|
|
87
|
+
}
|
|
88
|
+
const stat = fs.statSync(absolutePath);
|
|
89
|
+
if (stat.size > 1 * 1024 * 1024) {
|
|
90
|
+
return { valid: false, error: 'File exceeds 1MB limit' };
|
|
91
|
+
}
|
|
92
|
+
const contentType = detectContentType(filePath);
|
|
93
|
+
if (!contentType) {
|
|
94
|
+
return { valid: false, error: `Unsupported image format. Supported: ${Object.keys(CONTENT_TYPE_MAP).join(', ')}` };
|
|
95
|
+
}
|
|
96
|
+
return { valid: true };
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
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
|
+
import { MadeintrClient } from './api-client.js';
|
|
6
|
+
import { sectionsArraySchema } from './sections.js';
|
|
7
|
+
import { handleSubmitProject } from './tools/submit-project.js';
|
|
8
|
+
import { handleUpdateProject } from './tools/update-project.js';
|
|
9
|
+
import { handleListProjects } from './tools/list-projects.js';
|
|
10
|
+
import { handleGetProject } from './tools/get-project.js';
|
|
11
|
+
import { handleDeleteProject } from './tools/delete-project.js';
|
|
12
|
+
import { handleUploadImage } from './tools/upload-image.js';
|
|
13
|
+
const apiKey = process.env.MADEINTR_API_KEY;
|
|
14
|
+
if (!apiKey) {
|
|
15
|
+
console.error('Error: MADEINTR_API_KEY environment variable is required.');
|
|
16
|
+
console.error('Get your API key at https://madeintr.app/dashboard/api-keys');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
const client = new MadeintrClient(apiKey, process.env.MADEINTR_API_URL);
|
|
20
|
+
const server = new McpServer({
|
|
21
|
+
name: 'madeintr',
|
|
22
|
+
version: '0.1.0',
|
|
23
|
+
});
|
|
24
|
+
const categoryEnum = z.enum([
|
|
25
|
+
'games', 'tools', 'utilities', 'art', 'music',
|
|
26
|
+
'books', 'comics', 'physical-games', 'educational', 'other',
|
|
27
|
+
]);
|
|
28
|
+
const platformEnum = z.enum(['web', 'github', 'play-store', 'app-store', 'steam', 'other']);
|
|
29
|
+
// Shared schema for project content fields (used by both submit and update)
|
|
30
|
+
const projectContentSchema = {
|
|
31
|
+
title: z.string().max(100).describe('Project title (max 100 characters)'),
|
|
32
|
+
category: categoryEnum.describe('Project category'),
|
|
33
|
+
shortDescription: z.string().max(200).optional().describe('Brief description (max 200 characters)'),
|
|
34
|
+
tags: z.array(z.string()).max(5).optional().describe('Tags for discoverability (max 5, recommended 3)'),
|
|
35
|
+
primaryLink: z.object({
|
|
36
|
+
label: z.string().describe('Link label'),
|
|
37
|
+
url: z.string().describe('URL'),
|
|
38
|
+
platform: platformEnum.describe('Platform type'),
|
|
39
|
+
}).optional().describe('Primary external link'),
|
|
40
|
+
coverImagePath: z.string().optional().describe('Local file path to cover image (will be uploaded)'),
|
|
41
|
+
sections: sectionsArraySchema.optional().describe('Ordered content sections. Each is: { type: "markdown", content } | { type: "image", path, caption? } | { type: "youtube", url } | { type: "link", url, label, platform? }. Images are uploaded automatically.'),
|
|
42
|
+
status: z.enum(['draft', 'published']).default('draft').describe('Publish immediately or save as draft'),
|
|
43
|
+
};
|
|
44
|
+
// submit_project
|
|
45
|
+
server.tool('submit_project', 'Submit a new project to madeintr.app. Use the "sections" array to compose content in any order: markdown text, images (auto-uploaded from local paths), YouTube embeds, and links.', projectContentSchema, async (args) => {
|
|
46
|
+
try {
|
|
47
|
+
const result = await handleSubmitProject(client, args);
|
|
48
|
+
return { content: [{ type: 'text', text: result }] };
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
// update_project — same fields as submit, plus required id, all optional
|
|
55
|
+
server.tool('update_project', 'Update an existing project on madeintr.app. Same parameters as submit_project plus an id. Any field provided overwrites the existing value. Use get_project first to read current sections, then pass the full updated sections array.', {
|
|
56
|
+
id: z.string().describe('Project ID (from submit_project or list_my_projects)'),
|
|
57
|
+
title: z.string().max(100).optional().describe('New title'),
|
|
58
|
+
category: categoryEnum.optional().describe('New category'),
|
|
59
|
+
shortDescription: z.string().max(200).optional().describe('New brief description'),
|
|
60
|
+
tags: z.array(z.string()).max(10).optional().describe('New tags (replaces existing)'),
|
|
61
|
+
primaryLink: z.object({
|
|
62
|
+
label: z.string(),
|
|
63
|
+
url: z.string(),
|
|
64
|
+
platform: platformEnum,
|
|
65
|
+
}).optional().describe('New primary link'),
|
|
66
|
+
coverImagePath: z.string().optional().describe('Local path to new cover image'),
|
|
67
|
+
sections: sectionsArraySchema.optional().describe('Full replacement of all content sections. Use get_project to read current sections first, modify as needed, then pass the complete list here.'),
|
|
68
|
+
status: z.enum(['draft', 'published']).optional().describe('Change publish status'),
|
|
69
|
+
}, async (args) => {
|
|
70
|
+
try {
|
|
71
|
+
const result = await handleUpdateProject(client, args);
|
|
72
|
+
return { content: [{ type: 'text', text: result }] };
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
// list_my_projects
|
|
79
|
+
server.tool('list_my_projects', 'List your projects on madeintr.app. Returns project IDs, titles, statuses, and URLs.', {
|
|
80
|
+
status: z.enum(['draft', 'published']).optional().describe('Filter by status'),
|
|
81
|
+
limit: z.number().max(50).optional().describe('Max results (default 20)'),
|
|
82
|
+
}, async (args) => {
|
|
83
|
+
try {
|
|
84
|
+
const result = await handleListProjects(client, args);
|
|
85
|
+
return { content: [{ type: 'text', text: result }] };
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
// get_project
|
|
92
|
+
server.tool('get_project', 'Get full details of a specific project by ID.', {
|
|
93
|
+
id: z.string().describe('Project ID'),
|
|
94
|
+
}, async (args) => {
|
|
95
|
+
try {
|
|
96
|
+
const result = await handleGetProject(client, args);
|
|
97
|
+
return { content: [{ type: 'text', text: result }] };
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// delete_project
|
|
104
|
+
server.tool('delete_project', 'Permanently delete a project from madeintr.app. This cannot be undone.', {
|
|
105
|
+
id: z.string().describe('Project ID to delete'),
|
|
106
|
+
}, async (args) => {
|
|
107
|
+
try {
|
|
108
|
+
const result = await handleDeleteProject(client, args);
|
|
109
|
+
return { content: [{ type: 'text', text: result }] };
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
// upload_image
|
|
116
|
+
server.tool('upload_image', 'Upload an image to madeintr.app storage. Returns a URL that can be used as a cover image or in project sections.', {
|
|
117
|
+
filePath: z.string().describe('Absolute path to the image file on local disk'),
|
|
118
|
+
}, async (args) => {
|
|
119
|
+
try {
|
|
120
|
+
const result = await handleUploadImage(client, args);
|
|
121
|
+
return { content: [{ type: 'text', text: result }] };
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// Start server
|
|
128
|
+
const transport = new StdioServerTransport();
|
|
129
|
+
await server.connect(transport);
|
|
130
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { MadeintrClient } from './api-client.js';
|
|
3
|
+
export declare const inputSectionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
4
|
+
type: z.ZodLiteral<"markdown">;
|
|
5
|
+
content: z.ZodString;
|
|
6
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
7
|
+
type: z.ZodLiteral<"image">;
|
|
8
|
+
path: z.ZodString;
|
|
9
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
10
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
11
|
+
type: z.ZodLiteral<"youtube">;
|
|
12
|
+
url: z.ZodString;
|
|
13
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
14
|
+
type: z.ZodLiteral<"link">;
|
|
15
|
+
url: z.ZodString;
|
|
16
|
+
label: z.ZodString;
|
|
17
|
+
platform: z.ZodDefault<z.ZodEnum<{
|
|
18
|
+
web: "web";
|
|
19
|
+
github: "github";
|
|
20
|
+
"play-store": "play-store";
|
|
21
|
+
"app-store": "app-store";
|
|
22
|
+
steam: "steam";
|
|
23
|
+
other: "other";
|
|
24
|
+
}>>;
|
|
25
|
+
}, z.core.$strip>], "type">;
|
|
26
|
+
export declare const sectionsArraySchema: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
27
|
+
type: z.ZodLiteral<"markdown">;
|
|
28
|
+
content: z.ZodString;
|
|
29
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
30
|
+
type: z.ZodLiteral<"image">;
|
|
31
|
+
path: z.ZodString;
|
|
32
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
34
|
+
type: z.ZodLiteral<"youtube">;
|
|
35
|
+
url: z.ZodString;
|
|
36
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
37
|
+
type: z.ZodLiteral<"link">;
|
|
38
|
+
url: z.ZodString;
|
|
39
|
+
label: z.ZodString;
|
|
40
|
+
platform: z.ZodDefault<z.ZodEnum<{
|
|
41
|
+
web: "web";
|
|
42
|
+
github: "github";
|
|
43
|
+
"play-store": "play-store";
|
|
44
|
+
"app-store": "app-store";
|
|
45
|
+
steam: "steam";
|
|
46
|
+
other: "other";
|
|
47
|
+
}>>;
|
|
48
|
+
}, z.core.$strip>], "type">>;
|
|
49
|
+
export type InputSection = z.infer<typeof inputSectionSchema>;
|
|
50
|
+
export declare function extractYoutubeId(url: string): string | null;
|
|
51
|
+
export declare function generateSectionId(): string;
|
|
52
|
+
export declare function processSections(client: MadeintrClient, inputSections: InputSection[]): Promise<Record<string, unknown>[]>;
|
|
53
|
+
export declare function formatSectionsForDisplay(backendSections: Record<string, unknown>[]): string;
|
package/dist/sections.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { detectContentType, validateImageFile } from './api-client.js';
|
|
4
|
+
// --- Zod schema for MCP input sections ---
|
|
5
|
+
const platformValues = ['web', 'github', 'play-store', 'app-store', 'steam', 'other'];
|
|
6
|
+
export const inputSectionSchema = z.discriminatedUnion('type', [
|
|
7
|
+
z.object({
|
|
8
|
+
type: z.literal('markdown'),
|
|
9
|
+
content: z.string().max(10000).describe('Markdown content'),
|
|
10
|
+
}),
|
|
11
|
+
z.object({
|
|
12
|
+
type: z.literal('image'),
|
|
13
|
+
path: z.string().describe('Local file path to image'),
|
|
14
|
+
caption: z.string().optional().describe('Optional image caption'),
|
|
15
|
+
}),
|
|
16
|
+
z.object({
|
|
17
|
+
type: z.literal('youtube'),
|
|
18
|
+
url: z.string().describe('YouTube video URL'),
|
|
19
|
+
}),
|
|
20
|
+
z.object({
|
|
21
|
+
type: z.literal('link'),
|
|
22
|
+
url: z.string().describe('Link URL'),
|
|
23
|
+
label: z.string().describe('Display label for the link'),
|
|
24
|
+
platform: z.enum(platformValues).default('web').describe('Platform type (defaults to "web")'),
|
|
25
|
+
}),
|
|
26
|
+
]);
|
|
27
|
+
export const sectionsArraySchema = z.array(inputSectionSchema).max(20)
|
|
28
|
+
.describe('Ordered content sections. Each is one of: markdown, image (local file, auto-uploaded), youtube (video embed), link.');
|
|
29
|
+
// --- Utilities ---
|
|
30
|
+
export function extractYoutubeId(url) {
|
|
31
|
+
const match = url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/);
|
|
32
|
+
return match?.[1] ?? null;
|
|
33
|
+
}
|
|
34
|
+
export function generateSectionId() {
|
|
35
|
+
return Math.random().toString(36).substring(2, 10);
|
|
36
|
+
}
|
|
37
|
+
// --- Process input sections into backend format ---
|
|
38
|
+
export async function processSections(client, inputSections) {
|
|
39
|
+
const imageCount = inputSections.filter((s) => s.type === 'image').length;
|
|
40
|
+
if (imageCount > 5) {
|
|
41
|
+
throw new Error(`Too many image sections (${imageCount}). Maximum is 5.`);
|
|
42
|
+
}
|
|
43
|
+
const sections = [];
|
|
44
|
+
for (const input of inputSections) {
|
|
45
|
+
switch (input.type) {
|
|
46
|
+
case 'markdown':
|
|
47
|
+
sections.push({
|
|
48
|
+
id: generateSectionId(),
|
|
49
|
+
type: 'markdown',
|
|
50
|
+
content: input.content,
|
|
51
|
+
});
|
|
52
|
+
break;
|
|
53
|
+
case 'image': {
|
|
54
|
+
const validation = validateImageFile(input.path);
|
|
55
|
+
if (!validation.valid) {
|
|
56
|
+
throw new Error(`Image error (${input.path}): ${validation.error}`);
|
|
57
|
+
}
|
|
58
|
+
const contentType = detectContentType(input.path);
|
|
59
|
+
const filename = path.basename(input.path);
|
|
60
|
+
const { uploadUrl, downloadUrl } = await client.getUploadUrl(filename, contentType);
|
|
61
|
+
await client.uploadFile(uploadUrl, input.path, contentType);
|
|
62
|
+
sections.push({
|
|
63
|
+
id: generateSectionId(),
|
|
64
|
+
type: 'images',
|
|
65
|
+
urls: [downloadUrl],
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
case 'youtube': {
|
|
70
|
+
const videoId = extractYoutubeId(input.url);
|
|
71
|
+
if (!videoId) {
|
|
72
|
+
throw new Error(`Could not extract YouTube video ID from URL: ${input.url}`);
|
|
73
|
+
}
|
|
74
|
+
sections.push({
|
|
75
|
+
id: generateSectionId(),
|
|
76
|
+
type: 'video',
|
|
77
|
+
videoId,
|
|
78
|
+
});
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case 'link':
|
|
82
|
+
sections.push({
|
|
83
|
+
id: generateSectionId(),
|
|
84
|
+
type: 'link',
|
|
85
|
+
url: input.url,
|
|
86
|
+
label: input.label,
|
|
87
|
+
platform: input.platform ?? 'web',
|
|
88
|
+
});
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return sections;
|
|
93
|
+
}
|
|
94
|
+
// --- Format backend sections for get_project display ---
|
|
95
|
+
export function formatSectionsForDisplay(backendSections) {
|
|
96
|
+
const mapped = backendSections.map((s) => {
|
|
97
|
+
switch (s.type) {
|
|
98
|
+
case 'markdown':
|
|
99
|
+
return { type: 'markdown', content: s.content };
|
|
100
|
+
case 'images':
|
|
101
|
+
return { type: 'images', urls: s.urls };
|
|
102
|
+
case 'video':
|
|
103
|
+
return { type: 'youtube', videoId: s.videoId };
|
|
104
|
+
case 'link':
|
|
105
|
+
return { type: 'link', url: s.url, label: s.label, platform: s.platform };
|
|
106
|
+
default:
|
|
107
|
+
return s;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return JSON.stringify(mapped, null, 2);
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=sections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../src/sections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MadeintrClient } from '../api-client.js';
|
|
2
|
+
export declare const deleteProjectTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
properties: {
|
|
8
|
+
id: {
|
|
9
|
+
type: string;
|
|
10
|
+
description: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
required: string[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare function handleDeleteProject(client: MadeintrClient, args: {
|
|
17
|
+
id: string;
|
|
18
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const deleteProjectTool = {
|
|
2
|
+
name: 'delete_project',
|
|
3
|
+
description: 'Permanently delete a project from madeintr.app. This cannot be undone.',
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
id: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
description: 'Project ID to delete',
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
required: ['id'],
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
export async function handleDeleteProject(client, args) {
|
|
16
|
+
await client.deleteApp(args.id);
|
|
17
|
+
return `Project ${args.id} has been permanently deleted.`;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=delete-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-project.js","sourceRoot":"","sources":["../../src/tools/delete-project.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,wEAAwE;IACrF,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,EAAE,EAAE;gBACF,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,sBAAsB;aACpC;SACF;QACD,QAAQ,EAAE,CAAC,IAAI,CAAC;KACjB;CACF,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,IAAoB;IAEpB,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAC/B,OAAO,WAAW,IAAI,CAAC,EAAE,gCAAgC,CAAA;AAC3D,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { formatSectionsForDisplay } from '../sections.js';
|
|
2
|
+
export async function handleGetProject(client, args) {
|
|
3
|
+
const app = await client.getApp(args.id);
|
|
4
|
+
const sections = app.sections ?? [];
|
|
5
|
+
const tags = app.tags ?? [];
|
|
6
|
+
const primaryLink = app.primaryLink;
|
|
7
|
+
const header = [
|
|
8
|
+
`**${app.title}** (${app.status})`,
|
|
9
|
+
`ID: ${app.id}`,
|
|
10
|
+
`URL: ${app.url}`,
|
|
11
|
+
`Category: ${app.category}`,
|
|
12
|
+
tags.length > 0 ? `Tags: ${tags.join(', ')}` : null,
|
|
13
|
+
app.shortDescription ? `Short description: ${app.shortDescription}` : null,
|
|
14
|
+
app.coverImageURL ? `Cover image: ${app.coverImageURL}` : null,
|
|
15
|
+
primaryLink ? `Primary link: ${primaryLink.label} - ${primaryLink.url} (${primaryLink.platform})` : null,
|
|
16
|
+
`Views: ${app.viewCount}`,
|
|
17
|
+
`Created: ${app.createdAt}`,
|
|
18
|
+
`Updated: ${app.updatedAt}`,
|
|
19
|
+
].filter(Boolean).join('\n');
|
|
20
|
+
const sectionsOutput = sections.length > 0
|
|
21
|
+
? `\n\nSections (${sections.length}):\n${formatSectionsForDisplay(sections)}`
|
|
22
|
+
: '\n\nNo sections';
|
|
23
|
+
return header + sectionsOutput;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=get-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-project.js","sourceRoot":"","sources":["../../src/tools/get-project.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAEzD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAsB,EACtB,IAAoB;IAEpB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IAExC,MAAM,QAAQ,GAAI,GAAG,CAAC,QAAsC,IAAI,EAAE,CAAA;IAClE,MAAM,IAAI,GAAI,GAAG,CAAC,IAAiB,IAAI,EAAE,CAAA;IACzC,MAAM,WAAW,GAAG,GAAG,CAAC,WAA6C,CAAA;IAErE,MAAM,MAAM,GAAG;QACb,KAAK,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,MAAM,GAAG;QAClC,OAAO,GAAG,CAAC,EAAE,EAAE;QACf,QAAQ,GAAG,CAAC,GAAG,EAAE;QACjB,aAAa,GAAG,CAAC,QAAQ,EAAE;QAC3B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;QACnD,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,sBAAsB,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,IAAI;QAC1E,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,gBAAgB,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI;QAC9D,WAAW,CAAC,CAAC,CAAC,iBAAiB,WAAW,CAAC,KAAK,MAAM,WAAW,CAAC,GAAG,KAAK,WAAW,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI;QACxG,UAAU,GAAG,CAAC,SAAS,EAAE;QACzB,YAAY,GAAG,CAAC,SAAS,EAAE;QAC3B,YAAY,GAAG,CAAC,SAAS,EAAE;KAC5B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAE5B,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;QACxC,CAAC,CAAC,iBAAiB,QAAQ,CAAC,MAAM,OAAO,wBAAwB,CAAC,QAAQ,CAAC,EAAE;QAC7E,CAAC,CAAC,iBAAiB,CAAA;IAErB,OAAO,MAAM,GAAG,cAAc,CAAA;AAChC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MadeintrClient } from '../api-client.js';
|
|
2
|
+
export declare const listProjectsTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
properties: {
|
|
8
|
+
status: {
|
|
9
|
+
type: string;
|
|
10
|
+
enum: string[];
|
|
11
|
+
description: string;
|
|
12
|
+
};
|
|
13
|
+
limit: {
|
|
14
|
+
type: string;
|
|
15
|
+
description: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export declare function handleListProjects(client: MadeintrClient, args: {
|
|
21
|
+
status?: string;
|
|
22
|
+
limit?: number;
|
|
23
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export const listProjectsTool = {
|
|
2
|
+
name: 'list_my_projects',
|
|
3
|
+
description: 'List your projects on madeintr.app. Returns project IDs, titles, statuses, and URLs.',
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: 'object',
|
|
6
|
+
properties: {
|
|
7
|
+
status: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
enum: ['draft', 'published'],
|
|
10
|
+
description: 'Filter by status (optional)',
|
|
11
|
+
},
|
|
12
|
+
limit: {
|
|
13
|
+
type: 'number',
|
|
14
|
+
description: 'Maximum number of results (default 20, max 50)',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export async function handleListProjects(client, args) {
|
|
20
|
+
const result = await client.listApps({
|
|
21
|
+
status: args.status,
|
|
22
|
+
limit: args.limit,
|
|
23
|
+
});
|
|
24
|
+
if (result.apps.length === 0) {
|
|
25
|
+
const filter = args.status ? ` with status "${args.status}"` : '';
|
|
26
|
+
return `No projects found${filter}.`;
|
|
27
|
+
}
|
|
28
|
+
const lines = result.apps.map((app) => {
|
|
29
|
+
const status = app.status === 'published' ? '[Published]' : '[Draft]';
|
|
30
|
+
return `- ${status} **${app.title}** (ID: ${app.id})\n Category: ${app.category} | Views: ${app.viewCount}\n URL: ${app.url}`;
|
|
31
|
+
});
|
|
32
|
+
return `Found ${result.total} project(s):\n\n${lines.join('\n\n')}`;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=list-projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-projects.js","sourceRoot":"","sources":["../../src/tools/list-projects.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,sFAAsF;IACnG,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;gBAC5B,WAAW,EAAE,6BAA6B;aAC3C;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;SACF;KACF;CACF,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAsB,EACtB,IAAyC;IAEzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;QACnC,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,IAAI,CAAC,KAAK;KAClB,CAAC,CAAA;IAEF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;QACjE,OAAO,oBAAoB,MAAM,GAAG,CAAA;IACtC,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAA;QACrE,OAAO,KAAK,MAAM,MAAM,GAAG,CAAC,KAAK,WAAW,GAAG,CAAC,EAAE,kBAAkB,GAAG,CAAC,QAAQ,aAAa,GAAG,CAAC,SAAS,YAAY,GAAG,CAAC,GAAG,EAAE,CAAA;IACjI,CAAC,CAAC,CAAA;IAEF,OAAO,SAAS,MAAM,CAAC,KAAK,mBAAmB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAA;AACrE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MadeintrClient } from '../api-client.js';
|
|
2
|
+
import { type InputSection } from '../sections.js';
|
|
3
|
+
interface SubmitArgs {
|
|
4
|
+
title: string;
|
|
5
|
+
category: string;
|
|
6
|
+
shortDescription?: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
primaryLink?: {
|
|
9
|
+
label: string;
|
|
10
|
+
url: string;
|
|
11
|
+
platform: string;
|
|
12
|
+
};
|
|
13
|
+
coverImagePath?: string;
|
|
14
|
+
sections?: InputSection[];
|
|
15
|
+
status?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function handleSubmitProject(client: MadeintrClient, args: SubmitArgs): Promise<string>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { detectContentType, validateImageFile } from '../api-client.js';
|
|
3
|
+
import { processSections } from '../sections.js';
|
|
4
|
+
export async function handleSubmitProject(client, args) {
|
|
5
|
+
let coverImageURL = '';
|
|
6
|
+
// Upload cover image if provided
|
|
7
|
+
if (args.coverImagePath) {
|
|
8
|
+
const validation = validateImageFile(args.coverImagePath);
|
|
9
|
+
if (!validation.valid) {
|
|
10
|
+
return `Error with cover image: ${validation.error}`;
|
|
11
|
+
}
|
|
12
|
+
const contentType = detectContentType(args.coverImagePath);
|
|
13
|
+
const filename = path.basename(args.coverImagePath);
|
|
14
|
+
const { uploadUrl, downloadUrl } = await client.getUploadUrl(filename, contentType);
|
|
15
|
+
await client.uploadFile(uploadUrl, args.coverImagePath, contentType);
|
|
16
|
+
coverImageURL = downloadUrl;
|
|
17
|
+
}
|
|
18
|
+
// Process sections (upload images, extract youtube IDs, etc.)
|
|
19
|
+
const sections = await processSections(client, args.sections ?? []);
|
|
20
|
+
const payload = {
|
|
21
|
+
title: args.title,
|
|
22
|
+
category: args.category,
|
|
23
|
+
shortDescription: args.shortDescription ?? '',
|
|
24
|
+
tags: args.tags ?? [],
|
|
25
|
+
coverImageURL,
|
|
26
|
+
primaryLink: args.primaryLink ?? null,
|
|
27
|
+
sections,
|
|
28
|
+
status: args.status ?? 'draft',
|
|
29
|
+
};
|
|
30
|
+
const result = await client.createApp(payload);
|
|
31
|
+
const statusText = (args.status ?? 'draft') === 'published'
|
|
32
|
+
? 'Published'
|
|
33
|
+
: 'Saved as draft';
|
|
34
|
+
return `Project "${args.title}" submitted successfully! ${statusText}.\n\nProject ID: ${result.id}\nURL: ${result.url}\n\nYou can update it using the update_project tool with ID: ${result.id}`;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=submit-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"submit-project.js","sourceRoot":"","sources":["../../src/tools/submit-project.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,eAAe,EAAqB,MAAM,gBAAgB,CAAA;AAanE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,IAAgB;IAEhB,IAAI,aAAa,GAAG,EAAE,CAAA;IAEtB,iCAAiC;IACjC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACzD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,2BAA2B,UAAU,CAAC,KAAK,EAAE,CAAA;QACtD,CAAC;QACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAE,CAAA;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACnD,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;QACnF,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;QACpE,aAAa,GAAG,WAAW,CAAA;IAC7B,CAAC;IAED,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAA;IAEnE,MAAM,OAAO,GAA4B;QACvC,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,IAAI,EAAE;QAC7C,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE;QACrB,aAAa;QACb,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;QACrC,QAAQ;QACR,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,OAAO;KAC/B,CAAA;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAE9C,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,WAAW;QACzD,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,gBAAgB,CAAA;IAEpB,OAAO,YAAY,IAAI,CAAC,KAAK,6BAA6B,UAAU,oBAAoB,MAAM,CAAC,EAAE,UAAU,MAAM,CAAC,GAAG,gEAAgE,MAAM,CAAC,EAAE,EAAE,CAAA;AAClM,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MadeintrClient } from '../api-client.js';
|
|
2
|
+
import { type InputSection } from '../sections.js';
|
|
3
|
+
interface UpdateArgs {
|
|
4
|
+
id: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
shortDescription?: string;
|
|
7
|
+
category?: string;
|
|
8
|
+
tags?: string[];
|
|
9
|
+
coverImagePath?: string;
|
|
10
|
+
sections?: InputSection[];
|
|
11
|
+
primaryLink?: {
|
|
12
|
+
label: string;
|
|
13
|
+
url: string;
|
|
14
|
+
platform: string;
|
|
15
|
+
};
|
|
16
|
+
status?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function handleUpdateProject(client: MadeintrClient, args: UpdateArgs): Promise<string>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { detectContentType, validateImageFile } from '../api-client.js';
|
|
3
|
+
import { processSections } from '../sections.js';
|
|
4
|
+
export async function handleUpdateProject(client, args) {
|
|
5
|
+
const payload = {};
|
|
6
|
+
if (args.title !== undefined)
|
|
7
|
+
payload.title = args.title;
|
|
8
|
+
if (args.shortDescription !== undefined)
|
|
9
|
+
payload.shortDescription = args.shortDescription;
|
|
10
|
+
if (args.category !== undefined)
|
|
11
|
+
payload.category = args.category;
|
|
12
|
+
if (args.tags !== undefined)
|
|
13
|
+
payload.tags = args.tags;
|
|
14
|
+
if (args.primaryLink !== undefined)
|
|
15
|
+
payload.primaryLink = args.primaryLink;
|
|
16
|
+
if (args.status !== undefined)
|
|
17
|
+
payload.status = args.status;
|
|
18
|
+
// Upload new cover image if provided
|
|
19
|
+
if (args.coverImagePath) {
|
|
20
|
+
const validation = validateImageFile(args.coverImagePath);
|
|
21
|
+
if (!validation.valid) {
|
|
22
|
+
return `Error with cover image: ${validation.error}`;
|
|
23
|
+
}
|
|
24
|
+
const contentType = detectContentType(args.coverImagePath);
|
|
25
|
+
const filename = path.basename(args.coverImagePath);
|
|
26
|
+
const { uploadUrl, downloadUrl } = await client.getUploadUrl(filename, contentType);
|
|
27
|
+
await client.uploadFile(uploadUrl, args.coverImagePath, contentType);
|
|
28
|
+
payload.coverImageURL = downloadUrl;
|
|
29
|
+
}
|
|
30
|
+
// Process and replace sections if provided
|
|
31
|
+
if (args.sections !== undefined) {
|
|
32
|
+
payload.sections = await processSections(client, args.sections);
|
|
33
|
+
}
|
|
34
|
+
if (Object.keys(payload).length === 0) {
|
|
35
|
+
return 'No fields to update. Provide at least one field to change.';
|
|
36
|
+
}
|
|
37
|
+
const result = await client.updateApp(args.id, payload);
|
|
38
|
+
return `Project updated successfully!\n\nID: ${result.id}\nURL: ${result.url}\nUpdated at: ${result.updatedAt}`;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=update-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-project.js","sourceRoot":"","sources":["../../src/tools/update-project.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACvE,OAAO,EAAE,eAAe,EAAqB,MAAM,gBAAgB,CAAA;AAcnE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAsB,EACtB,IAAgB;IAEhB,MAAM,OAAO,GAA4B,EAAE,CAAA;IAE3C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;IACxD,IAAI,IAAI,CAAC,gBAAgB,KAAK,SAAS;QAAE,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAA;IACzF,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;IACjE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;IACrD,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS;QAAE,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;IAC1E,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;IAE3D,qCAAqC;IACrC,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACzD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,2BAA2B,UAAU,CAAC,KAAK,EAAE,CAAA;QACtD,CAAC;QACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAE,CAAA;QAC3D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QACnD,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;QACnF,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;QACpE,OAAO,CAAC,aAAa,GAAG,WAAW,CAAA;IACrC,CAAC;IAED,2CAA2C;IAC3C,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,QAAQ,GAAG,MAAM,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;IACjE,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,OAAO,4DAA4D,CAAA;IACrE,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;IAEvD,OAAO,wCAAwC,MAAM,CAAC,EAAE,UAAU,MAAM,CAAC,GAAG,iBAAiB,MAAM,CAAC,SAAS,EAAE,CAAA;AACjH,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MadeintrClient } from '../api-client.js';
|
|
2
|
+
export declare const uploadImageTool: {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: "object";
|
|
7
|
+
properties: {
|
|
8
|
+
filePath: {
|
|
9
|
+
type: string;
|
|
10
|
+
description: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
required: string[];
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export declare function handleUploadImage(client: MadeintrClient, args: {
|
|
17
|
+
filePath: string;
|
|
18
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { detectContentType, validateImageFile } from '../api-client.js';
|
|
3
|
+
export const uploadImageTool = {
|
|
4
|
+
name: 'upload_image',
|
|
5
|
+
description: 'Upload an image to madeintr.app storage. Returns a URL that can be used as a cover image or in project sections.',
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {
|
|
9
|
+
filePath: {
|
|
10
|
+
type: 'string',
|
|
11
|
+
description: 'Absolute path to the image file on local disk',
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
required: ['filePath'],
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
export async function handleUploadImage(client, args) {
|
|
18
|
+
const { filePath } = args;
|
|
19
|
+
const validation = validateImageFile(filePath);
|
|
20
|
+
if (!validation.valid) {
|
|
21
|
+
return `Error: ${validation.error}`;
|
|
22
|
+
}
|
|
23
|
+
const contentType = detectContentType(filePath);
|
|
24
|
+
const filename = path.basename(filePath);
|
|
25
|
+
const { uploadUrl, downloadUrl } = await client.getUploadUrl(filename, contentType);
|
|
26
|
+
await client.uploadFile(uploadUrl, filePath, contentType);
|
|
27
|
+
return `Image uploaded successfully!\n\nDownload URL: ${downloadUrl}\n\nUse this URL as coverImageURL or in an images section when submitting/updating a project.`;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=upload-image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload-image.js","sourceRoot":"","sources":["../../src/tools/upload-image.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AAEvE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,kHAAkH;IAC/H,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+CAA+C;aAC7D;SACF;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACvB;CACF,CAAA;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAsB,EACtB,IAA0B;IAE1B,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAA;IAEzB,MAAM,UAAU,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IAC9C,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACtB,OAAO,UAAU,UAAU,CAAC,KAAK,EAAE,CAAA;IACrC,CAAC;IAED,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,CAAE,CAAA;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAExC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;IACnF,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAA;IAEzD,OAAO,iDAAiD,WAAW,+FAA+F,CAAA;AACpK,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@madeintr/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for submitting projects to madeintr.app",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"madeintr-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsc --watch",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"mcp",
|
|
18
|
+
"madeintr",
|
|
19
|
+
"model-context-protocol"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
24
|
+
"zod": "^4.3.6"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "^22.0.0",
|
|
28
|
+
"typescript": "~5.7.0"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md"
|
|
36
|
+
]
|
|
37
|
+
}
|