nsf-awards-mcp
by MCP-Hive
README.md
# nsf-awards-mcp
MCP server for NSF award and funding data, packaged for one-line activation.
```
npx -y github:MCP-Hive/nsf-awards-mcp
```
This is a fork of [`@access-mcp/nsf-awards`](https://github.com/necyberteam/access-mcp/tree/main/packages/nsf-awards)
by ACCESS-CI, patched so that it starts when launched through `npx`. All of the
NSF query logic is upstream's; see [Relationship to upstream](#relationship-to-upstream).
## What it does
One tool, `search_nsf_awards`, over the [NSF Award Search API](https://resources.research.gov/common/webapi/awardapisearch-v1.htm):
| Parameter | Type | Purpose |
|---|---|---|
| `id` | string | Fetch a specific award by number, e.g. `2138259` |
| `query` | string | Search keywords in titles and abstracts |
| `pi` | string | Look up awards by principal investigator |
| `institution` | string | Filter by awardee organization |
| `primary_only` | boolean | Only awards where the institution is the primary recipient |
| `limit` | number | Max results (default 10) |
Returns `{total, items}`, where each item carries award number, title,
institution, PI and co-PIs, intended and to-date amounts, start and end dates,
and the abstract.
The upstream NSF API needs no API key, no registration, and no payment. NSF
award data, abstracts included, is a US government work in the public domain.
## Why this fork exists
Upstream's `src/index.ts` ends with:
```ts
if (import.meta.url === `file://${process.argv[1]}`) {
main().catch(...);
}
```
`npx` runs a package through its bin symlink. Node resolves symlinks when
computing `import.meta.url` but leaves `process.argv[1]` unresolved, so the two
are never equal, `main()` is never called, and the process exits 0 without ever
speaking JSON-RPC. The client sees only a closed connection:
```
$ npx -y @access-mcp/nsf-awards
(exits 0, no output)
```
This fork calls `main()` unconditionally, matching what the other servers in the
upstream monorepo already do.
Reported upstream as [necyberteam/access-mcp#66](https://github.com/necyberteam/access-mcp/issues/66).
If that is fixed and released, this fork stops being necessary.
## Relationship to upstream
Forked from `necyberteam/access-mcp` at commit
[`99004ce`](https://github.com/necyberteam/access-mcp/commit/99004ce7e52542e2b40d524341a1633fda0b8bf3).
Changes made here, and nothing else:
1. **`src/index.ts`** — removed the main-module guard described above.
2. **`vendor/access-mcp-shared/`** — vendored `packages/shared` from the same
commit. The published `@access-mcp/shared@0.9.0` tarball is *older* than its
own source tree and does not export `projectFields`, which
`src/server.ts` imports, so resolving that dependency from npm does not
build. Vendoring at the pinned commit keeps the tree self-consistent.
3. **Packaging** — a single bundled `server/bundle.mjs` and a root `bin`, so the
`npx -y github:` form works.
`src/server.ts` is unmodified.
## Packaging notes
Upstream is a `workspaces` monorepo whose root has no `bin`, so `npx` against a
plain fork of it has nothing to run. This repo is therefore a standalone
extraction with one `bin` at the root.
`build-bundle.mjs` inlines the source and every runtime dependency into
`server/bundle.mjs`, which is committed. The package declares **no runtime
`dependencies` and no `prepare` script**, so `npx -y github:...` clones the repo
and immediately executes — nothing to install, nothing to compile. That matters
when the server is cold-started inside a Lambda container.
The bundle is ESM because `src/server.ts` uses `createRequire(import.meta.url)`.
A `createRequire` shim is injected after the shebang for the CommonJS transitive
dependencies that call `require()` for node builtins.
## Development
```
npm install # dev dependencies only, needed to rebuild
npm run bundle # rebuild server/bundle.mjs
npm run smoketest # spawn the bundle, list tools, run a live NSF query
```
Verify the published one-liner end to end:
```
npm run smoketest -- github:MCP-Hive/nsf-awards-mcp
```
Commit the rebuilt `server/bundle.mjs` — it is the artifact `npx` executes.
## License
MIT, inherited from ACCESS-CI. See [LICENSE](LICENSE).
TDQS
A3.6/5.0
Scored across 1 tool
Disambiguation5/5
With only one tool, there is no possibility of confusion between tools. The tool's purpose is clearly described as searching NSF awards.
Naming Consistency5/5
The single tool name 'search_nsf_awards' follows a clear verb_noun snake_case convention, which is consistent with standard MCP naming practices and predictable.
Tool Count3/5
At one tool, the server feels thin, but it is scoped to a specific search function. This is borderline for the stated purpose of searching NSF awards and funding.
Completeness4/5
The search tool covers the primary need, but there are minor gaps such as lacking a direct 'get award by ID' endpoint. Agents can work around this by searching for and retrieving specific items from the results.
Maintenance
ActivityMaintained
ResponsivenessNo issues