Skip to content

Commit 73f4842

Browse files
authored
[exa-mcp-server] feat: add new server (#72)
1 parent 8bc0d36 commit 73f4842

17 files changed

+8191
-0
lines changed

exa-mcp-server/.actor/actor.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"actorSpecification": 1,
3+
"name": "exa-mcp-server",
4+
"title": "Exa MCP Server",
5+
"description": "HTTP MCP proxy to Exa's hosted MCP server (mcp.exa.ai). Connect via streamable HTTP.",
6+
"version": "0.0",
7+
"buildTag": "latest",
8+
"usesStandbyMode": true,
9+
"meta": {
10+
"templateId": "ts-mcp-server"
11+
},
12+
"input": {
13+
"title": "Actor input schema",
14+
"description": "This is Actor input schema",
15+
"type": "object",
16+
"schemaVersion": 1,
17+
"properties": {},
18+
"required": []
19+
},
20+
"dockerfile": "../Dockerfile",
21+
"webServerMcpPath": "/mcp",
22+
"minMemoryMbytes": 256,
23+
"maxMemoryMbytes": 1024
24+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"apify-actor-start": {
3+
"eventTitle": "Synthetic Actor start (covered first 5s)",
4+
"eventDescription": "Synthetic start event charged automatically by Apify. Do not charge manually in code.",
5+
"eventPriceUsd": 0.00005
6+
},
7+
"tool-request": {
8+
"eventTitle": "Generic tool request",
9+
"eventDescription": "Fallback fee when tool cannot be identified.",
10+
"eventPriceUsd": 0.03
11+
},
12+
"exa-get-code-context": {
13+
"eventTitle": "Exa: get_code_context_exa",
14+
"eventDescription": "Search and return relevant code/documentation context.",
15+
"eventPriceUsd": 0.06
16+
},
17+
"exa-web-search": {
18+
"eventTitle": "Exa: web_search_exa",
19+
"eventDescription": "Perform real-time Exa web search.",
20+
"eventPriceUsd": 0.04
21+
},
22+
"exa-company-research": {
23+
"eventTitle": "Exa: company_research",
24+
"eventDescription": "Crawl and summarize company information.",
25+
"eventPriceUsd": 0.08
26+
},
27+
"exa-crawling": {
28+
"eventTitle": "Exa: crawling",
29+
"eventDescription": "Fetch and extract content from specific URLs.",
30+
"eventPriceUsd": 0.02
31+
},
32+
"exa-linkedin-search": {
33+
"eventTitle": "Exa: linkedin_search",
34+
"eventDescription": "Search LinkedIn for companies and people via Exa.",
35+
"eventPriceUsd": 0.09
36+
},
37+
"exa-deep-research-start": {
38+
"eventTitle": "Exa: deep_researcher_start",
39+
"eventDescription": "Start a deep research task.",
40+
"eventPriceUsd": 0.12
41+
},
42+
"exa-deep-research-check": {
43+
"eventTitle": "Exa: deep_researcher_check",
44+
"eventDescription": "Check status and retrieve deep research results.",
45+
"eventPriceUsd": 0.05
46+
},
47+
"prompt-request": {
48+
"eventTitle": "Price for completing a prompt request",
49+
"eventDescription": "Flat fee for completing a prompt request.",
50+
"eventPriceUsd": 0.01
51+
},
52+
"completion-request": {
53+
"eventTitle": "Price for completing a completion request",
54+
"eventDescription": "Flat fee for completing a completion request.",
55+
"eventPriceUsd": 0.001
56+
},
57+
"resource-request": {
58+
"eventTitle": "Price for completing a resource request",
59+
"eventDescription": "Flat fee for completing a resource request.",
60+
"eventPriceUsd": 0.025
61+
},
62+
"list-request": {
63+
"eventTitle": "Price for completing a list request",
64+
"eventDescription": "Flat fee for completing a list request.",
65+
"eventPriceUsd": 0.001
66+
}
67+
}

exa-mcp-server/.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 4
6+
charset = utf-8
7+
trim_trailing_whitespace = true
8+
insert_final_newline = true
9+
end_of_line = lf

