@mediagraph/mcp 1.0.1 → 1.0.3

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.
Files changed (2) hide show
  1. package/dist/index.js +133 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10,6 +10,8 @@ import {
10
10
  ListToolsRequestSchema,
11
11
  ReadResourceRequestSchema
12
12
  } from "@modelcontextprotocol/sdk/types.js";
13
+ import { exec } from "child_process";
14
+ import { platform } from "os";
13
15
 
14
16
  // src/auth/oauth.ts
15
17
  import { createHash, randomBytes } from "crypto";
@@ -67,10 +69,11 @@ var OAuthHandler = class {
67
69
  });
68
70
  return `${this.config.oauthUrl}/oauth/authorize?${params.toString()}`;
69
71
  }
72
+ callbackPromise = null;
70
73
  /**
71
- * Start a local HTTP server to receive the OAuth callback
74
+ * Start the callback server and wait for it to be ready
72
75
  */
73
- async waitForCallback() {
76
+ async startCallbackServer() {
74
77
  return new Promise((resolve, reject) => {
75
78
  this.callbackServer = createServer((req, res) => {
76
79
  const url = new URL2(req.url || "/", `http://localhost:${this.config.redirectPort}`);
@@ -91,7 +94,8 @@ var OAuthHandler = class {
91
94
  </html>
92
95
  `);
93
96
  this.stopCallbackServer();
94
- reject(new Error(errorDescription || error));
97
+ this.callbackPromise?.reject(new Error(errorDescription || error));
98
+ this.callbackPromise = null;
95
99
  return;
96
100
  }
97
101
  if (!code || !state) {
@@ -106,7 +110,8 @@ var OAuthHandler = class {
106
110
  </html>
107
111
  `);
108
112
  this.stopCallbackServer();
109
- reject(new Error("Missing authorization code or state"));
113
+ this.callbackPromise?.reject(new Error("Missing authorization code or state"));
114
+ this.callbackPromise = null;
110
115
  return;
111
116
  }
112
117
  if (state !== this.state) {
@@ -121,7 +126,8 @@ var OAuthHandler = class {
121
126
  </html>
122
127
  `);
123
128
  this.stopCallbackServer();
124
- reject(new Error("State parameter mismatch"));
129
+ this.callbackPromise?.reject(new Error("State parameter mismatch"));
130
+ this.callbackPromise = null;
125
131
  return;
126
132
  }
127
133
  res.writeHead(200, { "Content-Type": "text/html" });
@@ -135,20 +141,43 @@ var OAuthHandler = class {
135
141
  </html>
136
142
  `);
137
143
  this.stopCallbackServer();
138
- resolve({ code, state });
144
+ this.callbackPromise?.resolve({ code, state });
145
+ this.callbackPromise = null;
139
146
  } else {
140
147
  res.writeHead(404);
141
148
  res.end("Not found");
142
149
  }
143
150
  });
151
+ this.callbackServer.on("error", (err) => {
152
+ reject(err);
153
+ });
144
154
  this.callbackServer.listen(this.config.redirectPort, () => {
155
+ resolve();
145
156
  });
157
+ });
158
+ }
159
+ /**
160
+ * Wait for the OAuth callback (server must be started first)
161
+ */
162
+ async waitForCallback() {
163
+ return new Promise((resolve, reject) => {
164
+ this.callbackPromise = { resolve, reject };
146
165
  setTimeout(() => {
147
- this.stopCallbackServer();
148
- reject(new Error("Authorization timed out"));
166
+ if (this.callbackPromise) {
167
+ this.stopCallbackServer();
168
+ this.callbackPromise.reject(new Error("Authorization timed out"));
169
+ this.callbackPromise = null;
170
+ }
149
171
  }, 5 * 60 * 1e3);
150
172
  });
151
173
  }
174
+ /**
175
+ * Start server and wait for callback (convenience method for CLI)
176
+ */
177
+ async startAndWaitForCallback() {
178
+ await this.startCallbackServer();
179
+ return this.waitForCallback();
180
+ }
152
181
  /**
153
182
  * Stop the callback server
154
183
  */
@@ -2941,6 +2970,48 @@ var oauthHandler = new OAuthHandler({
2941
2970
  redirectPort: config.redirectPort
2942
2971
  });
2943
2972
  var currentTokens = null;
