synartesis 0.8.7 → 0.9.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.
@@ -1,27 +1,34 @@
1
- # Policy for GitHub's MCP server.
1
+ # Policy for GitHub's MCP server, github/github-mcp-server, written against
2
+ # the tool reference in its README at v1.12.2.
2
3
  #
3
- # NOT verified against a live account. Everything here is derived from GitHub's
4
- # documented API shapes, which is exactly the position the filesystem policy was
5
- # in before it met a real server and turned out to be wrong in one place. Run
6
- # `synartesis check --manifest manifests/github.yaml` against your own token
7
- # before trusting it, and expect to correct at least one field.
4
+ # NOT verified against a live account. Every name and argument below was read
5
+ # from GitHub's own documentation, which is exactly the position the
6
+ # filesystem policy was in before it met a real server and turned out to be
7
+ # wrong in one place. Run `synartesis check` against your own token before
8
+ # trusting it, and expect to correct at least one field.
8
9
  #
9
- # The npm package @modelcontextprotocol/server-github is deprecated. The
10
- # supported server is github/github-mcp-server. Synartesis speaks stdio only,
11
- # so use the local binary rather than GitHub's hosted remote server.
10
+ # Why this was rewritten: 1.12 folded get_issue, update_issue, create_issue and
11
+ # get_pull_request into issue_read, issue_write and pull_request_read, and
12
+ # renamed update_pull_request's pull_number to pullNumber. The previous policy
13
+ # still named the old tools, and a policy that calls tools a server does not
14
+ # have used to stop the proxy starting -- so everyone who had wrapped GitHub
15
+ # and let it update was left with no GitHub at all. The proxy now holds such a
16
+ # rule instead of refusing to start, and this file names what 1.12 exposes.
12
17
  #
13
- # The honest limit of this adapter: GitHub has no ordinary-scope delete for most
14
- # things it creates. An issue can be closed but not un-created; a comment is
15
- # gone only if the author removes it; a published release stays published.
18
+ # The honest limit of this adapter: GitHub has no ordinary-scope delete for
19
+ # most things it creates. An issue can be closed but not un-created; a comment
20
+ # is gone only if its author removes it; a published release stays published.
16
21
  # Anything that puts a permanent, publicly visible record into the world is
17
- # gated rather than dressed up as reversible.
22
+ # held rather than dressed up as reversible -- and every write this file does
23
+ # not name is held too, because an unlisted tool falls to the fail-closed
24
+ # default.
18
25
  version: 1
19
26
 
20
27
  servers:
21
28
  github:
22
29
  command: github-mcp-server
23
30
  args: ["stdio"]
24
- # Read from your shell; never written into this file.
31
+ # Read from where the server is started; never written into this file.
25
32
  env:
26
33
  GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_PERSONAL_ACCESS_TOKEN}"
27
34
  # Nothing here has met a real github; every shape below comes from
@@ -30,50 +37,39 @@ servers:
30
37
 
31
38
  tools:
32
39
  # --- reads -------------------------------------------------------------
40
+ # 1.12 names most of its reads by suffix -- issue_read, pull_request_read,
41
+ # actions_get, projects_list -- as well as by the older prefixes.
33
42
  - match: "github.get_*"
34
43
  class: readonly
35
44
  - match: "github.list_*"
36
45
  class: readonly
37
46
  - match: "github.search_*"
38
47
  class: readonly
48
+ - match: "github.*_read"
49
+ class: readonly
50
+ - match: "github.*_get"
51
+ class: readonly
52
+ - match: "github.*_list"
53
+ class: readonly
54
+
55
+ # The one tool the `*_read` suffix would misread: it *marks* notifications
56
+ # read, which is a write. The longer name wins over the pattern above.
57
+ - match: "github.mark_all_notifications_read"
58
+ class: irreversible
59
+ gate: always
39
60
 
40
61
  # --- issues ------------------------------------------------------------
41
62
 
