@manudota/artist-mcp 1.5.2 → 1.5.3-staging.76
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/dist/audit.d.ts +11 -0
- package/dist/calendar.d.ts +3 -2
- package/dist/calendar.js +7 -7
- package/dist/dispatch.d.ts +2 -1
- package/dist/dispatch.js +4 -3
- package/dist/grants.d.ts +12 -8
- package/dist/grants.js +13 -19
- package/dist/index.js +4 -5
- package/dist/init.js +2 -3
- package/dist/server.d.ts +4 -3
- package/dist/server.js +11 -13
- package/package.json +3 -1
package/dist/audit.d.ts
CHANGED
|
@@ -12,6 +12,17 @@
|
|
|
12
12
|
* since it defends against forgetting rather than against the user.
|
|
13
13
|
*/
|
|
14
14
|
export declare const auditPath: () => string;
|
|
15
|
+
/**
|
|
16
|
+
* Where a completed write is recorded.
|
|
17
|
+
*
|
|
18
|
+
* Injected for the same reason the token resolver is: on this machine it is a
|
|
19
|
+
* file in the user's home directory, and hosted it is a row bound to one user.
|
|
20
|
+
* A file on a serverless host is one nobody will ever read, and "detectable and
|
|
21
|
+
* reversible" is the whole justification for these writes existing — so the
|
|
22
|
+
* sink has to be the caller's to choose. See
|
|
23
|
+
* docs/decisions/0002-hosted-writes.md.
|
|
24
|
+
*/
|
|
25
|
+
export type RecordWrite = (entry: WriteRecord) => Promise<void>;
|
|
15
26
|
export type WriteRecord = {
|
|
16
27
|
operation: string;
|
|
17
28
|
/** What was written, as the user would read it back. */
|
package/dist/calendar.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* and recurring series — are both cases where the obvious code returns
|
|
7
7
|
* something plausible and wrong, so they moved across unchanged.
|
|
8
8
|
*/
|
|
9
|
+
import { type RecordWrite } from './audit.js';
|
|
9
10
|
type CalendarTime = {
|
|
10
11
|
dateTime?: string;
|
|
11
12
|
date?: string;
|
|
@@ -227,7 +228,7 @@ export declare function previewEvent(token: string, params: Record<string, unkno
|
|
|
227
228
|
* inexpressible too. It does not prove a person read the preview, and no part
|
|
228
229
|
* of this protocol can.
|
|
229
230
|
*/
|
|
230
|
-
export declare function createEvent(token: string, params: Record<string, unknown
|
|
231
|
+
export declare function createEvent(token: string, params: Record<string, unknown>, record?: RecordWrite): Promise<{
|
|
231
232
|
created: {
|
|
232
233
|
id: string;
|
|
233
234
|
summary: string;
|
|
@@ -259,7 +260,7 @@ export declare function previewDeleteEvent(token: string, params: Record<string,
|
|
|
259
260
|
* notices absence — so what is written down has to be enough to put it back by
|
|
260
261
|
* hand once Google's 30-day bin has expired.
|
|
261
262
|
*/
|
|
262
|
-
export declare function deleteEvent(token: string, params: Record<string, unknown
|
|
263
|
+
export declare function deleteEvent(token: string, params: Record<string, unknown>, record?: RecordWrite): Promise<{
|
|
263
264
|
deleted: string;
|
|
264
265
|
calendar_id: string;
|
|
265
266
|
event_id: string;
|
package/dist/calendar.js
CHANGED
|
@@ -470,7 +470,7 @@ const describeDuplicate = async (token, calendarId, eventId) => {
|
|
|
470
470
|
* inexpressible too. It does not prove a person read the preview, and no part
|
|
471
471
|
* of this protocol can.
|
|
472
472
|
*/
|
|
473
|
-
export async function createEvent(token, params) {
|
|
473
|
+
export async function createEvent(token, params, record = recordWrite) {
|
|
474
474
|
const draft = draftFrom(params);
|
|
475
475
|
refuseUnsettled(draft);
|
|
476
476
|
const supplied = typeof params.confirmation_token === 'string' ? params.confirmation_token : '';
|
|
@@ -514,7 +514,7 @@ export async function createEvent(token, params) {
|
|
|
514
514
|
// the write another way leaves no trace at all — which is exactly what
|
|
515
515
|
// happened the first time this was run against a real calendar. The audit has
|
|
516
516
|
// to sit where the event is created or it is not an audit.
|
|
517
|
-
await
|
|
517
|
+
await record({
|
|
518
518
|
operation: 'create_calendar_event',
|
|
519
519
|
summary: renderDraft(draft),
|
|
520
520
|
target: `${draft.calendar_id}/${created.id ?? 'unknown'}`,
|
|
@@ -631,7 +631,7 @@ export async function previewDeleteEvent(token, params) {
|
|
|
631
631
|
* notices absence — so what is written down has to be enough to put it back by
|
|
632
632
|
* hand once Google's 30-day bin has expired.
|
|
633
633
|
*/
|
|
634
|
-
export async function deleteEvent(token, params) {
|
|
634
|
+
export async function deleteEvent(token, params, record = recordWrite) {
|
|
635
635
|
const calendarId = typeof params.calendar_id === 'string' && params.calendar_id.trim()
|
|
636
636
|
? params.calendar_id.trim()
|
|
637
637
|
: 'primary';
|
|
@@ -646,13 +646,13 @@ export async function deleteEvent(token, params) {
|
|
|
646
646
|
: 'The confirmation_token does not match this event. It has changed since ' +
|
|
647
647
|
'the preview, so preview again and show the musician what is there now.');
|
|
648
648
|
}
|
|
649
|
-
const
|
|
649
|
+
const written = renderExisting(event, calendarId);
|
|
650
650
|
await calendarDeleteEvent(calendarId, eventId, token);
|
|
651
|
-
await
|
|
651
|
+
await record({
|
|
652
652
|
operation: 'delete_calendar_event',
|
|
653
|
-
summary:
|
|
653
|
+
summary: written,
|
|
654
654
|
target: `${calendarId}/${eventId}`,
|
|
655
655
|
source_page: typeof params.source_page === 'string' ? params.source_page : null,
|
|
656
656
|
});
|
|
657
|
-
return { deleted:
|
|
657
|
+
return { deleted: written, calendar_id: calendarId, event_id: eventId };
|
|
658
658
|
}
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* Google connection has to be reported as such rather than surfacing as an
|
|
11
11
|
* unrelated Microsoft error.
|
|
12
12
|
*/
|
|
13
|
+
import { type RecordWrite } from './audit.js';
|
|
13
14
|
import { type ProviderName } from './tokens.js';
|
|
14
15
|
/**
|
|
15
16
|
* Every operation this server can carry out, with its provider and its effect.
|
|
@@ -109,6 +110,6 @@ export declare const connectedProviders: () => Promise<ProviderName[]>;
|
|
|
109
110
|
* stated once regardless of where the token was found.
|
|
110
111
|
*/
|
|
111
112
|
export type ResolveToken = (provider: ProviderName) => Promise<string>;
|
|
112
|
-
export declare const dispatchWith: (resolve: ResolveToken) => <T>(op: Operation, params?: Record<string, unknown>) => Promise<T>;
|
|
113
|
+
export declare const dispatchWith: (resolve: ResolveToken, record?: RecordWrite) => <T>(op: Operation, params?: Record<string, unknown>) => Promise<T>;
|
|
113
114
|
/** The local dispatcher: this machine's own connections, one process, one user. */
|
|
114
115
|
export declare const call: <T>(op: Operation, params?: Record<string, unknown>) => Promise<T>;
|
package/dist/dispatch.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* unrelated Microsoft error.
|
|
12
12
|
*/
|
|
13
13
|
import { GraphError } from './client.js';
|
|
14
|
+
import { recordWrite } from './audit.js';
|
|
14
15
|
import { mapAttachment, readAttachment } from './attachments.js';
|
|
15
16
|
import { createEvent, deleteEvent, listCalendars, listEvents, previewDeleteEvent, previewEvent, readEvent, } from './calendar.js';
|
|
16
17
|
import { listEmails, readEmail } from './mail.js';
|
|
@@ -72,7 +73,7 @@ export const connectedProviders = async () => {
|
|
|
72
73
|
const { providers } = await loadTokens();
|
|
73
74
|
return Object.keys(providers).filter((name) => providers[name] !== undefined);
|
|
74
75
|
};
|
|
75
|
-
export const dispatchWith = (resolve) => async (op, params = {}) => {
|
|
76
|
+
export const dispatchWith = (resolve, record = recordWrite) => async (op, params = {}) => {
|
|
76
77
|
const token = await resolve(PROVIDER_FOR[op]);
|
|
77
78
|
switch (op) {
|
|
78
79
|
case 'list_notes':
|
|
@@ -98,11 +99,11 @@ export const dispatchWith = (resolve) => async (op, params = {}) => {
|
|
|
98
99
|
case 'preview_calendar_event':
|
|
99
100
|
return (await previewEvent(token, params));
|
|
100
101
|
case 'create_calendar_event':
|
|
101
|
-
return (await createEvent(token, params));
|
|
102
|
+
return (await createEvent(token, params, record));
|
|
102
103
|
case 'preview_calendar_delete':
|
|
103
104
|
return (await previewDeleteEvent(token, params));
|
|
104
105
|
case 'delete_calendar_event':
|
|
105
|
-
return (await deleteEvent(token, params));
|
|
106
|
+
return (await deleteEvent(token, params, record));
|
|
106
107
|
case 'list_calendars':
|
|
107
108
|
// No parameters by design: the whole value is knowing the full set, and
|
|
108
109
|
// a filtered list of what exists is the reach problem again.
|
package/dist/grants.d.ts
CHANGED
|
@@ -43,21 +43,25 @@ export declare const isWriteCapability: (value: unknown) => value is WriteCapabi
|
|
|
43
43
|
* the tool they wanted was missing.
|
|
44
44
|
*/
|
|
45
45
|
export declare const parseGrants: (raw: string | undefined) => WriteCapability[];
|
|
46
|
-
export declare const setGrants: (capabilities: readonly WriteCapability[]) => void;
|
|
47
|
-
export declare const grantedWrites: () => readonly WriteCapability[];
|
|
48
46
|
/**
|
|
49
|
-
* Whether a write tool may be registered
|
|
47
|
+
* Whether a write tool may be registered, given what this caller was granted.
|
|
50
48
|
*
|
|
51
|
-
*
|
|
49
|
+
* A parameter, not module state. One stdio process serves one user and could
|
|
50
|
+
* safely hold it in a variable; the hosted route serves many users from one
|
|
51
|
+
* process, where a grant set per request would let one user's capability reach
|
|
52
|
+
* another's session. That failure would pass every test here, because every
|
|
53
|
+
* test runs one user at a time — so the shape has to prevent it rather than the
|
|
54
|
+
* discipline. See docs/decisions/0001-opt-in-calendar-writes.md.
|
|
55
|
+
*
|
|
56
|
+
* Registration, not refusal at call time: a tool that exists is a tool a model
|
|
52
57
|
* will try, and a refusal inside a tool result reads as an obstacle to route
|
|
53
|
-
* around rather than as a boundary
|
|
54
|
-
* present and saying no.
|
|
58
|
+
* around rather than as a boundary.
|
|
55
59
|
*/
|
|
56
|
-
export declare const isGranted: (capability: WriteCapability) => boolean;
|
|
60
|
+
export declare const isGranted: (grants: readonly WriteCapability[], capability: WriteCapability) => boolean;
|
|
57
61
|
/**
|
|
58
62
|
* How the grant is described wherever it is reported: `init`, `agents status`,
|
|
59
63
|
* and the workflow briefing. A capability nobody can see is one nobody accounts
|
|
60
64
|
* for, which is the handshake bug again — a correct thing that never reached
|
|
61
65
|
* the client.
|
|
62
66
|
*/
|
|
63
|
-
export declare const describeGrants: () => string;
|
|
67
|
+
export declare const describeGrants: (grants: readonly WriteCapability[]) => string;
|
package/dist/grants.js
CHANGED
|
@@ -68,36 +68,30 @@ export const parseGrants = (raw) => {
|
|
|
68
68
|
return [...new Set(named)];
|
|
69
69
|
};
|
|
70
70
|
/**
|
|
71
|
-
*
|
|
71
|
+
* Whether a write tool may be registered, given what this caller was granted.
|
|
72
72
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
granted = [...capabilities];
|
|
80
|
-
};
|
|
81
|
-
export const grantedWrites = () => granted;
|
|
82
|
-
/**
|
|
83
|
-
* Whether a write tool may be registered at all.
|
|
73
|
+
* A parameter, not module state. One stdio process serves one user and could
|
|
74
|
+
* safely hold it in a variable; the hosted route serves many users from one
|
|
75
|
+
* process, where a grant set per request would let one user's capability reach
|
|
76
|
+
* another's session. That failure would pass every test here, because every
|
|
77
|
+
* test runs one user at a time — so the shape has to prevent it rather than the
|
|
78
|
+
* discipline. See docs/decisions/0001-opt-in-calendar-writes.md.
|
|
84
79
|
*
|
|
85
|
-
* Registration, not refusal at call time
|
|
80
|
+
* Registration, not refusal at call time: a tool that exists is a tool a model
|
|
86
81
|
* will try, and a refusal inside a tool result reads as an obstacle to route
|
|
87
|
-
* around rather than as a boundary
|
|
88
|
-
* present and saying no.
|
|
82
|
+
* around rather than as a boundary.
|
|
89
83
|
*/
|
|
90
|
-
export const isGranted = (capability) =>
|
|
84
|
+
export const isGranted = (grants, capability) => grants.includes(capability);
|
|
91
85
|
/**
|
|
92
86
|
* How the grant is described wherever it is reported: `init`, `agents status`,
|
|
93
87
|
* and the workflow briefing. A capability nobody can see is one nobody accounts
|
|
94
88
|
* for, which is the handshake bug again — a correct thing that never reached
|
|
95
89
|
* the client.
|
|
96
90
|
*/
|
|
97
|
-
export const describeGrants = () => {
|
|
98
|
-
if (
|
|
91
|
+
export const describeGrants = (grants) => {
|
|
92
|
+
if (grants.length === 0) {
|
|
99
93
|
return 'Writes: none. This install can only read.';
|
|
100
94
|
}
|
|
101
|
-
const lines =
|
|
95
|
+
const lines = grants.map((name) => ` - ${name}: ${WRITE_CAPABILITIES[name]}`);
|
|
102
96
|
return `Writes granted to this install:\n${lines.join('\n')}`;
|
|
103
97
|
};
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { runInit, runUninstall } from './init.js';
|
|
|
3
3
|
import { runServer } from './server.js';
|
|
4
4
|
import { installAgentPack, runAgentsStatus, setLocalAgentRoot } from './agents.js';
|
|
5
5
|
import { runConnect, runDisconnect, runStatus } from './connect.js';
|
|
6
|
-
import { isWriteCapability, parseGrants
|
|
6
|
+
import { isWriteCapability, parseGrants } from './grants.js';
|
|
7
7
|
const argv = process.argv.slice(2);
|
|
8
8
|
/**
|
|
9
9
|
* Pull an option and its value out of the arguments wherever they appear.
|
|
@@ -67,10 +67,9 @@ try {
|
|
|
67
67
|
// only way the server learns where a user's playbooks live: there is no
|
|
68
68
|
// cwd here worth trusting.
|
|
69
69
|
setLocalAgentRoot(agentsDir || undefined);
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
await runServer();
|
|
70
|
+
// Handed in, not stashed. An ungranted write tool is never built, rather
|
|
71
|
+
// than built and refusing.
|
|
72
|
+
await runServer(grants);
|
|
74
73
|
break;
|
|
75
74
|
case 'init':
|
|
76
75
|
if (argv[1] && argv[1] !== '--local') {
|
package/dist/init.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isStagingVersion, packageVersion } from "./client.js";
|
|
|
5
5
|
import { sep } from "node:path";
|
|
6
6
|
import { configPath, ENTRY_NAME, readConfig, writeConfig } from "./config.js";
|
|
7
7
|
import { connectedProviders } from "./dispatch.js";
|
|
8
|
-
import { describeGrants
|
|
8
|
+
import { describeGrants } from "./grants.js";
|
|
9
9
|
const PACKAGE = "@manudota/artist-mcp";
|
|
10
10
|
const LOCAL_ENTRY = fileURLToPath(new URL("./index.js", import.meta.url));
|
|
11
11
|
/**
|
|
@@ -84,8 +84,7 @@ export const runInit = async ({ local = false, editableDir, grants = [], } = {})
|
|
|
84
84
|
// accounts for, and the useful line is the one that appears when the answer
|
|
85
85
|
// is "none" — that is what tells a user their install is still read-only.
|
|
86
86
|
console.log("");
|
|
87
|
-
|
|
88
|
-
console.log(describeGrants());
|
|
87
|
+
console.log(describeGrants(grants));
|
|
89
88
|
if (grants.length > 0) {
|
|
90
89
|
console.log("Reconnect Google so the grant is on the token: `artist-mcp connect google`. " +
|
|
91
90
|
"A refresh token carries the scopes it was granted with, so an existing " +
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { type WriteCapability } from "./grants.js";
|
|
2
3
|
import { type ResolvedEntry } from "./agents.js";
|
|
3
4
|
import { type Operation } from "./dispatch.js";
|
|
4
5
|
/**
|
|
@@ -18,11 +19,11 @@ type Dispatch = <T>(op: Operation, params?: Record<string, unknown>) => Promise<
|
|
|
18
19
|
*/
|
|
19
20
|
declare const renderWorkflowBriefing: (entries: ResolvedEntry[], load: (id: string) => Promise<{
|
|
20
21
|
content: string;
|
|
21
|
-
}
|
|
22
|
-
declare const createServer: (call: Dispatch) => Promise<McpServer>;
|
|
22
|
+
}>, writes?: readonly WriteCapability[]) => Promise<string>;
|
|
23
|
+
declare const createServer: (call: Dispatch, grants?: readonly WriteCapability[]) => Promise<McpServer>;
|
|
23
24
|
/**
|
|
24
25
|
* The stdio entry point, unchanged in behaviour: one process, one user, tokens
|
|
25
26
|
* from this machine. It is now the only place that knows about stdio.
|
|
26
27
|
*/
|
|
27
|
-
declare const runServer: () => Promise<void>;
|
|
28
|
+
declare const runServer: (grants?: readonly WriteCapability[]) => Promise<void>;
|
|
28
29
|
export { createServer, renderWorkflowBriefing, runServer, type Dispatch };
|
package/dist/server.js
CHANGED
|
@@ -2,7 +2,7 @@ import { join } from "node:path";
|
|
|
2
2
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
|
-
import { WRITE_CAPABILITIES,
|
|
5
|
+
import { WRITE_CAPABILITIES, isGranted } from "./grants.js";
|
|
6
6
|
import { listAgentWorkflows, loadAgentWorkflow } from "./agents.js";
|
|
7
7
|
import { GraphError } from "./client.js";
|
|
8
8
|
import { call as localCall } from "./dispatch.js";
|
|
@@ -103,7 +103,7 @@ const selectNotebook = async (call, notebook, tool) => {
|
|
|
103
103
|
: null;
|
|
104
104
|
return { pages, scope };
|
|
105
105
|
};
|
|
106
|
-
const serverVersion = '1.5.
|
|
106
|
+
const serverVersion = '1.5.3-staging.76'; // x-release-please-version
|
|
107
107
|
const errorResult = (err) => {
|
|
108
108
|
const message = err instanceof GraphError ? err.message : `Unexpected error: ${err}`;
|
|
109
109
|
return { content: [{ type: "text", text: message }], isError: true };
|
|
@@ -115,7 +115,7 @@ const errorResult = (err) => {
|
|
|
115
115
|
* tampering with the installed pack, which is how it was found in the first
|
|
116
116
|
* place.
|
|
117
117
|
*/
|
|
118
|
-
const renderWorkflowBriefing = async (entries, load) => {
|
|
118
|
+
const renderWorkflowBriefing = async (entries, load, writes = []) => {
|
|
119
119
|
// A one-line summary is enough to pick a role to load, but not to
|
|
120
120
|
// classify a page: the rules that separate one project type from
|
|
121
121
|
// another live in the body of the file. Intake is here for the same
|
|
@@ -214,7 +214,6 @@ const renderWorkflowBriefing = async (entries, load) => {
|
|
|
214
214
|
// seven roles and six policies, so a session must be told plainly when it is
|
|
215
215
|
// no longer true. The "none" line matters most: it is what keeps every
|
|
216
216
|
// read-only install saying the same thing it always said.
|
|
217
|
-
const writes = grantedWrites();
|
|
218
217
|
const capabilities = writes.length === 0
|
|
219
218
|
? [
|
|
220
219
|
"# What this install may change",
|
|
@@ -251,8 +250,7 @@ const renderWorkflowBriefing = async (entries, load) => {
|
|
|
251
250
|
* Derived, never restated. An install with no grant says so too — that line is
|
|
252
251
|
* the one that keeps a read-only install describing itself correctly.
|
|
253
252
|
*/
|
|
254
|
-
const capabilityLine = () => {
|
|
255
|
-
const writes = grantedWrites();
|
|
253
|
+
const capabilityLine = (writes) => {
|
|
256
254
|
if (writes.length === 0) {
|
|
257
255
|
return (" This install can only read. It cannot create, change or delete " +
|
|
258
256
|
"anything in OneNote, Gmail or Google Calendar, and must never offer to.");
|
|
@@ -263,7 +261,7 @@ const capabilityLine = () => {
|
|
|
263
261
|
"this server as read-only while any write is granted, and never write a " +
|
|
264
262
|
"value the notebook has not settled.");
|
|
265
263
|
};
|
|
266
|
-
const createServer = async (call) => {
|
|
264
|
+
const createServer = async (call, grants = []) => {
|
|
267
265
|
// Nothing is checked here on purpose. The server starts whether or not a
|
|
268
266
|
// provider is connected, and a tool that needs one says so when it is called:
|
|
269
267
|
// refusing to start would leave Claude Desktop reporting a broken server
|
|
@@ -302,7 +300,7 @@ const createServer = async (call) => {
|
|
|
302
300
|
// This is not the third copy of the rules that drifted in AGENTS.md: it is
|
|
303
301
|
// derived from the grant at startup, so it cannot say something the install
|
|
304
302
|
// is not. The rules themselves are still only in the pack.
|
|
305
|
-
capabilityLine();
|
|
303
|
+
capabilityLine(grants);
|
|
306
304
|
const server = new McpServer({ name: "artist-notes", version: serverVersion }, { instructions });
|
|
307
305
|
server.tool("list_agent_workflows", "List the read-only artist roles, project types, and policies available " +
|
|
308
306
|
"at runtime. Whatever comes back in full is in force as returned and is " +
|
|
@@ -312,7 +310,7 @@ const createServer = async (call) => {
|
|
|
312
310
|
"Anything listed as a one-line summary is not in force until loaded. " +
|
|
313
311
|
"Load the Orchestrator before handling a project.", {}, async () => {
|
|
314
312
|
try {
|
|
315
|
-
const text = await renderWorkflowBriefing(await listAgentWorkflows(), loadAgentWorkflow);
|
|
313
|
+
const text = await renderWorkflowBriefing(await listAgentWorkflows(), loadAgentWorkflow, grants);
|
|
316
314
|
return { content: [{ type: "text", text }] };
|
|
317
315
|
}
|
|
318
316
|
catch (err) {
|
|
@@ -793,7 +791,7 @@ const createServer = async (call) => {
|
|
|
793
791
|
// present and refusing: a tool that exists is a tool a model will try, and a
|
|
794
792
|
// refusal in a tool result reads as an obstacle to route around rather than
|
|
795
793
|
// as a boundary. See docs/decisions/0001-opt-in-calendar-writes.md.
|
|
796
|
-
if (isGranted("calendar-create")) {
|
|
794
|
+
if (isGranted(grants, "calendar-create")) {
|
|
797
795
|
server.tool("preview_calendar_event", "Call this before create_calendar_event — it is the only way to obtain the confirmation_token that one requires, and it is what puts the exact event in front of the musician. SHOW THE MUSICIAN WHAT IT RETURNS AND WAIT FOR THEIR YES. " +
|
|
798
796
|
"Renders a Google Calendar event exactly as it would be written, and " +
|
|
799
797
|
"lists what is already on that day in that calendar, so an event that " +
|
|
@@ -899,7 +897,7 @@ const createServer = async (call) => {
|
|
|
899
897
|
}
|
|
900
898
|
});
|
|
901
899
|
}
|
|
902
|
-
if (isGranted("calendar-delete")) {
|
|
900
|
+
if (isGranted(grants, "calendar-delete")) {
|
|
903
901
|
server.tool("preview_calendar_delete", "Call this before delete_calendar_event — it is the only way to obtain the confirmation_token that one requires. SHOW THE MUSICIAN WHAT IT RETURNS AND WAIT FOR THEIR YES. " +
|
|
904
902
|
"Shows the event that would be removed, read fresh from Google rather " +
|
|
905
903
|
"than from anything you were told about it. Changes nothing. Only an " +
|
|
@@ -1104,8 +1102,8 @@ const createServer = async (call) => {
|
|
|
1104
1102
|
* The stdio entry point, unchanged in behaviour: one process, one user, tokens
|
|
1105
1103
|
* from this machine. It is now the only place that knows about stdio.
|
|
1106
1104
|
*/
|
|
1107
|
-
const runServer = async () => {
|
|
1108
|
-
const server = await createServer(localCall);
|
|
1105
|
+
const runServer = async (grants = []) => {
|
|
1106
|
+
const server = await createServer(localCall, grants);
|
|
1109
1107
|
await server.connect(new StdioServerTransport());
|
|
1110
1108
|
};
|
|
1111
1109
|
export { createServer, renderWorkflowBriefing, runServer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manudota/artist-mcp",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3-staging.76",
|
|
4
4
|
"description": "MCP server that reads your OneNote notes, with optional Gmail and Calendar as supporting evidence, via a hosted connection.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
".": "./dist/index.js",
|
|
15
15
|
"./server": "./dist/server.js",
|
|
16
16
|
"./dispatch": "./dist/dispatch.js",
|
|
17
|
+
"./grants": "./dist/grants.js",
|
|
18
|
+
"./audit": "./dist/audit.js",
|
|
17
19
|
"./oauth": "./dist/oauth.js",
|
|
18
20
|
"./client": "./dist/client.js"
|
|
19
21
|
},
|