@jinshuju/mcp 0.2.0 → 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.
- package/README.md +32 -98
- package/dist/analytics.d.ts +23 -3
- package/dist/analytics.js +55 -2
- package/dist/api.js +2 -1
- package/dist/generated/meta.json +3 -2
- package/dist/generated/operations.json +192 -36
- package/dist/generated/schemas.json +1858 -90
- package/dist/generated/tools.json +793 -105
- package/dist/result.d.ts +2 -0
- package/dist/result.js +3 -1
- package/dist/types.d.ts +2 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,44 +5,51 @@ The tools are generated from the [open API v1 openapi.yaml](https://jinshuju.net
|
|
|
5
5
|
|
|
6
6
|
Two ways to use it:
|
|
7
7
|
|
|
8
|
-
- **Remote (HTTP)** — the official deployment
|
|
9
|
-
- **Local (stdio)** — `npx -y @jinshuju/mcp
|
|
8
|
+
- **Remote (HTTP)** — the official deployment at `https://jinshuju.net/mcp`, with OAuth sign-in; for claude.ai, Claude Code, Cursor, Windsurf and the like;
|
|
9
|
+
- **Local (stdio)** — `npx -y @jinshuju/mcp` with an access token; for clients that only run local servers.
|
|
10
10
|
|
|
11
11
|
## Remote use
|
|
12
12
|
|
|
13
|
-
Server URL: `https://
|
|
13
|
+
Server URL: `https://jinshuju.net/mcp`
|
|
14
14
|
|
|
15
|
-
| Client | Setup
|
|
16
|
-
| ----------- |
|
|
17
|
-
| claude.ai | Settings → Connectors → Add custom connector, enter the server URL, sign in to Jinshuju
|
|
18
|
-
| Claude Code | `claude mcp add jinshuju -s user --transport http https://
|
|
19
|
-
| Cursor | `{ "mcpServers": { "jinshuju": { "url": "https://
|
|
20
|
-
| Windsurf | Same as above, with the key `serverUrl`
|
|
15
|
+
| Client | Setup |
|
|
16
|
+
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| claude.ai | Settings → Connectors → Add custom connector, enter the server URL, sign in to Jinshuju |
|
|
18
|
+
| Claude Code | `claude mcp add jinshuju -s user --transport http https://jinshuju.net/mcp`, then run `/mcp` in Claude Code and sign in to Jinshuju there |
|
|
19
|
+
| Cursor | `{ "mcpServers": { "jinshuju": { "url": "https://jinshuju.net/mcp" } } }` |
|
|
20
|
+
| Windsurf | Same as above, with the key `serverUrl` |
|
|
21
21
|
|
|
22
22
|
Without OAuth (CI, scripts), send an access token directly: `--header "Authorization: Bearer YOUR_ACCESS_TOKEN"`, or add `headers` to the config.
|
|
23
23
|
Create a personal access token under [Profile → API](https://next.jinshuju.net/profile/api), and an account access token under [System settings → Account API](https://next.jinshuju.net/system/api_licence).
|
|
24
24
|
|
|
25
25
|
## Local use (stdio)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
# Sign in once (browser OAuth); the credential is stored in ~/.jinshuju/config.json and shared by the cli and mcp
|
|
29
|
-
npx -y @jinshuju/cli auth login
|
|
27
|
+
Pass an access token (created as above) in `JINSHUJU_ACCESS_TOKEN`:
|
|
30
28
|
|
|
29
|
+
```bash
|
|
31
30
|
# Claude Code
|
|
32
|
-
claude mcp add jinshuju -s user -- npx -y @jinshuju/mcp
|
|
31
|
+
claude mcp add jinshuju -s user -e JINSHUJU_ACCESS_TOKEN=your_token -- npx -y @jinshuju/mcp
|
|
33
32
|
```
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
|
|
34
|
+
Other clients:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"jinshuju": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": ["-y", "@jinshuju/mcp"],
|
|
42
|
+
"env": { "JINSHUJU_ACCESS_TOKEN": "your_token" }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
39
46
|
```
|
|
40
47
|
|
|
41
48
|
To check it works, ask the assistant to "list my Jinshuju forms".
|
|
42
49
|
|
|
43
50
|
## Tools
|
|
44
51
|
|
|
45
|
-
60 tools with the same names as those documented for the [Jinshuju MCP Server](https://open.jinshuju.net/mcp)
|
|
52
|
+
60 tools with the same names as those documented for the [Jinshuju MCP Server](https://open.jinshuju.net/mcp). Each tool maps to one operation in openapi.yaml; a few combine two operations:
|
|
46
53
|
|
|
47
54
|
| Category | Tools |
|
|
48
55
|
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -58,96 +65,23 @@ To check it works, ask the assistant to "list my Jinshuju forms".
|
|
|
58
65
|
| Uploads | upload_entry_attachment, upload_form_image, upload_import_file |
|
|
59
66
|
| Schemas | get_schema (reads an openapi schema by name, e.g. FieldInput, TextFieldInput) |
|
|
60
67
|
|
|
61
|
-
Differences from the tools documented at open.jinshuju.net/mcp:
|
|
62
|
-
|
|
63
|
-
- Presigned uploads (`prepare_*_upload`) are not in openapi.yaml; the `upload_*` tools here upload directly (the file is passed as base64);
|
|
64
|
-
- `update_entry` only updates partially (PATCH); there is no full replace;
|
|
65
|
-
- Data structures such as field types are served by the `get_schema` tool and the `jinshuju://schemas/{name}` resource.
|
|
66
|
-
|
|
67
68
|
The full tool → operation mapping is in `mcp.overlay.yaml` and `src/generated/meta.json`.
|
|
68
69
|
|
|
69
70
|
**Size.** The full tools/list is about 39k tokens (o200k estimate; about 36k without outputSchema).
|
|
70
71
|
It stays that size by not inlining large schemas: field definitions (52 types), form settings, themes and the like become a one-line pointer; unions that branch on type, such as table columns, keep only their common properties.
|
|
71
72
|
The model reads them on demand with `get_schema("FieldInput")` / `get_schema("TextFieldInput")`.
|
|
72
73
|
|
|
73
|
-
## Environment variables
|
|
74
|
-
|
|
75
|
-
| Variable | Meaning |
|
|
76
|
-
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
77
|
-
| `JINSHUJU_ACCESS_TOKEN` | Credential for stdio mode; when set, the config file is not read |
|
|
78
|
-
| `JINSHUJU_CONFIG` | Config file path, default `~/.jinshuju/config.json` |
|
|
79
|
-
| `JINSHUJU_API_BASE_URL` | API URL, default `https://jinshuju.net/api/v1` |
|
|
80
|
-
| `JINSHUJU_AUTH_HOST` | Authorization server, default `https://account.jinshuju.net` |
|
|
81
|
-
| `JINSHUJU_MCP_PUBLIC_URL` | Public URL in HTTP mode (the resource in the OAuth metadata); a comma-separated list is chosen by the request's Host; empty infers it from the request |
|
|
82
|
-
| `JINSHUJU_MCP_MAX_RESULT_CHARS` | Maximum characters of one result, default 120000; longer results are truncated with a hint to page |
|
|
83
|
-
| `JINSHUJU_MCP_TOKEN_CACHE_TTL_MS` | Token verification cache in HTTP mode, default 5 minutes |
|
|
84
|
-
| `POSTHOG_API_KEY` | PostHog project token (`phc_…`); when set, HTTP mode reports MCP analytics, see below |
|
|
85
|
-
| `POSTHOG_HOST` | PostHog ingestion host, default `https://us.i.posthog.com` |
|
|
86
|
-
| `JINSHUJU_MCP_COLLECT_INTENT` | Whether the model writes the user's intent in each call (`context` argument → `$mcp_intent`), default `true` |
|
|
87
|
-
| `SENTRY_DSN` | Sentry project DSN; when set, the Workers entry reports exceptions, see below |
|
|
88
|
-
| `SENTRY_ENVIRONMENT` | Sentry environment name, optional |
|
|
89
|
-
| `PORT` / `HOST` | Where the Node entry listens, default 8787 / 0.0.0.0 |
|
|
90
|
-
|
|
91
|
-
## Usage analytics (PostHog MCP analytics)
|
|
92
|
-
|
|
93
|
-
With `POSTHOG_API_KEY` set, the HTTP deployment reports tool usage through [@posthog/mcp](https://posthog.com/docs/mcp-analytics), on the same terms as the built-in MCP at jinshuju.net/mcp:
|
|
94
|
-
|
|
95
|
-
- Only `$mcp_initialize` (legacy handshake) and `$mcp_tool_call` are reported; `tools/list`, resources, `$identify` and `$exception` are not;
|
|
96
|
-
- A tool call records the tool name, the argument names (`$mcp_input_keys`), the duration, whether it failed and the truncated error, **but not the argument values or the result**;
|
|
97
|
-
- Every tool gets one more argument, `context`, where the model writes what the user wants to do (`$mcp_intent`); email addresses, phone numbers, IPs and card numbers in it are masked before sending.
|
|
98
|
-
With `JINSHUJU_MCP_COLLECT_INTENT=false` the argument is no longer advertised, and a client that still sends it gets no error;
|
|
99
|
-
- `distinct_id` is the Jinshuju user id; `$session_id` is derived from a hash of the token (one session per token); the client name / version come from the handshake or each request's `_meta`.
|
|
100
|
-
|
|
101
|
-
stdio (local) mode reports nothing.
|
|
102
|
-
|
|
103
|
-
## Error monitoring (Sentry)
|
|
104
|
-
|
|
105
|
-
The Workers entry (`src/worker.ts`) is wrapped with [@sentry/cloudflare](https://docs.sentry.io/platforms/javascript/guides/cloudflare/) and reports once `SENTRY_DSN` is set:
|
|
74
|
+
## Environment variables (stdio)
|
|
106
75
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
76
|
+
| Variable | Meaning |
|
|
77
|
+
| ------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
78
|
+
| `JINSHUJU_ACCESS_TOKEN` | Access token (personal or account) |
|
|
79
|
+
| `JINSHUJU_API_BASE_URL` | API URL, default `https://jinshuju.net/api/v1` |
|
|
80
|
+
| `JINSHUJU_MCP_MAX_RESULT_CHARS` | Maximum characters of one result, default 120000; longer results are truncated with a hint to page |
|
|
111
81
|
|
|
112
82
|
## Development
|
|
113
83
|
|
|
114
|
-
|
|
115
|
-
npm install
|
|
116
|
-
npm run generate # spec/openapi.yaml + mcp.overlay.yaml -> src/generated/ (operations / tools / schemas / meta)
|
|
117
|
-
npm run check # typecheck + oxlint + oxfmt
|
|
118
|
-
npm test # builds, then runs node:test without touching the network
|
|
119
|
-
npm run dev # local HTTP server: http://127.0.0.1:8787/mcp
|
|
120
|
-
npm run spec:update # fetches the latest live openapi.yaml and regenerates
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
After changing `mcp.overlay.yaml` or updating `spec/openapi.yaml`, run `npm run generate` and commit `src/generated/`; CI checks it.
|
|
124
|
-
|
|
125
|
-
## Deployment
|
|
126
|
-
|
|
127
|
-
- **Docker (official)**: `docker build -t jinshuju-mcp . && docker run -p 8787:8787 -e JINSHUJU_MCP_PUBLIC_URL=https://mcp.jinshuju.net jinshuju-mcp`
|
|
128
|
-
- **Cloudflare Workers (optional)**: `npx wrangler login && npm run worker:deploy`
|
|
129
|
-
- **WDL or another Workers-compatible platform (optional)**: with [`@wdl-dev/cli`](https://github.com/wdl-dev/cli) installed and its token configured, `npm run wdl:deploy`;
|
|
130
|
-
set the public URL as the secret `JINSHUJU_MCP_PUBLIC_URL` (`wdl secret put --worker jinshuju-mcp JINSHUJU_MCP_PUBLIC_URL`),
|
|
131
|
-
with several entry points comma-separated, e.g. `https://mcp.jinshuju.net,https://<ns>.<platform>/jinshuju-mcp`;
|
|
132
|
-
to report to PostHog add the secret `POSTHOG_API_KEY` (and `POSTHOG_HOST` if needed); to report to Sentry add `SENTRY_DSN`.
|
|
133
|
-
|
|
134
|
-
The service is stateless and needs no database, KV or Durable Objects.
|
|
135
|
-
|
|
136
|
-
## Evals
|
|
137
|
-
|
|
138
|
-
`evals/` is an automated, multi-model evaluation built from real usage: 42 tasks (categories 找表单 / 读数据 / 统计汇总 / 建表单 / 改设置 / 批量写入 / 导入 — find forms, read entries, aggregate, create forms, change settings, batch writes, import)
|
|
139
|
-
run against both this repository's MCP and the built-in MCP (jinshuju.net/mcp), are scored by assertions, produce pass-rate and token tables by model × MCP × category,
|
|
140
|
-
and write every run into a Jinshuju form. Usage, task format and metrics are in [evals/README.md](evals/README.md).
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
npm run eval -- seed # prepares fixture data in the eval account
|
|
144
|
-
npm run eval -- run # all tasks × EVAL_MODELS × new,builtin → evals/results/<run_id>/report.md
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Design notes
|
|
148
|
-
|
|
149
|
-
- [ARCHITECTURE.md](ARCHITECTURE.md) — modules, the path of one call, generation rules, authentication
|
|
150
|
-
- [evals/README.md](evals/README.md) — the eval system: sample set, runner, scoring, persistence
|
|
84
|
+
Building, running and deploying the server: [DEVELOPMENT.md](DEVELOPMENT.md). How it fits together: [ARCHITECTURE.md](ARCHITECTURE.md).
|
|
151
85
|
|
|
152
86
|
## License
|
|
153
87
|
|
package/dist/analytics.d.ts
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* PostHog MCP analytics (@posthog/mcp): the HTTP deployment reports how the tools are used. stdio runs on the user's
|
|
3
3
|
* own machine and reports nothing.
|
|
4
4
|
*
|
|
5
|
-
* What is captured
|
|
5
|
+
* What is captured:
|
|
6
6
|
* - only $mcp_initialize and $mcp_tool_call; tools/list, resources/*, $identify and $exception are all dropped;
|
|
7
7
|
* - a tool call records only argument names ($mcp_input_keys), never argument values or the result; a failure records
|
|
8
|
-
* its
|
|
8
|
+
* the truncated error text, its bucket ($mcp_error_type: validation / permission / timeout / rate_limited / api_4xx /
|
|
9
|
+
* api_5xx / internal, read off the text because the SDK types only thrown exceptions and our tools return isError
|
|
10
|
+
* results) and, for an API failure, the HTTP status ($mcp_error_status);
|
|
11
|
+
* - mcp_caller_type tells Jiri's remaining in-house path (client name mcp, python-httpx user agent) from everyone else (external);
|
|
9
12
|
* - intent: every tool gets a context argument where the model says what the user wants to do ($mcp_intent). The SDK
|
|
10
13
|
* scrubs emails / phone numbers / IPs / card numbers from it before sending; JINSHUJU_MCP_COLLECT_INTENT=false turns
|
|
11
14
|
* it off entirely (the argument is no longer offered and nothing is reported);
|
|
@@ -21,9 +24,26 @@
|
|
|
21
24
|
*/
|
|
22
25
|
import type { AuthInfo, McpServer } from '@modelcontextprotocol/server';
|
|
23
26
|
import type { Config } from './config.js';
|
|
24
|
-
/**
|
|
27
|
+
/** The question the model answers in the context argument; it becomes $mcp_intent. */
|
|
25
28
|
export declare const CONTEXT_DESCRIPTION = "Why are you calling this tool? Briefly describe the user's goal.";
|
|
26
29
|
export declare const CONTEXT_INSTRUCTIONS: string;
|
|
30
|
+
/** The buckets PostHog's own MCP analytics uses for $mcp_error_type, so its dashboards read our events directly. */
|
|
31
|
+
export type ErrorType = 'validation' | 'permission' | 'timeout' | 'rate_limited' | 'api_4xx' | 'api_5xx' | 'internal';
|
|
32
|
+
/**
|
|
33
|
+
* Buckets a failed tool call by its text, whose shapes are all ours: result.ts opens an API failure with `HTTP <status>:`
|
|
34
|
+
* and closes it with a hint, api.ts opens a TransportError with the reason, and the MCP SDK prefixes a validation failure.
|
|
35
|
+
* Anything else is an exception a tool threw, which is a bug of ours.
|
|
36
|
+
*/
|
|
37
|
+
export declare function classifyError(message: string): {
|
|
38
|
+
type: ErrorType;
|
|
39
|
+
status?: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Who is calling: `jiri` for the in-house assistant's remaining path through this server, which runs on the Python MCP
|
|
43
|
+
* SDK's defaults (client name mcp, python-httpx user agent) and nothing else does; `external` for everyone else. The
|
|
44
|
+
* retired built-in server reported the same two values.
|
|
45
|
+
*/
|
|
46
|
+
export declare function callerTypeOf(clientName: unknown, userAgent: unknown): 'jiri' | 'external';
|
|
27
47
|
export interface AnalyticsOptions {
|
|
28
48
|
/** PostHog project token (phc_…) */
|
|
29
49
|
apiKey: string;
|
package/dist/analytics.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { deriveSessionIdFromMCPSession, instrument } from '@posthog/mcp';
|
|
2
2
|
import { PostHog } from 'posthog-node';
|
|
3
3
|
import { sha256, userIdOf } from './auth.js';
|
|
4
|
+
import { FORBIDDEN_HINT } from './result.js';
|
|
4
5
|
import { TOOLS } from './tools.js';
|
|
5
6
|
import { CONTEXT_ARGUMENT } from './validation.js';
|
|
6
|
-
/**
|
|
7
|
+
/** The question the model answers in the context argument; it becomes $mcp_intent. */
|
|
7
8
|
export const CONTEXT_DESCRIPTION = "Why are you calling this tool? Briefly describe the user's goal.";
|
|
8
9
|
export const CONTEXT_INSTRUCTIONS = `Every tool takes a \`${CONTEXT_ARGUMENT}\` argument: say what the user is actually trying to get done, ` +
|
|
9
10
|
'in their own words, rather than restating what the tool does — it is what tells us which needs these tools ' +
|
|
@@ -24,6 +25,51 @@ const DECLARED_PARAMETER_NAMES = new Set([
|
|
|
24
25
|
'name',
|
|
25
26
|
...TOOLS.flatMap((tool) => Object.keys(tool.inputSchema.properties ?? {}))
|
|
26
27
|
]);
|
|
28
|
+
/**
|
|
29
|
+
* An argument problem caught before any request goes out: the MCP SDK's prefix on a validation.ts failure, get_schema's
|
|
30
|
+
* unknown name, a composite tool given nothing to send, a path parameter left empty; and validation.ts's own phrasings,
|
|
31
|
+
* should the SDK ever stop prefixing them.
|
|
32
|
+
*/
|
|
33
|
+
const VALIDATION_ERROR = /^(Input validation error|No schema named|Nothing to change|Missing path parameter|Unknown arguments)\b|Instance type|required property/;
|
|
34
|
+
/**
|
|
35
|
+
* Buckets a failed tool call by its text, whose shapes are all ours: result.ts opens an API failure with `HTTP <status>:`
|
|
36
|
+
* and closes it with a hint, api.ts opens a TransportError with the reason, and the MCP SDK prefixes a validation failure.
|
|
37
|
+
* Anything else is an exception a tool threw, which is a bug of ours.
|
|
38
|
+
*/
|
|
39
|
+
export function classifyError(message) {
|
|
40
|
+
const http = /^HTTP (\d{3}):/.exec(message);
|
|
41
|
+
if (http) {
|
|
42
|
+
const status = Number(http[1]);
|
|
43
|
+
if (status === 429)
|
|
44
|
+
return { type: 'rate_limited', status };
|
|
45
|
+
if (status === 403 && /\bscope\b/i.test(serverErrorLines(message)))
|
|
46
|
+
return { type: 'permission', status };
|
|
47
|
+
return { type: status >= 500 ? 'api_5xx' : 'api_4xx', status };
|
|
48
|
+
}
|
|
49
|
+
if (VALIDATION_ERROR.test(message))
|
|
50
|
+
return { type: 'validation' };
|
|
51
|
+
if (/^Request timed out\b/.test(message))
|
|
52
|
+
return { type: 'timeout' };
|
|
53
|
+
return { type: 'internal' };
|
|
54
|
+
}
|
|
55
|
+
/** What the API itself said: the lines between result.ts's `HTTP <status>:` line and its hint (the 403 hint mentions scope itself). */
|
|
56
|
+
function serverErrorLines(message) {
|
|
57
|
+
return message
|
|
58
|
+
.split('\n')
|
|
59
|
+
.slice(1)
|
|
60
|
+
.filter((line) => line !== FORBIDDEN_HINT && !line.startsWith('⚠'))
|
|
61
|
+
.join('\n');
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Who is calling: `jiri` for the in-house assistant's remaining path through this server, which runs on the Python MCP
|
|
65
|
+
* SDK's defaults (client name mcp, python-httpx user agent) and nothing else does; `external` for everyone else. The
|
|
66
|
+
* retired built-in server reported the same two values.
|
|
67
|
+
*/
|
|
68
|
+
export function callerTypeOf(clientName, userAgent) {
|
|
69
|
+
return clientName === 'mcp' && typeof userAgent === 'string' && userAgent.startsWith('python-httpx/')
|
|
70
|
+
? 'jiri'
|
|
71
|
+
: 'external';
|
|
72
|
+
}
|
|
27
73
|
/** Forwards the SDK's internal log to console only when something is wrong; drops the "Successfully set up…" every request prints. */
|
|
28
74
|
function warn(message) {
|
|
29
75
|
if (/^(Warning|Error|WARN)\b/.test(message))
|
|
@@ -64,7 +110,6 @@ export class McpAnalytics {
|
|
|
64
110
|
enableConversationId: false,
|
|
65
111
|
enableExceptionAutocapture: false,
|
|
66
112
|
identify: distinctId ? { distinctId } : null,
|
|
67
|
-
eventProperties: () => ({ mcp_caller_type: 'external' }),
|
|
68
113
|
shouldRecordInputKey: (key, { declared }) => declared || DECLARED_PARAMETER_NAMES.has(key),
|
|
69
114
|
beforeSend: this.beforeSend(sessionId),
|
|
70
115
|
logger: warn
|
|
@@ -96,6 +141,14 @@ export class McpAnalytics {
|
|
|
96
141
|
}
|
|
97
142
|
if (event.event === '$mcp_initialize' && this.repeatedHandshake(String(props.$session_id ?? '')))
|
|
98
143
|
return null;
|
|
144
|
+
if (event.event === '$mcp_tool_call' && props.$mcp_is_error === true) {
|
|
145
|
+
// The SDK types a thrown exception by its class; an isError result is always "Error", so the bucket comes from the text.
|
|
146
|
+
const { type, status } = classifyError(String(props.$mcp_error_message ?? ''));
|
|
147
|
+
props.$mcp_error_type = type;
|
|
148
|
+
if (status !== undefined)
|
|
149
|
+
props.$mcp_error_status = status;
|
|
150
|
+
}
|
|
151
|
+
props.mcp_caller_type = callerTypeOf(props.$mcp_client_name, props.$mcp_client_user_agent);
|
|
99
152
|
return event;
|
|
100
153
|
};
|
|
101
154
|
}
|
package/dist/api.js
CHANGED
|
@@ -21,11 +21,12 @@ export function buildUrl(baseUrl, op, args) {
|
|
|
21
21
|
const value = args[p.name];
|
|
22
22
|
if (value === undefined || value === null || value === '')
|
|
23
23
|
continue;
|
|
24
|
-
if (Array.isArray(value)) {
|
|
24
|
+
if (Array.isArray(value) && !p.json) {
|
|
25
25
|
for (const item of value)
|
|
26
26
|
url.searchParams.append(`${p.name}[]`, scalar(item));
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
|
+
// A `content: application/json` parameter goes as one value: the array as JSON text, a string (JSON text already) as is
|
|
29
30
|
url.searchParams.set(p.name, scalar(value));
|
|
30
31
|
}
|
|
31
32
|
}
|
package/dist/generated/meta.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"generatedFrom": {
|
|
3
3
|
"title": "Jinshuju API v1",
|
|
4
4
|
"version": "1.0",
|
|
5
|
-
"sha256": "
|
|
5
|
+
"sha256": "288548a94e3932e7"
|
|
6
6
|
},
|
|
7
7
|
"baseUrl": "https://jinshuju.net/api/v1",
|
|
8
8
|
"toolCount": 60,
|
|
9
|
-
"operationCount":
|
|
9
|
+
"operationCount": 128,
|
|
10
10
|
"tools": {
|
|
11
11
|
"list_forms": "listForms",
|
|
12
12
|
"get_form": "getForm",
|
|
@@ -95,6 +95,7 @@
|
|
|
95
95
|
"tags": {
|
|
96
96
|
"Forms": "Forms: list, structure, create and edit, plus field display rules, cooperators, copy, move and other related operations.",
|
|
97
97
|
"Form Settings": "Form settings: submission settings, access policy, Webhook, theme, closing rules, exam / evaluation scene settings.",
|
|
98
|
+
"Plugins": "Plugin center plugins (check-in for now). A plugin campaign is bound to one form, and only its creator can see and change it. The account must have enabled the plugin in the plugin center, or the request returns 402.",
|
|
98
99
|
"Entries": "Form entries: list, query, create, update, delete and batch operations.",
|
|
99
100
|
"Tables": "Tables (kind=table): structure and entries; field types are limited to the column types tables support.",
|
|
100
101
|
"Views": "Form / table views (view filters, sort, column configuration) and reading entries through a view.",
|