exa-mcp-server/.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# This file tells Git which files shouldn't be added to source control
2+
3+
.idea
4+
.vscode
5+
.zed
6+
storage
7+
apify_storage
8+
crawlee_storage
9+
node_modules
10+
dist
11+
tsconfig.tsbuildinfo
12+
13+
# Added by Apify CLI
14+
.venv

exa-mcp-server/.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.prettierignore

exa-mcp-server/.prettierrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"printWidth": 120,
3+
"singleQuote": true,
4+
"tabWidth": 4
5+
}

exa-mcp-server/Dockerfile

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Specify the base Docker image. You can read more about
2+
# the available images at https://docs.apify.com/sdk/js/docs/guides/docker-images
3+
# You can also use any other image from Docker Hub.
4+
FROM apify/actor-node:22 AS builder
5+
6+
# Check preinstalled packages
7+
RUN npm ls crawlee apify puppeteer playwright
8+
9+
# Copy just package.json and package-lock.json
10+
# to speed up the build using Docker layer cache.
11+
COPY --chown=myuser:myuser package*.json ./
12+
13+
# Install all dependencies. Don't audit to speed up the installation.
14+
RUN npm install --include=dev --audit=false
15+
16+
# Next, copy the source files using the user set
17+
# in the base image.
18+
COPY --chown=myuser:myuser . ./
19+
20+
# Install all dependencies and build the project.
21+
# Don't audit to speed up the installation.
22+
RUN npm run build
23+
24+
# Create final image
25+
FROM apify/actor-node:22
26+
27+
# Check preinstalled packages
28+
RUN npm ls crawlee apify puppeteer playwright
29+
30+
# Copy just package.json and package-lock.json
31+
# to speed up the build using Docker layer cache.
32+
COPY --chown=myuser:myuser package*.json ./
33+
34+
# Install NPM packages, skip optional and development dependencies to
35+
# keep the image small. Avoid logging too much and print the dependency
36+
# tree for debugging
37+
RUN npm --quiet set progress=false \
38+
&& npm install --omit=dev --omit=optional \
39+
&& echo "Installed NPM packages:" \
40+
&& (npm list --omit=dev --all || true) \
41+
&& echo "Node.js version:" \
42+
&& node --version \
43+
&& echo "NPM version:" \
44+
&& npm --version \
45+
&& rm -r ~/.npm
46+
47+
# Copy built JS files from builder image
48+
COPY --from=builder --chown=myuser:myuser /usr/src/app/dist ./dist
49+
50+
# Next, copy the remaining files and directories with the source code.
51+
# Since we do this after NPM install, quick build will be really fast
52+
# for most source file changes.
53+
COPY --chown=myuser:myuser . ./
54+
55+
# Run the image.
56+
CMD npm run start:prod --silent

