@motorical/scope-catalog 0.6.0 → 0.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/package.json +1 -1
- package/src/comms.js +37 -0
- package/src/implication.js +7 -0
- package/src/index.js +1 -0
- package/src/scopes.js +45 -0
- package/src/tools.js +14 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motorical/scope-catalog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Canonical MCP/OAuth scope metadata for Motorical — descriptions, Public API scope mapping, implied-read rules, and declarative tool/resource membership. One source of truth consumed by motorical-backend and @motorical/mcp.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"engines": {
|
package/src/comms.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Communications (marketing) MCP constants. Spec: motorical-docs specs/2026-10-27-comms-mcp-m2-auth-delegation-scopes-design.md.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the backend (grant resolver, OAuth consent), the Communications Block (delegation verification, route to scope table)
|
|
5
|
+
* and @motorical/mcp (the `communications` server), so the audience and the scope names cannot drift between them.
|
|
6
|
+
*/
|
|
7
|
+
const { MCP_HOST } = require('./tools');
|
|
8
|
+
|
|
9
|
+
/** Fixed order; also the order the scopes appear in SCOPES (after the nine core scopes, so existing order is untouched). */
|
|
10
|
+
const COMMS_SCOPES = [
|
|
11
|
+
'read:comms',
|
|
12
|
+
'write:comms.audience',
|
|
13
|
+
'write:comms.content',
|
|
14
|
+
'send:comms.campaign',
|
|
15
|
+
'manage:comms.workspace',
|
|
16
|
+
'manage:comms.webhooks',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/** What the FIRST consent asks for. Sending and managing are a step-up, so sending always has its own consent moment. */
|
|
20
|
+
const COMMS_INITIAL_SCOPES = ['read:comms', 'write:comms.audience', 'write:comms.content'];
|
|
21
|
+
|
|
22
|
+
/** The hosted server's canonical URI = its RFC 8707 audience = the `resource` stored on its grants. */
|
|
23
|
+
const COMMS_CANONICAL_URI = `${MCP_HOST}/v1/motorical_communications/mcp`;
|
|
24
|
+
|
|
25
|
+
/** Audience of the delegation assertion minted for this server. Distinct from the backend's `.../internal/mcp`, so neither can be replayed at the other. */
|
|
26
|
+
const COMMS_DELEGATION_AUDIENCE = 'https://api.motorical.com/internal/mcp/comms';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* How a NEW oauth_resource_servers row is created for a resource that needs more than the transactional defaults. The sync inserts
|
|
30
|
+
* these and never changes `enabled` or `block_types` of an existing row. The communications server is marketing-only and starts
|
|
31
|
+
* DISABLED: nobody can consent to it until it is switched on deliberately (Comms MCP M2d).
|
|
32
|
+
*/
|
|
33
|
+
const RESOURCE_SERVER_DEFAULTS = {
|
|
34
|
+
[COMMS_CANONICAL_URI]: { blockTypes: ['marketing'], enabled: false },
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = { COMMS_SCOPES, COMMS_INITIAL_SCOPES, COMMS_CANONICAL_URI, COMMS_DELEGATION_AUDIENCE, RESOURCE_SERVER_DEFAULTS };
|
package/src/implication.js
CHANGED
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
const MCP_IMPLIED_READ = {
|
|
8
8
|
'manage:webhooks': 'read:webhooks',
|
|
9
9
|
'manage:domains': 'read:domains',
|
|
10
|
+
// Every Communications write, send and manage scope can read what it works on. Never the other way, and never sideways:
|
|
11
|
+
// writing content does not imply sending.
|
|
12
|
+
'write:comms.audience': 'read:comms',
|
|
13
|
+
'write:comms.content': 'read:comms',
|
|
14
|
+
'send:comms.campaign': 'read:comms',
|
|
15
|
+
'manage:comms.workspace': 'read:comms',
|
|
16
|
+
'manage:comms.webhooks': 'read:comms',
|
|
10
17
|
};
|
|
11
18
|
|
|
12
19
|
function expandMcpImplied(grantedScopes) {
|
package/src/index.js
CHANGED
package/src/scopes.js
CHANGED
|
@@ -81,6 +81,51 @@ const SCOPES = {
|
|
|
81
81
|
agentDescription: 'List and read sending domains, their DNS records and email-authentication health, and read a Motor Block\'s configuration, without adding or verifying any domain.',
|
|
82
82
|
customerAction: 'View your sending domains and Motor Block configuration',
|
|
83
83
|
},
|
|
84
|
+
// Communications (marketing). One area per scope so the consent screen shows sending on its own line. No Public API scopes:
|
|
85
|
+
// the Comms API is not a Public API route, the Communications Block checks these itself. There is deliberately no scope for
|
|
86
|
+
// permanent delete, recycle-bin cleanup or GDPR export/erase: those stay human-only.
|
|
87
|
+
'read:comms': {
|
|
88
|
+
resource: 'comms',
|
|
89
|
+
level: 'read',
|
|
90
|
+
publicScopes: [],
|
|
91
|
+
agentDescription: 'Read Communications data for the workspaces the person chose: lists and contacts, templates, campaigns, reports and events, the workspace map and readiness, and run read-only checks (template preview, lint, link check, starter render). Never changes anything.',
|
|
92
|
+
customerAction: 'View your lists, templates, campaigns and results',
|
|
93
|
+
},
|
|
94
|
+
'write:comms.audience': {
|
|
95
|
+
resource: 'comms-audience',
|
|
96
|
+
level: 'manage',
|
|
97
|
+
publicScopes: [],
|
|
98
|
+
agentDescription: 'Create and change lists and contacts, add contacts (with a dry run), derive lists from lists, import, and add or remove suppressions. Includes everything read:comms grants. Cannot delete anything permanently.',
|
|
99
|
+
customerAction: 'Add and change your lists and contacts',
|
|
100
|
+
},
|
|
101
|
+
'write:comms.content': {
|
|
102
|
+
resource: 'comms-content',
|
|
103
|
+
level: 'manage',
|
|
104
|
+
publicScopes: [],
|
|
105
|
+
agentDescription: 'Create and change templates, the brand kit and campaign drafts, duplicate and compile campaigns, and send a test email to the account owner only. Includes everything read:comms grants. Does not send to your contacts.',
|
|
106
|
+
customerAction: 'Create and edit email templates and campaign drafts, and send test emails to you',
|
|
107
|
+
},
|
|
108
|
+
'send:comms.campaign': {
|
|
109
|
+
resource: 'comms-sending',
|
|
110
|
+
level: 'manage',
|
|
111
|
+
publicScopes: [],
|
|
112
|
+
agentDescription: 'Schedule a campaign (which sends it to the audience) and cancel a scheduled or sending one. Cancelling is final. Includes everything read:comms grants.',
|
|
113
|
+
customerAction: 'Send campaigns to your contacts (this is what actually emails people)',
|
|
114
|
+
},
|
|
115
|
+
'manage:comms.workspace': {
|
|
116
|
+
resource: 'comms-workspace',
|
|
117
|
+
level: 'manage',
|
|
118
|
+
publicScopes: [],
|
|
119
|
+
agentDescription: 'Change workspace settings (consent, open tracking, unsubscribe page) and which marketing Motor Blocks a workspace uses. Includes everything read:comms grants.',
|
|
120
|
+
customerAction: 'Change workspace settings and which sending addresses a workspace uses',
|
|
121
|
+
},
|
|
122
|
+
'manage:comms.webhooks': {
|
|
123
|
+
resource: 'comms-webhooks',
|
|
124
|
+
level: 'manage',
|
|
125
|
+
publicScopes: [],
|
|
126
|
+
agentDescription: 'Create, update, delete and test campaign event webhooks of the workspaces the person chose. Includes everything read:comms grants.',
|
|
127
|
+
customerAction: 'Manage your campaign event webhooks',
|
|
128
|
+
},
|
|
84
129
|
};
|
|
85
130
|
|
|
86
131
|
function listGrantableScopes() {
|
package/src/tools.js
CHANGED
|
@@ -34,13 +34,14 @@ const ANALYTICS_TOOLS = [
|
|
|
34
34
|
'motorical_get_error_codes',
|
|
35
35
|
'motorical_get_rate_limits',
|
|
36
36
|
'motorical_get_account_rate_limits',
|
|
37
|
-
'motorical_get_onboarding_state',
|
|
38
37
|
'motorical_whoami',
|
|
39
38
|
'motorical_get_logs',
|
|
40
39
|
'motorical_get_message_by_smtp_id',
|
|
41
40
|
];
|
|
42
41
|
|
|
43
42
|
const DOMAIN_TOOLS = [
|
|
43
|
+
// Domain verification, DNS readiness and Motor Block state: a domains read (GET /account/state needs config.read, which read:domains carries).
|
|
44
|
+
'motorical_get_onboarding_state',
|
|
44
45
|
'motorical_domain_list',
|
|
45
46
|
'motorical_domain_get',
|
|
46
47
|
'motorical_domain_dns_records',
|
|
@@ -85,6 +86,13 @@ const MOTOR_BLOCK_TOOLS = [
|
|
|
85
86
|
'motorical_motor_block_delete_status',
|
|
86
87
|
];
|
|
87
88
|
|
|
89
|
+
/**
|
|
90
|
+
* The hosted `communications` server (Comms MCP M2c). Two read-only proof tools that exercise the whole path (consent, delegation with
|
|
91
|
+
* the comms audience, grant resolution, scope table, workspace binding). Not in ALL_TOOLS and not on the main server: marketing has its
|
|
92
|
+
* own server and its own consent. More tools arrive in M3, each adding the scope it needs to this server's offer.
|
|
93
|
+
*/
|
|
94
|
+
const COMMS_TOOLS = ['comms_get_readiness', 'comms_get_map'];
|
|
95
|
+
|
|
88
96
|
const ALL_TOOLS = [
|
|
89
97
|
...new Set([
|
|
90
98
|
...TRANSACTIONAL_TOOLS,
|
|
@@ -112,6 +120,7 @@ const SERVER_TOOLS = {
|
|
|
112
120
|
sandbox: [...SANDBOX_TOOLS, ...ANY_GRANT_TOOLS],
|
|
113
121
|
webhooks: [...WEBHOOK_TOOLS, ...ANY_GRANT_TOOLS],
|
|
114
122
|
motorBlocks: [...MOTOR_BLOCK_TOOLS, ...ANY_GRANT_TOOLS],
|
|
123
|
+
communications: [...COMMS_TOOLS, ...ANY_GRANT_TOOLS],
|
|
115
124
|
signup: ['motorical_signup_handoff'],
|
|
116
125
|
};
|
|
117
126
|
|
|
@@ -134,7 +143,7 @@ const TOOL_SCOPES = {
|
|
|
134
143
|
motorical_get_error_codes: ['read:analytics'],
|
|
135
144
|
motorical_get_rate_limits: ['read:analytics'],
|
|
136
145
|
motorical_get_account_rate_limits: ['read:analytics'],
|
|
137
|
-
motorical_get_onboarding_state: ['read:
|
|
146
|
+
motorical_get_onboarding_state: ['read:domains'],
|
|
138
147
|
motorical_whoami: [], // any OAuth grant; see ANY_GRANT_TOOLS
|
|
139
148
|
motorical_get_logs: ['read:analytics'],
|
|
140
149
|
motorical_get_message_by_smtp_id: ['read:analytics'],
|
|
@@ -171,6 +180,8 @@ const TOOL_SCOPES = {
|
|
|
171
180
|
motorical_motor_block_reactivate: ['manage:motor-blocks'],
|
|
172
181
|
motorical_motor_block_delete: ['manage:motor-blocks'],
|
|
173
182
|
motorical_motor_block_delete_status: ['manage:motor-blocks'],
|
|
183
|
+
comms_get_readiness: ['read:comms'],
|
|
184
|
+
comms_get_map: ['read:comms'],
|
|
174
185
|
};
|
|
175
186
|
|
|
176
187
|
/** `|| []`: a tool with no entry (signup's own tool) contributes no scopes rather than throwing. */
|
|
@@ -186,6 +197,7 @@ const SERVER_SLUGS = {
|
|
|
186
197
|
sandbox: 'motorical_sandbox',
|
|
187
198
|
webhooks: 'motorical_webhooks',
|
|
188
199
|
motorBlocks: 'motorical_motor_blocks',
|
|
200
|
+
communications: 'motorical_communications',
|
|
189
201
|
signup: 'signup',
|
|
190
202
|
};
|
|
191
203
|
|