@dataville/dataville-mcp 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # dataville-mcp
2
2
 
3
+ [![M8ven Score](https://m8ven.ai/badge/mcp/datavilleorg-dataville-mcp-u1eou7?v=6abe1c0b98731d0af6f8978f1b3778e6)](https://m8ven.ai/mcp/datavilleorg-dataville-mcp-u1eou7?s=readme)
4
+ [![npm](https://img.shields.io/npm/v/@dataville/dataville-mcp)](https://www.npmjs.com/package/@dataville/dataville-mcp)
5
+ [![CI](https://github.com/datavilleorg/dataville-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/datavilleorg/dataville-mcp/actions/workflows/ci.yml)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
+
8
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=dataville&config=eyJ1cmwiOiJodHRwczovL2FwaS5kYXRhdmlsbGUuY29tL21jcCJ9)
9
+ [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_Dataville-0098FF?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=dataville&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fapi.dataville.com%2Fmcp%22%7D)
10
+
3
11
  MCP server exposing Dataville's data source API as tools for MCP clients (Claude Desktop, Claude Code, etc.).
4
12
 
5
13
  [Dataville](https://dataville.com) is a unified REST API over ten public datasets —
@@ -15,9 +23,45 @@ Requires a Dataville API key — get one from the [Dataville dashboard](https://
15
23
  - `list_dataville_sources` — lists the data sources available via `search_dataville`.
16
24
  - `search_dataville` — query a data source: `{ source, keywords, params? }`.
17
25
 
26
+ ## What you can ask
27
+
28
+ Once connected, ask in plain language and the client picks the source:
29
+
30
+ - "Find an arXiv paper on retrieval-augmented generation and summarize it."
31
+ - "What did Apple report in its latest SEC filing?"
32
+ - "What's the median household income in Travis County, Texas, per the US Census?"
33
+ - "How much protein is in 100 g of cooked lentils, according to USDA FoodData?"
34
+ - "Look up the `requests` package on PyPI — what's the latest version and license?"
35
+
18
36
  ## Setup
19
37
 
20
- Add this to your MCP client config (Claude Code / Claude Desktop), with `DATAVILLE_API_KEY` set to your own key:
38
+ This package is a local (stdio) MCP server: the client launches it on your
39
+ machine via `npx`. If you don't need it running locally, connecting to
40
+ Dataville's hosted endpoint instead takes one line and no install.
41
+
42
+ ### Hosted, in one line (no install)
43
+
44
+ Dataville also serves MCP directly over HTTP, so a client can connect without
45
+ running anything locally — no Node, no config file, no restart:
46
+
47
+ ```bash
48
+ claude mcp add --transport http dataville https://api.dataville.com/mcp
49
+ ```
50
+
51
+ That works with no credentials at all (anonymous limits). Add
52
+ `--header "Authorization: Bearer dataville_your_key_here"` for the full quota.
53
+ Cursor and VS Code users can use the install buttons at the top of this page.
54
+ Other clients take the same URL; the app's Integrations page has the exact
55
+ snippet for each. Use the hosted endpoint unless you specifically want to pin a
56
+ version or work offline — the rest of this section covers that local setup.
57
+
58
+ ### Prerequisites
59
+
60
+ - **Node.js** (LTS) installed — this is what runs `npx`. Without it the server
61
+ fails to start. Check with `node --version`.
62
+ - A **Dataville API key** — get one from https://app.dataville.com/api-keys.
63
+
64
+ The config block is the same everywhere; only *where* you put it differs:
21
65
 
22
66
  ```json
23
67
  {
@@ -35,7 +79,36 @@ Add this to your MCP client config (Claude Code / Claude Desktop), with `DATAVIL
35
79
 
36
80
  No install step needed — `npx` fetches and runs the package on demand.
37
81
 
38
- `DATAVILLE_API_BASE_URL` is optional and defaults to `https://api.dataville.com`; set it to `http://localhost:5000` to point at a local backend during development.
82
+ ### Claude Desktop
83
+
84
+ 1. Open **Settings → Developer → Edit Config**. This opens `claude_desktop_config.json`:
85
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
86
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
87
+ 2. Add the block above (merge into `mcpServers` if the file already has one),
88
+ with your real key.
89
+ 3. **Fully quit and reopen** Claude Desktop — quit from the menu bar / system
90
+ tray, not just closing the window.
91
+ 4. The dataville tools now appear under the tools icon in the chat box, and
92
+ Settings → Developer shows `dataville` running.
93
+
94
+ Note: the server appears as **tools**, not in the **Connectors** directory —
95
+ that directory only lists remote (hosted) connectors and will not find a local
96
+ server. Ask naturally ("get Apple's latest revenue from dataville") and the
97
+ client calls the tool.
98
+
99
+ ### Claude Code
100
+
101
+ ```bash
102
+ claude mcp add dataville -e DATAVILLE_API_KEY=dataville_your_key_here -- npx -y @dataville/dataville-mcp
103
+ ```
104
+
105
+ Restart the session so the tools load. Add `-s user` to make it available in
106
+ every project instead of just the current one.
107
+
108
+ ### Configuration
109
+
110
+ `DATAVILLE_API_BASE_URL` is optional and defaults to `https://api.dataville.com`;
111
+ set it to `http://localhost:5000` to point at a local backend during development.
39
112
 
40
113
  ### Running from source
41
114
 
@@ -46,6 +119,22 @@ npm install
46
119
  npm run build
47
120
  ```
48
121
 
122
+ ## Check that it works
123
+
124
+ Ask your client one of these. Each answer is checkable on purpose — a model that
125
+ skipped the tool and answered from memory sounds just as confident, so a reply
126
+ on its own proves nothing.
127
+
128
+ | Ask | What proves it |
129
+ | --- | --- |
130
+ | `Which data sources does Dataville have?` | Calls `list_dataville_sources` and names all eleven. |
131
+ | `Using Dataville, what is the latest version of the requests package on PyPI?` | A version you can confirm on pypi.org — and it moves, so it can't come from memory. |
132
+ | `Using Dataville, get the latest SEC filing for AAPL and its revenue.` | A form type, filing date, revenue figure, and a sec.gov link to open. |
133
+ | `Using Dataville, how much protein is in 100g of uncooked quinoa?` | The exact USDA figure, 14.1 g per 100 g. |
134
+
135
+ Clients show when a tool ran. If you don't see that, say "use dataville" in the
136
+ prompt to make it explicit, and check the answer against the source.
137
+
49
138
  ## Development
50
139
 
51
140
  ```bash
@@ -58,4 +147,12 @@ npm run build # tsc
58
147
 
59
148
  Publishes run from CI via npm trusted publishing (OIDC) — no tokens are stored.
60
149
  To cut a release: bump the version, update `CHANGELOG.md`, then publish a GitHub
61
- Release for the new tag. The `Publish` workflow builds, tests, and publishes to npm.
150
+ Release for the new tag. The `Publish` workflow builds, tests, and publishes to npm,
151
+ then publishes `server.json` to the [MCP Registry](https://registry.modelcontextprotocol.io)
152
+ (its version is set from `package.json`, so don't bump it by hand).
153
+
154
+ The registry name `com.dataville/dataville-mcp` is authorized by a DNS TXT record
155
+ on the `dataville.com` apex (`v=MCPv1; k=ed25519; p=<public key>`), checked
156
+ against the Ed25519 private key in the `MCP_PRIVATE_KEY` repo secret (hex). If the
157
+ `mcp-registry` job fails at login, check that record and secret, then re-run just
158
+ that job.
package/dist/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const DEFAULT_BASE_URL = "https://api.dataville.com";
2
2
  // Keep in sync with package.json version (enforced by a test).
3
- export const VERSION = "0.1.4";
3
+ export const VERSION = "0.1.6";
4
4
  const USER_AGENT = `dataville-mcp/${VERSION}`;
5
5
  export class DatavilleApiError extends Error {
6
6
  status;
@@ -35,6 +35,14 @@ function getConfig() {
35
35
  }
36
36
  export async function searchDataSource(source, keywords, params) {
37
37
  const { apiKey, baseUrl } = getConfig();
38
+ // encodeURIComponent leaves "." alone, and URL resolution collapses a "." or
39
+ // ".." segment — so source ".." would send the user's key to /<keywords>
40
+ // instead of a data route.
41
+ for (const [name, value] of [["source name", source], ["search term", keywords]]) {
42
+ if (value === "." || value === "..") {
43
+ throw new Error(`"${value}" is not a valid ${name}. Use list_dataville_sources to see valid source names.`);
44
+ }
45
+ }
38
46
  const url = new URL(`/${encodeURIComponent(source)}/${encodeURIComponent(keywords)}`, baseUrl);
39
47
  if (params) {
40
48
  for (const [key, value] of Object.entries(params)) {
package/dist/index.js CHANGED
@@ -1,44 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { z } from "zod";
5
- import { searchDataSource, VERSION } from "./client.js";
6
- import { DATAVILLE_SOURCES } from "./sources.js";
7
- const server = new McpServer({
8
- name: "dataville-mcp-server",
9
- version: VERSION,
10
- });
11
- server.registerTool("list_dataville_sources", {
12
- title: "List Dataville data sources",
13
- description: "List the data sources available through Dataville's search_dataville tool.",
14
- inputSchema: {},
15
- }, async () => ({
16
- content: [{ type: "text", text: JSON.stringify(DATAVILLE_SOURCES, null, 2) }],
17
- }));
18
- server.registerTool("search_dataville", {
19
- title: "Search a Dataville data source",
20
- description: "Query one of Dataville's data sources (see list_dataville_sources for valid source names) with a keyword string and optional query params.",
21
- inputSchema: {
22
- source: z.string().describe("Data source name, e.g. 'wikipedia', 'arxiv', 'edgar'"),
23
- keywords: z.string().describe("Search keywords or identifier for the query"),
24
- params: z
25
- .record(z.union([z.string(), z.number(), z.boolean()]))
26
- .optional()
27
- .describe("Optional additional query parameters"),
28
- },
29
- }, async ({ source, keywords, params }) => {
30
- try {
31
- const result = await searchDataSource(source, keywords, params);
32
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
33
- }
34
- catch (error) {
35
- const message = error instanceof Error ? error.message : String(error);
36
- return { content: [{ type: "text", text: message }], isError: true };
37
- }
38
- });
3
+ import { createServer } from "./server.js";
39
4
  async function main() {
40
5
  const transport = new StdioServerTransport();
41
- await server.connect(transport);
6
+ await createServer().connect(transport);
42
7
  }
43
8
  main().catch((error) => {
44
9
  console.error("Fatal error starting Dataville MCP server:", error);
package/dist/server.js ADDED
@@ -0,0 +1,53 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { z } from "zod";
3
+ import { searchDataSource, VERSION } from "./client.js";
4
+ import { DATAVILLE_SOURCES } from "./sources.js";
5
+ export function createServer() {
6
+ const server = new McpServer({
7
+ name: "dataville-mcp-server",
8
+ version: VERSION,
9
+ });
10
+ server.registerTool("list_dataville_sources", {
11
+ title: "List Dataville data sources",
12
+ description: "List the data sources available through Dataville's search_dataville tool.",
13
+ inputSchema: {},
14
+ // Returns a static list bundled with the server; makes no network calls.
15
+ annotations: {
16
+ readOnlyHint: true,
17
+ destructiveHint: false,
18
+ idempotentHint: true,
19
+ openWorldHint: false,
20
+ },
21
+ }, async () => ({
22
+ content: [{ type: "text", text: JSON.stringify(DATAVILLE_SOURCES, null, 2) }],
23
+ }));
24
+ server.registerTool("search_dataville", {
25
+ title: "Search a Dataville data source",
26
+ description: "Query one of Dataville's data sources (see list_dataville_sources for valid source names) with a keyword string and optional query params.",
27
+ inputSchema: {
28
+ source: z.string().describe("Data source name, e.g. 'wikipedia', 'arxiv', 'edgar'"),
29
+ keywords: z.string().describe("Search keywords or identifier for the query"),
30
+ params: z
31
+ .record(z.union([z.string(), z.number(), z.boolean()]))
32
+ .optional()
33
+ .describe("Optional additional query parameters"),
34
+ },
35
+ // A GET against the Dataville API, which fronts external data sources.
36
+ annotations: {
37
+ readOnlyHint: true,
38
+ destructiveHint: false,
39
+ idempotentHint: true,
40
+ openWorldHint: true,
41
+ },
42
+ }, async ({ source, keywords, params }) => {
43
+ try {
44
+ const result = await searchDataSource(source, keywords, params);
45
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
46
+ }
47
+ catch (error) {
48
+ const message = error instanceof Error ? error.message : String(error);
49
+ return { content: [{ type: "text", text: message }], isError: true };
50
+ }
51
+ });
52
+ return server;
53
+ }
package/dist/sources.js CHANGED
@@ -13,5 +13,5 @@ export const DATAVILLE_SOURCES = [
13
13
  { name: "openalex", description: "OpenAlex scholarly works" },
14
14
  { name: "pypi", description: "PyPI package metadata" },
15
15
  { name: "stackexchange", description: "Stack Exchange Q&A" },
16
- { name: "news", description: "News front-page headlines and summaries" },
16
+ { name: "news", description: "Front-page news headlines from a historical archive (not live/current news)" },
17
17
  ];
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@dataville/dataville-mcp",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
+ "mcpName": "com.dataville/dataville-mcp",
4
5
  "description": "MCP server exposing Dataville's data source API as tools for MCP clients",
5
6
  "private": false,
6
7
  "license": "MIT",