@orygn/opa-mcp 0.0.0 → 0.1.1
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/CHANGELOG.md +150 -0
- package/LICENSE +21 -0
- package/README.md +622 -2
- package/dist/config.d.ts +58 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +72 -0
- package/dist/config.js.map +1 -0
- package/dist/lib/errors.d.ts +18 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +25 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/logger.d.ts +10 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +57 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/opa-cli.d.ts +226 -0
- package/dist/lib/opa-cli.d.ts.map +1 -0
- package/dist/lib/opa-cli.js +283 -0
- package/dist/lib/opa-cli.js.map +1 -0
- package/dist/lib/opa-client.d.ts +47 -0
- package/dist/lib/opa-client.d.ts.map +1 -0
- package/dist/lib/opa-client.js +101 -0
- package/dist/lib/opa-client.js.map +1 -0
- package/dist/lib/output.d.ts +17 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +21 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/regal-cli.d.ts +79 -0
- package/dist/lib/regal-cli.d.ts.map +1 -0
- package/dist/lib/regal-cli.js +122 -0
- package/dist/lib/regal-cli.js.map +1 -0
- package/dist/lib/security.d.ts +16 -0
- package/dist/lib/security.d.ts.map +1 -0
- package/dist/lib/security.js +64 -0
- package/dist/lib/security.js.map +1 -0
- package/dist/lib/subprocess.d.ts +26 -0
- package/dist/lib/subprocess.d.ts.map +1 -0
- package/dist/lib/subprocess.js +72 -0
- package/dist/lib/subprocess.js.map +1 -0
- package/dist/lib/tool-helpers.d.ts +46 -0
- package/dist/lib/tool-helpers.d.ts.map +1 -0
- package/dist/lib/tool-helpers.js +73 -0
- package/dist/lib/tool-helpers.js.map +1 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +147 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +107 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/patterns.d.ts +9 -0
- package/dist/resources/patterns.d.ts.map +1 -0
- package/dist/resources/patterns.js +375 -0
- package/dist/resources/patterns.js.map +1 -0
- package/dist/resources/style-guide.d.ts +6 -0
- package/dist/resources/style-guide.d.ts.map +1 -0
- package/dist/resources/style-guide.js +187 -0
- package/dist/resources/style-guide.js.map +1 -0
- package/dist/server.d.ts +34 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +125 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/authoring/capabilities.d.ts +11 -0
- package/dist/tools/authoring/capabilities.d.ts.map +1 -0
- package/dist/tools/authoring/capabilities.js +57 -0
- package/dist/tools/authoring/capabilities.js.map +1 -0
- package/dist/tools/authoring/check.d.ts +18 -0
- package/dist/tools/authoring/check.d.ts.map +1 -0
- package/dist/tools/authoring/check.js +71 -0
- package/dist/tools/authoring/check.js.map +1 -0
- package/dist/tools/authoring/deps.d.ts +8 -0
- package/dist/tools/authoring/deps.d.ts.map +1 -0
- package/dist/tools/authoring/deps.js +51 -0
- package/dist/tools/authoring/deps.js.map +1 -0
- package/dist/tools/authoring/format.d.ts +8 -0
- package/dist/tools/authoring/format.d.ts.map +1 -0
- package/dist/tools/authoring/format.js +44 -0
- package/dist/tools/authoring/format.js.map +1 -0
- package/dist/tools/authoring/index.d.ts +11 -0
- package/dist/tools/authoring/index.d.ts.map +1 -0
- package/dist/tools/authoring/index.js +17 -0
- package/dist/tools/authoring/index.js.map +1 -0
- package/dist/tools/authoring/inspect.d.ts +10 -0
- package/dist/tools/authoring/inspect.d.ts.map +1 -0
- package/dist/tools/authoring/inspect.js +47 -0
- package/dist/tools/authoring/inspect.js.map +1 -0
- package/dist/tools/authoring/lint.d.ts +18 -0
- package/dist/tools/authoring/lint.d.ts.map +1 -0
- package/dist/tools/authoring/lint.js +111 -0
- package/dist/tools/authoring/lint.js.map +1 -0
- package/dist/tools/authoring/parse.d.ts +7 -0
- package/dist/tools/authoring/parse.d.ts.map +1 -0
- package/dist/tools/authoring/parse.js +43 -0
- package/dist/tools/authoring/parse.js.map +1 -0
- package/dist/tools/bundles/build.d.ts +8 -0
- package/dist/tools/bundles/build.d.ts.map +1 -0
- package/dist/tools/bundles/build.js +87 -0
- package/dist/tools/bundles/build.js.map +1 -0
- package/dist/tools/bundles/index.d.ts +10 -0
- package/dist/tools/bundles/index.d.ts.map +1 -0
- package/dist/tools/bundles/index.js +7 -0
- package/dist/tools/bundles/index.js.map +1 -0
- package/dist/tools/bundles/sign.d.ts +8 -0
- package/dist/tools/bundles/sign.d.ts.map +1 -0
- package/dist/tools/bundles/sign.js +47 -0
- package/dist/tools/bundles/sign.js.map +1 -0
- package/dist/tools/evaluation/_shared.d.ts +55 -0
- package/dist/tools/evaluation/_shared.d.ts.map +1 -0
- package/dist/tools/evaluation/_shared.js +102 -0
- package/dist/tools/evaluation/_shared.js.map +1 -0
- package/dist/tools/evaluation/bench.d.ts +9 -0
- package/dist/tools/evaluation/bench.d.ts.map +1 -0
- package/dist/tools/evaluation/bench.js +76 -0
- package/dist/tools/evaluation/bench.js.map +1 -0
- package/dist/tools/evaluation/compile.d.ts +11 -0
- package/dist/tools/evaluation/compile.d.ts.map +1 -0
- package/dist/tools/evaluation/compile.js +19 -0
- package/dist/tools/evaluation/compile.js.map +1 -0
- package/dist/tools/evaluation/eval.d.ts +10 -0
- package/dist/tools/evaluation/eval.d.ts.map +1 -0
- package/dist/tools/evaluation/eval.js +35 -0
- package/dist/tools/evaluation/eval.js.map +1 -0
- package/dist/tools/evaluation/index.d.ts +11 -0
- package/dist/tools/evaluation/index.d.ts.map +1 -0
- package/dist/tools/evaluation/index.js +11 -0
- package/dist/tools/evaluation/index.js.map +1 -0
- package/dist/tools/evaluation/test.d.ts +28 -0
- package/dist/tools/evaluation/test.d.ts.map +1 -0
- package/dist/tools/evaluation/test.js +74 -0
- package/dist/tools/evaluation/test.js.map +1 -0
- package/dist/tools/helpers/describe-policy.d.ts +26 -0
- package/dist/tools/helpers/describe-policy.d.ts.map +1 -0
- package/dist/tools/helpers/describe-policy.js +76 -0
- package/dist/tools/helpers/describe-policy.js.map +1 -0
- package/dist/tools/helpers/explain-decision.d.ts +41 -0
- package/dist/tools/helpers/explain-decision.d.ts.map +1 -0
- package/dist/tools/helpers/explain-decision.js +75 -0
- package/dist/tools/helpers/explain-decision.js.map +1 -0
- package/dist/tools/helpers/generate-test-skeleton.d.ts +8 -0
- package/dist/tools/helpers/generate-test-skeleton.d.ts.map +1 -0
- package/dist/tools/helpers/generate-test-skeleton.js +93 -0
- package/dist/tools/helpers/generate-test-skeleton.js.map +1 -0
- package/dist/tools/helpers/index.d.ts +12 -0
- package/dist/tools/helpers/index.d.ts.map +1 -0
- package/dist/tools/helpers/index.js +11 -0
- package/dist/tools/helpers/index.js.map +1 -0
- package/dist/tools/helpers/suggest-fix.d.ts +15 -0
- package/dist/tools/helpers/suggest-fix.d.ts.map +1 -0
- package/dist/tools/helpers/suggest-fix.js +119 -0
- package/dist/tools/helpers/suggest-fix.js.map +1 -0
- package/dist/tools/index.d.ts +31 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/server-management/_shared.d.ts +9 -0
- package/dist/tools/server-management/_shared.d.ts.map +1 -0
- package/dist/tools/server-management/_shared.js +41 -0
- package/dist/tools/server-management/_shared.js.map +1 -0
- package/dist/tools/server-management/data.d.ts +4 -0
- package/dist/tools/server-management/data.d.ts.map +1 -0
- package/dist/tools/server-management/data.js +90 -0
- package/dist/tools/server-management/data.js.map +1 -0
- package/dist/tools/server-management/decisions.d.ts +4 -0
- package/dist/tools/server-management/decisions.d.ts.map +1 -0
- package/dist/tools/server-management/decisions.js +87 -0
- package/dist/tools/server-management/decisions.js.map +1 -0
- package/dist/tools/server-management/index.d.ts +11 -0
- package/dist/tools/server-management/index.d.ts.map +1 -0
- package/dist/tools/server-management/index.js +11 -0
- package/dist/tools/server-management/index.js.map +1 -0
- package/dist/tools/server-management/policies.d.ts +4 -0
- package/dist/tools/server-management/policies.d.ts.map +1 -0
- package/dist/tools/server-management/policies.js +94 -0
- package/dist/tools/server-management/policies.js.map +1 -0
- package/dist/tools/server-management/status.d.ts +4 -0
- package/dist/tools/server-management/status.d.ts.map +1 -0
- package/dist/tools/server-management/status.js +82 -0
- package/dist/tools/server-management/status.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +86 -4
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Curated Rego style guide. Adapted from the Styra reference plus the
|
|
3
|
+
* OPA team's own conventions, condensed for LLM consumption.
|
|
4
|
+
*/
|
|
5
|
+
export const STYLE_GUIDE = `# Rego style guide
|
|
6
|
+
|
|
7
|
+
A condensed reference for writing idiomatic, maintainable Rego. Adapted
|
|
8
|
+
from the Styra style guide and the OPA project's conventions.
|
|
9
|
+
|
|
10
|
+
## Always import \`rego.v1\`
|
|
11
|
+
|
|
12
|
+
Every \`.rego\` file should start with the v1 import. It enables the
|
|
13
|
+
modern syntax (\`if\`, \`contains\`, \`every\`) and disables the older
|
|
14
|
+
implicit-membership operator that's a frequent source of bugs.
|
|
15
|
+
|
|
16
|
+
\`\`\`rego
|
|
17
|
+
package authz
|
|
18
|
+
|
|
19
|
+
import rego.v1
|
|
20
|
+
\`\`\`
|
|
21
|
+
|
|
22
|
+
OPA 1.0 (released January 2025) treats this as the default, but
|
|
23
|
+
including it explicitly makes intent clear and keeps the file portable
|
|
24
|
+
to older OPA installations.
|
|
25
|
+
|
|
26
|
+
## Package layout mirrors directory layout
|
|
27
|
+
|
|
28
|
+
Match \`package foo.bar\` with the file path \`foo/bar/main.rego\` (or
|
|
29
|
+
\`foo/bar/<anything>.rego\`). Regal flags mismatches as
|
|
30
|
+
\`directory-package-mismatch\`.
|
|
31
|
+
|
|
32
|
+
For a multi-file package, group by responsibility:
|
|
33
|
+
|
|
34
|
+
\`\`\`
|
|
35
|
+
authz/
|
|
36
|
+
main.rego # principal decision (allow / deny)
|
|
37
|
+
rbac.rego # role-based access checks
|
|
38
|
+
abac.rego # attribute-based access checks
|
|
39
|
+
helpers.rego # shared helpers, no decisions
|
|
40
|
+
main_test.rego # tests for principal decisions
|
|
41
|
+
rbac_test.rego # tests for rbac
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
Tests live in \`*_test.rego\` siblings of the source they test, in the
|
|
45
|
+
same package or a \`<package>_test\` package.
|
|
46
|
+
|
|
47
|
+
## Naming
|
|
48
|
+
|
|
49
|
+
- Rule names: \`snake_case\`.
|
|
50
|
+
- Boolean rules: read like predicates — \`allow\`, \`is_admin\`,
|
|
51
|
+
\`should_log\`. Avoid \`is_not_blocked\` (double negative).
|
|
52
|
+
- Set/object rules: read like nouns — \`grants\`, \`roles\`, \`reasons\`.
|
|
53
|
+
- Helper rules: \`_\` prefix is *not* a convention; just give them names
|
|
54
|
+
that explain what they return.
|
|
55
|
+
|
|
56
|
+
Names that conflict with reserved words (\`type\`, \`time\`, \`input\`) won't
|
|
57
|
+
parse. Names matching builtins (\`http\`, \`json\`) shadow them.
|
|
58
|
+
|
|
59
|
+
## Default deny
|
|
60
|
+
|
|
61
|
+
Every principal decision should have a default fallback so the policy
|
|
62
|
+
returns a value even when no rule matches.
|
|
63
|
+
|
|
64
|
+
\`\`\`rego
|
|
65
|
+
default allow := false
|
|
66
|
+
|
|
67
|
+
allow if {
|
|
68
|
+
input.user.role == "admin"
|
|
69
|
+
}
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
The same applies to set-valued reasons:
|
|
73
|
+
|
|
74
|
+
\`\`\`rego
|
|
75
|
+
deny contains reason if {
|
|
76
|
+
not allow
|
|
77
|
+
reason := "not authorized"
|
|
78
|
+
}
|
|
79
|
+
\`\`\`
|
|
80
|
+
|
|
81
|
+
## Comprehensions vs \`every\`
|
|
82
|
+
|
|
83
|
+
When you need a value derived from a collection, use a comprehension:
|
|
84
|
+
|
|
85
|
+
\`\`\`rego
|
|
86
|
+
admin_users := {u | some u in input.users; u.role == "admin"}
|
|
87
|
+
\`\`\`
|
|
88
|
+
|
|
89
|
+
When you need to assert that a property holds for every element, use
|
|
90
|
+
\`every\` (introduced in OPA 0.41):
|
|
91
|
+
|
|
92
|
+
\`\`\`rego
|
|
93
|
+
allow if {
|
|
94
|
+
every claim in input.token.claims {
|
|
95
|
+
claim.verified == true
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
\`every\` is clearer than the older \`not <comprehension>\` idiom and
|
|
101
|
+
short-circuits on the first failure.
|
|
102
|
+
|
|
103
|
+
## Annotations
|
|
104
|
+
|
|
105
|
+
Public rules deserve a metadata block so consumers know what they do.
|
|
106
|
+
|
|
107
|
+
\`\`\`rego
|
|
108
|
+
# METADATA
|
|
109
|
+
# title: Authorization decision for HTTP requests
|
|
110
|
+
# description: |
|
|
111
|
+
# Returns true when the requesting principal has a role with a
|
|
112
|
+
# permission entry for the requested action on the requested
|
|
113
|
+
# resource. Anonymous requests always deny.
|
|
114
|
+
# entrypoint: true
|
|
115
|
+
allow if {
|
|
116
|
+
some role in input.principal.roles
|
|
117
|
+
permission_grants[role][input.action]
|
|
118
|
+
}
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
Annotations show up in \`opa inspect\`, the registry, and editor
|
|
122
|
+
hovers. They are also extracted by \`rego_describe_policy\`.
|
|
123
|
+
|
|
124
|
+
## Schema annotations
|
|
125
|
+
|
|
126
|
+
For policies that are sensitive to input shape, attach a JSON Schema:
|
|
127
|
+
|
|
128
|
+
\`\`\`rego
|
|
129
|
+
# METADATA
|
|
130
|
+
# schemas:
|
|
131
|
+
# - input: schema.input
|
|
132
|
+
allow if {
|
|
133
|
+
input.user.id != ""
|
|
134
|
+
}
|
|
135
|
+
\`\`\`
|
|
136
|
+
|
|
137
|
+
Combined with \`opa check --schema\`, this turns input-shape mismatches
|
|
138
|
+
into compile errors instead of runtime undefineds.
|
|
139
|
+
|
|
140
|
+
## Anti-patterns
|
|
141
|
+
|
|
142
|
+
- **\`http.send\` in the decision path.** Each call adds round-trip
|
|
143
|
+
latency. If you must, scope it to a small, cacheable read.
|
|
144
|
+
- **Deep \`with\` chains.** \`x with input as ... with data as ...\` more
|
|
145
|
+
than two layers deep is a smell — the test is doing too much. Split.
|
|
146
|
+
- **\`print\` and \`trace\`.** Useful in development; remove before
|
|
147
|
+
shipping. Regal flags both as \`print-or-trace-call\`.
|
|
148
|
+
- **Mixing \`if\` and the legacy implicit form in the same file.** Pick
|
|
149
|
+
one. With \`rego.v1\` imported you cannot use the implicit form.
|
|
150
|
+
|
|
151
|
+
## Tests
|
|
152
|
+
|
|
153
|
+
\`opa test\` runs every rule whose name starts with \`test_\`. A test
|
|
154
|
+
either evaluates to true (pass) or fails to evaluate (fail). The
|
|
155
|
+
common shape:
|
|
156
|
+
|
|
157
|
+
\`\`\`rego
|
|
158
|
+
package authz_test
|
|
159
|
+
|
|
160
|
+
import rego.v1
|
|
161
|
+
import data.authz
|
|
162
|
+
|
|
163
|
+
test_admin_can_delete if {
|
|
164
|
+
authz.allow with input as {
|
|
165
|
+
"user": {"role": "admin"},
|
|
166
|
+
"action": "delete",
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
test_viewer_cannot_delete if {
|
|
171
|
+
not authz.allow with input as {
|
|
172
|
+
"user": {"role": "viewer"},
|
|
173
|
+
"action": "delete",
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
Run with \`opa test -v ./...\` for verbose output. Add \`--coverage\` to
|
|
179
|
+
verify which lines were exercised.
|
|
180
|
+
|
|
181
|
+
## References
|
|
182
|
+
|
|
183
|
+
- Official Rego style guide: https://docs.styra.com/regal/rego-style-guide
|
|
184
|
+
- OPA documentation: https://www.openpolicyagent.org/docs/latest/
|
|
185
|
+
- Regal linter rules: https://docs.styra.com/regal/rules
|
|
186
|
+
`;
|
|
187
|
+
//# sourceMappingURL=style-guide.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style-guide.js","sourceRoot":"","sources":["../../src/resources/style-guide.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqL1B,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
4
|
+
import { type Config } from './config.js';
|
|
5
|
+
export declare const SERVER_NAME = "orygn-opa-mcp";
|
|
6
|
+
export declare const SERVER_VERSION = "0.1.1";
|
|
7
|
+
/**
|
|
8
|
+
* Construct an `McpServer`, register every tool / prompt / resource
|
|
9
|
+
* onto it, and return it. Exported for tests so they can drive a
|
|
10
|
+
* fully-loaded server without standing up a stdio transport.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildServer(config: Config): McpServer;
|
|
13
|
+
/**
|
|
14
|
+
* Probe the configured `opa` and `regal` binaries at startup and log
|
|
15
|
+
* warnings if either is unreachable. Runs in the background so it
|
|
16
|
+
* doesn't delay the MCP `initialize` handshake. Most users only see
|
|
17
|
+
* the failure when they call a tool; surfacing it early in the log
|
|
18
|
+
* file gives operators a place to look when diagnosing
|
|
19
|
+
* `OPA_BINARY_NOT_FOUND` (most often caused by Claude Desktop's
|
|
20
|
+
* reduced PATH on macOS and Windows).
|
|
21
|
+
*
|
|
22
|
+
* Exported for tests; production callers don't await it.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runStartupSelfCheck(config: Config): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Entry-point flow: load config from env, build the server, connect
|
|
27
|
+
* to the supplied transport (defaults to stdio for production).
|
|
28
|
+
*
|
|
29
|
+
* Tests pass an in-memory transport so the connection succeeds
|
|
30
|
+
* without touching real stdio. Production callers omit the argument
|
|
31
|
+
* and get the standard stdio transport.
|
|
32
|
+
*/
|
|
33
|
+
export declare function main(transport?: Transport): Promise<McpServer>;
|
|
34
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAYA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAQtD,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAC3C,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAoBrD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BvE;AAED;;;;;;;GAOG;AACH,wBAAsB,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAepE"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @orygn/opa-mcp — entry point.
|
|
4
|
+
*
|
|
5
|
+
* Initializes the MCP server, registers tools/prompts/resources,
|
|
6
|
+
* and connects the stdio transport.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: never write to stdout from anywhere in this process —
|
|
9
|
+
* stdout is the MCP protocol channel. Use `logger` (file) or stderr.
|
|
10
|
+
*/
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
|
+
import { loadConfig } from './config.js';
|
|
15
|
+
import { initLogger, logger } from './lib/logger.js';
|
|
16
|
+
import { OpaCli } from './lib/opa-cli.js';
|
|
17
|
+
import { RegalCli } from './lib/regal-cli.js';
|
|
18
|
+
import { registerPrompts } from './prompts/index.js';
|
|
19
|
+
import { registerResources } from './resources/index.js';
|
|
20
|
+
import { registerTools } from './tools/index.js';
|
|
21
|
+
export const SERVER_NAME = 'orygn-opa-mcp';
|
|
22
|
+
export const SERVER_VERSION = '0.1.1';
|
|
23
|
+
/**
|
|
24
|
+
* Construct an `McpServer`, register every tool / prompt / resource
|
|
25
|
+
* onto it, and return it. Exported for tests so they can drive a
|
|
26
|
+
* fully-loaded server without standing up a stdio transport.
|
|
27
|
+
*/
|
|
28
|
+
export function buildServer(config) {
|
|
29
|
+
initLogger(config.logFile, config.logLevel);
|
|
30
|
+
logger.info('starting orygn-opa-mcp', {
|
|
31
|
+
version: SERVER_VERSION,
|
|
32
|
+
opaUrl: config.opaUrl,
|
|
33
|
+
opaBinary: config.opaBinary,
|
|
34
|
+
regalBinary: config.regalBinary,
|
|
35
|
+
});
|
|
36
|
+
const server = new McpServer({
|
|
37
|
+
name: SERVER_NAME,
|
|
38
|
+
version: SERVER_VERSION,
|
|
39
|
+
});
|
|
40
|
+
registerTools(server, config);
|
|
41
|
+
registerPrompts(server, config);
|
|
42
|
+
registerResources(server, config);
|
|
43
|
+
return server;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Probe the configured `opa` and `regal` binaries at startup and log
|
|
47
|
+
* warnings if either is unreachable. Runs in the background so it
|
|
48
|
+
* doesn't delay the MCP `initialize` handshake. Most users only see
|
|
49
|
+
* the failure when they call a tool; surfacing it early in the log
|
|
50
|
+
* file gives operators a place to look when diagnosing
|
|
51
|
+
* `OPA_BINARY_NOT_FOUND` (most often caused by Claude Desktop's
|
|
52
|
+
* reduced PATH on macOS and Windows).
|
|
53
|
+
*
|
|
54
|
+
* Exported for tests; production callers don't await it.
|
|
55
|
+
*/
|
|
56
|
+
export async function runStartupSelfCheck(config) {
|
|
57
|
+
const opa = new OpaCli(config);
|
|
58
|
+
const regal = new RegalCli(config);
|
|
59
|
+
const [opaVersion, regalVersion] = await Promise.all([
|
|
60
|
+
opa.version().catch(() => null),
|
|
61
|
+
regal.version().catch(() => null),
|
|
62
|
+
]);
|
|
63
|
+
if (opaVersion === null) {
|
|
64
|
+
logger.warn('startup self-check: opa binary not reachable; rego_* tools will fail', {
|
|
65
|
+
opaBinary: config.opaBinary,
|
|
66
|
+
hint: 'set OPA_BINARY to an absolute path, or ensure opa is on PATH for the launching process. Most often hit under Claude Desktop, which spawns servers with a reduced PATH on macOS and Windows.',
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
logger.info('startup self-check: opa OK', { version: opaVersion });
|
|
71
|
+
}
|
|
72
|
+
if (regalVersion === null) {
|
|
73
|
+
logger.warn('startup self-check: regal binary not reachable; rego_lint will return REGAL_NOT_FOUND', {
|
|
74
|
+
regalBinary: config.regalBinary,
|
|
75
|
+
hint: 'set REGAL_BINARY to an absolute path, or ensure regal is on PATH. Regal is optional; only rego_lint requires it.',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
logger.info('startup self-check: regal OK', { version: regalVersion });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Entry-point flow: load config from env, build the server, connect
|
|
84
|
+
* to the supplied transport (defaults to stdio for production).
|
|
85
|
+
*
|
|
86
|
+
* Tests pass an in-memory transport so the connection succeeds
|
|
87
|
+
* without touching real stdio. Production callers omit the argument
|
|
88
|
+
* and get the standard stdio transport.
|
|
89
|
+
*/
|
|
90
|
+
export async function main(transport) {
|
|
91
|
+
const config = loadConfig();
|
|
92
|
+
const server = buildServer(config);
|
|
93
|
+
const connectTo = transport ?? new StdioServerTransport();
|
|
94
|
+
await server.connect(connectTo);
|
|
95
|
+
logger.info('connected to transport, ready for requests');
|
|
96
|
+
// Fire-and-forget; do not block initialize on subprocess probes.
|
|
97
|
+
void runStartupSelfCheck(config).catch((cause) => {
|
|
98
|
+
logger.error('startup self-check threw unexpectedly', { error: cause });
|
|
99
|
+
});
|
|
100
|
+
return server;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Auto-run when this module is invoked as the entry point (`node
|
|
104
|
+
* dist/server.js` or via the `opa-mcp` bin shim). Tests that import
|
|
105
|
+
* `server.ts` directly do not trip this branch.
|
|
106
|
+
*/
|
|
107
|
+
function isEntryPoint() {
|
|
108
|
+
const argv1 = process.argv[1];
|
|
109
|
+
if (!argv1)
|
|
110
|
+
return false;
|
|
111
|
+
try {
|
|
112
|
+
return import.meta.url === pathToFileURL(argv1).href;
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (isEntryPoint()) {
|
|
119
|
+
main().catch((cause) => {
|
|
120
|
+
logger.error('fatal error in server entry', { error: cause });
|
|
121
|
+
console.error('orygn-opa-mcp fatal error:', cause);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Config } from '../../config.js';
|
|
3
|
+
export interface RegoCapabilitiesOutput {
|
|
4
|
+
builtins?: unknown[];
|
|
5
|
+
future_keywords?: unknown[];
|
|
6
|
+
features?: unknown[];
|
|
7
|
+
wasm_abi_versions?: unknown[];
|
|
8
|
+
versions?: string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function registerRegoCapabilities(server: McpServer, config: Config): void;
|
|
11
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../../src/tools/authoring/capabilities.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAoB9C,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAkDhF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rego_capabilities` — list OPA's built-in functions and feature flags.
|
|
3
|
+
*
|
|
4
|
+
* Useful as a reference when authoring policies, especially for
|
|
5
|
+
* answering "is `crypto.x509.parse_certificates` available?" without
|
|
6
|
+
* grepping the OPA repo.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { OpaCli } from '../../lib/opa-cli.js';
|
|
10
|
+
import { err, ok } from '../../lib/errors.js';
|
|
11
|
+
import { mapSubprocessFailure, tryParseJson, withToolEnvelope } from '../../lib/tool-helpers.js';
|
|
12
|
+
const RegoCapabilitiesInput = {
|
|
13
|
+
current: z
|
|
14
|
+
.boolean()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Print the capabilities of the currently installed OPA. Mutually exclusive with `version`.'),
|
|
17
|
+
version: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('A specific OPA capabilities version (e.g. "v0.69.0"). When neither flag is set, lists available versions.'),
|
|
21
|
+
};
|
|
22
|
+
export function registerRegoCapabilities(server, config) {
|
|
23
|
+
const opa = new OpaCli(config);
|
|
24
|
+
server.registerTool('rego_capabilities', {
|
|
25
|
+
title: 'OPA capabilities',
|
|
26
|
+
description: 'Return OPA capabilities — the available builtins, future keywords, features, and WASM ABI versions. With `current: true`, returns the running OPA\'s capabilities. With `version: "v0.69.0"`, returns those of a specific version. With neither, lists available named versions.',
|
|
27
|
+
inputSchema: RegoCapabilitiesInput,
|
|
28
|
+
}, async ({ current, version }) => {
|
|
29
|
+
return withToolEnvelope(config, async () => {
|
|
30
|
+
if (current && version) {
|
|
31
|
+
return err('INVALID_INPUT', 'rego_capabilities accepts at most one of `current` or `version`.');
|
|
32
|
+
}
|
|
33
|
+
const result = await opa.capabilities({ current, version });
|
|
34
|
+
const subprocessFailure = mapSubprocessFailure(result, 'opa');
|
|
35
|
+
if (subprocessFailure)
|
|
36
|
+
return subprocessFailure;
|
|
37
|
+
if (result.exitCode !== 0) {
|
|
38
|
+
return err('INVALID_INPUT', 'opa capabilities exited non-zero — `version` is likely unrecognized.', { details: { stderr: result.stderr.trim(), version } });
|
|
39
|
+
}
|
|
40
|
+
// When listing versions (no flags), output is a newline-separated
|
|
41
|
+
// list of names. Otherwise, output is JSON.
|
|
42
|
+
const trimmed = result.stdout.trim();
|
|
43
|
+
if (!current && !version) {
|
|
44
|
+
const versions = trimmed.length === 0 ? [] : trimmed.split(/\r?\n/).filter(Boolean);
|
|
45
|
+
return ok({ versions });
|
|
46
|
+
}
|
|
47
|
+
const parsed = tryParseJson(trimmed);
|
|
48
|
+
if (parsed === undefined) {
|
|
49
|
+
return err('UNKNOWN_ERROR', 'opa capabilities produced no parseable JSON output.', {
|
|
50
|
+
details: { stdout: trimmed },
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
return ok(parsed);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../src/tools/authoring/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAEjG,MAAM,qBAAqB,GAAG;IAC5B,OAAO,EAAE,CAAC;SACP,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CACP,2FAA2F,CAC5F;IACH,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,2GAA2G,CAC5G;CACJ,CAAC;AAUF,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,MAAc;IACxE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACT,kRAAkR;QACpR,WAAW,EAAE,qBAAqB;KACnC,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAC7B,OAAO,gBAAgB,CAAyB,MAAM,EAAE,KAAK,IAAI,EAAE;YACjE,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;gBACvB,OAAO,GAAG,CACR,eAAe,EACf,kEAAkE,CACnE,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YAC5D,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC9D,IAAI,iBAAiB;gBAAE,OAAO,iBAAiB,CAAC;YAEhD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,GAAG,CACR,eAAe,EACf,sEAAsE,EACtE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,CACvD,CAAC;YACJ,CAAC;YAED,kEAAkE;YAClE,4CAA4C;YAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;gBACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACpF,OAAO,EAAE,CAAyB,EAAE,QAAQ,EAAE,CAAC,CAAC;YAClD,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAyB,OAAO,CAAC,CAAC;YAC7D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,GAAG,CAAC,eAAe,EAAE,qDAAqD,EAAE;oBACjF,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;iBAC7B,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAyB,MAAM,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Config } from '../../config.js';
|
|
3
|
+
interface CheckErrorRecord {
|
|
4
|
+
message?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
location?: {
|
|
7
|
+
file?: string;
|
|
8
|
+
row?: number;
|
|
9
|
+
col?: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface RegoCheckOutput {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
errors: CheckErrorRecord[];
|
|
15
|
+
}
|
|
16
|
+
export declare function registerRegoCheck(server: McpServer, config: Config): void;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/tools/authoring/check.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA6B9C,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA6DzE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rego_check` — type-check Rego using `opa check`.
|
|
3
|
+
*
|
|
4
|
+
* Returns `{ valid: true }` when the policy passes. On failure,
|
|
5
|
+
* returns the structured error report `opa check --format=json` writes
|
|
6
|
+
* to its stderr stream.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { OpaCli } from '../../lib/opa-cli.js';
|
|
10
|
+
import { err, ok } from '../../lib/errors.js';
|
|
11
|
+
import { mapSubprocessFailure, tryParseJson, validatePaths, withToolEnvelope, } from '../../lib/tool-helpers.js';
|
|
12
|
+
const RegoCheckInput = {
|
|
13
|
+
source: z.string().optional().describe('Inline Rego source. Mutually exclusive with `paths`.'),
|
|
14
|
+
paths: z
|
|
15
|
+
.array(z.string())
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Filesystem paths to check. Each path must be inside an allowed root (OPA_MCP_ALLOWED_PATHS).'),
|
|
18
|
+
strict: z
|
|
19
|
+
.boolean()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Enable strict mode — fail on unused vars, deprecated builtins, etc.'),
|
|
22
|
+
capabilities: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Path to a capabilities JSON file restricting allowed builtins.'),
|
|
26
|
+
schemaDir: z.string().optional().describe('Schema directory for input/data validation.'),
|
|
27
|
+
};
|
|
28
|
+
export function registerRegoCheck(server, config) {
|
|
29
|
+
const opa = new OpaCli(config);
|
|
30
|
+
server.registerTool('rego_check', {
|
|
31
|
+
title: 'Check Rego',
|
|
32
|
+
description: 'Type-check Rego with `opa check`. Returns `{ valid: true, errors: [] }` on success, or a list of structured diagnostics with file/line locations on failure. Provide either `source` for inline checking or `paths` for file/directory checking.',
|
|
33
|
+
inputSchema: RegoCheckInput,
|
|
34
|
+
}, async ({ source, paths, strict, capabilities, schemaDir }) => {
|
|
35
|
+
return withToolEnvelope(config, async () => {
|
|
36
|
+
if (!source && !paths?.length) {
|
|
37
|
+
return err('INVALID_INPUT', 'rego_check requires either `source` or at least one entry in `paths`.');
|
|
38
|
+
}
|
|
39
|
+
if (source && paths?.length) {
|
|
40
|
+
return err('INVALID_INPUT', 'rego_check does not accept both `source` and `paths` — pass one or the other.');
|
|
41
|
+
}
|
|
42
|
+
let resolvedPaths;
|
|
43
|
+
if (paths?.length) {
|
|
44
|
+
const validation = validatePaths(paths, config, { mustExist: true });
|
|
45
|
+
if (!validation.ok)
|
|
46
|
+
return validation.error;
|
|
47
|
+
resolvedPaths = validation.resolved;
|
|
48
|
+
}
|
|
49
|
+
const result = await opa.check({
|
|
50
|
+
source,
|
|
51
|
+
paths: resolvedPaths,
|
|
52
|
+
strict,
|
|
53
|
+
capabilities,
|
|
54
|
+
schemaDir,
|
|
55
|
+
});
|
|
56
|
+
const subprocessFailure = mapSubprocessFailure(result, 'opa');
|
|
57
|
+
if (subprocessFailure)
|
|
58
|
+
return subprocessFailure;
|
|
59
|
+
if (result.exitCode === 0) {
|
|
60
|
+
return ok({ valid: true, errors: [] });
|
|
61
|
+
}
|
|
62
|
+
// `opa check --format=json` writes diagnostics to stderr.
|
|
63
|
+
const parsed = tryParseJson(result.stderr);
|
|
64
|
+
if (!parsed) {
|
|
65
|
+
return err('INVALID_REGO', 'opa check exited non-zero but produced no parseable diagnostics.', { details: { stderr: result.stderr.trim(), stdout: result.stdout.trim() } });
|
|
66
|
+
}
|
|
67
|
+
return ok({ valid: false, errors: parsed.errors ?? [] });
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/tools/authoring/check.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,cAAc,GAAG;IACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IAC9F,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CACP,8FAA8F,CAC/F;IACH,MAAM,EAAE,CAAC;SACN,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,qEAAqE,CAAC;IAClF,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,gEAAgE,CAAC;IAC7E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;CACzF,CAAC;AAaF,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,MAAc;IACjE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ;QACE,KAAK,EAAE,YAAY;QACnB,WAAW,EACT,kPAAkP;QACpP,WAAW,EAAE,cAAc;KAC5B,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,EAAE;QAC3D,OAAO,gBAAgB,CAAkB,MAAM,EAAE,KAAK,IAAI,EAAE;YAC1D,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;gBAC9B,OAAO,GAAG,CACR,eAAe,EACf,uEAAuE,CACxE,CAAC;YACJ,CAAC;YACD,IAAI,MAAM,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;gBAC5B,OAAO,GAAG,CACR,eAAe,EACf,+EAA+E,CAChF,CAAC;YACJ,CAAC;YAED,IAAI,aAAmC,CAAC;YACxC,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC;gBAClB,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACrE,IAAI,CAAC,UAAU,CAAC,EAAE;oBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;gBAC5C,aAAa,GAAG,UAAU,CAAC,QAAQ,CAAC;YACtC,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC;gBAC7B,MAAM;gBACN,KAAK,EAAE,aAAa;gBACpB,MAAM;gBACN,YAAY;gBACZ,SAAS;aACV,CAAC,CAAC;YAEH,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC9D,IAAI,iBAAiB;gBAAE,OAAO,iBAAiB,CAAC;YAEhD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,EAAE,CAAkB,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;YAC1D,CAAC;YAED,0DAA0D;YAC1D,MAAM,MAAM,GAAG,YAAY,CAAkC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,OAAO,GAAG,CACR,cAAc,EACd,kEAAkE,EAClE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,CAC5E,CAAC;YACJ,CAAC;YACD,OAAO,EAAE,CAAkB,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Config } from '../../config.js';
|
|
3
|
+
export interface RegoDepsOutput {
|
|
4
|
+
base?: unknown[];
|
|
5
|
+
virtual?: unknown[];
|
|
6
|
+
}
|
|
7
|
+
export declare function registerRegoDeps(server: McpServer, config: Config): void;
|
|
8
|
+
//# sourceMappingURL=deps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/tools/authoring/deps.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAuB9C,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAsCxE"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rego_deps` — static dependency analysis for a Rego ref.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `opa deps`. Given a target like `data.example.allow`, returns
|
|
5
|
+
* the base (input/data) and virtual (rule) document references the
|
|
6
|
+
* target depends on. Helpful for impact analysis when a data shape
|
|
7
|
+
* changes.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { OpaCli } from '../../lib/opa-cli.js';
|
|
11
|
+
import { err, ok } from '../../lib/errors.js';
|
|
12
|
+
import { mapSubprocessFailure, tryParseJson, validatePaths, withToolEnvelope, } from '../../lib/tool-helpers.js';
|
|
13
|
+
const RegoDepsInput = {
|
|
14
|
+
paths: z
|
|
15
|
+
.array(z.string())
|
|
16
|
+
.min(1)
|
|
17
|
+
.describe('Policy / data paths to load before computing dependencies. Each must be inside an allowed root (OPA_MCP_ALLOWED_PATHS).'),
|
|
18
|
+
ref: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1)
|
|
21
|
+
.describe('Reference to compute dependencies for, e.g. "data.example.allow".'),
|
|
22
|
+
};
|
|
23
|
+
export function registerRegoDeps(server, config) {
|
|
24
|
+
const opa = new OpaCli(config);
|
|
25
|
+
server.registerTool('rego_deps', {
|
|
26
|
+
title: 'Rego dependency analysis',
|
|
27
|
+
description: 'Static dependency analysis for a Rego reference. Given a target ref like "data.example.allow", returns the base document references (input/data leaves) and virtual document references (rules) it depends on, transitively.',
|
|
28
|
+
inputSchema: RegoDepsInput,
|
|
29
|
+
}, async ({ paths, ref }) => {
|
|
30
|
+
return withToolEnvelope(config, async () => {
|
|
31
|
+
const validation = validatePaths(paths, config, { mustExist: true });
|
|
32
|
+
if (!validation.ok)
|
|
33
|
+
return validation.error;
|
|
34
|
+
const result = await opa.deps({ paths: validation.resolved, ref });
|
|
35
|
+
const subprocessFailure = mapSubprocessFailure(result, 'opa');
|
|
36
|
+
if (subprocessFailure)
|
|
37
|
+
return subprocessFailure;
|
|
38
|
+
if (result.exitCode !== 0) {
|
|
39
|
+
return err('INVALID_REGO', 'opa deps exited non-zero — the policy did not compile or the ref is invalid.', { details: { stderr: result.stderr.trim(), ref } });
|
|
40
|
+
}
|
|
41
|
+
const parsed = tryParseJson(result.stdout);
|
|
42
|
+
if (parsed === undefined) {
|
|
43
|
+
return err('UNKNOWN_ERROR', 'opa deps produced no parseable JSON output.', {
|
|
44
|
+
details: { stdout: result.stdout.trim() },
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return ok(parsed);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=deps.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../src/tools/authoring/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,aAAa,GAAG;IACpB,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,yHAAyH,CAC1H;IACH,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,mEAAmE,CAAC;CACjF,CAAC;AAOF,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAc;IAChE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,8NAA8N;QAChO,WAAW,EAAE,aAAa;KAC3B,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE;QACvB,OAAO,gBAAgB,CAAiB,MAAM,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAE5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YACnE,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC9D,IAAI,iBAAiB;gBAAE,OAAO,iBAAiB,CAAC;YAEhD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,GAAG,CACR,cAAc,EACd,8EAA8E,EAC9E,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CACnD,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAiB,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,GAAG,CAAC,eAAe,EAAE,6CAA6C,EAAE;oBACzE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;iBAC1C,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAiB,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Config } from '../../config.js';
|
|
3
|
+
export interface RegoFormatOutput {
|
|
4
|
+
formatted: string;
|
|
5
|
+
changed: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function registerRegoFormat(server: McpServer, config: Config): void;
|
|
8
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/tools/authoring/format.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAS9C,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA2C1E"}
|