42
- # An issue cannot be deleted through the API, only closed. Closing is not
43
- # the same as never having existed: people were notified.
44
- - match: "github.create_issue"
63
+ # One tool that creates an issue or updates one, chosen by its `method`
64
+ # argument. An update could be undone from an issue_read taken first; a
65
+ # creation cannot be undone at all -- an issue can be closed but not
66
+ # un-created, and people were notified. A rule matches a tool by name alone,
67
+ # so it cannot tell the two apart, and treating the whole tool as undoable
68
+ # would promise an undo for every issue the agent opens. Held.
69
+ - match: "github.issue_write"
45
70
  class: irreversible
46
71
  gate: always
47
72
 
48
- # get_issue returns labels and assignees as objects while update_issue takes
49
- # bare names, so the inverse projects the one field it needs out of each.
50
- # `[]` reads the same key from every element and does nothing else; it is
51
- # still a path, not a transform.
52
- - match: "github.update_issue"
53
- class: reversible
54
- snapshot:
55
- tool: "github.get_issue"
56
- args:
57
- owner: "$.owner"
58
- repo: "$.repo"
59
- issue_number: "$.issue_number"
60
- # What GitHub says when the thing is not there. Anything else the
61
- # pre-read reports -- a permissions change, a rate limit -- is a failed
62
- # snapshot rather than absence, and the write is refused instead of being
63
- # offered for approval as a creation.
64
- absent_when: ["Not Found", "404"]
65
- inverse:
66
- tool: "github.update_issue"
67
- args:
68
- owner: "$.owner"
69
- repo: "$.repo"
70
- issue_number: "$.issue_number"
71
- title: "$snapshot.title"
72
- body: "$snapshot.body"
73
- state: "$snapshot.state"
74
- labels: "$snapshot.labels[].name"
75
- assignees: "$snapshot.assignees[].login"
76
-
77
73
  - match: "github.add_issue_comment"
78
74
  class: irreversible
79
75
  gate: always
@@ -83,14 +79,17 @@ tools:
83
79
  class: irreversible
84
80
  gate: always
85
81
 
82
+ # pullNumber, not pull_number, in 1.12 -- the previous policy's inverse would
83
+ # have lost the one argument that says which pull request to put back.
86
84
  - match: "github.update_pull_request"
87
85
  class: reversible
88
86
  snapshot:
89
- tool: "github.get_pull_request"
87
+ tool: "github.pull_request_read"
90
88
  args:
89
+ method: "get"
91
90
  owner: "$.owner"
92
91
  repo: "$.repo"
93
- pull_number: "$.pull_number"
92
+ pullNumber: "$.pullNumber"
94
93
  # What GitHub says when the thing is not there. Anything else the
95
94
  # pre-read reports -- a permissions change, a rate limit -- is a failed
96
95
  # snapshot rather than absence, and the write is refused instead of being
@@ -101,7 +100,7 @@ tools:
101
100
  args:
102
101
  owner: "$.owner"
103
102
  repo: "$.repo"
104
- pull_number: "$.pull_number"
103
+ pullNumber: "$.pullNumber"
105
104
  title: "$snapshot.title"
106
105
  body: "$snapshot.body"
107
106
  state: "$snapshot.state"
@@ -109,38 +108,14 @@ tools:
109
108
  - match: "github.merge_pull_request"
110
109
  class: irreversible
111
110
  gate: always
112
- - match: "github.create_pull_request_review"
113
- class: irreversible
114
- gate: always
115
- - match: "github.create_and_submit_pull_request_review"
116
- class: irreversible
117
- gate: always
118
- - match: "github.submit_pending_pull_request_review"
111
+
112
+ # Creates, submits or deletes a review, by `method`. A submitted review is
113
+ # public and cannot be withdrawn; held whole for the same reason issue_write
114
+ # is.
115
+ - match: "github.pull_request_review_write"
119
116
  class: irreversible
120
117
  gate: always
121
118
 
