Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8c79030
feat: add AI Research Tools page under Learn menu
nesanders May 29, 2026
4d27dfd
feat: add parallel embedding backfill script with exponential backoff
nesanders May 30, 2026
91fbbd2
feat: add Dockerfile and Next.js proxy rewrite for MCP server Cloud R…
nesanders May 31, 2026
5c36346
feat: add per-token rate limiting and Cloud Run deployment for dev
nesanders May 31, 2026
1a3f9e8
feat: implement Option B proxy — Next.js API route forwards to privat…
nesanders May 31, 2026
0e5a55a
feat: implement B1 — Firebase Function proxy for MCP server
nesanders May 31, 2026
30d8d4f
fix: set MCP_SERVER_URL env var for mcpProxy function on dev
nesanders May 31, 2026
b027b17
fix: resolve full proxy chain for Firebase Function → Cloud Run MCP. …
nesanders Jun 1, 2026
bbce16f
chore: remove debug logging from mcpProxy function
nesanders Jun 1, 2026
9340796
docs: polish AI Research Tools user guide
nesanders Jun 1, 2026
8aa78a7
chore: update lockfiles after google-auth-library install
nesanders Jun 1, 2026
4f45cec
chore: ignore .gcloudignore
nesanders Jun 1, 2026
3704e9e
style: apply Prettier formatting
nesanders Jun 2, 2026
c5a753a
chore: gitignore CLAUDE.md (local dev notes)
nesanders Jun 2, 2026
5c5a5d3
chore: merge upstream/main, resolve functions/yarn.lock conflict
nesanders Jun 2, 2026
18682b0
docs: update implementation plan with current architecture and auth f…
nesanders Jun 3, 2026
c32d74c
style: apply Prettier formatting to implementation_plan.md
nesanders Jun 3, 2026
da5b462
fix: address PR review comment
nesanders Jun 18, 2026
8fa3937
Merge remote-tracking branch 'upstream/main' into mcp-server-deploy
nesanders Jun 18, 2026
7b0f035
chore: remove unused google-auth-library, restore yarn.lock registry
nesanders Jun 18, 2026
5dbf308
feat: extract hardcoded strings to i18n for AI pages
nesanders Jun 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,5 @@ cert.txt
# local MCP server config (contains auth tokens)
.mcp.json
mcp-server/create-agent-key.ts
.gcloudignore
CLAUDE.md
3 changes: 3 additions & 0 deletions components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
NavbarLinkBallotQuestions,
DESKTOP_NAV_ITEM_CLASS,
NavbarLinkAI,
NavbarLinkAiTools,
NavbarLinkBills,
NavbarLinkHearings,
NavbarLinkEditProfile,
Expand Down Expand Up @@ -92,6 +93,7 @@ const MobileNav: React.FC<React.PropsWithChildren<unknown>> = () => {
<NavbarLinkEffective handleClick={closeNav} />
<NavbarLinkProcess handleClick={closeNav} />
<NavbarLinkWhyUse handleClick={closeNav} />
<NavbarLinkAiTools handleClick={closeNav} />
</NavDropdown>
</Nav>
)
Expand Down Expand Up @@ -270,6 +272,7 @@ const DesktopNav: React.FC<React.PropsWithChildren<unknown>> = () => {
<NavbarLinkEffective />
<NavbarLinkProcess />
<NavbarLinkWhyUse />
<NavbarLinkAiTools />
</Dropdown.Menu>
</Dropdown>
</div>
Expand Down
20 changes: 20 additions & 0 deletions components/NavbarComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,26 @@ export const Avatar = () => {
)
}

export const NavbarLinkAiTools: React.FC<
React.PropsWithChildren<{
handleClick?: any
other?: any
}>
> = ({ handleClick, other }) => {
const isMobile = useMediaQuery("(max-width: 768px)")
const { t } = useTranslation(["common", "auth"])
return (
<NavbarDropdownLink
className={isMobile ? "navLink-primary" : ""}
href="/learn/ai-tools"
handleClick={handleClick}
other={other}
>
{t("navigation.aiTools")}
</NavbarDropdownLink>
)
}

