magicpod-mcp-server 0.1.0 → 0.1.2

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/build/index.js CHANGED
@@ -4,6 +4,7 @@ import { Command } from "commander";
4
4
  import { searchMagicpodArticles } from "./tools/search-magicpod-articles.js";
5
5
  import { readMagicpodArticle } from "./tools/read-magicpod-article.js";
6
6
  import { initMagicPodApiProxy } from "./tools/magicpod-web-api.js";
7
+ import { apiV1_0UploadFileCreate } from "./tools/api-v1-0-upload-file-create.js";
7
8
  const program = new Command();
8
9
  program.option("--api-token <key>", "MagicPod API token to use");
9
10
  program.parse(process.argv);
@@ -15,6 +16,7 @@ if (!options.apiToken) {
15
16
  async function main() {
16
17
  const baseUrl = process.env.BASE_URL || "https://app.magicpod.com";
17
18
  const proxy = await initMagicPodApiProxy(baseUrl, options.apiToken, [
19
+ apiV1_0UploadFileCreate(baseUrl, options.apiToken),
18
20
  searchMagicpodArticles(),
19
21
  readMagicpodArticle(),
20
22
  ]);
@@ -12,7 +12,7 @@ export class MCPProxy {
12
12
  openApiLookup;
13
13
  constructor(name, openApiSpec, apiToken, otherTools) {
14
14
  this.otherTools = otherTools;
15
- this.server = new Server({ name, version: "0.1.0" }, { capabilities: { tools: {} } });
15
+ this.server = new Server({ name, version: "0.1.1" }, { capabilities: { tools: {} } });
16
16
  const baseUrl = openApiSpec.servers?.[0].url;
17
17
  if (!baseUrl) {
18
18
  throw new Error("No base URL found in OpenAPI spec");
@@ -84,7 +84,7 @@ export class MCPProxy {
84
84
  // to reduce the tool list response size
85
85
  // TODO description is actually required
86
86
  const inputSchema = JSON.parse(JSON.stringify(method.inputSchema));
87
- this.removeDescriptions(inputSchema);
87
+ // this.removeDescriptions(inputSchema);
88
88
  // 95% of the response size is consumed by $defs
89
89
  const body = method.inputSchema.properties?.body;
90
90
  if (body == null || typeof body === "boolean") {
@@ -0,0 +1,67 @@
1
+ import { z } from "zod";
2
+ import fs from "fs";
3
+ import path from "node:path";
4
+ import axios from "axios";
5
+ import FormData from "form-data";
6
+ export const apiV1_0UploadFileCreate = (baseUrl, apiToken) => {
7
+ return {
8
+ name: "API-v1_0_upload-file_create",
9
+ description: "Upload target app files (.app, .ipa, .apk or .aab) to MagicPod cloud",
10
+ inputSchema: z.object({
11
+ organizationName: z
12
+ .string()
13
+ .describe("The organization name to upload the file"),
14
+ projectName: z.string().describe("The project name to upload the file"),
15
+ localFilePath: z
16
+ .string()
17
+ .describe("A local file path to upload to MagicPod. Note that an absolute path is required. Its extension must be .app, .ipa, .apk or .aab"),
18
+ }),
19
+ handleRequest: async ({ organizationName, projectName, localFilePath }) => {
20
+ try {
21
+ if (!fs.existsSync(localFilePath)) {
22
+ return {
23
+ content: [
24
+ {
25
+ type: "text",
26
+ text: "No such file exists. Note that an absolute path is required",
27
+ },
28
+ ],
29
+ };
30
+ }
31
+ const formData = new FormData();
32
+ const fileStream = fs.createReadStream(localFilePath);
33
+ const fileName = path.basename(localFilePath);
34
+ formData.append("file", fileStream, fileName);
35
+ const url = `${baseUrl}/api/v1.0/${organizationName}/${projectName}/upload-file/`;
36
+ const response = await axios.post(url, formData, {
37
+ headers: {
38
+ ...formData.getHeaders(),
39
+ Authorization: `Token ${apiToken}`,
40
+ },
41
+ });
42
+ if (response.status !== 200) {
43
+ return {
44
+ content: [
45
+ {
46
+ type: "text",
47
+ text: "an error happened in uploading the file",
48
+ },
49
+ ],
50
+ };
51
+ }
52
+ }
53
+ catch (error) {
54
+ console.error("Failed to upload the file: ", error instanceof Error ? error.message : String(error));
55
+ throw error;
56
+ }
57
+ return {
58
+ content: [
59
+ {
60
+ type: "text",
61
+ text: JSON.stringify({ message: "succeeded to upload the file" }),
62
+ },
63
+ ],
64
+ };
65
+ },
66
+ };
67
+ };
@@ -27,7 +27,8 @@ const unsupportedPaths = [
27
27
  '/v1.0/{organization_name}/{project_name}/batch-runs/{batch_run_number}/screenshots/',
28
28
  '/v1.0/{organization_name}/{project_name}/screenshots/{batch_task_id}/',
29
29
  '/v1.0/magicpod-clients/api/{os}/{tag_or_version}/',
30
- '/v1.0/magicpod-clients/local/{os}/{version}/'
30
+ '/v1.0/magicpod-clients/local/{os}/{version}/',
31
+ '/v1.0/{organization_name}/{project_name}/upload-file/'
31
32
  ];
32
33
  export const initMagicPodApiProxy = async (baseUrl, apiToken, tools) => {
33
34
  const schemaUrl = `${baseUrl}/api/v1.0/doc/?format=openapi`;
@@ -19,7 +19,8 @@ const makeRequest = async (query, locale) => {
19
19
  export const searchMagicpodArticles = () => {
20
20
  return {
21
21
  name: "search-magicpod-articles",
22
- description: "Search the list of articles on MagicPod help center by specified keywords",
22
+ description: "This tool searches the list of articles on MagicPod help center by specified keywords. " +
23
+ "You must use this tool whenever you mention MagicPod's specification since it has always been updated.",
23
24
  inputSchema: z.object({
24
25
  query: z
25
26
  .string()
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "magicpod-mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Model Context Protocol server for MagicPod integration",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "magicpod-mcp-server": "./build/index.js"
8
8
  },
9
9
  "scripts": {
10
- "build": "tsc && chmod 755 build/index.js"
10
+ "build": "tsc && chmod 755 build/index.js",
11
+ "publish": "npm publish --access public"
11
12
  },
12
13
  "keywords": [
13
14
  "mcp",
@@ -19,6 +20,7 @@
19
20
  "type": "git",
20
21
  "url": "git+https://github.com/Magic-Pod/magicpod-mcp-server.git"
21
22
  },
23
+ "homepage": "https://magicpod.com/",
22
24
  "publishConfig": {
23
25
  "access": "public"
24
26
  },
@@ -29,7 +31,9 @@
29
31
  "@anthropic-ai/sdk": "^0.33.1",
30
32
  "@modelcontextprotocol/sdk": "^1.9.0",
31
33
  "@types/mustache": "^4.2.5",
34
+ "axios": "^1.8.4",
32
35
  "commander": "^13.1.0",
36
+ "form-data": "^4.0.2",
33
37
  "json-schema": "^0.4.0",
34
38
  "mustache": "^4.2.0",
35
39
  "openai": "^4.91.1",
@@ -40,6 +44,7 @@
40
44
  "zod": "^3.24.2"
41
45
  },
42
46
  "devDependencies": {
47
+ "@types/form-data": "^2.2.1",
43
48
  "@types/json-schema": "^7.0.15",
44
49
  "@types/node": "^22.14.0",
45
50
  "@types/swagger2openapi": "^7.0.4",