@clipform/mcp-server 3.0.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/README.template.md +1 -1
- package/dist/auth-context.d.ts +13 -0
- package/dist/auth-context.js +1 -1
- package/dist/{chunk-EXV5M7YV.js → chunk-236IGTEY.js} +2 -2
- package/dist/{chunk-HZMMOSEM.js → chunk-A5CFGL27.js} +1 -1
- package/dist/chunk-A5CFGL27.js.map +1 -0
- package/dist/{chunk-KCF7ZVDI.js → chunk-EQ6WNIA5.js} +2 -2
- package/dist/{chunk-QBPE32AV.js → chunk-J7727374.js} +318 -80
- package/dist/chunk-J7727374.js.map +1 -0
- package/dist/{chunk-KNOCYZHG.js → chunk-VZKMOMFJ.js} +29 -10
- package/dist/chunk-VZKMOMFJ.js.map +1 -0
- package/dist/index.js +5 -5
- package/dist/prompts.js +3 -3
- package/dist/resources.js +3 -3
- package/dist/server.js +5 -5
- package/package.json +4 -3
- package/dist/chunk-HZMMOSEM.js.map +0 -1
- package/dist/chunk-KNOCYZHG.js.map +0 -1
- package/dist/chunk-QBPE32AV.js.map +0 -1
- /package/dist/{chunk-EXV5M7YV.js.map → chunk-236IGTEY.js.map} +0 -0
- /package/dist/{chunk-KCF7ZVDI.js.map → chunk-EQ6WNIA5.js.map} +0 -0
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
82
82
|
| `clipform_delete_node_media` | Remove media from a node. |
|
|
83
83
|
| `clipform_set_logic` | Set the next node for one or more nodes, wiring a linear route (A to B to C). |
|
|
84
84
|
| `clipform_log_generation` | Internal audit step run by a form-generation workflow. |
|
|
85
|
-
| `clipform_search_news` |
|
|
85
|
+
| `clipform_search_news` | Search recent news articles from NewsAPI and The Guardian and return them as structured results. |
|
|
86
86
|
| `clipform_generate_tts` | Generate narration audio from text with word-level captions. |
|
|
87
87
|
| `clipform_search_media` | Search images or stock video clips. |
|
|
88
88
|
| `clipform_render_composition` | Render a specialised video composition to MP4 or PNG - custom animated visuals that a video template can't provide, such as geography animations or designed motion graphics. |
|
|
@@ -102,7 +102,7 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
102
102
|
|
|
103
103
|
## How it works
|
|
104
104
|
|
|
105
|
-
**Remote (OAuth):** Bearer tokens are audience-bound to `https://mcp.clipform.io` (RFC 8707) and scoped to `mcp` only. Forms land directly in the workspace you approved during consent.
|
|
105
|
+
**Remote (OAuth):** Bearer tokens are audience-bound to `https://mcp.clipform.io` (RFC 8707) and scoped to `mcp` only. Forms land directly in the workspace you approved during consent by default. One connection reaches every workspace you belong to in the same company: pass `workspace_id` (ids from `clipform_whoami`) on `clipform_create_form`, `clipform_import_form`, `clipform_list_forms`, `clipform_upload_media_asset`, or `clipform_generate_tts`, or a `form_id` from another workspace on any form tool - including `clipform_upload_media_asset`, `clipform_generate_tts`, and `clipform_complete_media_upload`, where it's a routing hint only (the result still lands in that workspace's media library, not on a node). Membership is re-checked on every call, and results name the workspace.
|
|
106
106
|
|
|
107
107
|
**Local with API key:** The `CLIPFORM_API_KEY` is sent as a standard `Authorization: Bearer` header. Forms are created directly in the key's workspace with your plan tier limits.
|
|
108
108
|
|
package/README.template.md
CHANGED
|
@@ -75,7 +75,7 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
75
75
|
|
|
76
76
|
## How it works
|
|
77
77
|
|
|
78
|
-
**Remote (OAuth):** Bearer tokens are audience-bound to `{{MCP_URL}}` (RFC 8707) and scoped to `mcp` only. Forms land directly in the workspace you approved during consent.
|
|
78
|
+
**Remote (OAuth):** Bearer tokens are audience-bound to `{{MCP_URL}}` (RFC 8707) and scoped to `mcp` only. Forms land directly in the workspace you approved during consent by default. One connection reaches every workspace you belong to in the same company: pass `workspace_id` (ids from `clipform_whoami`) on `clipform_create_form`, `clipform_import_form`, `clipform_list_forms`, `clipform_upload_media_asset`, or `clipform_generate_tts`, or a `form_id` from another workspace on any form tool - including `clipform_upload_media_asset`, `clipform_generate_tts`, and `clipform_complete_media_upload`, where it's a routing hint only (the result still lands in that workspace's media library, not on a node). Membership is re-checked on every call, and results name the workspace.
|
|
79
79
|
|
|
80
80
|
**Local with API key:** The `CLIPFORM_API_KEY` is sent as a standard `Authorization: Bearer` header. Forms are created directly in the key's workspace with your plan tier limits.
|
|
81
81
|
|
package/dist/auth-context.d.ts
CHANGED
|
@@ -17,6 +17,19 @@ interface McpAuthContext {
|
|
|
17
17
|
is_anonymous?: boolean;
|
|
18
18
|
auth_via?: "oauth";
|
|
19
19
|
mcp_mint_proof?: string;
|
|
20
|
+
resolveWorkspace?: (target: {
|
|
21
|
+
workspace_id?: string;
|
|
22
|
+
form_id?: string;
|
|
23
|
+
}) => Promise<{
|
|
24
|
+
workspace_id: string;
|
|
25
|
+
workspace_name: string;
|
|
26
|
+
api_key: string;
|
|
27
|
+
} | null>;
|
|
28
|
+
listWorkspaces?: () => Promise<{
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
}[]>;
|
|
32
|
+
default_workspace_id?: string;
|
|
20
33
|
}
|
|
21
34
|
/**
|
|
22
35
|
* Marker header the in-process MCP tool layer sets on its outgoing API
|
package/dist/auth-context.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
FULL_CAPS,
|
|
6
6
|
callApi,
|
|
7
7
|
getSessionContext
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VZKMOMFJ.js";
|
|
9
9
|
|
|
10
10
|
// src/lib/guides.ts
|
|
11
11
|
var guidesPromise = null;
|
|
@@ -143,4 +143,4 @@ export {
|
|
|
143
143
|
getGuideUri,
|
|
144
144
|
registerResources
|
|
145
145
|
};
|
|
146
|
-
//# sourceMappingURL=chunk-
|
|
146
|
+
//# sourceMappingURL=chunk-236IGTEY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/auth-context.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\n\n/**\n * Identity of the end-user a given MCP request is acting on behalf of.\n *\n * Populated by the in-process host (apps/api) after validating an OAuth\n * Bearer on /mcp. The MCP tool layer reads it to decide which workspace\n * forms should land in and which plan tier gates apply.\n *\n * NOT populated when the server runs as a local stdio process (npx) - in\n * that mode tools fall back to edit-token based auth.\n */\nexport interface McpAuthContext {\n user_id: string;\n workspace_id: string;\n scopes: string[];\n tool_name?: string;\n api_key?: string;\n // Set when the human behind this tool call is an anonymous Supabase\n // session (apps/api's app-chat lane, #2983/#2984) - api-client.ts's\n // getAuthHeaders reads it to mark the outgoing bot-key HTTP request so the\n // API can propagate the restriction even though the request itself\n // authenticates with an API key, not a JWT.\n is_anonymous?: boolean;\n // Set on the OAuth branch of apps/api's mcp/handler.ts when this request's\n // bot API key was resolved on behalf of an OAuth-connected user (#3716) -\n // api-client.ts's getAuthHeaders reads it to mark the outgoing request so\n // /v1/me can report auth_mode \"oauth\" instead of the generic \"api_key\" the\n // bot-key lane would otherwise get, even though the request itself\n // authenticates with an API key, not an OAuth token.\n auth_via?: \"oauth\";\n // #3330 review fix (blocker 1): an HMAC proof (apps/api's mcp-mint-proof.ts)\n // that THIS exact request's #1415 anon lane freshly minted a brand-new anon\n // identity for `workspace_id` - set only on the mint branch of\n // resolveAnonymousMcpAuth, never when auth was resolved via an inbound\n // form_id (even the caller's own). Lets create-form.ts safely offer a\n // same-UID claim link without ever deriving \"who to bind it to\" from a\n // body-supplied id, which would let a batch smuggling another tenant's\n // form_id alongside a create_form call mint a claim token for THAT\n // tenant's identity instead of the caller's own.\n mcp_mint_proof?: string;\n // #3822: set ONLY on the OAuth branch of apps/api's mcp/handler.ts. Lets a\n // single tool call target another workspace the connected user belongs to\n // (per-call, never per-request - see the #3330 note in the package\n // CLAUDE.md). The host re-checks membership on every call and returns that\n // workspace's own bot key, or null to mean \"act in the default workspace\n // unchanged\" (target is the default, or a form_id the user can't reach -\n // the API then answers exactly as it did before targeting existed). Anon + stdio contexts never carry it, so they\n // stay pinned to one workspace.\n resolveWorkspace?: (target: {\n workspace_id?: string;\n form_id?: string;\n }) => Promise<{ workspace_id: string; workspace_name: string; api_key: string } | null>;\n // #3822: the workspaces the connected user may target (same set\n // resolveWorkspace accepts). OAuth lane only.\n listWorkspaces?: () => Promise<{ id: string; name: string }[]>;\n // #3822: the workspace picked at authorize time - what a call with no\n // `workspace_id` acts in. OAuth lane only (workspace_id above is swapped\n // per call when a target is resolved, this never is).\n default_workspace_id?: string;\n}\n\n/**\n * Marker header the in-process MCP tool layer sets on its outgoing API\n * requests (api-client.ts) when `is_anonymous` is true, so an anonymous\n * app-chat session can't launder itself into an unrestricted API-key caller\n * by asking the bot to publish/mint credentials on its behalf. apps/api's\n * authMiddleware / workspaceAccessMiddleware / requireWorkspaceWriteAuth\n * read this on the API-key path and set isAnonymous accordingly - trusting\n * it is safe because it can only RESTRICT a caller: a real integration that\n * sets this header on its own API-key requests only denies itself, it can\n * never use it to gain anonymous-JWT privileges it doesn't already have.\n */\nexport const MCP_ANONYMOUS_HEADER = \"x-clipform-anonymous\";\n\n/**\n * Marker header the in-process MCP tool layer sets on its outgoing API\n * requests (api-client.ts) when `auth_via` is \"oauth\", so /v1/me can report\n * `auth_mode: \"oauth\"` for an OAuth-connected user instead of the generic\n * \"api_key\" the bot-key lane would otherwise get (#3716). Label-only: it\n * changes nothing but the reported string. Trusting it from the wire is\n * safe because a direct API-key caller who sets this header on their own\n * request only mislabels their own whoami output - they gain no privilege,\n * exactly the same reasoning as MCP_ANONYMOUS_HEADER above (except that\n * header can only restrict, and this one can only relabel).\n */\nexport const MCP_AUTH_VIA_HEADER = \"x-clipform-auth-via\";\n\n/**\n * Carries `mcp_mint_proof` on the same outgoing bot-key request. Unlike\n * MCP_ANONYMOUS_HEADER (a boolean that can only ever RESTRICT), this header's\n * VALUE matters - it names an identity a claim token gets bound to - so its\n * value is HMAC-signed (mcp-mint-proof.ts) rather than trusted raw: a direct\n * external caller reaching `POST /v1/forms` with any valid workspace API key\n * could otherwise hand-set an unsigned \"mint uid\" header to an arbitrary\n * victim's uid themselves (#3330 review).\n */\nexport const MCP_MINT_PROOF_HEADER = \"x-clipform-mcp-mint-proof\";\n\nconst storage = new AsyncLocalStorage<McpAuthContext>();\n\nexport function runWithMcpAuth<T>(ctx: McpAuthContext, fn: () => Promise<T> | T): Promise<T> | T {\n return storage.run(ctx, fn);\n}\n\nexport function getMcpAuth(): McpAuthContext | undefined {\n return storage.getStore();\n}\n\nexport function runWithMcpTool<T>(toolName: string, fn: () => Promise<T> | T): Promise<T> | T {\n const parent = storage.getStore();\n if (!parent) return fn();\n return storage.run({ ...parent, tool_name: toolName }, fn);\n}\n"],"mappings":";AAAA,SAAS,yBAAyB;AAyE3B,IAAM,uBAAuB;AAa7B,IAAM,sBAAsB;AAW5B,IAAM,wBAAwB;AAErC,IAAM,UAAU,IAAI,kBAAkC;AAE/C,SAAS,eAAkB,KAAqB,IAA0C;AAC/F,SAAO,QAAQ,IAAI,KAAK,EAAE;AAC5B;AAEO,SAAS,aAAyC;AACvD,SAAO,QAAQ,SAAS;AAC1B;AAEO,SAAS,eAAkB,UAAkB,IAA0C;AAC5F,QAAM,SAAS,QAAQ,SAAS;AAChC,MAAI,CAAC,OAAQ,QAAO,GAAG;AACvB,SAAO,QAAQ,IAAI,EAAE,GAAG,QAAQ,WAAW,SAAS,GAAG,EAAE;AAC3D;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
WORKFLOW_TYPES,
|
|
4
4
|
getDiscoveryParams,
|
|
5
5
|
getSessionContextWithAuth
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VZKMOMFJ.js";
|
|
7
7
|
import {
|
|
8
8
|
__export
|
|
9
9
|
} from "./chunk-G3PMV62Z.js";
|
|
@@ -4856,4 +4856,4 @@ export {
|
|
|
4856
4856
|
getWorkflowText,
|
|
4857
4857
|
registerPrompts
|
|
4858
4858
|
};
|
|
4859
|
-
//# sourceMappingURL=chunk-
|
|
4859
|
+
//# sourceMappingURL=chunk-EQ6WNIA5.js.map
|