export const NavbarLinkAI: React.FC<
React.PropsWithChildren<{
handleClick?: any
Expand Down
16 changes: 16 additions & 0 deletions components/about/MapleAI/MapleAI.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useTranslation } from "next-i18next"
import { Container, Row, Col } from "../../bootstrap"
import { Internal } from "../../links"
import {
MemberItem,
Divider,
Expand Down Expand Up @@ -184,6 +185,21 @@ const MapleAI = () => {
</SectionContainer>
</Col>
</Row>
<Row>
<Col className="py-3">
<SectionContainer>
<SectionTitle className="p-2">{t("aiResearch.title")}</SectionTitle>
<DescrContainer className="py-3 px-4">
{t("aiResearch.desc")}
</DescrContainer>
<DescrContainer className="pb-3 px-4">
<Internal href="/learn/ai-tools">
{t("aiResearch.linkText")}
</Internal>
</DescrContainer>
</SectionContainer>
</Col>
</Row>
Comment on lines +188 to +202

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to move the text from this section into mapleAI.json for translatability.

</Container>
)
}
Expand Down
313 changes: 313 additions & 0 deletions components/learn/AiTools/AiTools.tsx

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This page has a bunch of text that could be moved to a json for next-i18next translatability. Could use mapleAI.json.

Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
import { useTranslation } from "next-i18next"
import styled from "styled-components"
import { Container, Row, Col } from "../../bootstrap"
import {
DescrContainer,
Divider,
PageDescr,
PageTitle,
SectionContainer,
SectionTitle
} from "../../shared/CommonComponents"
import { Internal } from "../../links"

const ExampleBox = styled.div`
background: var(--maple-surface-raised);
border-left: 4px solid var(--maple-brand-primary);
border-radius: 0 var(--maple-radius-md) var(--maple-radius-md) 0;
padding: 1rem 1.25rem;
margin: 0.75rem 0;
font-size: 15px;
font-style: italic;
color: var(--maple-text-body);
`

const StepNumber = styled.div`
display: flex;
align-items: center;
justify-content: center;
width: 2rem;
height: 2rem;
border-radius: 50%;
background: var(--maple-brand-primary);
color: white;
font-weight: 700;
font-size: 1rem;
flex-shrink: 0;
margin-right: 0.75rem;
`

const StepRow = styled.div`
display: flex;
align-items: flex-start;
padding: 0.75rem 1.25rem;
`

const StepText = styled.div`
font-size: 16px;
font-weight: 500;
color: var(--maple-text-body);
line-height: 1.5;
`

const ExampleLabel = styled.div`
font-size: 13px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--maple-brand-primary);
margin-bottom: 0.25rem;
`