122
- # A pending review is a draft only its author can see, so deleting one puts
123
- # nothing into the world. Recreating it restores the draft but not the
124
- # comments that were inside it, which is a compensation rather than a
125
- # reversal, and undo will report it as unverified.
126
- - match: "github.delete_pending_pull_request_review"
127
- class: compensable
128
- inverse:
129
- tool: "github.create_pending_pull_request_review"
130
- args:
131
- owner: "$.owner"
132
- repo: "$.repo"
133
- pull_number: "$.pull_number"
134
-
135
- - match: "github.create_pending_pull_request_review"
136
- class: compensable
137
- inverse:
138
- tool: "github.delete_pending_pull_request_review"
139
- args:
140
- owner: "$.owner"
141
- repo: "$.repo"
142
- pull_number: "$.pull_number"
143
-
144
119
  # --- file contents -----------------------------------------------------
145
120
 
146
121
  # The sha must be the blob being replaced at the moment of the revert, which
@@ -172,6 +147,13 @@ tools:
172
147
  sha: "$result.content.sha"
173
148
  message: "Revert agent change to $.path"
174
149
 
150
+ # A commit removing the file. The contents are gone from the branch head and
151
+ # would have to be read first to be put back, which this server's read does
152
+ # not return in a form an inverse can use unchanged. Held.
153
+ - match: "github.delete_file"
154
+ class: irreversible
155
+ gate: always
156
+
175
157
  # A multi-file push is one commit touching many paths. This format captures
176
158
  # one pre-read per action, not one per path, so there is nothing honest to
177
159
  # restore from.
@@ -188,13 +170,13 @@ tools:
188
170
  - match: "github.create_repository"
189
171
  class: irreversible
190
172
  gate: always
191
- - match: "github.create_release"
173
+ - match: "github.delete_repository"
192
174
  class: irreversible
193
175
  gate: always
194
176
 
