@clipform/mcp-server 3.3.2 → 3.8.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 +5 -7
- package/README.template.md +5 -7
- package/dist/api-client.d.ts +78 -0
- package/dist/api-client.js +22 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth-context.d.ts +10 -1
- package/dist/auth-context.js +5 -1
- package/dist/{chunk-7I765YTD.js → chunk-FC7D3235.js} +4364 -4941
- package/dist/chunk-FC7D3235.js.map +1 -0
- package/dist/{chunk-65MTGAFF.js → chunk-JRASOR5T.js} +102 -103
- package/dist/chunk-JRASOR5T.js.map +1 -0
- package/dist/chunk-KWR2WJQI.js +15361 -0
- package/dist/chunk-KWR2WJQI.js.map +1 -0
- package/dist/chunk-S6RYUVDM.js +102 -0
- package/dist/chunk-S6RYUVDM.js.map +1 -0
- package/dist/{chunk-KHRY3A3M.js → chunk-V5AI2TSQ.js} +21 -9
- package/dist/chunk-V5AI2TSQ.js.map +1 -0
- package/dist/{chunk-A5CFGL27.js → chunk-VPF6MLKM.js} +5 -1
- package/dist/chunk-VPF6MLKM.js.map +1 -0
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/instrument.d.ts +20 -3
- package/dist/instrument.js +45 -39
- package/dist/instrument.js.map +1 -1
- package/dist/prompts.js +4 -3
- package/dist/resources.js +4 -3
- package/dist/server.js +6 -5
- package/package.json +8 -4
- package/dist/chunk-5J5N7KTW.js +0 -4859
- package/dist/chunk-5J5N7KTW.js.map +0 -1
- package/dist/chunk-65MTGAFF.js.map +0 -1
- package/dist/chunk-7I765YTD.js.map +0 -1
- package/dist/chunk-A5CFGL27.js.map +0 -1
- package/dist/chunk-KHRY3A3M.js.map +0 -1
package/README.md
CHANGED
|
@@ -44,17 +44,13 @@ claude mcp add clipform -e CLIPFORM_API_KEY=cf_xxx -- npx -y @clipform/mcp-serve
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
You can also pass the key as a CLI flag: `npx -y @clipform/mcp-server --api-key=cf_xxx`
|
|
50
|
-
|
|
51
|
-
**Anonymous mode** (no API key): Forms go into a shared workspace with the free-tier 3-node limit. You'll get a claim URL to move forms into your account.
|
|
47
|
+
Generate an API key in your Clipform dashboard under **Developers > API keys**. The local server always needs one - to try Clipform without an account, connect to `https://mcp.clipform.io` instead (see "How it works").
|
|
52
48
|
|
|
53
49
|
### Environment variables
|
|
54
50
|
|
|
55
51
|
| Variable | Required | Purpose |
|
|
56
52
|
|----------|----------|---------|
|
|
57
|
-
| `CLIPFORM_API_KEY` | For workspace auth | Bearer key - forms land in the key's workspace with its plan limits. Also unlocks the creative tools (search, TTS, video rendering).
|
|
53
|
+
| `CLIPFORM_API_KEY` | For workspace auth | Bearer key - forms land in the key's workspace with its plan limits. Also unlocks the creative tools (search, TTS, video rendering). Required by the local server. |
|
|
58
54
|
| `API_URL` | Yes | Clipform API base URL (`https://api.clipform.io`, or your local/self-hosted API). |
|
|
59
55
|
|
|
60
56
|
## Tools
|
|
@@ -106,7 +102,9 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
106
102
|
|
|
107
103
|
**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
104
|
|
|
109
|
-
**
|
|
105
|
+
**Remote anonymous (no sign-in):** Connecting to `https://mcp.clipform.io` without signing in builds into a temporary account of the session's own. Forms stay drafts with a private preview link - nothing goes live - and while unclaimed, the form UUID is the credential to edit it. Build results include a one-time claim URL that signs you into that account (on the first form, periodically after, and at the form limit); free-plan limits apply. The local stdio server always needs `CLIPFORM_API_KEY`.
|
|
106
|
+
|
|
107
|
+
These tools need a signed-in Clipform account (OAuth, or an API key): `clipform_list_forms`, `clipform_whoami`, `clipform_get_results`, `clipform_get_responses`, `clipform_delete_form`. An anonymous remote session that calls one is asked to sign in instead. Everything else, including `clipform_get_guide`, `clipform_get_workflow` and `clipform_list_assets`, works without an account.
|
|
110
108
|
|
|
111
109
|
Forms are created with a start node and end screen automatically - you just add the nodes in between.
|
|
112
110
|
|
package/README.template.md
CHANGED
|
@@ -50,17 +50,13 @@ claude mcp add clipform -e CLIPFORM_API_KEY=cf_xxx -- npx -y {{PKG}}
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
You can also pass the key as a CLI flag: `npx -y {{PKG}} --api-key=cf_xxx`
|
|
56
|
-
|
|
57
|
-
**Anonymous mode** (no API key): Forms go into a shared workspace with the free-tier 3-node limit. You'll get a claim URL to move forms into your account.
|
|
53
|
+
Generate an API key in your Clipform dashboard under **Developers > API keys**. The local server always needs one - to try Clipform without an account, connect to `{{MCP_URL}}` instead (see "How it works").
|
|
58
54
|
|
|
59
55
|
### Environment variables
|
|
60
56
|
|
|
61
57
|
| Variable | Required | Purpose |
|
|
62
58
|
|----------|----------|---------|
|
|
63
|
-
| `CLIPFORM_API_KEY` | For workspace auth | Bearer key - forms land in the key's workspace with its plan limits. Also unlocks the creative tools (search, TTS, video rendering).
|
|
59
|
+
| `CLIPFORM_API_KEY` | For workspace auth | Bearer key - forms land in the key's workspace with its plan limits. Also unlocks the creative tools (search, TTS, video rendering). Required by the local server. |
|
|
64
60
|
| `API_URL` | Yes | Clipform API base URL (`{{API_URL}}`, or your local/self-hosted API). |
|
|
65
61
|
|
|
66
62
|
## Tools
|
|
@@ -79,7 +75,9 @@ Your MCP client lists these automatically on connect (via `tools/list`). Full re
|
|
|
79
75
|
|
|
80
76
|
**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
77
|
|
|
82
|
-
**
|
|
78
|
+
**Remote anonymous (no sign-in):** Connecting to `{{MCP_URL}}` without signing in builds into a temporary account of the session's own. Forms stay drafts with a private preview link - nothing goes live - and while unclaimed, the form UUID is the credential to edit it. Build results include a one-time claim URL that signs you into that account (on the first form, periodically after, and at the form limit); free-plan limits apply. The local stdio server always needs `CLIPFORM_API_KEY`.
|
|
79
|
+
|
|
80
|
+
These tools need a signed-in Clipform account (OAuth, or an API key): `clipform_list_forms`, `clipform_whoami`, `clipform_get_results`, `clipform_get_responses`, `clipform_delete_form`. An anonymous remote session that calls one is asked to sign in instead. Everything else, including `clipform_get_guide`, `clipform_get_workflow` and `clipform_list_assets`, works without an account.
|
|
83
81
|
|
|
84
82
|
Forms are created with a start node and end screen automatically - you just add the nodes in between.
|
|
85
83
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
interface ApiOptions {
|
|
2
|
+
method?: string;
|
|
3
|
+
body?: Record<string, unknown>;
|
|
4
|
+
params?: Record<string, string>;
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
}
|
|
7
|
+
type ApiResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
data: Record<string, unknown>;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
status: number;
|
|
13
|
+
error: string;
|
|
14
|
+
apiMessage?: string;
|
|
15
|
+
code?: string;
|
|
16
|
+
reason?: string;
|
|
17
|
+
};
|
|
18
|
+
declare function callApi(path: string, options?: ApiOptions): Promise<ApiResult>;
|
|
19
|
+
/** Next-step hint by status + path so an agent can recover instead of
|
|
20
|
+
* retrying blind (#651). The raw API message stays first, hint second. */
|
|
21
|
+
declare function recoveryHint(status: number, path: string, reason?: string): string | undefined;
|
|
22
|
+
declare function errorResult(message: string, meta?: Record<string, unknown>): {
|
|
23
|
+
_meta?: Record<string, unknown> | undefined;
|
|
24
|
+
content: {
|
|
25
|
+
type: "text";
|
|
26
|
+
text: string;
|
|
27
|
+
}[];
|
|
28
|
+
isError: boolean;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* True exactly when a callApi failure is the `assertNotAnonymous` account
|
|
32
|
+
* gate (apps/api/src/lib/anonymous-guard.ts) - triple-keyed on status + code
|
|
33
|
+
* + reason so an ordinary 403 (PLAN_LIMIT, a genuine authorization denial, a
|
|
34
|
+
* 500) never escalates an already-logged-in caller into a pointless OAuth
|
|
35
|
+
* re-auth (#4088 over-escalation guard). The only MCP-reachable trigger
|
|
36
|
+
* today is `clipform_update_form`'s `is_live: true` (publish) - see that
|
|
37
|
+
* tool's own comment for why `clipform_create_form`'s use of this same
|
|
38
|
+
* predicate is currently dead code.
|
|
39
|
+
*/
|
|
40
|
+
declare function isAnonymousAccountRequired(result: {
|
|
41
|
+
status: number;
|
|
42
|
+
code?: string;
|
|
43
|
+
reason?: string;
|
|
44
|
+
}): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Builds the `_meta["mcp/www_authenticate"]` array a tool result carries to
|
|
47
|
+
* trigger the Apps SDK's tool-level OAuth escalation (#4088): an array of
|
|
48
|
+
* RFC 6750 Bearer challenge strings, the runtime half of the two-part
|
|
49
|
+
* contract (the other half is the static MCP_TOOL_SECURITY declaration) -
|
|
50
|
+
* per the Apps SDK auth docs, metadata alone never triggers the flow,
|
|
51
|
+
* only a runtime error carrying this `_meta` key does. Same challenge shape
|
|
52
|
+
* `apps/api/src/mcp/handler.ts` already emits as a real `WWW-Authenticate`
|
|
53
|
+
* HTTP header for a bad/missing Bearer - this is the tool-result equivalent
|
|
54
|
+
* for a caller that reached a tool (anonymously) but hit a feature that
|
|
55
|
+
* requires an account.
|
|
56
|
+
*/
|
|
57
|
+
declare function authChallengeMeta(errorCode: string, description: string, resourceMetadata?: string): Record<string, unknown>;
|
|
58
|
+
declare function textResult(text: string): {
|
|
59
|
+
content: {
|
|
60
|
+
type: "text";
|
|
61
|
+
text: string;
|
|
62
|
+
}[];
|
|
63
|
+
};
|
|
64
|
+
/** Like textResult, but also carries a machine-readable `structuredContent`.
|
|
65
|
+
* A tool that declares an `outputSchema` MUST return `structuredContent` on
|
|
66
|
+
* every non-error result (the MCP SDK validates it and throws otherwise) - use
|
|
67
|
+
* this for every success/empty path, and `errorResult` (exempt) for failures.
|
|
68
|
+
* Project to the schema's explicit field set here - never pass raw API rows
|
|
69
|
+
* (response-hygiene invariant, #797). */
|
|
70
|
+
declare function structuredResult(text: string, structuredContent: Record<string, unknown>): {
|
|
71
|
+
content: {
|
|
72
|
+
type: "text";
|
|
73
|
+
text: string;
|
|
74
|
+
}[];
|
|
75
|
+
structuredContent: Record<string, unknown>;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export { authChallengeMeta, callApi, errorResult, isAnonymousAccountRequired, recoveryHint, structuredResult, textResult };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
authChallengeMeta,
|
|
3
|
+
callApi,
|
|
4
|
+
errorResult,
|
|
5
|
+
isAnonymousAccountRequired,
|
|
6
|
+
recoveryHint,
|
|
7
|
+
structuredResult,
|
|
8
|
+
textResult
|
|
9
|
+
} from "./chunk-JRASOR5T.js";
|
|
10
|
+
import "./chunk-VPF6MLKM.js";
|
|
11
|
+
import "./chunk-PBQ5BQWD.js";
|
|
12
|
+
import "./chunk-G3PMV62Z.js";
|
|
13
|
+
export {
|
|
14
|
+
authChallengeMeta,
|
|
15
|
+
callApi,
|
|
16
|
+
errorResult,
|
|
17
|
+
isAnonymousAccountRequired,
|
|
18
|
+
recoveryHint,
|
|
19
|
+
structuredResult,
|
|
20
|
+
textResult
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/auth-context.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ interface McpAuthContext {
|
|
|
17
17
|
is_anonymous?: boolean;
|
|
18
18
|
auth_via?: "oauth";
|
|
19
19
|
mcp_mint_proof?: string;
|
|
20
|
+
mcp_session_proof?: string;
|
|
20
21
|
resolveWorkspace?: (target: {
|
|
21
22
|
workspace_id?: string;
|
|
22
23
|
form_id?: string;
|
|
@@ -30,6 +31,10 @@ interface McpAuthContext {
|
|
|
30
31
|
name: string;
|
|
31
32
|
}[]>;
|
|
32
33
|
default_workspace_id?: string;
|
|
34
|
+
mcp_session_id?: string;
|
|
35
|
+
loadInternalContent?: (kind: "guides" | "assets", params?: {
|
|
36
|
+
type?: string;
|
|
37
|
+
}) => Promise<Record<string, unknown>>;
|
|
33
38
|
}
|
|
34
39
|
/**
|
|
35
40
|
* Marker header the in-process MCP tool layer sets on its outgoing API
|
|
@@ -65,8 +70,12 @@ declare const MCP_AUTH_VIA_HEADER = "x-clipform-auth-via";
|
|
|
65
70
|
* victim's uid themselves (#3330 review).
|
|
66
71
|
*/
|
|
67
72
|
declare const MCP_MINT_PROOF_HEADER = "x-clipform-mcp-mint-proof";
|
|
73
|
+
/** #4090: carries `mcp_session_proof` (same trust model as MCP_MINT_PROOF_HEADER: HMAC-verified server-side, never trusted raw). */
|
|
74
|
+
declare const MCP_SESSION_PROOF_HEADER = "x-clipform-mcp-session-proof";
|
|
75
|
+
/** Carries `mcp_session_id` to the API for funnel analytics only (#4657). */
|
|
76
|
+
declare const MCP_SESSION_ID_HEADER = "x-clipform-mcp-session-id";
|
|
68
77
|
declare function runWithMcpAuth<T>(ctx: McpAuthContext, fn: () => Promise<T> | T): Promise<T> | T;
|
|
69
78
|
declare function getMcpAuth(): McpAuthContext | undefined;
|
|
70
79
|
declare function runWithMcpTool<T>(toolName: string, fn: () => Promise<T> | T): Promise<T> | T;
|
|
71
80
|
|
|
72
|
-
export { MCP_ANONYMOUS_HEADER, MCP_AUTH_VIA_HEADER, MCP_MINT_PROOF_HEADER, type McpAuthContext, getMcpAuth, runWithMcpAuth, runWithMcpTool };
|
|
81
|
+
export { MCP_ANONYMOUS_HEADER, MCP_AUTH_VIA_HEADER, MCP_MINT_PROOF_HEADER, MCP_SESSION_ID_HEADER, MCP_SESSION_PROOF_HEADER, type McpAuthContext, getMcpAuth, runWithMcpAuth, runWithMcpTool };
|
package/dist/auth-context.js
CHANGED
|
@@ -2,15 +2,19 @@ import {
|
|
|
2
2
|
MCP_ANONYMOUS_HEADER,
|
|
3
3
|
MCP_AUTH_VIA_HEADER,
|
|
4
4
|
MCP_MINT_PROOF_HEADER,
|
|
5
|
+
MCP_SESSION_ID_HEADER,
|
|
6
|
+
MCP_SESSION_PROOF_HEADER,
|
|
5
7
|
getMcpAuth,
|
|
6
8
|
runWithMcpAuth,
|
|
7
9
|
runWithMcpTool
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-VPF6MLKM.js";
|
|
9
11
|
import "./chunk-G3PMV62Z.js";
|
|
10
12
|
export {
|
|
11
13
|
MCP_ANONYMOUS_HEADER,
|
|
12
14
|
MCP_AUTH_VIA_HEADER,
|
|
13
15
|
MCP_MINT_PROOF_HEADER,
|
|
16
|
+
MCP_SESSION_ID_HEADER,
|
|
17
|
+
MCP_SESSION_PROOF_HEADER,
|
|
14
18
|
getMcpAuth,
|
|
15
19
|
runWithMcpAuth,
|
|
16
20
|
runWithMcpTool
|