export const AiTools = () => {
const { t } = useTranslation("aiTools")

return (
<Container>
<Row>
<Col>
<PageTitle>{t("title")}</PageTitle>
</Col>
</Row>
<Row>
<Col className="py-3">
<PageDescr>{t("description")}</PageDescr>
</Col>
</Row>

{/* What is it */}
<Row>
<Col className="py-3">
<SectionContainer>
<SectionTitle className="p-2">{t("section1.title")}</SectionTitle>
<DescrContainer className="py-3 px-4">
{t("section1.desc1")}
</DescrContainer>
<DescrContainer className="pb-3 px-4">
{t("section1.desc2Pre")}{" "}
<b>
<a
href="https://modelcontextprotocol.io/introduction"
target="_blank"
rel="noreferrer"
>
{t("section1.desc2LinkText")}
</a>
</b>
{t("section1.desc2Post")}
</DescrContainer>
</SectionContainer>
</Col>
</Row>

{/* What you can do */}
<Row>
<Col className="py-3">
<SectionContainer>
<SectionTitle className="p-2">{t("section2.title")}</SectionTitle>
<DescrContainer className="py-3 px-4">
{t("section2.intro")}
</DescrContainer>
<DescrContainer className="pb-1 px-4">
<ul>
<li className="pb-3">
<b>{t("section2.item1Bold")}</b> {t("section2.item1Main")}
</li>
<li className="pb-3">
<b>{t("section2.item2Bold")}</b> {t("section2.item2Main")}
</li>
<li className="pb-3">
<b>{t("section2.item3Bold")}</b> {t("section2.item3Main")}
</li>
<li className="pb-3">
<b>{t("section2.item4Bold")}</b> {t("section2.item4Main")}
</li>
<li className="pb-3">
<b>{t("section2.item5Bold")}</b> {t("section2.item5Main")}
</li>
<li className="pb-3">
<b>{t("section2.item6Bold")}</b> {t("section2.item6Main")}
</li>
<li>
<b>{t("section2.item7Bold")}</b> {t("section2.item7Main")}
</li>
</ul>
</DescrContainer>
</SectionContainer>
</Col>
</Row>

{/* Examples */}
<Row>
<Col className="py-3">
<SectionContainer>
<SectionTitle className="p-2">{t("section3.title")}</SectionTitle>
<DescrContainer className="py-3 px-4">
{t("section3.intro")}
</DescrContainer>
<div className="px-4 pb-4">
<ExampleLabel>{t("section3.example1Label")}</ExampleLabel>
<ExampleBox>
&ldquo;{t("section3.example1Text")}&rdquo;
</ExampleBox>

<ExampleLabel>{t("section3.example2Label")}</ExampleLabel>
<ExampleBox>
&ldquo;{t("section3.example2Text")}&rdquo;
</ExampleBox>

<ExampleLabel>{t("section3.example3Label")}</ExampleLabel>
<ExampleBox>
&ldquo;{t("section3.example3Text")}&rdquo;
</ExampleBox>

<ExampleLabel>{t("section3.example4Label")}</ExampleLabel>
<ExampleBox>
&ldquo;{t("section3.example4Text")}&rdquo;
</ExampleBox>
</div>
</SectionContainer>
</Col>
</Row>

{/* How to get started */}
<Row>
<Col className="py-3">
<SectionContainer>
<SectionTitle className="p-2">{t("section4.title")}</SectionTitle>
<DescrContainer className="py-3 px-4">
{t("section4.intro")}
</DescrContainer>
<StepRow>
<StepNumber>1</StepNumber>
<StepText>
<b>{t("section4.step1Bold")}</b> {t("section4.step1Pre")}{" "}
<Internal href="/login">{t("section4.step1LinkText")}</Internal>
{t("section4.step1Post")}
</StepText>
</StepRow>
<Divider />
<StepRow>
<StepNumber>2</StepNumber>
<StepText>
<b>{t("section4.step2Bold")}</b> {t("section4.step2Intro")}
<ul style={{ marginTop: "0.5rem" }}>
<li className="pb-2">
<b>{t("section4.step2item1Bold")}</b>{" "}
{t("section4.step2item1Tag")} {t("section4.step2item1Pre")}{" "}
<a
href="https://claude.ai/download"
target="_blank"
rel="noreferrer"
>
{t("section4.step2item1Link1")}
</a>
{t("section4.step2item1Mid")}{" "}
<a
href="https://modelcontextprotocol.io/quickstart/user"
target="_blank"
rel="noreferrer"
>
{t("section4.step2item1Link2")}
</a>
{t("section4.step2item1Post")}
</li>
<li className="pb-2">
<b>{t("section4.step2item2Bold")}</b>{" "}
{t("section4.step2item2Tag")} {t("section4.step2item2Pre")}{" "}
<a
href="https://help.openai.com/en/articles/11487775-connectors-in-chatgpt"
target="_blank"
rel="noreferrer"
>
{t("section4.step2item2LinkText")}
</a>{" "}
{t("section4.step2item2Post")}
</li>
<li>
<b>{t("section4.step2item3Bold")}</b>{" "}
{t("section4.step2item3Main")}
</li>
</ul>
</StepText>
</StepRow>
<Divider />
<StepRow>
<StepNumber>3</StepNumber>
<StepText>
<b>{t("section4.step3Bold")}</b> {t("section4.step3Pre")}{" "}
<Internal href="/dev/token">
{t("section4.step3LinkText")}
</Internal>{" "}
{t("section4.step3Post")}
</StepText>
</StepRow>
<Divider />
<StepRow>
<StepNumber>4</StepNumber>
<StepText>
<b>{t("section4.step4Bold")}</b> {t("section4.step4Pre")}{" "}
<code>YOUR_TOKEN_HERE</code> {t("section4.step4Post")}
</StepText>
</StepRow>
<div className="px-4 pb-4">
<pre
style={{
background: "var(--maple-surface-raised)",
borderRadius: "var(--maple-radius-md)",
padding: "1rem",
fontSize: "13px",
overflowX: "auto"
}}
>{`{
"mcpServers": {
"maple": {
"type": "http",
"url": "https://mapletestimony.org/api/mcp",
"headers": {
"X-Maple-Token": "Bearer YOUR_TOKEN_HERE"
}
}
}
}`}</pre>
</div>
<Divider />
<StepRow>
<StepNumber>5</StepNumber>
<StepText>
<b>{t("section4.step5Bold")}</b> {t("section4.step5Post")}
</StepText>
</StepRow>
<DescrContainer className="py-3 px-4">
<b>{t("section4.needHelp")}</b> {t("section4.needHelpPost")}{" "}
<a href="mailto:info@mapletestimony.org">
info@mapletestimony.org
</a>
.
</DescrContainer>
</SectionContainer>
</Col>
</Row>

{/* Privacy */}
<Row>
<Col className="py-3">
<SectionContainer>
<SectionTitle className="p-2">{t("section5.title")}</SectionTitle>
<DescrContainer className="py-3 px-4">
{t("section5.desc1")}
</DescrContainer>
<DescrContainer className="pb-3 px-4">
{t("section5.desc2Pre")}{" "}
<Internal href="/about/how-maple-uses-ai">
{t("section5.desc2LinkText")}
</Internal>
</DescrContainer>
</SectionContainer>
</Col>
</Row>
</Container>
)
}

export default AiTools
Loading
Loading