@bouroo/ollama-cloud-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +252 -0
- package/dist/index.js +35132 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kawin Viriyaprasopsook
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# @bouroo/ollama-cloud-mcp
|
|
2
|
+
|
|
3
|
+
[](https://github.com/bouroo/ollama-cloud-mcp/actions/workflows/ci.yml)
|
|
4
|
+
|
|
5
|
+
An MCP server that exposes [Ollama's web search and web fetch](https://docs.ollama.com/capabilities/web-search)
|
|
6
|
+
capabilities as two tools, `web_search` and `web_fetch`, over stdio.
|
|
7
|
+
|
|
8
|
+
The server is a thin, dependency-free wrapper around two endpoints:
|
|
9
|
+
|
|
10
|
+
| Endpoint | Method | Purpose |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| `POST https://ollama.com/api/web_search` | `query`, `max_results` | Ranked web results with title, URL and content excerpt |
|
|
13
|
+
| `POST https://ollama.com/api/web_fetch` | `url` | A page's title, extracted content and outbound links |
|
|
14
|
+
|
|
15
|
+
Both are authenticated with a bearer token from a free Ollama account.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
- Node.js — the current Active LTS. CI tracks `lts/*`, and no `engines` floor is
|
|
20
|
+
declared, so no version is claimed that CI does not actually test.
|
|
21
|
+
- A free Ollama account and an API key from <https://ollama.com/settings/keys>
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
Create a key at <https://ollama.com/settings/keys>, then register the server with
|
|
26
|
+
your MCP client.
|
|
27
|
+
|
|
28
|
+
**Claude Code**
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
claude mcp add ollama-cloud --env OLLAMA_API_KEY=your-key-here -- npx -y @bouroo/ollama-cloud-mcp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Claude Desktop / other clients** — add to `claude_desktop_config.json` or the
|
|
35
|
+
equivalent `mcpServers` block:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"ollama-cloud": {
|
|
41
|
+
"command": "npx",
|
|
42
|
+
"args": ["-y", "@bouroo/ollama-cloud-mcp"],
|
|
43
|
+
"env": { "OLLAMA_API_KEY": "your-key-here" }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
No install step is needed — `npx` fetches and runs the package, which is published
|
|
50
|
+
as a single self-contained bundle with no runtime dependencies.
|
|
51
|
+
|
|
52
|
+
## Tools
|
|
53
|
+
|
|
54
|
+
### `web_search`
|
|
55
|
+
|
|
56
|
+
Search the web and return ranked results.
|
|
57
|
+
|
|
58
|
+
| Argument | Type | Required | Notes |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| `query` | string | yes | The search term, e.g. `"what is ollama?"` |
|
|
61
|
+
| `max_results` | integer | no | 1–10. Defaults to `5`. |
|
|
62
|
+
|
|
63
|
+
Returns `structuredContent.results`: an array of `{ title, url, content }`, plus a
|
|
64
|
+
readable text rendering:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Web search results for "what is ollama?" (2):
|
|
68
|
+
|
|
69
|
+
[1] Ollama
|
|
70
|
+
URL: https://ollama.com/
|
|
71
|
+
Cloud models are now available in Ollama...
|
|
72
|
+
|
|
73
|
+
[2] What is Ollama? Introduction to the AI model management tool
|
|
74
|
+
URL: https://www.hostinger.com/tutorials/what-is-ollama
|
|
75
|
+
An introduction to running and managing local models...
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `web_fetch`
|
|
79
|
+
|
|
80
|
+
Fetch a single page and return its content.
|
|
81
|
+
|
|
82
|
+
| Argument | Type | Required | Notes |
|
|
83
|
+
| --- | --- | --- | --- |
|
|
84
|
+
| `url` | string | yes | May omit the scheme: `"ollama.com"` becomes `https://ollama.com/`. Only `http` and `https` are accepted. |
|
|
85
|
+
|
|
86
|
+
Returns `structuredContent`: `{ title, content, links }`, plus a readable text
|
|
87
|
+
rendering:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
Fetched ollama.com
|
|
91
|
+
Title: Ollama
|
|
92
|
+
|
|
93
|
+
Cloud models are now available in Ollama...
|
|
94
|
+
|
|
95
|
+
Links (2):
|
|
96
|
+
- http://ollama.com/
|
|
97
|
+
- https://github.com/ollama/ollama
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Configuration
|
|
101
|
+
|
|
102
|
+
| Variable | Required | Default | Description |
|
|
103
|
+
| --- | --- | --- | --- |
|
|
104
|
+
| `OLLAMA_API_KEY` | For the hosted API | — | Bearer token for `https://ollama.com`. |
|
|
105
|
+
| `OLLAMA_HOST` | No | `https://ollama.com` | Override the API base URL. A bare `host:port` is treated as `http://`, matching Ollama's own convention — e.g. `OLLAMA_HOST=127.0.0.1:11434` talks to a local daemon instead. |
|
|
106
|
+
|
|
107
|
+
Pointing `OLLAMA_HOST` at a local, signed-in Ollama daemon is supported and needs
|
|
108
|
+
no API key: the daemon handles its own authentication. If `OLLAMA_API_KEY` is set,
|
|
109
|
+
it is always sent.
|
|
110
|
+
|
|
111
|
+
## Behaviour notes
|
|
112
|
+
|
|
113
|
+
- **Errors are returned as tool errors, not crashes.** A missing key, a rejected
|
|
114
|
+
key (HTTP 401/403), rate limiting (429) or a server error (5xx) comes back as
|
|
115
|
+
`isError: true` with a message naming the cause, so the model can explain it
|
|
116
|
+
instead of the client losing the server.
|
|
117
|
+
- **An empty result set is not an error** — `web_search` reports
|
|
118
|
+
`No web results found for "<query>".`
|
|
119
|
+
- **Requests time out after 30 seconds** rather than hanging the tool call.
|
|
120
|
+
- **stdout carries only the MCP protocol stream.** All diagnostics go to stderr.
|
|
121
|
+
- Ollama's docs suggest a context length of at least ~32,000 tokens when feeding
|
|
122
|
+
fetched pages to a model; `web_fetch` returns page content verbatim and does not
|
|
123
|
+
truncate it.
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
Requires [Bun](https://bun.sh) for the toolchain; the published artifact runs on
|
|
128
|
+
plain Node.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
bun install
|
|
132
|
+
bun run typecheck # tsc --noEmit
|
|
133
|
+
bun run test # unit + in-memory MCP protocol tests
|
|
134
|
+
bun run build # bundles src/index.ts -> dist/index.js
|
|
135
|
+
bun run smoke # end-to-end stdio handshake against dist/
|
|
136
|
+
|
|
137
|
+
# With a key, exercise the live API as well:
|
|
138
|
+
OLLAMA_API_KEY=... node scripts/smoke.mjs "what is ollama?"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`bun run smoke` drives the built server over real stdio: it performs the MCP
|
|
142
|
+
initialize handshake, lists tools, and calls `web_search`. Without
|
|
143
|
+
`OLLAMA_API_KEY` it asserts the missing-key error path instead, which still proves
|
|
144
|
+
the request wiring end to end.
|
|
145
|
+
|
|
146
|
+
Layout:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
src/ollama.ts API client: config, URL normalization, error mapping
|
|
150
|
+
src/server.ts MCP tool registration and response formatting
|
|
151
|
+
src/index.ts CLI entry point (stdio transport, --help, --version)
|
|
152
|
+
test/ unit tests and in-memory MCP protocol tests
|
|
153
|
+
scripts/smoke.mjs end-to-end stdio smoke test
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Releasing
|
|
157
|
+
|
|
158
|
+
npm publishing uses [trusted publishing](https://docs.npmjs.com/trusted-publishers)
|
|
159
|
+
(OIDC): GitHub mints a short-lived identity token for the run, npm exchanges it for
|
|
160
|
+
publish credentials, and a provenance attestation is attached automatically. No
|
|
161
|
+
long-lived npm token is stored in this repository.
|
|
162
|
+
|
|
163
|
+
### One-time setup
|
|
164
|
+
|
|
165
|
+
Trusted publishing **cannot publish the first version of a package** — npm requires
|
|
166
|
+
the package to exist before a trusted publisher can be configured
|
|
167
|
+
([npm/cli#8544](https://github.com/npm/cli/issues/8544), still open as of August 2026).
|
|
168
|
+
Bootstrap once, then never again:
|
|
169
|
+
|
|
170
|
+
1. Publish `0.1.0` by any one-off method:
|
|
171
|
+
- enable 2FA on the npm account and run `npm publish --otp=<code>` locally, or
|
|
172
|
+
- mint a short-lived granular token (read-write on `@bouroo`) and publish with it.
|
|
173
|
+
|
|
174
|
+
npm rejects a publish backed by neither 2FA nor a bypass-2FA granular token:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
403 Two-factor authentication or granular access token with bypass 2fa
|
|
178
|
+
enabled is required to publish packages.
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. Configure the trusted publisher at **npmjs.com → the package → Settings →
|
|
182
|
+
Trusted Publisher → GitHub Actions**:
|
|
183
|
+
- Repository: `bouroo/ollama-cloud-mcp`
|
|
184
|
+
- Workflow filename: `release.yml` — filename only, including the extension
|
|
185
|
+
- Environment: leave blank, the workflow uses none
|
|
186
|
+
3. Every release after that publishes with no secret at all.
|
|
187
|
+
|
|
188
|
+
### Cutting a release
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
npm version patch # or minor / major — bumps package.json and tags the commit
|
|
192
|
+
git push --follow-tags
|
|
193
|
+
gh release create v0.1.1 --generate-notes
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
`.github/workflows/release.yml` refuses to proceed unless the tag matches
|
|
197
|
+
`package.json` and that version is not already on npm, re-runs the gates, and then
|
|
198
|
+
stages the publish over OIDC.
|
|
199
|
+
|
|
200
|
+
To re-run a failed stage without cutting a new release, use
|
|
201
|
+
**Actions → Release → Run workflow**.
|
|
202
|
+
|
|
203
|
+
### Approving a staged publish
|
|
204
|
+
|
|
205
|
+
The trusted publisher grants **stage-publish only**, so the workflow uploads into
|
|
206
|
+
npm's staging area rather than publishing directly. Staged publishing defers the
|
|
207
|
+
proof-of-presence (2FA) check to the approval step, which is what lets CI run
|
|
208
|
+
without a maintainer present. A human finishes it:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npm stage list # find the stage id
|
|
212
|
+
npm stage approve <id> # publishes it (2FA required)
|
|
213
|
+
npm stage reject <id> # discards it
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Nothing moves the `latest` tag until that approval, so a staged release can be
|
|
217
|
+
inspected — or discarded — before it reaches anyone.
|
|
218
|
+
|
|
219
|
+
### Gotchas
|
|
220
|
+
|
|
221
|
+
- **npm CLI 11.5.1+ and Node 22.14.0+** are required. The npm bundled with
|
|
222
|
+
`setup-node` is often older, so the workflow runs `npm install -g npm@latest` and
|
|
223
|
+
fails with a clear message if the version is still too low.
|
|
224
|
+
- The publisher is matched on **repository plus workflow filename**, so renaming or
|
|
225
|
+
moving `release.yml` silently breaks publishing.
|
|
226
|
+
- A publish rejected by npm reports one of two errors, and both point at the trust
|
|
227
|
+
configuration rather than at your code. The tell that the OIDC path itself worked
|
|
228
|
+
is the line just above the error:
|
|
229
|
+
`publish Provenance statement published to transparency log: ...`.
|
|
230
|
+
- **`403 ... OIDC permission denied for this action`** — the OIDC token was minted
|
|
231
|
+
and accepted, but no trusted-publisher relationship matches this repository and
|
|
232
|
+
workflow filename. Re-check both on the package's settings page.
|
|
233
|
+
- **`404`** — the package does not exist on npm yet, so there is nothing to attach
|
|
234
|
+
a publisher to. See the one-time setup above.
|
|
235
|
+
- `prepack` runs the typecheck, tests and build, so a tarball always carries fresh
|
|
236
|
+
output. The package is a bundle: `dependencies` is empty and consumers install
|
|
237
|
+
nothing.
|
|
238
|
+
|
|
239
|
+
## Continuous integration
|
|
240
|
+
|
|
241
|
+
`.github/workflows/ci.yml` runs on every push to `main` and every pull request,
|
|
242
|
+
on the current Active LTS (`lts/*`):
|
|
243
|
+
|
|
244
|
+
- type-check, test, build
|
|
245
|
+
- drive a **full MCP handshake against a copy of the built bundle sitting alone in
|
|
246
|
+
an empty directory**, with no `node_modules` to fall back on — this is what
|
|
247
|
+
makes the "zero runtime dependencies" claim tested rather than asserted
|
|
248
|
+
- the same handshake against the source build
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT
|