2973
+ var isAuthInProgress = false;
2974
+ function openBrowser(url) {
2975
+ const command = platform() === "darwin" ? `open "${url}"` : platform() === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
2976
+ exec(command, (error) => {
2977
+ if (error) {
2978
+ console.error("Failed to open browser:", error);
2979
+ }
2980
+ });
2981
+ }
2982
+ async function runAutoAuth() {
2983
+ if (isAuthInProgress) {
2984
+ while (isAuthInProgress) {
2985
+ await new Promise((resolve) => setTimeout(resolve, 100));
2986
+ }
2987
+ return currentTokens !== null;
2988
+ }
2989
+ isAuthInProgress = true;
2990
+ try {
2991
+ const authUrl = oauthHandler.getAuthorizationUrl();
2992
+ await oauthHandler.startCallbackServer();
2993
+ openBrowser(authUrl);
2994
+ const { code } = await oauthHandler.waitForCallback();
2995
+ const tokens = await oauthHandler.exchangeCode(code);
2996
+ currentTokens = tokens;
2997
+ const whoami = await client.whoami();
2998
+ const storedData = {
2999
+ tokens,
3000
+ organizationId: whoami.organization.id,
3001
+ organizationName: whoami.organization.name,
3002
+ userId: whoami.user.id,
3003
+ userEmail: whoami.user.email
3004
+ };
3005
+ tokenStore.save(storedData);
3006
+ return true;
3007
+ } catch (error) {
3008
+ console.error("Auto-auth failed:", error);
3009
+ oauthHandler.stopCallbackServer();
3010
+ return false;
3011
+ } finally {
3012
+ isAuthInProgress = false;
3013
+ }
3014
+ }
2944
3015
  async function getAccessToken() {
2945
3016
  if (currentTokens && Date.now() < currentTokens.expires_at - 3e5) {
2946
3017
  return currentTokens.access_token;
@@ -2992,27 +3063,32 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
2992
3063
  });
2993
3064
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
2994
3065
  const { name, arguments: args } = request.params;
2995
- const token = await getAccessToken();
3066
+ let token = await getAccessToken();
2996
3067
  if (!token) {
2997
- return {
2998
- content: [
2999
- {
3000
- type: "text",
3001
- text: `Not authenticated with Mediagraph. Please run the authorization flow first.
3002
-
3003
- To authorize:
3004
- 1. Run: npx @mediagraph/mcp authorize
3005
- 2. Complete the OAuth flow in your browser
3006
- 3. Return here and try again
3007
-
3008
- Or set your credentials via environment variables:
3009
- - MEDIAGRAPH_CLIENT_ID (required)
3010
- - MEDIAGRAPH_CLIENT_SECRET (optional, for confidential clients)
3011
- `
3012
- }
3013
- ],
3014
- isError: true
3015
- };
3068
+ const authSuccess = await runAutoAuth();
3069
+ if (!authSuccess) {
3070
+ return {
3071
+ content: [
3072
+ {
3073
+ type: "text",
3074
+ text: "Failed to authenticate with Mediagraph. Please try again or check your browser for the authorization window."
3075
+ }
3076
+ ],
3077
+ isError: true
3078
+ };
3079
+ }
3080
+ token = await getAccessToken();
3081
+ if (!token) {
3082
+ return {
3083
+ content: [
3084
+ {
3085
+ type: "text",
3086
+ text: "Authentication completed but failed to retrieve access token. Please try again."
3087
+ }
3088
+ ],
3089
+ isError: true
3090
+ };
3091
+ }
3016
3092
  }
3017
3093
  const result = await handleTool(name, args || {}, toolContext);
3018
3094
  return {
@@ -3026,7 +3102,14 @@ server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
3026
3102
  };
3027
3103
  });
3028
3104
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
3029
- const token = await getAccessToken();
3105
+ let token = await getAccessToken();
3106
+ if (!token) {
3107
+ const authSuccess = await runAutoAuth();
3108
+ if (!authSuccess) {
3109
+ return { resources: [] };
3110
+ }
3111
+ token = await getAccessToken();
3112
+ }
3030
3113
  if (!token) {
3031
3114
  return { resources: [] };
3032
3115
  }
@@ -3035,14 +3118,29 @@ server.setRequestHandler(ListResourcesRequestSchema, async () => {
3035
3118
  });
3036
3119
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
3037
3120
  const { uri } = request.params;
3038
- const token = await getAccessToken();
3121
+ let token = await getAccessToken();
3122
+ if (!token) {
3123
+ const authSuccess = await runAutoAuth();
3124
+ if (!authSuccess) {
3125
+ return {
3126
+ contents: [
3127
+ {
3128
+ uri,
3129
+ mimeType: "text/plain",
3130
+ text: "Failed to authenticate with Mediagraph. Please try again."
3131
+ }
3132
+ ]
3133
+ };
3134
+ }
3135
+ token = await getAccessToken();
3136
+ }
3039
3137
  if (!token) {
3040
3138
  return {
3041
3139
  contents: [
3042
3140
  {
3043
3141
  uri,
3044
3142
  mimeType: "text/plain",
3045
- text: "Not authenticated with Mediagraph. Please authorize first."
3143
+ text: "Authentication completed but failed to retrieve access token."
3046
3144
  }
3047
3145
  ]
3048
3146
  };
@@ -3062,7 +3160,10 @@ async function runAuthorize() {
3062
3160
  console.log("Starting Mediagraph OAuth authorization...");
3063
3161
  console.log("");
3064
3162
  const authUrl = oauthHandler.getAuthorizationUrl();
3065
- console.log("Please open this URL in your browser:");
3163
+ await oauthHandler.startCallbackServer();
3164
+ openBrowser(authUrl);
3165
+ console.log("Opening browser for authorization...");
3166
+ console.log("If the browser does not open, please visit:");
3066
3167
  console.log("");
3067
3168
  console.log(authUrl);
3068
3169
  console.log("");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mediagraph/mcp",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "MCP server for Mediagraph - Media Asset Management Platform",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",