@aporthq/aport-agent-guardrails 1.0.8
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/LICENSE +217 -0
- package/README.md +481 -0
- package/bin/agent-guardrails +133 -0
- package/bin/aport-create-passport.sh +444 -0
- package/bin/aport-cursor-hook.sh +90 -0
- package/bin/aport-guardrail-api.sh +108 -0
- package/bin/aport-guardrail-bash.sh +394 -0
- package/bin/aport-guardrail-v2.sh +5 -0
- package/bin/aport-guardrail.sh +5 -0
- package/bin/aport-resolve-paths.sh +71 -0
- package/bin/aport-status.sh +276 -0
- package/bin/frameworks/crewai.sh +49 -0
- package/bin/frameworks/cursor.sh +95 -0
- package/bin/frameworks/langchain.sh +48 -0
- package/bin/frameworks/n8n.sh +36 -0
- package/bin/frameworks/openclaw.sh +19 -0
- package/bin/lib/allowlist.sh +18 -0
- package/bin/lib/common.sh +28 -0
- package/bin/lib/config.sh +46 -0
- package/bin/lib/constants.sh +232 -0
- package/bin/lib/detect.sh +65 -0
- package/bin/lib/error.sh +269 -0
- package/bin/lib/passport.sh +19 -0
- package/bin/lib/templates/.gitkeep +1 -0
- package/bin/lib/templates/config.yaml +6 -0
- package/bin/lib/validation.sh +206 -0
- package/bin/openclaw +660 -0
- package/docs/ADDING_A_FRAMEWORK.md +87 -0
- package/docs/AGENTS.md.example +40 -0
- package/docs/CODE_REVIEW.md +192 -0
- package/docs/DEPLOYMENT_READINESS.md +81 -0
- package/docs/FAQ_SECURITY_SCANNERS.md +373 -0
- package/docs/FRAMEWORK_ROADMAP.md +41 -0
- package/docs/HOSTED_PASSPORT_SETUP.md +362 -0
- package/docs/IMPLEMENTING_YOUR_OWN_EVALUATOR.md +433 -0
- package/docs/OPENCLAW_COMPATIBILITY.md +73 -0
- package/docs/OPENCLAW_LOCAL_INTEGRATION.md +596 -0
- package/docs/OPENCLAW_TOOLS_AND_POLICIES.md +54 -0
- package/docs/QUICKSTART.md +470 -0
- package/docs/QUICKSTART_OPENCLAW_PLUGIN.md +470 -0
- package/docs/README.md +28 -0
- package/docs/RELEASE.md +87 -0
- package/docs/REPO_LAYOUT.md +47 -0
- package/docs/SKILLS_ECOSYSTEM_ANALYSIS_FEB17.md +1260 -0
- package/docs/TOOL_POLICY_MAPPING.md +46 -0
- package/docs/UPGRADE.md +46 -0
- package/docs/VERIFICATION_METHODS.md +97 -0
- package/docs/assets/README.md +8 -0
- package/docs/assets/porter.svg +54 -0
- package/docs/development/ERROR_CODES.md +616 -0
- package/docs/frameworks/GITHUB_ISSUE_PROPOSALS.md +1105 -0
- package/docs/frameworks/crewai.md +114 -0
- package/docs/frameworks/cursor.md +159 -0
- package/docs/frameworks/langchain.md +72 -0
- package/docs/frameworks/n8n.md +40 -0
- package/docs/frameworks/openclaw.md +40 -0
- package/docs/launch/ADD_APORT_AWESOME_LISTS_INSTRUCTIONS.md +146 -0
- package/docs/launch/ANNOUNCEMENT_GUIDE.md +266 -0
- package/docs/launch/AWESOME_REPOS.md +53 -0
- package/docs/launch/CURSOR_VSCODE_HOOKS_RESEARCH.md +77 -0
- package/docs/launch/DEMO_TERMINAL_OUTPUT.txt +48 -0
- package/docs/launch/DRY_AND_PLAN_CHECKLIST.md +47 -0
- package/docs/launch/EVIDENCE_README.md +61 -0
- package/docs/launch/EVIDENCE_TERMINAL_CAPTURE.txt +10 -0
- package/docs/launch/FRAMEWORK_SUPPORT_PLAN.md +1640 -0
- package/docs/launch/LAUNCH_READINESS_CHECKLIST.md +237 -0
- package/docs/launch/LAUNCH_STRATEGY_SUMMARY.md +464 -0
- package/docs/launch/OPENCLAW_FEEDBACK_AND_FIXES.md +85 -0
- package/docs/launch/POST_1_VALENTINE_IMPROVED.md +233 -0
- package/docs/launch/POST_2_GUARDRAIL_IMPROVED.md +369 -0
- package/docs/launch/PRE_LAUNCH_FIXES.md +766 -0
- package/docs/launch/QUICK_LAUNCH_CHECKLIST.md +400 -0
- package/docs/launch/READINESS_SUMMARY.md +262 -0
- package/docs/launch/README.md +68 -0
- package/docs/launch/USER_STORIES.md +327 -0
- package/docs/launch/scripts/add-aport-awesome-pr.sh +69 -0
- package/docs/operations/MONITORING.md +588 -0
- package/docs/reviews/2026-02-18-staff-review.md +268 -0
- package/extensions/openclaw-aport/README.md +415 -0
- package/extensions/openclaw-aport/index.js +625 -0
- package/extensions/openclaw-aport/openclaw-aport.js +7 -0
- package/extensions/openclaw-aport/openclaw.plugin.json +46 -0
- package/extensions/openclaw-aport/package.json +36 -0
- package/extensions/openclaw-aport/test.js +307 -0
- package/external/aport-policies/README.md +363 -0
- package/external/aport-policies/agent.session.create.v1/README.md +345 -0
- package/external/aport-policies/agent.session.create.v1/policy.json +162 -0
- package/external/aport-policies/agent.tool.register.v1/README.md +361 -0
- package/external/aport-policies/agent.tool.register.v1/policy.json +172 -0
- package/external/aport-policies/code.release.publish.v1/README.md +51 -0
- package/external/aport-policies/code.release.publish.v1/policy.json +121 -0
- package/external/aport-policies/code.repository.merge.v1/README.md +287 -0
- package/external/aport-policies/code.repository.merge.v1/express.example.js +332 -0
- package/external/aport-policies/code.repository.merge.v1/fastapi.example.py +370 -0
- package/external/aport-policies/code.repository.merge.v1/policy.json +162 -0
- package/external/aport-policies/data.export.create.v1/README.md +226 -0
- package/external/aport-policies/data.export.create.v1/express.example.js +172 -0
- package/external/aport-policies/data.export.create.v1/fastapi.example.py +165 -0
- package/external/aport-policies/data.export.create.v1/policy.json +133 -0
- package/external/aport-policies/data.report.ingest.v1/README.md +134 -0
- package/external/aport-policies/data.report.ingest.v1/express.example.js +105 -0
- package/external/aport-policies/data.report.ingest.v1/minimal-example.js +68 -0
- package/external/aport-policies/data.report.ingest.v1/policy.json +174 -0
- package/external/aport-policies/finance.crypto.trade.v1/README.md +146 -0
- package/external/aport-policies/finance.crypto.trade.v1/express.example.js +109 -0
- package/external/aport-policies/finance.crypto.trade.v1/minimal-example.js +65 -0
- package/external/aport-policies/finance.crypto.trade.v1/policy.json +176 -0
- package/external/aport-policies/finance.payment.charge.v1/README.md +326 -0
- package/external/aport-policies/finance.payment.charge.v1/express.example.js +250 -0
- package/external/aport-policies/finance.payment.charge.v1/fastapi.example.py +227 -0
- package/external/aport-policies/finance.payment.charge.v1/minimal-example.js +64 -0
- package/external/aport-policies/finance.payment.charge.v1/policy.json +224 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.template.json +40 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/payments-charge-policy.test.js +817 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/test_payments_charge_policy.py +486 -0
- package/external/aport-policies/finance.payment.payout.v1/README.md +78 -0
- package/external/aport-policies/finance.payment.payout.v1/policy.json +181 -0
- package/external/aport-policies/finance.payment.refund.v1/README.md +275 -0
- package/external/aport-policies/finance.payment.refund.v1/express.example.js +167 -0
- package/external/aport-policies/finance.payment.refund.v1/fastapi.example.py +136 -0
- package/external/aport-policies/finance.payment.refund.v1/minimal-example.js +183 -0
- package/external/aport-policies/finance.payment.refund.v1/policy.json +216 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/refunds-policy.test.js +924 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/test_refunds_policy.py +778 -0
- package/external/aport-policies/finance.transaction.execute.v1/README.md +309 -0
- package/external/aport-policies/finance.transaction.execute.v1/express.example.js +261 -0
- package/external/aport-policies/finance.transaction.execute.v1/fastapi.example.py +231 -0
- package/external/aport-policies/finance.transaction.execute.v1/minimal-example.js +78 -0
- package/external/aport-policies/finance.transaction.execute.v1/policy.json +189 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.template.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/test_transactions_policy.py +214 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/transactions-policy.test.js +306 -0
- package/external/aport-policies/governance.data.access.v1/README.md +292 -0
- package/external/aport-policies/governance.data.access.v1/express.example.js +321 -0
- package/external/aport-policies/governance.data.access.v1/fastapi.example.py +279 -0
- package/external/aport-policies/governance.data.access.v1/minimal-example.js +65 -0
- package/external/aport-policies/governance.data.access.v1/policy.json +208 -0
- package/external/aport-policies/governance.data.access.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/data-access-policy.test.js +308 -0
- package/external/aport-policies/governance.data.access.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.instance.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.template.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/test_data_access_policy.py +214 -0
- package/external/aport-policies/legal.contract.review.v1/README.md +109 -0
- package/external/aport-policies/legal.contract.review.v1/policy.json +378 -0
- package/external/aport-policies/legal.contract.review.v1/tests/legal-contract-review-policy.test.js +609 -0
- package/external/aport-policies/legal.contract.review.v1/tests/passport.template.json +49 -0
- package/external/aport-policies/mcp.tool.execute.v1/README.md +301 -0
- package/external/aport-policies/mcp.tool.execute.v1/policy.json +141 -0
- package/external/aport-policies/messaging.message.send.v1/README.md +230 -0
- package/external/aport-policies/messaging.message.send.v1/express.example.js +183 -0
- package/external/aport-policies/messaging.message.send.v1/fastapi.example.py +193 -0
- package/external/aport-policies/messaging.message.send.v1/policy.json +144 -0
- package/external/aport-policies/policy-template.json +107 -0
- package/external/aport-policies/system.command.execute.v1/README.md +275 -0
- package/external/aport-policies/system.command.execute.v1/policy.json +146 -0
- package/external/aport-spec/CONTRIBUTING.md +273 -0
- package/external/aport-spec/LICENSE +21 -0
- package/external/aport-spec/README.md +168 -0
- package/external/aport-spec/conformance/README.md +294 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/allow_users.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/deny_pii.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/allow_users.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/deny_pii.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/passports/template.json +29 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/allow_50usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_150usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_currency.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/allow_50usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_150usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_currency.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/passports/template.json +42 -0
- package/external/aport-spec/conformance/package.json +44 -0
- package/external/aport-spec/conformance/pnpm-lock.yaml +642 -0
- package/external/aport-spec/conformance/src/cases.ts +371 -0
- package/external/aport-spec/conformance/src/ed25519.ts +167 -0
- package/external/aport-spec/conformance/src/jcs.ts +85 -0
- package/external/aport-spec/conformance/src/runner.ts +533 -0
- package/external/aport-spec/conformance/src/validators.ts +185 -0
- package/external/aport-spec/conformance/test-runner.js +315 -0
- package/external/aport-spec/conformance/tsconfig.json +21 -0
- package/external/aport-spec/error-schema.json +192 -0
- package/external/aport-spec/index.json +12 -0
- package/external/aport-spec/integrations/clawmoat/README.md +12 -0
- package/external/aport-spec/integrations/shield/README.md +245 -0
- package/external/aport-spec/integrations/shield/adapters/index.js +116 -0
- package/external/aport-spec/integrations/shield/adapters/system-command-execute.js +133 -0
- package/external/aport-spec/integrations/shield/test/README.md +58 -0
- package/external/aport-spec/integrations/shield/test/shield.md +40 -0
- package/external/aport-spec/integrations/shield/test/test-shield-to-verify.js +274 -0
- package/external/aport-spec/metrics-schema.json +504 -0
- package/external/aport-spec/oap/CHANGELOG.md +54 -0
- package/external/aport-spec/oap/VERSION.md +40 -0
- package/external/aport-spec/oap/capability-registry.md +229 -0
- package/external/aport-spec/oap/conformance.md +257 -0
- package/external/aport-spec/oap/decision-schema.json +114 -0
- package/external/aport-spec/oap/examples/context.refund.usd.50.json +9 -0
- package/external/aport-spec/oap/examples/decision.allow.sample.json +20 -0
- package/external/aport-spec/oap/examples/decision.deny.sample.json +23 -0
- package/external/aport-spec/oap/examples/passport.instance.v1.json +50 -0
- package/external/aport-spec/oap/examples/passport.template.v1.json +71 -0
- package/external/aport-spec/oap/oap-spec.md +426 -0
- package/external/aport-spec/oap/passport-schema.json +396 -0
- package/external/aport-spec/oap/security.md +213 -0
- package/external/aport-spec/oap/vc/context-oap-v1.jsonld +137 -0
- package/external/aport-spec/oap/vc/examples/oap-decision-vc.json +37 -0
- package/external/aport-spec/oap/vc/examples/oap-passport-vc.json +68 -0
- package/external/aport-spec/oap/vc/tools/INTEGRATION.md +375 -0
- package/external/aport-spec/oap/vc/tools/README.md +278 -0
- package/external/aport-spec/oap/vc/tools/examples/decision-to-vc.js +66 -0
- package/external/aport-spec/oap/vc/tools/examples/passport-to-vc.js +83 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-decision.js +77 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-passport.js +94 -0
- package/external/aport-spec/oap/vc/tools/package.json +38 -0
- package/external/aport-spec/oap/vc/tools/pnpm-lock.yaml +472 -0
- package/external/aport-spec/oap/vc/tools/src/cli.ts +226 -0
- package/external/aport-spec/oap/vc/tools/src/crypto-utils.ts +427 -0
- package/external/aport-spec/oap/vc/tools/src/index.ts +653 -0
- package/external/aport-spec/oap/vc/tools/src/test.ts +148 -0
- package/external/aport-spec/oap/vc/tools/src/vp.ts +382 -0
- package/external/aport-spec/oap/vc/tools/test-simple.js +214 -0
- package/external/aport-spec/oap/vc/tools/tsconfig.json +19 -0
- package/external/aport-spec/oap/vc/vc-mapping.md +443 -0
- package/external/aport-spec/passport-schema.json +586 -0
- package/external/aport-spec/rate-limiting.md +136 -0
- package/external/aport-spec/transport-profile.md +325 -0
- package/external/aport-spec/webhook-spec.md +314 -0
- package/package.json +70 -0
- package/skills/aport-agent-guardrail/SKILL.md +314 -0
- package/src/evaluator.js +252 -0
- package/src/server/index.js +72 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# MCP Tool Execution Policy v1
|
|
2
|
+
|
|
3
|
+
**Policy ID:** `mcp.tool.execute.v1`
|
|
4
|
+
**Status:** Active
|
|
5
|
+
**Min Assurance:** L1
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The MCP Tool Execution Policy provides pre-action governance for Model Context Protocol (MCP) tool execution by AI agents. This policy enforces server allowlists, tool restrictions, parameter validation, and rate limits to ensure secure MCP integration.
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
- **Multi-Tool AI Agents**: Executing tools across multiple MCP servers
|
|
14
|
+
- **GitHub Integration**: Using GitHub MCP tools (pull requests, issues, etc.)
|
|
15
|
+
- **Database Operations**: Executing database queries via MCP
|
|
16
|
+
- **API Integration**: Calling external APIs through MCP tools
|
|
17
|
+
- **Development Workflows**: Automating development tasks with MCP
|
|
18
|
+
|
|
19
|
+
## Required Capabilities
|
|
20
|
+
|
|
21
|
+
- `mcp.tool.execute`
|
|
22
|
+
|
|
23
|
+
## Required Limits
|
|
24
|
+
|
|
25
|
+
- `allowed_servers` (array of strings): Allowlist of MCP server URLs
|
|
26
|
+
- `max_calls_per_minute` (integer): Maximum tool calls per minute
|
|
27
|
+
|
|
28
|
+
## Optional Limits
|
|
29
|
+
|
|
30
|
+
- `allowed_tools` (array of strings): Specific tools allowed
|
|
31
|
+
- `allowed_tool_prefixes` (array of strings): Tool name prefixes allowed
|
|
32
|
+
- `blocked_tools` (array of strings): Specific tools blocked
|
|
33
|
+
- `max_timeout` (integer): Maximum tool execution timeout
|
|
34
|
+
- `max_parameter_size` (integer): Maximum parameter size in bytes
|
|
35
|
+
- `require_session_tracking` (boolean): Require session IDs for all calls
|
|
36
|
+
|
|
37
|
+
## Context Schema
|
|
38
|
+
|
|
39
|
+
### Required Fields
|
|
40
|
+
|
|
41
|
+
- `server` (string): MCP server URL
|
|
42
|
+
- `tool` (string): MCP tool name
|
|
43
|
+
- `parameters` (object): Tool-specific parameters
|
|
44
|
+
|
|
45
|
+
### Optional Fields
|
|
46
|
+
|
|
47
|
+
- `session_id` (string): MCP session identifier
|
|
48
|
+
- `timeout` (integer): Tool execution timeout
|
|
49
|
+
- `context` (object): Additional context
|
|
50
|
+
- `user_id` (string): User on whose behalf tool is executed
|
|
51
|
+
- `mcp_servers`, `mcp_tools`, `mcp_session`: Audit trail fields
|
|
52
|
+
|
|
53
|
+
## Evaluation Rules
|
|
54
|
+
|
|
55
|
+
1. **passport_status_active**: Passport must be active
|
|
56
|
+
2. **mcp_capability**: Agent must have `mcp.tool.execute` capability
|
|
57
|
+
3. **server_allowlist**: MCP server must be in allowed list
|
|
58
|
+
4. **tool_allowlist**: Tool must be allowed (exact match or prefix match)
|
|
59
|
+
5. **rate_limit**: Calls per minute must not exceed limit
|
|
60
|
+
6. **timeout_limit**: Timeout must not exceed maximum
|
|
61
|
+
7. **parameter_size_limit**: Parameters must not exceed size limit
|
|
62
|
+
|
|
63
|
+
## Example Passport Limits
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"limits": {
|
|
68
|
+
"mcp.tool.execute": {
|
|
69
|
+
"allowed_servers": [
|
|
70
|
+
"https://mcp.github.com",
|
|
71
|
+
"https://mcp.stripe.com",
|
|
72
|
+
"https://mcp.internal.company.com"
|
|
73
|
+
],
|
|
74
|
+
"allowed_tools": [
|
|
75
|
+
"github.pull_requests.create",
|
|
76
|
+
"github.pull_requests.merge",
|
|
77
|
+
"github.issues.create",
|
|
78
|
+
"stripe.customers.create",
|
|
79
|
+
"stripe.charges.create"
|
|
80
|
+
],
|
|
81
|
+
"allowed_tool_prefixes": [
|
|
82
|
+
"github.pull_requests.",
|
|
83
|
+
"github.issues.",
|
|
84
|
+
"stripe.customers."
|
|
85
|
+
],
|
|
86
|
+
"blocked_tools": [
|
|
87
|
+
"github.repos.delete",
|
|
88
|
+
"stripe.subscriptions.cancel"
|
|
89
|
+
],
|
|
90
|
+
"max_calls_per_minute": 60,
|
|
91
|
+
"max_timeout": 120,
|
|
92
|
+
"max_parameter_size": 102400,
|
|
93
|
+
"require_session_tracking": true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Example Request Context
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"server": "https://mcp.github.com",
|
|
104
|
+
"tool": "github.pull_requests.create",
|
|
105
|
+
"parameters": {
|
|
106
|
+
"owner": "myorg",
|
|
107
|
+
"repo": "myrepo",
|
|
108
|
+
"title": "Add new feature",
|
|
109
|
+
"head": "feature-branch",
|
|
110
|
+
"base": "main",
|
|
111
|
+
"body": "This PR adds a new feature"
|
|
112
|
+
},
|
|
113
|
+
"session_id": "sess_abc123",
|
|
114
|
+
"timeout": 60,
|
|
115
|
+
"user_id": "user_xyz789"
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Example Decision (Allow)
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"decision_id": "dec_mcp001",
|
|
124
|
+
"policy_id": "mcp.tool.execute.v1",
|
|
125
|
+
"passport_id": "pass_abc123",
|
|
126
|
+
"owner_id": "org_12345",
|
|
127
|
+
"assurance_level": "L1",
|
|
128
|
+
"allow": true,
|
|
129
|
+
"reasons": [{
|
|
130
|
+
"code": "oap.allowed",
|
|
131
|
+
"message": "All policy checks passed"
|
|
132
|
+
}],
|
|
133
|
+
"issued_at": "2026-02-14T22:00:00Z",
|
|
134
|
+
"expires_at": "2026-02-14T22:00:30Z",
|
|
135
|
+
"passport_digest": "sha256:...",
|
|
136
|
+
"signature": "ed25519:...",
|
|
137
|
+
"kid": "oap:registry:key-2026-02"
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Example Decision (Deny - Tool Not Allowed)
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"decision_id": "dec_mcp002",
|
|
146
|
+
"policy_id": "mcp.tool.execute.v1",
|
|
147
|
+
"passport_id": "pass_abc123",
|
|
148
|
+
"owner_id": "org_12345",
|
|
149
|
+
"assurance_level": "L1",
|
|
150
|
+
"allow": false,
|
|
151
|
+
"reasons": [{
|
|
152
|
+
"code": "oap.tool_not_allowed",
|
|
153
|
+
"message": "MCP tool 'github.repos.delete' is not in allowed list"
|
|
154
|
+
}],
|
|
155
|
+
"issued_at": "2026-02-14T22:00:00Z",
|
|
156
|
+
"expires_at": "2026-02-14T22:00:30Z",
|
|
157
|
+
"passport_digest": "sha256:...",
|
|
158
|
+
"signature": "ed25519:...",
|
|
159
|
+
"kid": "oap:registry:key-2026-02"
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Security Best Practices
|
|
164
|
+
|
|
165
|
+
1. **Server Allowlist**: Only allow trusted MCP servers
|
|
166
|
+
2. **Tool Restrictions**: Use granular tool permissions (not wildcards)
|
|
167
|
+
3. **Rate Limiting**: Prevent abuse with conservative rate limits
|
|
168
|
+
4. **Session Tracking**: Require session IDs for audit trails
|
|
169
|
+
5. **Parameter Validation**: Enforce parameter size limits
|
|
170
|
+
6. **Tool Prefixes**: Use prefixes for tool families (e.g., "github.pull_requests.")
|
|
171
|
+
7. **Block Dangerous Tools**: Explicitly block destructive operations
|
|
172
|
+
8. **Progressive Limits**: Start strict and relax based on behavior
|
|
173
|
+
9. **Status Webhooks**: Subscribe for instant revocation
|
|
174
|
+
10. **Audit Logging**: Log all MCP tool calls with parameters
|
|
175
|
+
|
|
176
|
+
## Error Codes
|
|
177
|
+
|
|
178
|
+
- `oap.passport_suspended`: Passport is not active
|
|
179
|
+
- `oap.unknown_capability`: Missing mcp.tool.execute capability
|
|
180
|
+
- `oap.server_not_allowed`: MCP server not in allowlist
|
|
181
|
+
- `oap.tool_not_allowed`: Tool not in allowlist
|
|
182
|
+
- `oap.rate_limit_exceeded`: Too many calls per minute
|
|
183
|
+
- `oap.timeout_exceeded`: Timeout exceeds maximum
|
|
184
|
+
- `oap.parameter_size_exceeded`: Parameters too large
|
|
185
|
+
|
|
186
|
+
## Integration Examples
|
|
187
|
+
|
|
188
|
+
### TypeScript (MCP Client)
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { MCPClient } from '@modelcontextprotocol/client';
|
|
192
|
+
import axios from 'axios';
|
|
193
|
+
|
|
194
|
+
async function executeMCPTool(
|
|
195
|
+
passport: Passport,
|
|
196
|
+
server: string,
|
|
197
|
+
tool: string,
|
|
198
|
+
parameters: Record<string, any>
|
|
199
|
+
) {
|
|
200
|
+
const context = {
|
|
201
|
+
server,
|
|
202
|
+
tool,
|
|
203
|
+
parameters,
|
|
204
|
+
session_id: generateSessionId(),
|
|
205
|
+
timeout: 60
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Check policy
|
|
209
|
+
const decision = await axios.post('https://api.aport.io/v1/decide', {
|
|
210
|
+
passport_id: passport.passport_id,
|
|
211
|
+
policy_id: 'mcp.tool.execute.v1',
|
|
212
|
+
context
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (!decision.data.allow) {
|
|
216
|
+
throw new Error(`MCP tool blocked: ${decision.data.reasons[0].message}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Execute MCP tool
|
|
220
|
+
const client = new MCPClient(server);
|
|
221
|
+
const result = await client.callTool(tool, parameters, {
|
|
222
|
+
timeout: context.timeout * 1000
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return result;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Python (MCP Integration)
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
import httpx
|
|
233
|
+
from mcp_client import MCPClient
|
|
234
|
+
|
|
235
|
+
async def execute_mcp_tool(
|
|
236
|
+
passport: dict,
|
|
237
|
+
server: str,
|
|
238
|
+
tool: str,
|
|
239
|
+
parameters: dict
|
|
240
|
+
):
|
|
241
|
+
context = {
|
|
242
|
+
"server": server,
|
|
243
|
+
"tool": tool,
|
|
244
|
+
"parameters": parameters,
|
|
245
|
+
"session_id": generate_session_id(),
|
|
246
|
+
"timeout": 60
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# Check policy
|
|
250
|
+
async with httpx.AsyncClient() as client:
|
|
251
|
+
response = await client.post(
|
|
252
|
+
"https://api.aport.io/v1/decide",
|
|
253
|
+
json={
|
|
254
|
+
"passport_id": passport["passport_id"],
|
|
255
|
+
"policy_id": "mcp.tool.execute.v1",
|
|
256
|
+
"context": context
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
decision = response.json()
|
|
260
|
+
|
|
261
|
+
if not decision["allow"]:
|
|
262
|
+
raise PermissionError(f"MCP tool blocked: {decision['reasons'][0]['message']}")
|
|
263
|
+
|
|
264
|
+
# Execute MCP tool
|
|
265
|
+
mcp_client = MCPClient(server)
|
|
266
|
+
result = await mcp_client.call_tool(
|
|
267
|
+
tool,
|
|
268
|
+
parameters,
|
|
269
|
+
timeout=context["timeout"]
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
return result
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## MCP Tool Name Conventions
|
|
276
|
+
|
|
277
|
+
MCP tools follow the convention: `<service>.<resource>.<action>`
|
|
278
|
+
|
|
279
|
+
Examples:
|
|
280
|
+
- `github.pull_requests.create`
|
|
281
|
+
- `github.pull_requests.merge`
|
|
282
|
+
- `github.issues.create`
|
|
283
|
+
- `stripe.customers.create`
|
|
284
|
+
- `stripe.charges.refund`
|
|
285
|
+
- `database.queries.execute`
|
|
286
|
+
- `api.endpoints.call`
|
|
287
|
+
|
|
288
|
+
Use `allowed_tool_prefixes` for tool families:
|
|
289
|
+
- `github.pull_requests.*` → All PR operations
|
|
290
|
+
- `github.issues.*` → All issue operations
|
|
291
|
+
- `stripe.customers.*` → All customer operations
|
|
292
|
+
|
|
293
|
+
## Version History
|
|
294
|
+
|
|
295
|
+
- **v1.0.0** (2026-02-14): Initial release
|
|
296
|
+
|
|
297
|
+
## References
|
|
298
|
+
|
|
299
|
+
- [Model Context Protocol Specification](https://modelcontextprotocol.io)
|
|
300
|
+
- [OAP Specification](https://github.com/aporthq/aport-spec)
|
|
301
|
+
- [MCP Tool Registry](https://mcp.tools)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mcp.tool.execute.v1",
|
|
3
|
+
"name": "MCP Tool Execution Policy",
|
|
4
|
+
"description": "Pre-action governance for Model Context Protocol (MCP) tool execution. Enforces server allowlists, tool restrictions, parameter validation, and rate limits for secure MCP integration.",
|
|
5
|
+
"version": "1.0.0",
|
|
6
|
+
"status": "active",
|
|
7
|
+
"requires_capabilities": ["mcp.tool.execute"],
|
|
8
|
+
"min_assurance": "L0",
|
|
9
|
+
"limits_required": ["allowed_servers", "max_calls_per_minute"],
|
|
10
|
+
"required_fields": ["server", "tool", "parameters"],
|
|
11
|
+
"optional_fields": ["session_id", "timeout", "context", "user_id"],
|
|
12
|
+
"enforcement": {
|
|
13
|
+
"server_allowlist_enforced": true,
|
|
14
|
+
"tool_allowlist_enforced": true,
|
|
15
|
+
"rate_limits_enforced": true,
|
|
16
|
+
"parameter_validation_enforced": true,
|
|
17
|
+
"session_tracking_enforced": false
|
|
18
|
+
},
|
|
19
|
+
"mcp": {
|
|
20
|
+
"require_allowlisted_if_present": true
|
|
21
|
+
},
|
|
22
|
+
"advice": [
|
|
23
|
+
"Use server allowlists to prevent unauthorized MCP connections",
|
|
24
|
+
"Restrict tools to minimum required for agent functionality",
|
|
25
|
+
"Enforce rate limits to prevent MCP server abuse",
|
|
26
|
+
"Validate tool parameters against expected schemas",
|
|
27
|
+
"Log all MCP tool calls for Verifiable Attestation",
|
|
28
|
+
"Use session tracking for cross-tool audit trails",
|
|
29
|
+
"Subscribe to status webhooks for instant suspend",
|
|
30
|
+
"Implement progressive limits for new MCP integrations",
|
|
31
|
+
"Monitor MCP usage patterns for anomalies",
|
|
32
|
+
"Consider tool-specific parameter restrictions"
|
|
33
|
+
],
|
|
34
|
+
"required_context": {
|
|
35
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
36
|
+
"type": "object",
|
|
37
|
+
"required": ["server", "tool", "parameters"],
|
|
38
|
+
"properties": {
|
|
39
|
+
"server": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"format": "uri",
|
|
42
|
+
"description": "MCP server URL (e.g., 'https://mcp.github.com')"
|
|
43
|
+
},
|
|
44
|
+
"tool": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"minLength": 1,
|
|
47
|
+
"maxLength": 200,
|
|
48
|
+
"pattern": "^[a-zA-Z0-9._-]+$",
|
|
49
|
+
"description": "MCP tool name (e.g., 'github.pull_requests.create')"
|
|
50
|
+
},
|
|
51
|
+
"parameters": {
|
|
52
|
+
"type": "object",
|
|
53
|
+
"description": "Tool-specific parameters"
|
|
54
|
+
},
|
|
55
|
+
"session_id": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"description": "MCP session identifier for tracking"
|
|
58
|
+
},
|
|
59
|
+
"timeout": {
|
|
60
|
+
"type": "integer",
|
|
61
|
+
"minimum": 1,
|
|
62
|
+
"maximum": 300,
|
|
63
|
+
"description": "Tool execution timeout in seconds"
|
|
64
|
+
},
|
|
65
|
+
"context": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"description": "Additional context for tool execution"
|
|
68
|
+
},
|
|
69
|
+
"user_id": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "User on whose behalf the tool is being executed"
|
|
72
|
+
},
|
|
73
|
+
"mcp_servers": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "string" },
|
|
76
|
+
"description": "Additional MCP servers being used"
|
|
77
|
+
},
|
|
78
|
+
"mcp_tools": {
|
|
79
|
+
"type": "array",
|
|
80
|
+
"items": { "type": "string" },
|
|
81
|
+
"description": "Additional MCP tools being used"
|
|
82
|
+
},
|
|
83
|
+
"mcp_session": {
|
|
84
|
+
"type": "string",
|
|
85
|
+
"description": "MCP session identifier for audit trail"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"evaluation_rules_version": "1.0",
|
|
90
|
+
"evaluation_rules": [
|
|
91
|
+
{
|
|
92
|
+
"name": "server_allowlist",
|
|
93
|
+
"type": "expression",
|
|
94
|
+
"condition": "limits.allowed_servers.includes(context.server) || limits.allowed_servers.includes('*')",
|
|
95
|
+
"deny_code": "oap.server_not_allowed",
|
|
96
|
+
"description": "MCP server must be in allowed list"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"name": "server_url_format",
|
|
100
|
+
"type": "custom_validator",
|
|
101
|
+
"validator": "validateMCPServer",
|
|
102
|
+
"deny_code": "oap.invalid_server_url",
|
|
103
|
+
"description": "MCP server URL must be valid and secure"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"name": "tool_allowlist",
|
|
107
|
+
"type": "expression",
|
|
108
|
+
"condition": "(limits.allowed_tools && (limits.allowed_tools.includes(context.tool) || limits.allowed_tools.includes('*'))) || (limits.allowed_tool_prefixes && limits.allowed_tool_prefixes.some(prefix => context.tool.startsWith(prefix)))",
|
|
109
|
+
"deny_code": "oap.tool_not_allowed",
|
|
110
|
+
"description": "MCP tool must be in allowed list or match allowed prefix"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "rate_limit",
|
|
114
|
+
"type": "custom_validator",
|
|
115
|
+
"validator": "validateMCPRateLimit",
|
|
116
|
+
"deny_code": "oap.rate_limit_exceeded",
|
|
117
|
+
"description": "MCP tool calls must not exceed rate limit"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "timeout_limit",
|
|
121
|
+
"type": "expression",
|
|
122
|
+
"condition": "!context.timeout || !limits.max_timeout || context.timeout <= limits.max_timeout",
|
|
123
|
+
"deny_code": "oap.timeout_exceeded",
|
|
124
|
+
"description": "Tool timeout must not exceed limit"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"name": "parameter_size_limit",
|
|
128
|
+
"type": "custom_validator",
|
|
129
|
+
"validator": "validateParameterSize",
|
|
130
|
+
"deny_code": "oap.parameter_size_exceeded",
|
|
131
|
+
"description": "Tool parameters must not exceed size limit"
|
|
132
|
+
}
|
|
133
|
+
],
|
|
134
|
+
"cache": {
|
|
135
|
+
"default_ttl_seconds": 30,
|
|
136
|
+
"suspend_invalidate_seconds": 15
|
|
137
|
+
},
|
|
138
|
+
"deprecation": null,
|
|
139
|
+
"created_at": "2026-02-14T00:00:00Z",
|
|
140
|
+
"updated_at": "2026-02-14T00:00:00Z"
|
|
141
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Messaging Policy Pack v1
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `messaging.message.send.v1` policy pack protects messaging endpoints with rate limits, channel restrictions, and mention policies. This is designed as a PLG (Product-Led Growth) on-ramp for harmless messaging use cases across Slack, Discord, Email, and other channels.
|
|
6
|
+
|
|
7
|
+
## Policy Requirements
|
|
8
|
+
|
|
9
|
+
| **Requirement** | **Value** | **Description** |
|
|
10
|
+
|-----------------|-----------|-----------------|
|
|
11
|
+
| **Capability** | `messaging.send` | Agent must have messaging capability |
|
|
12
|
+
| **Assurance** | L0 | Minimum assurance level required |
|
|
13
|
+
| **Rate Limits** | `msgs_per_min`, `msgs_per_day` | Required rate limiting configuration |
|
|
14
|
+
|
|
15
|
+
## Limits Configuration
|
|
16
|
+
|
|
17
|
+
### Required Limits
|
|
18
|
+
|
|
19
|
+
- **`msgs_per_min`**: Maximum messages per minute (1-1000)
|
|
20
|
+
- **`msgs_per_day`**: Maximum messages per day (1-50000)
|
|
21
|
+
|
|
22
|
+
### Capability Parameters
|
|
23
|
+
|
|
24
|
+
- **`channels_allowlist`**: Comma-separated list of allowed channels (slack, discord, email)
|
|
25
|
+
- **`mention_policy`**: Policy for @mentions (none, limited, all)
|
|
26
|
+
- **`max_recipients`**: Maximum number of recipients per message
|
|
27
|
+
|
|
28
|
+
## Example Usage
|
|
29
|
+
|
|
30
|
+
### Express.js
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const { requirePolicy } = require("@aporthq/middleware-express");
|
|
34
|
+
|
|
35
|
+
app.post("/messages", requirePolicy("messaging.message.send.v1"), async (req, res) => {
|
|
36
|
+
const { channel, recipients, content, mentions } = req.body;
|
|
37
|
+
const passport = req.policyResult.passport;
|
|
38
|
+
|
|
39
|
+
// Policy automatically enforces:
|
|
40
|
+
// - Channel allowlist validation
|
|
41
|
+
// - Rate limiting (msgs_per_min, msgs_per_day)
|
|
42
|
+
// - Mention policy enforcement
|
|
43
|
+
// - Assurance level checking (L0+)
|
|
44
|
+
|
|
45
|
+
// Your messaging logic here
|
|
46
|
+
const message_id = await sendMessage({
|
|
47
|
+
channel,
|
|
48
|
+
recipients,
|
|
49
|
+
content,
|
|
50
|
+
mentions,
|
|
51
|
+
agent_id: passport.agent_id,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
res.json({ success: true, message_id });
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### FastAPI
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from aport.middleware import require_policy
|
|
62
|
+
|
|
63
|
+
@app.post("/messages")
|
|
64
|
+
@require_policy("messaging.message.send.v1")
|
|
65
|
+
async def send_message(request: Request, message_data: MessageRequest):
|
|
66
|
+
passport = request.state.policy_result.passport
|
|
67
|
+
|
|
68
|
+
# Policy automatically enforces all requirements
|
|
69
|
+
# Your messaging logic here
|
|
70
|
+
|
|
71
|
+
return {"success": True, "message_id": message_id}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Policy Violations
|
|
75
|
+
|
|
76
|
+
### Channel Not Allowlisted
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"error": "messaging_policy_violation",
|
|
81
|
+
"reason": "channel_not_allowlisted",
|
|
82
|
+
"channel": "teams",
|
|
83
|
+
"allowed_channels": ["slack", "discord", "email"],
|
|
84
|
+
"upgrade_instructions": "Add 'teams' to your passport's channels_allowlist parameter"
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Rate Limit Exceeded
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
{
|
|
92
|
+
"error": "messaging_policy_violation",
|
|
93
|
+
"reason": "rate_limit_exceeded",
|
|
94
|
+
"limit_type": "per_minute",
|
|
95
|
+
"current_usage": 95,
|
|
96
|
+
"limit": 100,
|
|
97
|
+
"retry_after": 60
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Mention Policy Violation
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"error": "messaging_policy_violation",
|
|
106
|
+
"reason": "mention_not_allowed",
|
|
107
|
+
"mention_policy": "limited",
|
|
108
|
+
"violation": "@everyone mentions not allowed with limited policy"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Best Practices
|
|
113
|
+
|
|
114
|
+
### Implementation
|
|
115
|
+
|
|
116
|
+
1. **Rate Limiting**: Implement proper rate limiting per agent and per channel
|
|
117
|
+
2. **Channel Validation**: Always validate channels against the allowlist
|
|
118
|
+
3. **Mention Control**: Enforce mention policies to prevent spam
|
|
119
|
+
4. **Verifiable Attestation**: Log all message attempts for security monitoring
|
|
120
|
+
5. **Error Handling**: Provide clear error messages for policy violations
|
|
121
|
+
|
|
122
|
+
### Security
|
|
123
|
+
|
|
124
|
+
1. **Monitor Patterns**: Watch for spam patterns and suspicious activity
|
|
125
|
+
2. **Webhook Integration**: Subscribe to status webhooks for instant suspend
|
|
126
|
+
3. **Content Filtering**: Consider implementing content filtering for harmful messages
|
|
127
|
+
4. **Channel-Specific Limits**: Implement different limits for different channels
|
|
128
|
+
|
|
129
|
+
### Performance
|
|
130
|
+
|
|
131
|
+
1. **Cache Verification**: Cache passport verification results (60s TTL recommended)
|
|
132
|
+
2. **Async Processing**: Use async processing for bulk message operations
|
|
133
|
+
3. **Rate Limiter**: Use Redis or similar for distributed rate limiting
|
|
134
|
+
4. **Batch Operations**: Support batch messaging with proper limit checking
|
|
135
|
+
|
|
136
|
+
## Why This Policy Pack?
|
|
137
|
+
|
|
138
|
+
- **Mass Market**: Messaging is harmless and perfect for PLG onboarding
|
|
139
|
+
- **Demo Friendly**: Easy to demonstrate limits and suspend functionality
|
|
140
|
+
- **Channel Diversity**: Supports multiple messaging platforms (Slack, Discord, Email)
|
|
141
|
+
- **Scalable**: Rate limits prevent abuse while allowing legitimate use
|
|
142
|
+
- **Compliance Ready**: Built-in Verifiable Attestation and policy enforcement
|
|
143
|
+
|
|
144
|
+
## Integration Examples
|
|
145
|
+
|
|
146
|
+
- **Customer Support**: Automated responses via Slack/Discord
|
|
147
|
+
- **Marketing**: Email campaigns with rate limiting
|
|
148
|
+
- **Notifications**: System alerts across multiple channels
|
|
149
|
+
- **Community Management**: Moderated Discord/Slack interactions
|
|
150
|
+
- **Internal Tools**: Employee messaging and announcements
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
## Required Context
|
|
154
|
+
|
|
155
|
+
This policy requires the following context (JSON Schema):
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
160
|
+
"type": "object",
|
|
161
|
+
"required": [
|
|
162
|
+
"channel_id",
|
|
163
|
+
"message",
|
|
164
|
+
"message_type"
|
|
165
|
+
],
|
|
166
|
+
"properties": {
|
|
167
|
+
"channel_id": {
|
|
168
|
+
"type": "string",
|
|
169
|
+
"minLength": 1,
|
|
170
|
+
"description": "Target channel identifier"
|
|
171
|
+
},
|
|
172
|
+
"message": {
|
|
173
|
+
"type": "string",
|
|
174
|
+
"minLength": 1,
|
|
175
|
+
"maxLength": 2000,
|
|
176
|
+
"description": "Message content"
|
|
177
|
+
},
|
|
178
|
+
"message_type": {
|
|
179
|
+
"type": "string",
|
|
180
|
+
"enum": [
|
|
181
|
+
"text",
|
|
182
|
+
"embed",
|
|
183
|
+
"file",
|
|
184
|
+
"reaction"
|
|
185
|
+
],
|
|
186
|
+
"description": "Type of message"
|
|
187
|
+
},
|
|
188
|
+
"mentions": {
|
|
189
|
+
"type": "array",
|
|
190
|
+
"items": {
|
|
191
|
+
"type": "string"
|
|
192
|
+
},
|
|
193
|
+
"description": "User or role mentions in the message"
|
|
194
|
+
},
|
|
195
|
+
"attachments": {
|
|
196
|
+
"type": "array",
|
|
197
|
+
"items": {
|
|
198
|
+
"type": "object",
|
|
199
|
+
"properties": {
|
|
200
|
+
"url": {
|
|
201
|
+
"type": "string"
|
|
202
|
+
},
|
|
203
|
+
"filename": {
|
|
204
|
+
"type": "string"
|
|
205
|
+
},
|
|
206
|
+
"size": {
|
|
207
|
+
"type": "integer"
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"description": "File attachments"
|
|
212
|
+
},
|
|
213
|
+
"thread_id": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"description": "Thread identifier for threaded messages"
|
|
216
|
+
},
|
|
217
|
+
"reply_to": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"description": "Message ID being replied to"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
You can also fetch this live via the discovery endpoint:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
curl -s "https://aport.io/api/policies/messaging.message.send.v1?format=schema"
|
|
229
|
+
```
|
|
230
|
+
|