1
1
name : MCP Tests
2
2
3
3
on :
4
- push :
5
- branches :
6
4
pull_request :
7
-
8
5
jobs :
9
6
# ##########################################################################
10
7
# 1 - Local integration tests (always run)
11
8
# ##########################################################################
12
9
local :
13
10
runs-on : ubuntu-latest
14
-
15
11
# Dummy key lets the clients authenticate against the local servers.
16
12
env :
17
13
API_KEY : ci-test-key
18
14
19
15
steps :
20
16
- uses : actions/checkout@v4
21
17
18
+ - name : Read Python version from .python-version
19
+ id : python-version
20
+ run : |
21
+ PY_VERSION=$(cat .python-version)
22
+ echo "version=$PY_VERSION" >> $GITHUB_OUTPUT
23
+
22
24
- uses : actions/setup-python@v5
23
25
with :
24
- python-version : " 3.11 "
26
+ python-version : ${{ steps.python-version.outputs.version }}
25
27
26
- # Optional: cache wheels to speed up numpy / scipy installs
27
28
- uses : actions/cache@v4
28
29
with :
29
30
path : ~/.cache/pip
@@ -33,47 +34,106 @@ jobs:
33
34
run : |
34
35
python -m pip install --upgrade pip
35
36
pip install -r requirements.txt
36
- pip install -r requirements-dev.txt
37
37
38
38
- name : Run pytest (local transports)
39
39
run : pytest -q
40
40
41
-
42
41
# ##########################################################################
43
- # 2 - Remote smoke-test (only when secrets are set)
44
- #
45
- # • Put MCP_SERVER_URL → “https://<app>.herokuapp.com”
46
- # • Put API_KEY → same key you set as Heroku config var
47
- #
48
- # The fixture auto-skips the remote case if these are missing, so
49
- # the job is conditionally *created* only when both secrets exist.
42
+ # 2 - Deploy this PR to a temp Heroku app and run tests against deployed app (in addition to 'local')
50
43
# ##########################################################################
51
44
remote :
52
- if : ${{ secrets.MCP_SERVER_URL != '' && secrets.API_KEY != '' }}
53
45
runs-on : ubuntu-latest
54
-
55
46
env :
56
- MCP_SERVER_URL : ${{ secrets.MCP_SERVER_URL }}
57
- API_KEY : ${{ secrets.API_KEY }}
47
+ HEROKU_API_KEY : ${{ secrets.HEROKU_API_KEY }}
48
+ API_KEY : ci-test-key
49
+ # also note that github CI doesn't have access to your app's config vars, so here we're setting the remote
50
+ # server type to streamable HTTP. Folks using SSE would need to change this line for their e2e remote integration
51
+ # tests to test SSE instead of streamable HTTP.
52
+ REMOTE_SERVER_TRANSPORT_MODULE : streamable_http_server
53
+ # $APP_NAME is set below because we need to shorten the repo owner's name, as a precaution
58
54
59
55
steps :
60
56
- uses : actions/checkout@v4
57
+ with :
58
+ fetch-depth : 0 # <-- disables shallow clone, which heroku is upset by when running git push heroku later on
59
+
60
+ # Setting a short $APP_NAME that will be unique even if folks choose to fork this repo --> avoids clashes.
61
+ # Needs to be shortened if the github repo owner has a long name (max 30 char app name heroku limit).
62
+ - name : Generate short APP_NAME
63
+ id : appname
64
+ run : |
65
+ OWNER_SHORT=${GITHUB_REPOSITORY_OWNER:0:5}
66
+ REPO_NAME=$(basename "$GITHUB_REPOSITORY")
67
+ PR_NUMBER=$(jq .number "$GITHUB_EVENT_PATH")
68
+ APP_NAME="${OWNER_SHORT}-${REPO_NAME}-${PR_NUMBER}"
69
+ echo "APP_NAME=$APP_NAME"
70
+ echo "APP_NAME=$APP_NAME" >> $GITHUB_ENV
71
+
72
+ - name : Read Python version from .python-version
73
+ id : python-version
74
+ run : |
75
+ PY_VERSION=$(cat .python-version)
76
+ echo "version=$PY_VERSION" >> $GITHUB_OUTPUT
61
77
62
78
- uses : actions/setup-python@v5
63
79
with :
64
- python-version : " 3.11"
80
+ python-version : ${{ steps.python-version.outputs.version }}
81
+
82
+ - name : Install Heroku CLI
83
+ run : |
84
+ curl https://cli-assets.heroku.com/install.sh | sh
85
+
86
+ - name : Log in to Heroku
87
+ run : |
88
+ echo "$HEROKU_API_KEY" | heroku auth:token
89
+
90
+ - name : Pre-cleanup (destroy app if it exists)
91
+ continue-on-error : true
92
+ run : |
93
+ heroku apps:destroy --app $APP_NAME --confirm $APP_NAME
94
+
95
+ # github CI can't use our app.json, so the config etc bits must be set manually.
96
+ # note WEB_CONCURRENCY is important! You get non-deterministic errors w/out it.
97
+ - name : Create temp Heroku app for this PR
98
+ run : |
99
+ heroku create $APP_NAME
100
+ heroku buildpacks:set heroku/python -a $APP_NAME
101
+ heroku config:set API_KEY=$API_KEY --app $APP_NAME
102
+ heroku config:set STDIO_MODE_ONLY=false
103
+ heroku config:set REMOTE_SERVER_TRANSPORT_MODULE=$REMOTE_SERVER_TRANSPORT_MODULE --app $APP_NAME
104
+ heroku config:set WEB_CONCURRENCY=1 --app $APP_NAME
105
+
106
+ - name : Deploy this branch to Heroku
107
+ run : |
108
+ git push https://heroku:[email protected] /$APP_NAME.git HEAD:refs/heads/main --force
65
109
66
110
- uses : actions/cache@v4
67
111
with :
68
112
path : ~/.cache/pip
69
113
key : ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
70
114
71
- - name : Install dependencies
115
+ - name : Install test dependencies
72
116
run : |
73
117
python -m pip install --upgrade pip
74
118
pip install -r requirements.txt
75
119
76
- # We reuse the *same* test-suite; the fixture detects MCP_SERVER_URL
77
- # and adds the “remote” parameter automatically.
78
- - name : Run pytest (remote smoke)
79
- run : pytest -q
120
+ - name : Get Heroku env vars
121
+ id : heroku_env
122
+ run : |
123
+ url=$(heroku info -s -a $APP_NAME | grep web_url | cut -d= -f2 | tr -d '\n')
124
+ echo "url=$url" >> "$GITHUB_OUTPUT"
125
+
126
+ - name : Run pytest against deployed app
127
+ env :
128
+ MCP_SERVER_URL : ${{ steps.heroku_env.outputs.url }}
129
+ run : |
130
+ echo "APP_NAME = $APP_NAME"
131
+ echo "MCP_SERVER_URL = $MCP_SERVER_URL"
132
+ echo "REMOTE_SERVER_TRANSPORT_MODULE = $REMOTE_SERVER_TRANSPORT_MODULE"
133
+ echo "API_KEY is ${API_KEY:+set}" # won't print the key, just confirms it's non-empty
134
+ pytest -q
135
+
136
+ - name : Destroy Heroku app after test
137
+ if : always()
138
+ run : |
139
+ heroku apps:destroy --app $APP_NAME --confirm $APP_NAME
0 commit comments