195
- # This policy is written for the server version named at the top. A later
196
- # version can keep a tool's name and change what it takes, which would leave
197
- # the policy above describing something else -- and undo would still produce an
198
- # answer. `synartesis pin` prints a `pins:` block for the server you actually
199
- # have; with it pasted in, a tool whose shape has moved stops the proxy at
200
- # startup instead of being quietly trusted.
177
+ # Written for github-mcp-server v1.12.2. A later version can keep a tool's name
178
+ # and change what it takes, which would leave the policy above describing
179
+ # something else -- and undo would still produce an answer. `synartesis pin`
180
+ # prints a `pins:` block for the server you actually have; with it pasted in, a
181
+ # tool whose shape has moved stops the proxy at startup instead of being
182
+ # quietly trusted.
@@ -0,0 +1,106 @@
1
+ # Policy for @playwright/mcp.
2
+ #
3
+ # Written against 1.64.0 from the server's own tools/list, read-only hints and
4
+ # all.
5
+ #
6
+ # Nothing a browser does can be undone. There is no inverse for a click, a
7
+ # submitted form or a page left behind. Holding every one of them made this
8
+ # server unusable behind Synartesis, since an agent driving a page clicks
9
+ # dozens of times a minute. So this policy records instead of holding: each
10
+ # interaction is classed as a call that cannot be undone, so every screen says
11
+ # so, and is written to the journal with its arguments. `show` gives you the
12
+ # whole session afterwards. It does not ask before each one.
13
+ #
14
+ # Three tools are still held, because each reaches past the page. Running code
15
+ # the agent wrote has the full reach of the browser context, and it is how a
16
+ # page's contents become an arbitrary action. A file upload sends something
17
+ # from your disk to whoever runs the page, and so does a drop, which carries
18
+ # files too. A tool this file does not mention is held until a rule says
19
+ # otherwise, the same as everywhere else, so a new tool in a later version is
20
+ # not let through by accident.
21
+ #
22
+ # Recorded is not reversible. If a page is somewhere an agent's click could do
23
+ # real harm -- your bank, a production admin panel -- this policy does not
24
+ # protect you from that click. It tells you it happened.
25
+ version: 1
26
+
27
+ servers:
28
+ playwright:
29
+ command: npx
30
+ args: ["-y", "@playwright/mcp@latest"]
31
+ provenance: live
32
+
33
+ tools:
34
+ # --- reads: the tools the server itself marks read-only ------------------
35
+ - match: "playwright.browser_snapshot"
36
+ class: readonly
37
+ - match: "playwright.browser_take_screenshot"
38
+ class: readonly
39
+ - match: "playwright.browser_console_messages"
40
+ class: readonly
41
+ - match: "playwright.browser_network_requests"
42
+ class: readonly
43
+ - match: "playwright.browser_network_request"
44
+ class: readonly
45
+ - match: "playwright.browser_find"
46
+ class: readonly
47
+ - match: "playwright.browser_wait_for"
48
+ class: readonly
49
+
50
+ # --- held: each reaches past the page -------------------------------------
51
+ - match: "playwright.browser_run_code_unsafe"
52
+ class: irreversible
53
+ gate: always
54
+ - match: "playwright.browser_evaluate"
55
+ class: irreversible
56
+ gate: always
57
+ - match: "playwright.browser_file_upload"
58
+ class: irreversible
59
+ gate: always
60
+ - match: "playwright.browser_drop"
61
+ class: irreversible
62
+ gate: always
63
+
64
+ # --- recorded, not held: what driving a page is ---------------------------
65
+ - match: "playwright.browser_navigate"
66
+ class: irreversible
67
+ gate: never
68
+ - match: "playwright.browser_navigate_back"
69
+ class: irreversible
70
+ gate: never
71
+ - match: "playwright.browser_click"
72
+ class: irreversible
73
+ gate: never
74
+ - match: "playwright.browser_type"
75
+ class: irreversible
76
+ gate: never
77
+ - match: "playwright.browser_fill_form"
78
+ class: irreversible
79
+ gate: never
80
+ - match: "playwright.browser_press_key"
81
+ class: irreversible
82
+ gate: never
83
+ - match: "playwright.browser_select_option"
84
+ class: irreversible
85
+ gate: never
86
+ - match: "playwright.browser_hover"
87
+ class: irreversible
88
+ gate: never
89
+ - match: "playwright.browser_drag"
90
+ class: irreversible
91
+ gate: never
92
+ - match: "playwright.browser_handle_dialog"
93
+ class: irreversible
94
+ gate: never
95
+ - match: "playwright.browser_tabs"
96
+ class: irreversible
97
+ gate: never
98
+ - match: "playwright.browser_resize"
99
+ class: irreversible
100
+ gate: never
101
+ - match: "playwright.browser_emulate_media"
102
+ class: irreversible
103
+ gate: never
104
+ - match: "playwright.browser_close"
105
+ class: irreversible
106
+ gate: never
@@ -0,0 +1,27 @@
1
+ # Policy for tavily-mcp.
2
+ #
3
+ # Written against 0.2.22 from the server's own tools/list.
4
+ #
5
+ # Search, extract, crawl, map and research all read the web and change
6
+ # nothing. The server does not mark them read-only.
7
+ #
8
+ # A tool a later version adds is held until a rule says what it does.
9
+ version: 1
10
+
11
+ servers:
12
+ tavily:
13
+ command: npx
14
+ args: ["-y", "tavily-mcp"]
15
+ provenance: live
16
+
17
+ tools:
18
+ - match: "tavily.tavily_search"
19
+ class: readonly
20
+ - match: "tavily.tavily_extract"
21
+ class: readonly
22
+ - match: "tavily.tavily_crawl"
23
+ class: readonly
24
+ - match: "tavily.tavily_map"
25
+ class: readonly
26
+ - match: "tavily.tavily_research"
27
+ class: readonly
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synartesis",
3
- "version": "0.8.7",
3
+ "version": "0.9.0",
4
4
  "description": "An undo layer for AI agents.",
5
5
  "type": "module",
6
6
  "private": false,