@upload-post/mcp 0.3.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.
Files changed (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/dist/client.d.ts +32 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +61 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +66 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/oauth/auth_resolver.d.ts +33 -0
  12. package/dist/oauth/auth_resolver.d.ts.map +1 -0
  13. package/dist/oauth/auth_resolver.js +30 -0
  14. package/dist/oauth/auth_resolver.js.map +1 -0
  15. package/dist/oauth/authorize.d.ts +18 -0
  16. package/dist/oauth/authorize.d.ts.map +1 -0
  17. package/dist/oauth/authorize.js +26 -0
  18. package/dist/oauth/authorize.js.map +1 -0
  19. package/dist/oauth/config.d.ts +19 -0
  20. package/dist/oauth/config.d.ts.map +1 -0
  21. package/dist/oauth/config.js +28 -0
  22. package/dist/oauth/config.js.map +1 -0
  23. package/dist/oauth/http_utils.d.ts +8 -0
  24. package/dist/oauth/http_utils.d.ts.map +1 -0
  25. package/dist/oauth/http_utils.js +48 -0
  26. package/dist/oauth/http_utils.js.map +1 -0
  27. package/dist/oauth/introspect_cache.d.ts +19 -0
  28. package/dist/oauth/introspect_cache.d.ts.map +1 -0
  29. package/dist/oauth/introspect_cache.js +40 -0
  30. package/dist/oauth/introspect_cache.js.map +1 -0
  31. package/dist/oauth/metadata.d.ts +35 -0
  32. package/dist/oauth/metadata.d.ts.map +1 -0
  33. package/dist/oauth/metadata.js +43 -0
  34. package/dist/oauth/metadata.js.map +1 -0
  35. package/dist/oauth/registration.d.ts +14 -0
  36. package/dist/oauth/registration.d.ts.map +1 -0
  37. package/dist/oauth/registration.js +40 -0
  38. package/dist/oauth/registration.js.map +1 -0
  39. package/dist/oauth/tokens.d.ts +15 -0
  40. package/dist/oauth/tokens.d.ts.map +1 -0
  41. package/dist/oauth/tokens.js +43 -0
  42. package/dist/oauth/tokens.js.map +1 -0
  43. package/dist/oauth/upstream_client.d.ts +32 -0
  44. package/dist/oauth/upstream_client.d.ts.map +1 -0
  45. package/dist/oauth/upstream_client.js +62 -0
  46. package/dist/oauth/upstream_client.js.map +1 -0
  47. package/dist/schemas.d.ts +38 -0
  48. package/dist/schemas.d.ts.map +1 -0
  49. package/dist/schemas.js +121 -0
  50. package/dist/schemas.js.map +1 -0
  51. package/dist/server.d.ts +4 -0
  52. package/dist/server.d.ts.map +1 -0
  53. package/dist/server.js +36 -0
  54. package/dist/server.js.map +1 -0
  55. package/dist/tools/analytics.d.ts +4 -0
  56. package/dist/tools/analytics.d.ts.map +1 -0
  57. package/dist/tools/analytics.js +74 -0
  58. package/dist/tools/analytics.js.map +1 -0
  59. package/dist/tools/comments.d.ts +4 -0
  60. package/dist/tools/comments.d.ts.map +1 -0
  61. package/dist/tools/comments.js +108 -0
  62. package/dist/tools/comments.js.map +1 -0
  63. package/dist/tools/dms.d.ts +4 -0
  64. package/dist/tools/dms.d.ts.map +1 -0
  65. package/dist/tools/dms.js +100 -0
  66. package/dist/tools/dms.js.map +1 -0
  67. package/dist/tools/ffmpeg.d.ts +4 -0
  68. package/dist/tools/ffmpeg.d.ts.map +1 -0
  69. package/dist/tools/ffmpeg.js +96 -0
  70. package/dist/tools/ffmpeg.js.map +1 -0
  71. package/dist/tools/media_uploads.d.ts +4 -0
  72. package/dist/tools/media_uploads.d.ts.map +1 -0
  73. package/dist/tools/media_uploads.js +106 -0
  74. package/dist/tools/media_uploads.js.map +1 -0
  75. package/dist/tools/pages.d.ts +4 -0
  76. package/dist/tools/pages.d.ts.map +1 -0
  77. package/dist/tools/pages.js +101 -0
  78. package/dist/tools/pages.js.map +1 -0
  79. package/dist/tools/queue.d.ts +4 -0
  80. package/dist/tools/queue.d.ts.map +1 -0
  81. package/dist/tools/queue.js +79 -0
  82. package/dist/tools/queue.js.map +1 -0
  83. package/dist/tools/schedule.d.ts +4 -0
  84. package/dist/tools/schedule.d.ts.map +1 -0
  85. package/dist/tools/schedule.js +48 -0
  86. package/dist/tools/schedule.js.map +1 -0
  87. package/dist/tools/status.d.ts +4 -0
  88. package/dist/tools/status.d.ts.map +1 -0
  89. package/dist/tools/status.js +67 -0
  90. package/dist/tools/status.js.map +1 -0
  91. package/dist/tools/upload.d.ts +10 -0
  92. package/dist/tools/upload.d.ts.map +1 -0
  93. package/dist/tools/upload.js +397 -0
  94. package/dist/tools/upload.js.map +1 -0
  95. package/dist/tools/upload_studio.d.ts +3 -0
  96. package/dist/tools/upload_studio.d.ts.map +1 -0
  97. package/dist/tools/upload_studio.js +808 -0
  98. package/dist/tools/upload_studio.js.map +1 -0
  99. package/dist/tools/users.d.ts +4 -0
  100. package/dist/tools/users.d.ts.map +1 -0
  101. package/dist/tools/users.js +95 -0
  102. package/dist/tools/users.js.map +1 -0
  103. package/dist/transport/http.d.ts +33 -0
  104. package/dist/transport/http.d.ts.map +1 -0
  105. package/dist/transport/http.js +263 -0
  106. package/dist/transport/http.js.map +1 -0
  107. package/dist/transport/stdio.d.ts +3 -0
  108. package/dist/transport/stdio.d.ts.map +1 -0
  109. package/dist/transport/stdio.js +7 -0
  110. package/dist/transport/stdio.js.map +1 -0
  111. package/examples/mcp-config.json +11 -0
  112. package/package.json +68 -0
@@ -0,0 +1,48 @@
1
+ const MAX_BODY_BYTES = 64 * 1024;
2
+ export async function readBuffer(req) {
3
+ const chunks = [];
4
+ let total = 0;
5
+ for await (const chunk of req) {
6
+ const buf = chunk;
7
+ total += buf.length;
8
+ if (total > MAX_BODY_BYTES)
9
+ throw new Error("body too large");
10
+ chunks.push(buf);
11
+ }
12
+ return Buffer.concat(chunks);
13
+ }
14
+ export async function readJsonBody(req) {
15
+ const buf = await readBuffer(req);
16
+ if (buf.length === 0)
17
+ return null;
18
+ return JSON.parse(buf.toString("utf8"));
19
+ }
20
+ export async function readFormBody(req) {
21
+ const buf = await readBuffer(req);
22
+ if (buf.length === 0)
23
+ return {};
24
+ const params = new URLSearchParams(buf.toString("utf8"));
25
+ const out = {};
26
+ for (const [k, v] of params)
27
+ out[k] = v;
28
+ return out;
29
+ }
30
+ export function sendJson(res, status, body) {
31
+ res.statusCode = status;
32
+ res.setHeader("content-type", "application/json");
33
+ res.setHeader("cache-control", "no-store");
34
+ res.end(JSON.stringify(body));
35
+ }
36
+ export function sendError(res, status, error, description) {
37
+ const body = { error };
38
+ if (description)
39
+ body.error_description = description;
40
+ sendJson(res, status, body);
41
+ }
42
+ export function sendRedirect(res, url) {
43
+ res.statusCode = 302;
44
+ res.setHeader("location", url);
45
+ res.setHeader("cache-control", "no-store");
46
+ res.end();
47
+ }
48
+ //# sourceMappingURL=http_utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http_utils.js","sourceRoot":"","sources":["../../src/oauth/http_utils.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,CAAC;AAEjC,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAoB;IACnD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,KAAe,CAAC;QAC5B,KAAK,IAAI,GAAG,CAAC,MAAM,CAAC;QACpB,IAAI,KAAK,GAAG,cAAc;YAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;QAC9D,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAoB;IACrD,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAClC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAoB;IACrD,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IACzE,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC3C,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,GAAmB,EACnB,MAAc,EACd,KAAa,EACb,WAAoB;IAEpB,MAAM,IAAI,GAA2B,EAAE,KAAK,EAAE,CAAC;IAC/C,IAAI,WAAW;QAAE,IAAI,CAAC,iBAAiB,GAAG,WAAW,CAAC;IACtD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAmB,EAAE,GAAW;IAC3D,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;IACrB,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IAC/B,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC3C,GAAG,CAAC,GAAG,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { IntrospectResult } from "./upstream_client.js";
2
+ /**
3
+ * Tiny in-process TTL cache for introspection results. Avoids round-tripping
4
+ * upstream on every /mcp request. Keyed by SHA-256(token) so plaintext tokens
5
+ * are never held in memory beyond the request that issued the lookup.
6
+ *
7
+ * No LRU bound by count: entries expire on TTL and are evicted lazily on read.
8
+ * If you anticipate >10k concurrent active tokens, swap this for `lru-cache`.
9
+ */
10
+ export declare class IntrospectCache {
11
+ private readonly ttlMs;
12
+ private store;
13
+ constructor(ttlMs: number);
14
+ get(token: string): IntrospectResult | null;
15
+ set(token: string, value: IntrospectResult): void;
16
+ invalidate(token: string): void;
17
+ private keyFor;
18
+ }
19
+ //# sourceMappingURL=introspect_cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect_cache.d.ts","sourceRoot":"","sources":["../../src/oauth/introspect_cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;;;;;GAOG;AACH,qBAAa,eAAe;IAGd,OAAO,CAAC,QAAQ,CAAC,KAAK;IAFlC,OAAO,CAAC,KAAK,CAAqE;gBAErD,KAAK,EAAE,MAAM;IAE1C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAW3C,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAOjD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI/B,OAAO,CAAC,MAAM;CAGf"}
@@ -0,0 +1,40 @@
1
+ import { createHash } from "node:crypto";
2
+ /**
3
+ * Tiny in-process TTL cache for introspection results. Avoids round-tripping
4
+ * upstream on every /mcp request. Keyed by SHA-256(token) so plaintext tokens
5
+ * are never held in memory beyond the request that issued the lookup.
6
+ *
7
+ * No LRU bound by count: entries expire on TTL and are evicted lazily on read.
8
+ * If you anticipate >10k concurrent active tokens, swap this for `lru-cache`.
9
+ */
10
+ export class IntrospectCache {
11
+ ttlMs;
12
+ store = new Map();
13
+ constructor(ttlMs) {
14
+ this.ttlMs = ttlMs;
15
+ }
16
+ get(token) {
17
+ const key = this.keyFor(token);
18
+ const entry = this.store.get(key);
19
+ if (!entry)
20
+ return null;
21
+ if (entry.expiresAt < Date.now()) {
22
+ this.store.delete(key);
23
+ return null;
24
+ }
25
+ return entry.value;
26
+ }
27
+ set(token, value) {
28
+ this.store.set(this.keyFor(token), {
29
+ value,
30
+ expiresAt: Date.now() + this.ttlMs,
31
+ });
32
+ }
33
+ invalidate(token) {
34
+ this.store.delete(this.keyFor(token));
35
+ }
36
+ keyFor(token) {
37
+ return createHash("sha256").update(token).digest("hex");
38
+ }
39
+ }
40
+ //# sourceMappingURL=introspect_cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect_cache.js","sourceRoot":"","sources":["../../src/oauth/introspect_cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;;;GAOG;AACH,MAAM,OAAO,eAAe;IAGG;IAFrB,KAAK,GAAG,IAAI,GAAG,EAA0D,CAAC;IAElF,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;IAAG,CAAC;IAE9C,GAAG,CAAC,KAAa;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,KAAa,EAAE,KAAuB;QACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;YACjC,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK;SACnC,CAAC,CAAC;IACL,CAAC;IAED,UAAU,CAAC,KAAa;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;CACF"}
@@ -0,0 +1,35 @@
1
+ import type { ServerResponse } from "node:http";
2
+ import type { OAuthConfig } from "./config.js";
3
+ /**
4
+ * RFC 9728 — OAuth 2.0 Protected Resource Metadata.
5
+ * claude.ai (and other MCP-spec clients) fetch this when they hit /mcp and
6
+ * receive a 401 with WWW-Authenticate pointing here. From it they learn which
7
+ * authorization servers can issue tokens for this resource.
8
+ */
9
+ export declare function protectedResourceMetadata(cfg: OAuthConfig): {
10
+ resource: string;
11
+ authorization_servers: string[];
12
+ bearer_methods_supported: string[];
13
+ resource_documentation: string;
14
+ scopes_supported: string[];
15
+ };
16
+ /**
17
+ * RFC 8414 — OAuth 2.0 Authorization Server Metadata.
18
+ * Claude.ai uses this to discover where to register, where to send the user
19
+ * for authorization, and where to exchange codes for tokens.
20
+ */
21
+ export declare function authorizationServerMetadata(cfg: OAuthConfig): {
22
+ issuer: string;
23
+ authorization_endpoint: string;
24
+ token_endpoint: string;
25
+ revocation_endpoint: string;
26
+ registration_endpoint: string;
27
+ response_types_supported: string[];
28
+ grant_types_supported: string[];
29
+ token_endpoint_auth_methods_supported: string[];
30
+ code_challenge_methods_supported: string[];
31
+ scopes_supported: string[];
32
+ service_documentation: string;
33
+ };
34
+ export declare function serveJson(res: ServerResponse, body: unknown, status?: number): void;
35
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,WAAW;;;;;;EAQzD;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,WAAW;;;;;;;;;;;;EAc3D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,SAAM,GAAG,IAAI,CAMhF"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * RFC 9728 — OAuth 2.0 Protected Resource Metadata.
3
+ * claude.ai (and other MCP-spec clients) fetch this when they hit /mcp and
4
+ * receive a 401 with WWW-Authenticate pointing here. From it they learn which
5
+ * authorization servers can issue tokens for this resource.
6
+ */
7
+ export function protectedResourceMetadata(cfg) {
8
+ return {
9
+ resource: `${cfg.issuer}/mcp`,
10
+ authorization_servers: [cfg.issuer],
11
+ bearer_methods_supported: ["header"],
12
+ resource_documentation: "https://docs.upload-post.com/guides/mcp-server-integration",
13
+ scopes_supported: ["mcp.full"],
14
+ };
15
+ }
16
+ /**
17
+ * RFC 8414 — OAuth 2.0 Authorization Server Metadata.
18
+ * Claude.ai uses this to discover where to register, where to send the user
19
+ * for authorization, and where to exchange codes for tokens.
20
+ */
21
+ export function authorizationServerMetadata(cfg) {
22
+ return {
23
+ issuer: cfg.issuer,
24
+ authorization_endpoint: `${cfg.issuer}/authorize`,
25
+ token_endpoint: `${cfg.issuer}/token`,
26
+ revocation_endpoint: `${cfg.issuer}/revoke`,
27
+ registration_endpoint: `${cfg.issuer}/register`,
28
+ response_types_supported: ["code"],
29
+ grant_types_supported: ["authorization_code", "refresh_token"],
30
+ token_endpoint_auth_methods_supported: ["none"],
31
+ code_challenge_methods_supported: ["S256"],
32
+ scopes_supported: ["mcp.full"],
33
+ service_documentation: "https://docs.upload-post.com/guides/mcp-server-integration",
34
+ };
35
+ }
36
+ export function serveJson(res, body, status = 200) {
37
+ res.statusCode = status;
38
+ res.setHeader("content-type", "application/json");
39
+ res.setHeader("cache-control", "public, max-age=3600");
40
+ res.setHeader("access-control-allow-origin", "*");
41
+ res.end(JSON.stringify(body));
42
+ }
43
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/oauth/metadata.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAAgB;IACxD,OAAO;QACL,QAAQ,EAAE,GAAG,GAAG,CAAC,MAAM,MAAM;QAC7B,qBAAqB,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;QACnC,wBAAwB,EAAE,CAAC,QAAQ,CAAC;QACpC,sBAAsB,EAAE,4DAA4D;QACpF,gBAAgB,EAAE,CAAC,UAAU,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAAgB;IAC1D,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,sBAAsB,EAAE,GAAG,GAAG,CAAC,MAAM,YAAY;QACjD,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,QAAQ;QACrC,mBAAmB,EAAE,GAAG,GAAG,CAAC,MAAM,SAAS;QAC3C,qBAAqB,EAAE,GAAG,GAAG,CAAC,MAAM,WAAW;QAC/C,wBAAwB,EAAE,CAAC,MAAM,CAAC;QAClC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QAC9D,qCAAqC,EAAE,CAAC,MAAM,CAAC;QAC/C,gCAAgC,EAAE,CAAC,MAAM,CAAC;QAC1C,gBAAgB,EAAE,CAAC,UAAU,CAAC;QAC9B,qBAAqB,EAAE,4DAA4D;KACpF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAmB,EAAE,IAAa,EAAE,MAAM,GAAG,GAAG;IACxE,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,sBAAsB,CAAC,CAAC;IACvD,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ /**
3
+ * RFC 7591 — Dynamic Client Registration.
4
+ *
5
+ * Stateless: we don't persist registered clients. PKCE + the redirect_uri
6
+ * allow-list (enforced server-side on token exchange) cover the security
7
+ * properties that registration would otherwise provide. So /register just
8
+ * mints a fresh client_id and echoes back the metadata.
9
+ *
10
+ * This is the pragmatic pattern used by most public-client MCP servers — the
11
+ * spec explicitly allows it (§3.2.1 "client_secret is OPTIONAL").
12
+ */
13
+ export declare function handleRegistration(req: IncomingMessage, res: ServerResponse): Promise<void>;
14
+ //# sourceMappingURL=registration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.d.ts","sourceRoot":"","sources":["../../src/oauth/registration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAKjE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BjG"}
@@ -0,0 +1,40 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { readJsonBody, sendJson, sendError } from "./http_utils.js";
3
+ /**
4
+ * RFC 7591 — Dynamic Client Registration.
5
+ *
6
+ * Stateless: we don't persist registered clients. PKCE + the redirect_uri
7
+ * allow-list (enforced server-side on token exchange) cover the security
8
+ * properties that registration would otherwise provide. So /register just
9
+ * mints a fresh client_id and echoes back the metadata.
10
+ *
11
+ * This is the pragmatic pattern used by most public-client MCP servers — the
12
+ * spec explicitly allows it (§3.2.1 "client_secret is OPTIONAL").
13
+ */
14
+ export async function handleRegistration(req, res) {
15
+ let body = {};
16
+ try {
17
+ body = (await readJsonBody(req)) ?? {};
18
+ }
19
+ catch {
20
+ return sendError(res, 400, "invalid_request", "Body must be valid JSON");
21
+ }
22
+ const clientName = typeof body.client_name === "string" ? body.client_name : "MCP Client";
23
+ const redirectUris = Array.isArray(body.redirect_uris) ? body.redirect_uris : [];
24
+ if (redirectUris.length === 0) {
25
+ return sendError(res, 400, "invalid_redirect_uri", "At least one redirect_uri is required");
26
+ }
27
+ const clientId = `mcp_${randomBytes(16).toString("hex")}`;
28
+ const issuedAt = Math.floor(Date.now() / 1000);
29
+ sendJson(res, 201, {
30
+ client_id: clientId,
31
+ client_id_issued_at: issuedAt,
32
+ client_name: clientName,
33
+ redirect_uris: redirectUris,
34
+ token_endpoint_auth_method: "none",
35
+ grant_types: ["authorization_code", "refresh_token"],
36
+ response_types: ["code"],
37
+ scope: "mcp.full",
38
+ });
39
+ }
40
+ //# sourceMappingURL=registration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration.js","sourceRoot":"","sources":["../../src/oauth/registration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEpE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,GAAoB,EAAE,GAAmB;IAChF,IAAI,IAAI,GAA4B,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC;IAC1F,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,sBAAsB,EAAE,uCAAuC,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;IAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAE/C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;QACjB,SAAS,EAAE,QAAQ;QACnB,mBAAmB,EAAE,QAAQ;QAC7B,WAAW,EAAE,UAAU;QACvB,aAAa,EAAE,YAAY;QAC3B,0BAA0B,EAAE,MAAM;QAClC,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;QACpD,cAAc,EAAE,CAAC,MAAM,CAAC;QACxB,KAAK,EAAE,UAAU;KAClB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { UpstreamOAuthClient } from "./upstream_client.js";
3
+ import type { IntrospectCache } from "./introspect_cache.js";
4
+ /**
5
+ * POST /token — RFC 6749 §4.1.3 + §6 (refresh). Public client (PKCE), so no
6
+ * client_secret. We forward to the Upload-Post backend which owns the
7
+ * codes/tokens; this server just translates the wire format.
8
+ */
9
+ export declare function handleToken(req: IncomingMessage, res: ServerResponse, upstream: UpstreamOAuthClient): Promise<void>;
10
+ /**
11
+ * POST /revoke — RFC 7009. We also drop the cache so any cached entry for
12
+ * this token is killed immediately even if other instances re-introspect.
13
+ */
14
+ export declare function handleRevoke(req: IncomingMessage, res: ServerResponse, upstream: UpstreamOAuthClient, cache: IntrospectCache): Promise<void>;
15
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,IAAI,CAAC,CAaf"}
@@ -0,0 +1,43 @@
1
+ import { readFormBody, sendError, sendJson } from "./http_utils.js";
2
+ /**
3
+ * POST /token — RFC 6749 §4.1.3 + §6 (refresh). Public client (PKCE), so no
4
+ * client_secret. We forward to the Upload-Post backend which owns the
5
+ * codes/tokens; this server just translates the wire format.
6
+ */
7
+ export async function handleToken(req, res, upstream) {
8
+ let form;
9
+ try {
10
+ form = await readFormBody(req);
11
+ }
12
+ catch {
13
+ return sendError(res, 400, "invalid_request", "Body must be form-urlencoded");
14
+ }
15
+ if (!form.grant_type)
16
+ return sendError(res, 400, "invalid_request", "grant_type required");
17
+ const params = new URLSearchParams(form);
18
+ const response = await upstream.exchangeOrRefresh(params);
19
+ res.statusCode = response.status;
20
+ res.setHeader("content-type", "application/json");
21
+ res.setHeader("cache-control", "no-store");
22
+ res.end(response.body);
23
+ }
24
+ /**
25
+ * POST /revoke — RFC 7009. We also drop the cache so any cached entry for
26
+ * this token is killed immediately even if other instances re-introspect.
27
+ */
28
+ export async function handleRevoke(req, res, upstream, cache) {
29
+ let form;
30
+ try {
31
+ form = await readFormBody(req);
32
+ }
33
+ catch {
34
+ return sendError(res, 400, "invalid_request", "Body must be form-urlencoded");
35
+ }
36
+ const token = (form.token ?? "").trim();
37
+ if (token) {
38
+ cache.invalidate(token);
39
+ await upstream.revoke(token);
40
+ }
41
+ sendJson(res, 200, { success: true });
42
+ }
43
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/oauth/tokens.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEpE;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAoB,EACpB,GAAmB,EACnB,QAA6B;IAE7B,IAAI,IAA4B,CAAC;IACjC,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,8BAA8B,CAAC,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;IAE3F,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1D,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;IACjC,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;IAC3C,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAoB,EACpB,GAAmB,EACnB,QAA6B,EAC7B,KAAsB;IAEtB,IAAI,IAA4B,CAAC;IACjC,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,EAAE,8BAA8B,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,KAAK,EAAE,CAAC;QACV,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACxB,MAAM,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,32 @@
1
+ import type { OAuthConfig } from "./config.js";
2
+ /**
3
+ * Thin wrapper around the Upload-Post backend's internal OAuth endpoints.
4
+ * The MCP server never touches a database — all OAuth state lives upstream.
5
+ * This keeps schema ownership in one place and means the MCP container
6
+ * doesn't need DB credentials.
7
+ */
8
+ export declare class UpstreamOAuthClient {
9
+ private readonly cfg;
10
+ constructor(cfg: OAuthConfig);
11
+ /** Proxies form data through to /api/uploadposts/oauth/token. */
12
+ exchangeOrRefresh(form: URLSearchParams): Promise<{
13
+ status: number;
14
+ body: string;
15
+ }>;
16
+ /** Proxies token revocation. */
17
+ revoke(token: string): Promise<void>;
18
+ /**
19
+ * Resolves an opaque access token to {email, api_key, scope, client_id}.
20
+ * Authenticated upstream with the shared internal secret. Returns null on
21
+ * inactive / unknown / network failure.
22
+ */
23
+ introspect(accessToken: string): Promise<IntrospectResult | null>;
24
+ }
25
+ export interface IntrospectResult {
26
+ active: true;
27
+ email: string;
28
+ api_key: string;
29
+ scope: string;
30
+ client_id?: string;
31
+ }
32
+ //# sourceMappingURL=upstream_client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upstream_client.d.ts","sourceRoot":"","sources":["../../src/oauth/upstream_client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;GAKG;AACH,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,WAAW;IAE7C,iEAAiE;IAC3D,iBAAiB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IASzF,gCAAgC;IAC1B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1C;;;;OAIG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;CAwBxE;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Thin wrapper around the Upload-Post backend's internal OAuth endpoints.
3
+ * The MCP server never touches a database — all OAuth state lives upstream.
4
+ * This keeps schema ownership in one place and means the MCP container
5
+ * doesn't need DB credentials.
6
+ */
7
+ export class UpstreamOAuthClient {
8
+ cfg;
9
+ constructor(cfg) {
10
+ this.cfg = cfg;
11
+ }
12
+ /** Proxies form data through to /api/uploadposts/oauth/token. */
13
+ async exchangeOrRefresh(form) {
14
+ const r = await fetch(`${this.cfg.upstreamBaseUrl}/api/uploadposts/oauth/token`, {
15
+ method: "POST",
16
+ headers: { "content-type": "application/x-www-form-urlencoded" },
17
+ body: form.toString(),
18
+ });
19
+ return { status: r.status, body: await r.text() };
20
+ }
21
+ /** Proxies token revocation. */
22
+ async revoke(token) {
23
+ await fetch(`${this.cfg.upstreamBaseUrl}/api/uploadposts/oauth/revoke`, {
24
+ method: "POST",
25
+ headers: { "content-type": "application/x-www-form-urlencoded" },
26
+ body: new URLSearchParams({ token }).toString(),
27
+ }).catch(() => undefined);
28
+ }
29
+ /**
30
+ * Resolves an opaque access token to {email, api_key, scope, client_id}.
31
+ * Authenticated upstream with the shared internal secret. Returns null on
32
+ * inactive / unknown / network failure.
33
+ */
34
+ async introspect(accessToken) {
35
+ try {
36
+ const r = await fetch(`${this.cfg.upstreamBaseUrl}/api/uploadposts/oauth/introspect`, {
37
+ method: "POST",
38
+ headers: {
39
+ "content-type": "application/json",
40
+ "x-internal-secret": this.cfg.internalSecret,
41
+ },
42
+ body: JSON.stringify({ token: accessToken }),
43
+ });
44
+ if (!r.ok)
45
+ return null;
46
+ const data = (await r.json());
47
+ if (!data.active || !data.api_key || !data.email)
48
+ return null;
49
+ return {
50
+ active: true,
51
+ email: data.email,
52
+ api_key: data.api_key,
53
+ scope: data.scope ?? "mcp.full",
54
+ client_id: data.client_id,
55
+ };
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ }
62
+ //# sourceMappingURL=upstream_client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upstream_client.js","sourceRoot":"","sources":["../../src/oauth/upstream_client.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IACD;IAA7B,YAA6B,GAAgB;QAAhB,QAAG,GAAH,GAAG,CAAa;IAAG,CAAC;IAEjD,iEAAiE;IACjE,KAAK,CAAC,iBAAiB,CAAC,IAAqB;QAC3C,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,8BAA8B,EAAE;YAC/E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;SACtB,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;IACpD,CAAC;IAED,gCAAgC;IAChC,KAAK,CAAC,MAAM,CAAC,KAAa;QACxB,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,+BAA+B,EAAE;YACtE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE;SAChD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC5B,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,WAAmB;QAClC,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,mCAAmC,EAAE;gBACpF,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,mBAAmB,EAAE,IAAI,CAAC,GAAG,CAAC,cAAc;iBAC7C;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;aAC7C,CAAC,CAAC;YACH,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,OAAO,IAAI,CAAC;YACvB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAqD,CAAC;YAClF,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YAC9D,OAAO;gBACL,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,UAAU;gBAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,38 @@
1
+ import { z } from "zod";
2
+ export declare const VideoPlatform: z.ZodEnum<["tiktok", "instagram", "youtube", "linkedin", "facebook", "pinterest", "threads", "bluesky", "x", "google_business", "discord", "telegram"]>;
3
+ export declare const PhotoPlatform: z.ZodEnum<["tiktok", "instagram", "linkedin", "facebook", "pinterest", "threads", "reddit", "bluesky", "x", "google_business", "discord", "telegram"]>;
4
+ export declare const TextPlatform: z.ZodEnum<["x", "linkedin", "facebook", "threads", "reddit", "bluesky", "google_business", "discord", "telegram"]>;
5
+ export declare const AnalyticsPlatform: z.ZodEnum<["tiktok", "instagram", "youtube", "linkedin", "facebook", "pinterest", "threads", "bluesky", "x", "reddit", "google_business"]>;
6
+ /**
7
+ * Common scheduling/queue fields shared by every upload tool.
8
+ */
9
+ export declare const schedulingFields: {
10
+ scheduledDate: z.ZodOptional<z.ZodString>;
11
+ timezone: z.ZodOptional<z.ZodString>;
12
+ addToQueue: z.ZodOptional<z.ZodBoolean>;
13
+ maxPostsPerSlot: z.ZodOptional<z.ZodNumber>;
14
+ asyncUpload: z.ZodOptional<z.ZodBoolean>;
15
+ autogenerate: z.ZodOptional<z.ZodBoolean>;
16
+ autogenerateTitle: z.ZodOptional<z.ZodBoolean>;
17
+ autogenerateDescription: z.ZodOptional<z.ZodBoolean>;
18
+ autogenerateLanguage: z.ZodOptional<z.ZodString>;
19
+ };
20
+ export declare const genericResultOutputSchema: {
21
+ result: z.ZodUnknown;
22
+ };
23
+ /** Standard MCP-style content envelope. */
24
+ export type ToolResult = {
25
+ content: Array<{
26
+ type: "text";
27
+ text: string;
28
+ }>;
29
+ structuredContent?: {
30
+ result: unknown;
31
+ };
32
+ isError?: boolean;
33
+ };
34
+ export declare function ok(payload: unknown): ToolResult;
35
+ export declare function fail(err: unknown): ToolResult;
36
+ /** Wrap any tool handler so SDK/HTTP errors bubble up as MCP isError results. */
37
+ export declare function safe<TArgs>(handler: (args: TArgs) => Promise<unknown>): (args: TArgs) => Promise<ToolResult>;
38
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,yJAaxB,CAAC;AAEH,eAAO,MAAM,aAAa,wJAaxB,CAAC;AAEH,eAAO,MAAM,YAAY,oHAUvB,CAAC;AAEH,eAAO,MAAM,iBAAiB,4IAY5B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;CAgC5B,CAAC;AAEF,eAAO,MAAM,yBAAyB;;CAErC,CAAC;AAEF,2CAA2C;AAC3C,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,wBAAgB,EAAE,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAa/C;AAED,wBAAgB,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAO7C;AAED,iFAAiF;AACjF,wBAAgB,IAAI,CAAC,KAAK,EACxB,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,GACzC,CAAC,IAAI,EAAE,KAAK,KAAK,OAAO,CAAC,UAAU,CAAC,CAStC"}
@@ -0,0 +1,121 @@
1
+ import { z } from "zod";
2
+ export const VideoPlatform = z.enum([
3
+ "tiktok",
4
+ "instagram",
5
+ "youtube",
6
+ "linkedin",
7
+ "facebook",
8
+ "pinterest",
9
+ "threads",
10
+ "bluesky",
11
+ "x",
12
+ "google_business",
13
+ "discord",
14
+ "telegram",
15
+ ]);
16
+ export const PhotoPlatform = z.enum([
17
+ "tiktok",
18
+ "instagram",
19
+ "linkedin",
20
+ "facebook",
21
+ "pinterest",
22
+ "threads",
23
+ "reddit",
24
+ "bluesky",
25
+ "x",
26
+ "google_business",
27
+ "discord",
28
+ "telegram",
29
+ ]);
30
+ export const TextPlatform = z.enum([
31
+ "x",
32
+ "linkedin",
33
+ "facebook",
34
+ "threads",
35
+ "reddit",
36
+ "bluesky",
37
+ "google_business",
38
+ "discord",
39
+ "telegram",
40
+ ]);
41
+ export const AnalyticsPlatform = z.enum([
42
+ "tiktok",
43
+ "instagram",
44
+ "youtube",
45
+ "linkedin",
46
+ "facebook",
47
+ "pinterest",
48
+ "threads",
49
+ "bluesky",
50
+ "x",
51
+ "reddit",
52
+ "google_business",
53
+ ]);
54
+ /**
55
+ * Common scheduling/queue fields shared by every upload tool.
56
+ */
57
+ export const schedulingFields = {
58
+ scheduledDate: z
59
+ .string()
60
+ .optional()
61
+ .describe("ISO 8601 date for scheduled publishing, e.g. '2026-12-25T10:00:00Z'. Omit for immediate post."),
62
+ timezone: z
63
+ .string()
64
+ .optional()
65
+ .describe("IANA timezone for scheduled date, e.g. 'Europe/Madrid'."),
66
+ addToQueue: z
67
+ .boolean()
68
+ .optional()
69
+ .describe("Insert into the user's posting queue instead of publishing now."),
70
+ maxPostsPerSlot: z.number().int().positive().optional(),
71
+ asyncUpload: z
72
+ .boolean()
73
+ .optional()
74
+ .describe("Return immediately with request_id (default true)."),
75
+ autogenerate: z
76
+ .boolean()
77
+ .optional()
78
+ .describe("If true, AI generates native per-platform title/description from the media and fills any field left empty."),
79
+ autogenerateTitle: z.boolean().optional().describe("Generate only the title with AI."),
80
+ autogenerateDescription: z.boolean().optional().describe("Generate only the description with AI."),
81
+ autogenerateLanguage: z
82
+ .string()
83
+ .optional()
84
+ .describe("Force the AI output language (ISO code); omit to auto-detect from the media."),
85
+ };
86
+ export const genericResultOutputSchema = {
87
+ result: z.unknown(),
88
+ };
89
+ export function ok(payload) {
90
+ return {
91
+ content: [
92
+ {
93
+ type: "text",
94
+ text: typeof payload === "string"
95
+ ? payload
96
+ : JSON.stringify(payload, null, 2),
97
+ },
98
+ ],
99
+ structuredContent: { result: payload },
100
+ };
101
+ }
102
+ export function fail(err) {
103
+ const message = err instanceof Error ? err.message : typeof err === "string" ? err : JSON.stringify(err);
104
+ return {
105
+ isError: true,
106
+ content: [{ type: "text", text: message }],
107
+ };
108
+ }
109
+ /** Wrap any tool handler so SDK/HTTP errors bubble up as MCP isError results. */
110
+ export function safe(handler) {
111
+ return async (args) => {
112
+ try {
113
+ const result = await handler(args);
114
+ return ok(result);
115
+ }
116
+ catch (err) {
117
+ return fail(err);
118
+ }
119
+ };
120
+ }
121
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { UploadPostMcpClient } from "./client.js";
3
+ export declare function buildServer(client: UploadPostMcpClient): McpServer;
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAmB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAcnE,wBAAgB,WAAW,CAAC,MAAM,EAAE,mBAAmB,GAAG,SAAS,CA0BlE"}