Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions .github/workflows/mcp-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ on:
branches: [main]
paths:
- 'plugins/**'
- 'chatgpt-app-submission.json'
- '.github/workflows/mcp-check.yml'
pull_request:
paths:
- 'plugins/**'
- 'chatgpt-app-submission.json'
- '.github/workflows/mcp-check.yml'
schedule:
- cron: '17 8 * * *'
Expand Down Expand Up @@ -83,9 +85,10 @@ jobs:
payload = json.load(fh)
if 'result' not in payload:
sys.exit(f"::error::tools/list returned no result: {json.dumps(payload)[:400]}")
served = set()
served_tools = {}
for tool in payload['result']['tools']:
served.add(tool['name'])
served_tools[tool['name']] = tool
served = set(served_tools)
if not served:
sys.exit('::error::tools/list returned no tools.')

Expand All @@ -102,4 +105,23 @@ jobs:
if missing or extra:
sys.exit(1)
print(f"README documents all {len(served)} served tools.")
submission = json.load(open('chatgpt-app-submission.json'))
assert set(submission['tools']) == served, 'Submission tool names differ from tools/list'
assert len(submission['test_cases']) == 5
assert len(submission['negative_test_cases']) == 3
for name, tool in submission['tools'].items():
for hint in ('readOnlyHint', 'openWorldHint', 'destructiveHint'):
assert type(tool['annotations'][hint]) is bool
if served_tools[name].get('annotations', {}).get(hint) != tool['annotations'][hint]:
message = f'{name}.{hint} differs from production; deploy matching server metadata before submitting'
if os.environ.get('GITHUB_EVENT_NAME') == 'pull_request':
print(f'::warning::{message}')
else:
sys.exit(f'::error::{message}')
for field in ('read_only_justification', 'open_world_justification', 'destructive_justification'):
assert tool['justifications'][field].strip()
for case in submission['test_cases']:
assert set(map(str.strip, case['tools_triggered'].split(','))) <= served
assert all(case['tools_triggered'] is None for case in submission['negative_test_cases'])
print('Submission has explicit annotations, justifications, five positive cases, and three negative cases.')
PY
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ codex plugin add greptile@greptile-plugin

The plugin gives Codex two ways to work with Greptile:

- the **Greptile MCP server**, for reading and resolving review results and for searching your knowledge base and coding patterns
- the **Greptile MCP server**, for reading review results and for searching your knowledge base and coding patterns
- the **Greptile CLI**, for reviewing your working branch before a pull request exists

Both authenticate over OAuth against your Greptile account. There is no API key to create and nothing to install — the CLI ships with the plugin, so it needs no npm or Homebrew install, only Node 22+ on your machine.

See [`plugins/greptile`](./plugins/greptile) for setup, workflows, and the full tool list.

For directory submission artifacts and checks, see [SUBMISSION.md](./SUBMISSION.md).
66 changes: 66 additions & 0 deletions SUBMISSION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# OpenAI submission

Use the [OpenAI submission guide](https://developers.openai.com/plugins/deploy/submission)
and [error reference](https://developers.openai.com/plugins/deploy/submission-errors).

`chatgpt-app-submission.json` contains listing copy, annotation justifications for
21 remote tools, five positive test cases, and three negative test cases. It was
prepared using OpenAI's [submission skill](https://github.com/openai/plugins/blob/main/plugins/openai-developers/skills/chatgpt-app-submission/SKILL.md).
Expected outputs describe acceptance criteria; they are not a record of completed tests.

PR checks validate the submission structure and warn about production annotation
drift, so preparation can merge before the server deployment. On main, scheduled
and manual MCP checks fail on that drift. A green PR check is not proof that the
production server is ready for submission.

## Prepare and upload

1. Confirm production `tools/list` advertises the same tool names and annotation
values as the JSON. Rescan the production MCP server in the portal, then import
`chatgpt-app-submission.json`. An import cannot fix missing server annotations.
2. Complete the portal's domain verification on the MCP hostname or an allowed
parent hostname. Keep the account-specific challenge and credentials out of this repository.
3. Use the **With MCP** submission flow for `https://api.greptile.com/mcp` with
OAuth. Upload the bundled skills and verify both `login` and `review` appear and
pass scanning. Preserve `scripts/greptile.mjs` and the skills' relative paths.
4. Run all five positive and three negative cases using an isolated reviewer
account with synthetic repository data. The write cases consume review credits
or create an inactive rule; use the demo organization. Ensure account access
and review credits remain available throughout the review period.
5. Verify CLI login and branch review in Codex separately from remote MCP login.
Record the supported workflows and add the recording URL to the portal.
6. Fill the support URL, directory icons, reviewer credentials and instructions,
countries, and release notes. Review policy attestations before submitting.

The installable plugin is `plugins/greptile`, not the marketplace repository root.
To create its archive from a committed revision:

```sh
git archive --format=zip --output=/tmp/greptile-plugin.zip HEAD:plugins/greptile
```

This archive includes MCP configuration. Do not use it for the portal's
**Skills only** flow, which excludes MCP configuration. Confirm the portal accepts
the skill upload and includes the bundled CLI before treating packaging as verified.

## Review findings

- No input field explicitly asks for passwords, tokens, MFA codes, payment-card
data, health information, or government identifiers. Free-form rule text and
metadata should contain only content the user wants stored in Greptile.
- Tools return account identity, repository content, review comments, and analytics
within the caller's access. The listing and test instructions describe these uses.
- `trigger_code_review` can consume credits and publish or overwrite review
feedback on GitHub or GitLab; its annotations must remain non-read-only,
open-world, and destructive. `create_custom_context` adds private persistent
data without overwriting an existing record.
- No MCP widget is included, so there is no widget CSP to narrow or UI screenshot
requirement for this version.
- All 21 tools listed in the JSON currently omit `outputSchema`. Add an
`outputSchema` so models can use each tool's results more reliably; see the
[MCP tool specification](https://modelcontextprotocol.io/specification/draft/server/tools#tool).
This is a recommendation, not a missing-annotation blocker; do not invent schemas
in the import JSON.
- The OAuth scan reports that enterprise domain restrictions are unavailable.
Supporting those restrictions requires verified-email OpenID Connect metadata;
ordinary OAuth tool discovery has succeeded.
Loading
Loading