exa-mcp-server/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
## Exa MCP Server
2+
3+
HTTP MCP proxy to Exa's hosted MCP server at https://mcp.exa.ai/mcp. This Actor exposes a streamable HTTP endpoint so MCP clients can connect using an Apify-hosted URL with Bearer auth.
4+
5+
## How to use
6+
7+
This server uses mcp-remote to connect to Exa and supports optional EXA_API_KEY (appended to the URL as exaApiKey).
8+
9+
## Connection URL
10+
11+
MCP clients can connect to this server at:
12+
13+
https://mcp-servers--exa-mcp-server.apify.actor/mcp
14+
15+
## Client Configuration
16+
17+
Use this configuration in your MCP client (replace your-apify-token with your token from Apify Console):
18+
19+
{
20+
"mcpServers": {
21+
"exa": {
22+
"type": "http",
23+
"url": "https://mcp-servers--exa-mcp-server.apify.actor/mcp",
24+
"headers": {
25+
"Authorization": "Bearer YOUR_APIFY_TOKEN"
26+
}
27+
}
28+
}
29+
}
30+
31+
Optionally set EXA_API_KEY as an Actor environment variable to use your Exa key.
32+
33+
### Pay per event
34+
35+
This Actor uses the [Pay Per Event (PPE)](https://docs.apify.com/platform/actors/publishing/monetize#pay-per-event-pricing-model) model. Exa tool calls map to events defined in [.actor/pay_per_event.json](.actor/pay_per_event.json) such as `exa-get-code-context`, `exa-web-search`, etc. Unknown tools fall back to `tool-request`.
36+
37+
To charge users, define events in JSON format and save them on the Apify platform. Here is an example schema with the `tool-request` event:
38+
39+
Event charging is performed in `src/billing.ts` based on the MCP method and tool name.
40+
41+
To set up the PPE model: in Actor Monetization settings, choose Pay per event and paste the content of [.actor/pay_per_event.json](.actor/pay_per_event.json).
42+
43+
## Credits and links
44+
45+
- [What is Anthropic's Model Context Protocol?](https://blog.apify.com/what-is-model-context-protocol/)
46+
- [How to use MCP with Apify Actors](https://blog.apify.com/how-to-use-mcp/)
47+
- All credits to the original authors of https://github.com/exa-labs/exa-mcp-server (or hosted Exa at https://mcp.exa.ai/mcp)
48+
- Claim this MCP server – write to [email protected].
49+
- [Apify MCP servers monorepo](https://github.com/apify/mcp-servers)
50+
- [Apify MCP server](https://mcp.apify.com)
51+
- [Apify MCP server documentation](https://docs.apify.com/platform/integrations/mcp)
52+
- [Apify MCP client](https://apify.com/jiri.spilka/tester-mcp-client)
53+
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
54+
- [TypeScript tutorials in Academy](https://docs.apify.com/academy/node-js)
55+
- [Apify SDK documentation](https://docs.apify.com/sdk/js/)
56+
57+
58+
## Getting started
59+
60+
For complete information [see this article](https://docs.apify.com/platform/actors/development#build-actor-locally). To run the Actor use the following command:
61+
62+
```bash
63+
apify run
64+
```
65+
66+
## Deploy to Apify
67+
68+
### Connect Git repository to Apify
69+
70+
If you've created a Git repository for the project, you can easily connect to Apify:
71+
72+
1. Go to [Actor creation page](https://console.apify.com/actors/new)
73+
2. Click on **Link Git Repository** button
74+
75+
### Push project on your local machine to Apify
76+
77+
You can also deploy the project on your local machine to Apify without the need for the Git repository.
78+
79+
1. Log in to Apify. You will need to provide your [Apify API Token](https://console.apify.com/account/integrations) to complete this action.
80+
81+
```bash
82+
apify login
83+
```
84+
85+
2. Deploy your Actor. This command will deploy and build the Actor on the Apify Platform. You can find your newly created Actor under [Actors -> My Actors](https://console.apify.com/actors?tab=my).
86+
87+
```bash
88+
apify push
89+
```
90+
91+
## Documentation reference
92+
93+
To learn more about Apify and Actors, take a look at the following resources:
94+
95+
- [Apify SDK for JavaScript documentation](https://docs.apify.com/sdk/js)
96+
- [Apify SDK for Python documentation](https://docs.apify.com/sdk/python)
97+
- [Apify Platform documentation](https://docs.apify.com/platform)
98+
- [Join our developer community on Discord](https://discord.com/invite/jyEM2PRvMU)

exa-mcp-server/eslint.config.mjs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import prettier from 'eslint-config-prettier';
2+
3+
import apify from '@apify/eslint-config/ts.js';
4+
import globals from 'globals';
5+
import tsEslint from 'typescript-eslint';
6+
7+
// eslint-disable-next-line import/no-default-export
8+
export default [
9+
{ ignores: ['**/dist', 'eslint.config.mjs'] },
10+
...apify,
11+
prettier,
12+
{
13+
languageOptions: {
14+
parser: tsEslint.parser,
15+
parserOptions: {
16+
project: 'tsconfig.json',
17+
},
18+
globals: {
19+
...globals.node,
20+
...globals.jest,
21+
},
22+
},
23+
plugins: {
24+
'@typescript-eslint': tsEslint.plugin,
25+
},
26+
rules: {
27+
'no-console': 0,
28+
},
29+
},
30+
];

0 commit comments

Comments
 (0)